TECH 으로 돌아가기
TECH HACKER NEWS 오늘 8분 읽기 24 READS

M4 맥에 리눅스를 올리기까지: WFI 명령어가 레지스터를 지우는 하드웨어의 함정

M4 맥에 리눅스를 올리기까지: WFI 명령어가 레지스터를 지우는 하드웨어의 함정
SOURCE IMAGE · HACKER NEWS

애플 실리콘 기반 맥에서 메인라인 리눅스를 돌리려는 노력은 아사히 리눅스(Asahi Linux) 프로젝트를 중심으로 수년째 이어져 왔다. M1부터 M3까지는 m1n1 하이퍼바이저로 macOS 드라이버와 하드웨어가 주고받는 MMIO(메모리 맵 입출력) 접근을 추적해 동작을 역분석하는 방식이 효과적이었다. 그런데 2024년 11월에 구입한 M4 맥 미니는 이전 세대와 비슷하리라는 기대와 달리 새로운 벽에 부딪혔다. M4가 애플 실리콘 중 처음으로 SPTM(Secure Page Table Monitor)을 강제하는 세대였기 때문이다. SPTM은 macOS XNU 커널의 취약점을 완화하기 위한 하드웨어 보안 기능인데, 이 때문에 macOS를 하이퍼바이저 아래에서 구동하려면 m1n1에 상당한 수정이 필요했고, 기존의 MMIO 추적 기반 역분석 경로가 사실상 막혔다.

부팅의 첫 관문들

하이퍼바이저 작업과 별개로, 저자는 보안 부팅을 완화하고 macOS 복구 모드를 통해 m1n1을 커스텀 부트 오브젝트로 설치한 뒤 시리얼 콘솔로 로그를 들여다보며 리눅스 부팅을 직접 시도했다. 초기에는 m1n1이 BRINGUP 모드에서만 겨우 시작됐고, 그 외에는 GXF(Guarded Exception Levels) 초기화 도중 바로 크래시가 났다. 확인 결과 M4 계열 SoC의 로우 부트(raw boot) 모드에서는 GXF 기능이 잠겨 있거나 비활성화되어 있었고, 해당 머신에서는 초기화를 조건부로 건너뛰는 것이 올바른 처리였다. 또 하나의 걸림돌은 RVBAR(Reset Vector Base Address Register), 즉 각 CPU 코어가 전원이 켜질 때 실행을 시작하는 주소를 지정하는 레지스터였다. m1n1은 평소 이 값을 직접 써넣지만 M4에서는 그 쓰기 동작 자체가 크래시를 유발했다. 다행히 이미 올바른 값이 들어 있어, 쓰기를 생략하는 것으로 해결됐다.

커널이 실제로 실행되는지조차 알 수 없던 단계에서는 가장 원시적인 방법이 돌파구가 됐다. m1n1의 debug_putc 어셈블리 루틴을 가져와 글자 'a' 하나를 찍도록 고쳐 커널 부팅 극초기 코드에 삽입했고, "Vectoring to next stage" 다음에 'a'가 출력되는 것을 확인했다. 이렇게 부팅 코드를 이분 탐색한 끝에 문제 지점이 arch/arm64/kernel/head.S의 MMU 초기화 코드임을 짚어냈다. 원인은 MMU 자체의 크래시가 아니라 UART 접근 방식이었다. MMU가 켜지면 모든 메모리 접근이 페이지 테이블을 통해 물리 주소로 변환되는데, m1n1은 MMIO 영역을 동일한 가상 주소로 노출하는 매핑을 만드는 반면 리눅스는 그렇게 하지 않아, MMU 활성화 직후 UART에 접근할 수 없게 되는 것이었다. 여기에 디바이스 트리에 stdout-path = "serial0" 지정이 빠져 있던 점까지 보완하자, 비로소 리눅스가 초기 크래시 때마다 레지스터 덤프와 스택 트레이스를 쏟아내기 시작했다.

핵심 난제: 아키텍처 규격을 어기는 WFI

m1n1이 보조 코어를 띄우지 않던 문제는 하드코딩된 smp_start_offset 값이 비어 있던 탓이었고, M1~M3용 값을 넣자 보조 코어가 기동했다. 그러나 곧 더 난해한 크래시가 나타났다. 애플 실리콘은 예전부터 WFI(Wait For Interrupt) 명령에 관한 특이 동작이 있었다. XNU 코드에서 ARM64_REG_CYC_OVRD_ok2pwrdn_force_mask라 불리는 치킨 비트(chicken bit)의 상태에 따라, WFI를 실행하면 CPU 레지스터 x0~x31이 0으로 지워진다. XNU는 이를 대비해 WFI 전후로 레지스터를 스택에 저장했다 복원했고, M1~M3에서는 m1n1이 이 동작을 꺼서 일반 arm64 프로세서처럼 만들었다. 아사히 커널은 이후 더 깊은 절전 상태 진입과 단일 코어 부스트를 위해 이 동작을 다시 켰다.

문제는 M4에서 이 치킨 비트가 잠겼거나 아예 사라진 것으로 보이며, 기본 동작이 ARM64 규격을 위반한다는 데 있다. 규격은 WFI가 완료될 수 있는 구성이라면 아키텍처 상태를 잃어서는 안 된다고 명시하지만, M4는 그렇지 않았다. 2026년 4월, 저자는 커널 내 모든 WFI와 WFIT(타임아웃이 있는 WFI) 명령을 NOP(아무 동작도 하지 않는 명령)으로 치환하는 방식으로 모든 코어를 켠 채 리눅스를 부팅하는 데 성공했다. 이 WFI 우회는 M4 Pro, M4 Max, 그리고 M5 칩에서도 동일하게 통하는 것으로 확인됐다.

상류화를 둘러싼 해법

임시 성공을 메인라인에 반영하는 과정은 간단치 않았다. 처음에는 실리콘의 오동작을 부팅 중 메모리 패치로 바로잡는 리눅스의 기존 에라타(errata) 프레임워크를 검토했으나 폐기됐다. WFI를 NOP으로 바꿔야 하는 경우를 정확히 판별하기가 어렵기 때문이다. 특히 macOS 하이퍼바이저 위의 가상 머신에서는 WFI가 트랩되어 게스트 스케줄링에 쓰이는데, 이 경우까지 에라타 로직이 발동하면 곤란하고, 중첩 가상화까지 고려하면 가상화 여부 탐지 자체가 복잡해진다. 이에 Will Deacon은 다른 방향을 제안했다. 커널이 새로운 부트 인자로 WFI 유휴 동작을 끌 수 있게 하고, m1n1이 WFI가 고장 난 것으로 알려진 베어메탈 머신에서만 조건부로 해당 인자를 붙이도록 하는 것이다. 코어를 절전 상태로 보내는 일은 당분간 다운스트림 cpuidle-apple 드라이버가 맡되, Sven의 PSCI EFI conduit 작업이 향후 상류 해법으로 유망하다고 평가됐다.

결과적으로 WFI·WFIT 크래시를 막는 메커니즘은 메인라인 리눅스와 m1n1 모두에 병합됐고, 최신 릴리스는 M4 맥에서 보조 코어까지 포함해 네이티브로 셸까지 부팅할 수 있게 됐다. 다만 실무적 관점에서 이 성과의 위치를 분명히 해 둘 필요가 있다. 지금 확보된 것은 모든 코어를 쓰며 셸에 도달하는 수준이지 일상적으로 쓸 수 있는 데스크톱 환경이 아니다. 내장 카메라, 디스플레이 컨트롤러, GPU 초기화 같은 복잡한 주변장치의 역분석은 여전히 느리지만 꾸준히 진행 중이며, 이들 작업에는 macOS를 하이퍼바이저 아래에서 추적할 수 있게 하는 Sven의 m1n1 작업이 토대가 된다. 요컨대 M4 이후 세대의 근본적인 부팅 장애물 하나가 제거된 것이며, 그 성과가 아사히 리눅스가 아니라 상류 프로젝트에 직접 반영돼 모두가 활용할 수 있게 됐다는 점이 이번 작업의 실질적 의미다.

SOURCE · HACKER NEWS
원문 전체 보기 → https://yuka.dev/blog-2026-10-02-linux-m4.html
SHARE
NEXT · CHOOSE

변화를 읽었다면,
내가 만들 수익 구조를 고릅니다.

정보를 더 모으는 데서 멈추지 않고, 광고·외주·판매·중개·구독 중 내 상황에 맞는 출발점을 정해보세요.

21가지 수익 구조 살펴보기 →
처리 중...