---
title: "Mac OS X를 닌텐도 Wii에 포팅한 이야기 — 부트로더부터 USB 드라이버까지"
published: 2026-04-08T15:40:00.000Z
canonical: https://jeff.news/article/1627
---
# Mac OS X를 닌텐도 Wii에 포팅한 이야기 — 부트로더부터 USB 드라이버까지

Mac OS X 10.0 Cheetah를 닌텐도 Wii에서 네이티브로 구동하는 데 성공한 프로젝트. 커스텀 부트로더 작성, XNU 커널 패치, Hollywood SoC용 IOKit 드라이버 개발, 듀얼 프레임버퍼(RGB→YUV 변환), USB 지원까지 전 과정을 상세히 다룸.

- **Mac OS X 10.0 Cheetah를 닌텐도 Wii에서 네이티브로 돌렸다** — Linux, NetBSD, Windows NT에 이어 Wii에 포팅된 네 번째 OS. 2013년 대학교 2학년 때 아이디어만 품고 10년 넘게 묵혔다가 드디어 완성
  - 2021년 Reddit 댓글: "이게 될 확률은 0%다" → 오히려 동기부여가 됐다고 함

## 하드웨어 호환성 분석

- Wii의 CPU는 PowerPC 750CL — G3 iBook/iMac에 쓰인 PowerPC 750CXe의 진화형이라 CPU 자체는 호환 가능성 높았음
- RAM이 문제였음: Wii는 88MB인데 MEM1(24MB 1T-SRAM) + MEM2(64MB GDDR3)로 분리된 특이한 구조
  - Mac OS X Cheetah 공식 요구사항은 128MB지만, 비공식으로 더 적은 메모리에서도 부팅 가능
  - QEMU로 64MB RAM에서 Cheetah 부팅 테스트 → 문제없이 동작 확인

## 부트로더를 밑바닥부터 작성

- 실제 맥은 Open Firmware → BootX → XNU 커널 순서로 부팅하는데, XNU가 돌기 시작하면 앞의 두 단계는 더 이상 필요 없음
  - Open Firmware나 BootX를 포팅하는 건 불필요한 삽질이라고 판단, Wii Linux 프로젝트처럼 커스텀 부트로더를 처음부터 작성
- 부트로더가 해야 할 일: Wii 하드웨어 초기화 → SD 카드에서 커널 로드 → 디바이스 트리 생성 → 커널에 제어 넘기기
- Mach-O 바이너리 포맷으로 된 XNU 커널을 메모리에 올리는 로더를 구현하고, 커널 진입점 주소로 점프하는 방식

> [!IMPORTANT]
> 커널이 실행되면서 Wii 전용 하드웨어 설정을 덮어쓰기 때문에, 시리얼 디버깅이나 비디오 출력이 전부 꺼져버림. 이걸 해결하려고 **커널 바이너리를 패치해서 Wii 전면 LED를 깜빡이게** 만들어 "여기까지는 왔다"를 확인하는 방법을 씀

## 커널 패치와 빌드 환경

- XNU는 Wii의 메모리 레이아웃(MEM1: 0x00000000, MEM2: 0x10000000)과 호환 안 되는 BAT(Block Address Translation) 설정을 함
  - 커널 소스를 직접 수정해서 Wii 메모리 레이아웃에 맞춤
- 25년 된 OS 커널을 빌드하기 위한 개발환경이 꽤 기발함:
  - 모던 macOS 호스트에서 QEMU로 Mac OS X Cheetah 게스트를 돌림 (헤드리스)
  - NFS로 소스 코드 공유, SSH로 게스트 제어, 호스트에서 편집 → 게스트에서 빌드
- BAT 패치 + USB Gecko로 콘솔 출력 리다이렉트 후, 가상 메모리·IOKit·BSD 서브시스템 모두 초기화 성공 — "Still waiting for root device"까지 도달

## IOKit 드라이버 작성 — Hollywood SoC 대응

- Wii는 PCI 버스가 아니라 Hollywood라는 커스텀 SoC를 사용함 → IOPCIFamily를 그대로 쓸 수 없어서 Hollywood용 드라이버를 직접 구현
  - Hollywood 드라이버가 디바이스 트리의 하위 노드를 순회하면서 nub(연결점)을 생성·발행
- **SD 카드 드라이버**: IOBlockStorageDevice를 서브클래싱
  - Wii의 ARM 코프로세서(Starlet)에서 돌아가는 MINI와 IPC로 통신하여 SD 카드 읽기/쓰기 구현
  - 캐시된 메모리 버그가 까다로웠음 — ARM CPU가 RAM에 쓴 데이터를 PowerPC CPU가 캐시에서 읽어 stale 데이터를 받는 문제 → uncached 메모리 사용으로 해결
- **프레임버퍼 드라이버**: Wii의 비디오 하드웨어는 YUV 16bit를 기대하는데 Mac OS X는 RGB를 씀
  - Wii Linux 프로젝트에서 영감받아 **듀얼 프레임버퍼 전략** 적용: RGB 프레임버퍼(OS용) + YUV 프레임버퍼(디스플레이용), 초당 60회 변환

## USB 지원 — 소스 코드 없는 디버깅의 고통

- AppleUSBOHCI 드라이버를 쓰려 했는데 3가지 장벽:
  - Apple이 Cheetah/Puma용 IOUSBFamily 소스를 공개하지 않음 (다른 건 다 있는데!)
  - AppleUSBOHCI가 IOPCIDevice에만 붙게 되어 있어서, Wii의 Hollywood nub에 매칭 안 됨 → IOPCIDevice를 상속한 가짜 PCI nub을 만들어 우회
  - Wii는 하드웨어에서 바이트 스왑(reversed-little-endian)을 하는데, IOUSBFamily는 소프트웨어에서도 스왑 → **이중 스왑 문제** 발생
- Ghidra로 바이트 스왑 명령어를 수동 패치하려 했으나 실패 (비행기에서 몇 시간 삽질...)
  - 결국 IRC에서 옛날 CVS 레포를 구해서 IOUSBFamily를 소스에서 빌드 → USB 키보드/마우스 동작 성공

- **최종 결과: Mac OS X Cheetah가 Wii에서 풀 데스크톱으로 부팅되고 USB 키보드/마우스로 조작 가능** — 하와이 여행 중에 Wii를 가져가서 마일스톤을 찍었다는 게 진짜 집념

---

## 기술 맥락

- 이 프로젝트가 가능했던 핵심 이유는 Darwin/XNU가 오픈소스라는 거예요. 커널과 IOKit 드라이버 모델이 공개되어 있으니까, 하드웨어만 비슷하면 포팅 시도라도 해볼 수 있는 거거든요. 반대로 Quartz나 Finder 같은 GUI 계층은 닫혀 있지만, 커널만 돌아가면 그 위에 얹히는 구조라 별도 패치 없이 동작해요.
- IOKit의 provider-client 모델이 이 프로젝트에서 핵심적인 역할을 했어요. 드라이버가 nub을 통해 체인처럼 연결되는 구조라, Hollywood SoC용 드라이버만 제대로 만들면 그 위에 SD 카드, USB 등을 쌓아올릴 수 있었거든요. PCI가 없는 환경에서 IOPCIDevice를 상속한 가짜 nub을 만든 건 꽤 창의적인 해킹이에요.
- Wii의 reversed-little-endian 바이트 오더링 문제는 크로스 플랫폼 하드웨어 개발에서 자주 만나는 함정이에요. 하드웨어가 이미 엔디안 변환을 해주는데 소프트웨어도 변환하면 이중 스왑이 되는 건데, 소스 코드 없이 바이너리만으로 이걸 고치려다 실패한 게 오히려 교훈적이에요. 결국 소스 코드의 가치를 증명한 셈이죠.
- 25년 된 커널을 빌드하기 위해 QEMU + NFS + SSH를 조합한 크로스 컴파일 환경 구성도 흥미로워요. 레거시 소프트웨어 빌드 환경을 재현하는 건 실무에서도 종종 마주치는 문제인데, 가상화로 당시 OS를 그대로 올리는 게 가장 확실한 방법이에요.

## 핵심 포인트

- Wii의 PowerPC 750CL CPU가 G3 맥과 같은 계열이라 포팅 가능성이 있었음
- Open Firmware/BootX 대신 커스텀 부트로더를 밑바닥부터 작성
- Wii 전용 Hollywood SoC에 맞는 IOKit 드라이버를 직접 구현 — SD 카드, 프레임버퍼, USB까지
- YUV/RGB 불일치를 듀얼 프레임버퍼 전략으로 해결
- IRC에서 구한 옛날 CVS 레포로 IOUSBFamily 소스 빌드에 성공하여 USB 입력 완성

## 인사이트

2013년부터 품어온 아이디어를 10년 넘게 묵혔다가, Windows NT의 Wii 포팅 소식에 자극받아 완성한 프로젝트. Darwin/XNU 오픈소스 덕에 가능했고, 소스 코드 없이 바이너리 패치로 해결하려다 실패한 USB 파트가 오히려 오픈소스의 가치를 증명함.
