[릴스 해설] 닌텐도 위(Wii)에서 Mac OS X을 돌린 프로젝트, 기술 풀어보기


이 글은 기술 릴스에 등장한 기술을 풀어 설명하는 “릴스 해설” 시리즈입니다. 릴스 출처는 Bryan Keller의 블로그(릴스에는 Brian Keller로 표기). 정확한 사실은 원본 프로젝트를 기준으로 정리했어요.

최근 한 릴스가 돌았어요. “닌텐도 위(Wii)로 맥북을 만든 개발자”라는 내용이었죠. 거실에서 볼링 치던 그 게임기에서 애플의 Mac OS X이 돌아간다는 이야기예요. 릴스는 짧아서 “PowerPC라서 가능했다”, “부트로더·커널 패치·드라이버를 손봤다” 정도만 짚고 넘어가요. 그 안에 어떤 기술이 있었는지 풀어봅니다.

정정: 릴스에서는 “Mac OS X 10.4 타이거”가 돌아갔다고 했지만, 원본 프로젝트가 포팅한 건 **10.0 치타(Cheetah)**예요. 타이거는 아직 포팅되지 않았어요. 릴스 대사에 약간 부정확한 부분이 있어요.

왜 위에서 Mac OS X이 가능했나 — PowerPC

열쇠는 CPU 아키텍처였어요. 닌텐도 위의 CPU ’브로드웨이(Broadway)’는 IBM이 만든 PowerPC 750CL로, 729MHz로 동작해요. 이 칩은 애플이 과거 G3 아이북·아이맥에 쓰던 PowerPC 750CXe의 후예예요. 즉 위와 그 시절 Mac은 같은 PowerPC 계열을 썼던 거죠.

애플은 2005~2006년 Intel로 전환하기 전까지 Mac을 PowerPC로 돌렸어요. 그래서 PowerPC용으로 만들어진 옛 Mac OS X을 위의 PowerPC CPU에서 실행할 수 있는 가능성이 있었던 겁니다. CPU가 같은 언어(명령어 집합)를 쓰니까요.

위의 하드웨어, 현실은 어땠나

릴스가 “처참한 스펙”이라고 한 건 사실이에요.

  • CPU: 브로드웨이(PowerPC 750CL) 729MHz — 요즘 스마트워치보다 약한 단일 코어.
  • RAM: 24MB(1T-SRAM, MEM1) + 64MB(GDDR3, MEM2) = 총 88MB.
  • GPU: ’할리우드(Hollywood)’라는 시스템 칩(SoC). 그 안에는 ARM 기반 보조 프로세서 ’스타렛(Starlet)’까지 들어 있어요.

가장 큰 장벽은 메모리예요. Mac OS X 10.0 치타의 공식 최소 메모리는 128MB인데 위는 88MB가 전부예요. 개발자 Bryan Keller는 QEMU(에뮬레이터)로 64MB에서도 치타가 부팅되는지 먼저 검증한 뒤, 시스템에서 쓸데없는 걸 덜어내는 방식으로 88MB에 맞췄어요.

부트로더(Bootloader) — 컴퓨터가 켜질 때 제일 먼저 도는 코드

부트로더는 전원을 켰을 때 운영체제를 메모리에 올리고 실행을 넘겨주는 첫 번째 프로그램이에요.

옛 PowerPC Mac의 부팅 순서는 이랬어요: Open Firmware(펌웨어) → BootX(Mac OS X 부트로더) → XNU(커널). Keller는 여기서 Open Firmware와 BootX를 건너뛰고, 위 전용 부트로더를 처음부터 직접 짰어요(이름도 wiiMac). 위 하드웨어는 고정이라 일일이 스캔할 필요 없이, 최소한의 초기화 + 커널 로드 + 디바이스 트리 생성만 하면 됐거든요.

커널 패치 — Mac OS X의 심장을 고쳐 끼다

Mac OS X의 코어(Darwin)는 오픈소스라서, XNU라는 커널의 소스를 직접 고칠 수 있어요. Keller는 위에 맞게 커널을 패치했어요.

  • 커널은 Mach-O라는 실행 파일 포맷으로 저장돼요. 부트로더는 이 포맷을 해독해 커널을 메모리에 올려요.
  • 위의 메모리 배치(MEM1은 0x00000000, MEM2는 0x10000000)는 Mac OS X가 기대하는 배치와 달라서, 메모리 주소 변환(BAT, Block Address Translation) 설정을 손봤어요.
  • 디버깅은 재밌게도 위 앞면 LED를 깜빡이게 하는 방식으로 했어요. 직렬 디버그 출력이 안 되니까, 커널 안 특정 위치의 명령을 “LED 켜기” 명령으로 바꿔치기(바이너리 패치)하며 진행 상황을 추적한 거예요. 디스어셈블러(Hopper)로 커널 이진 파일을 뜯어봤어요.

디바이스 트리(Device Tree) — 하드웨어 목록을 OS에 알려주기

운영체제는 “이 기기에 어떤 하드웨어가 달려 있다”를 알아야 해요. 진짜 Mac은 부트로더가 하드웨어를 스캔해 이 목록(디바이스 트리)을 만들지만, 위는 하드웨어가 항상 똑같아서 Keller는 그냥 트리를 코드에 하드코딩했어요.

IOKit 드라이버 — OS와 하드웨어를 잇는 다리

드라이버는 운영체제가 하드웨어를 다루게 해주는 코드예요. Mac OS X은 IOKit이라는 드라이버 모델을 쓰는데, C++로 짜고 ‘제공자-클라이언트(provider-client)’ 구조로 이어져요. 특정 장치 드라이버가 ’눕(nub)’이라는 연결점에 붙고, 그 눕이 다시 상위 드라이버와 통신하는 식이에요.

Keller가 위에 맞춰 짠 드라이버들이 핵심이에요.

  • 할리우드(Hollywood) 드라이버: 위는 Mac처럼 PCI 버스를 안 쓰고, ’할리우드’라는 전용 SoC로 하드웨어를 연결해요. 그 안의 ARM 코프로세서 ’스타렛’이 실제 하드웨어 접근을 담당하고, PowerPC 코어와는 IPC(프로세서 간 통신)로 대화해요. Mac용 PCI 드라이버를 그대로 못 쓰니 위 전용 드라이버를 새로 짰어요.
  • SD 카드 드라이버: 시스템이 깔린 SD 카드를 읽으려면 필요해요. 스타렛(ARM)에서 도는 MINI라는 프로그램에 IPC로 명령을 보내 SD 카드를 읽고 썼어요. 까다로운 건 ’캐시 일관성’이에요 — ARM이 쓴 데이터를 PowerPC가 읽을 때 캐시된 옛값이 나오지 않도록, 캐시가 안 되는(uncached) 메모리를 썼어요.
  • 프레임버퍼 드라이버: 화면을 띄우려면 픽셀 데이터가 들어있는 메모리(프레임버퍼)가 필요해요. 문제는 위의 영상 하드웨어가 YUV 포맷을 원하는데 Mac OS X은 RGB를 쓴다는 거였어요. 그래서 RGB 프레임버퍼와 YUV 프레임버퍼 두 개를 두고, 1초에 60번 RGB를 YUV로 변환해 출력하는 방식으로 해결했어요.
  • USB 드라이버: 키보드·마우스를 쓰려면 위의 USB 포트가 작동해야 해요. Mac OS X의 USB 드라이버(AppleUSBOHCI)는 ’리틀 엔디안’을 가정하는데, 위는 ’역 리틀 엔디안(reversed-little-endian)’이라는 특이한 방식이라 바이트 순서가 안 맞았어요. 게다가 그 당시 USB 스택 소스가 없어서 IRC에서 누군가가 공유해 준 옛 소스를 구해 고쳤고, 역어셈블러(Ghidra)로 바이트 스왑 명령을 찾아 패치하기도 했어요.

홈브류와 BootMii — 위에서 임의 코드를 돌리려면

이 모든 작업의 전제는 “위에서 내 코드를 실행할 수 있어야 한다”였어요. 위는 ’탈옥(jailbreak)’이 가능한 기기라서, Homebrew ChannelBootMii 같은 도구로 누구나 하드웨어에 직접 접근해 임의 프로그램을 돌릴 수 있어요. Keller의 부트로더도 이 경로로 실행됐어요.

어떻게 연결되나

한 줄로 요약하면: 같은 PowerPC 계열 CPU라는 공통분모 덕에 Mac OS X을 위에서 실행할 ’가능성’이 있었고, 그 가능성을 직접 짠 부트로더 + 패치한 XNU 커널 + 위 전용 IOKit 드라이버로 현실로 만든 프로젝트예요. 핵심은 Mac OS X의 오픈소스 코어(Darwin/XNU/IOKit)를 고칠 수 있었다는 점이에요. 닫힌 부분(상위 GUI)은 그대로 돌아가게 두고, 열린 부분만 위에 맞춰 손본 거죠.

릴스가 말한 “하드웨어의 한계는 생각보다 유연하다”는 건, 결국 이 ’같은 아키텍처 + 오픈소스 코어 + 집요한 패치’가 만나야 비로소 가능한 이야기였어요.

출처: Bryan Keller의 블로그 “Porting Mac OS X to the Nintendo Wii” + GitHub wiiMac / wii-macosx-cheetah-drivers / MacRumors 보도.