Nintendo GameCube/Wii 계열에 클래식 Mac OS를 이식하는 프로젝트 가 처음으로 데스크톱 부팅에 성공했으며, 실제 Wii 하드웨어에서는 Mac OS 7.6이 약 40초 만에 부팅됨
OpenBIOS와 런타임 패치 로 부팅 환경을 구성하고, Mac OS가 전제하는 Macintosh의 메모리 배치, 인터럽트 컨트롤러, 전원 관리 장치 등을 Nintendo 하드웨어에 맞게 수정함
저장 장치를 SCSI 장치처럼 보이게 하는 드라이버 를 구현하고, 디스크 드라이버 로딩 방식과 부팅 장치 판별, 비정렬 버퍼 처리 문제를 해결해 부팅을 진행함
Dolphin 에뮬레이터와 실제 하드웨어의 차이 도 장애물이었으며, MacsBug 충돌은 에뮬레이션 오류로 확인됨
아직 공개 배포와는 거리가 먼 상태 이며, 다음 작업은 Wii의 SD/USB 컨트롤러 지원, Wii U 이식, 일부 RAM 제한을 넘어서는 패치 실험임
이식 대상과 프로젝트의 출발점
프로젝트는 ArtX 계열 칩셋을 사용하는 PowerPC 시스템 에 클래식 Mac OS를 이식하는 작업으로, GameCube와 Wii를 대상으로 하며 향후 Wii U까지 확장할 계획임
GameCube의 Flipper 통합 칩셋은 ATI가 ArtX를 인수할 당시 사실상 설계가 끝난 상태였음
Wii의 Vegas와 후속 리비전 Bollywood, Wii U의 Latte는 그 직접적인 후계 계열임
이번에 처음 데스크톱 진입 에 성공했으며, CHRP 호환 기종 시대 이후 Apple 외부에서 새로운 시스템에 클래식 Mac OS를 이식해 데스크톱까지 부팅한 첫 사례일 가능성이 있음
기존 NT 이식 작업 중 PowerPC Mac 노트북을 구해 이들에도 NT를 이식했고, 각 기종의 작업이 서로의 개선으로 이어짐
이 과정에서 클래식 Mac OS를 접하고, 1980년대부터 겹겹이 쌓인 각종 편법에 매력을 느낌
TBXI의 m68k 부분은 PowerPC 시대 내내 SuperMario 라는 이름을 사용했음
작업은 업스트림 OpenBIOS를 포크한 2025년 6월 22일 시작됐으며, 코딩 에이전트나 LLM 없이 코딩, 역공학, 디버깅을 직접 수행함
재미와 학습이 목적이므로 AI 사용은 그 목적에 맞지 않는다고 판단함
OpenBIOS와 초기 부팅 환경
“New World” 클래식 Mac OS의 부트로더 Trampoline 은 Open Firmware 환경에서 실행되므로, 먼저 OpenBIOS 를 이식해야 했음
비슷한 시기에 Goldfish64가 Wii용 Mac OS X 이식을 시작하면서 만든 OpenBIOS 포트에서 일부 드라이버를 가져옴
해당 포트는 Wii/Wii U만 대상으로 했지만, 이번 작업은 GameCube도 지원 해야 했으므로 그대로 사용하지 않음
디스플레이 드라이버 등 기존 코드를 재사용하기 위해 NT용 ARC 펌웨어 로더를 빅 엔디언 ELF 를 읽도록 수정함
초기 디스크 접근에는 EXI 버스 용 드라이버 두 개를 이식함. EXI는 Nintendo와 Macronix가 SPI에 붙인 이름임
SD Gecko 는 GameCube 메모리 카드 슬롯을 통해 SPI 방식으로 SD 카드에 접근하는 단순 연결 어댑터임
EXI-IDE 드라이버는 실제 하드웨어가 아니라, 저수준 디버깅을 위해 수정한 Dolphin 트리의 부정확한 에뮬레이션에 맞춰져 있음
이전 NT 포트는 기존 홈브루 로더와 호환되도록 FAT 파일시스템 안의 디스크 이미지 를 사용했으나, FAT32의 이미지 크기 제한은 4GB였고 후기 클래식 Mac OS에는 더 큰 이미지가 필요했음
초기 테스트에서는 디스크 형식을 확정하지 않고 “Mac OS ROM” TBXI 파일을 FAT 파일시스템의 \ppc\bootinfo.txt
에 놓아 OpenBIOS가 로드하게 함
향후 기존 CD 이미지를 거의 수정하지 않고 사용할 수 있도록, 가능한 많은 패치를 실행 시점에 가깝게 적용 하는 방식을 택함
Trampoline의 메모리 배치 가정 수정
Trampoline의 물리 주소 계산 은 Nintendo 하드웨어와 맞지 않았음
버퍼 주소가 잘못된 물리 주소로 계산되는 부분을 유효한 주소로 바꿈
커널의 메모리 청크 목록과 페이지 테이블 항목을 설정하는 대응 코드도 수정함
기존 코드는 물리 주소 0x8000_0000
이상을 MMIO 영역 으로 가정했으며, 원래 실행되던 시스템에서는 PCI 버스 주소 공간에 해당했음
Nintendo 시스템에는 이 가정이 맞지 않고, Wii U에서는 해당 주소가 RAM 일부에 해당함
RAM 영역 사이의 빈 공간 일부에 MMIO가 들어가는 배치도 기존 가정과 충돌함
커널 메모리 청크 목록의 초기 MMIO 매핑 을 물리 주소 0x0100_0000
에서 가상 주소 0xE000_0000
으로, 길이 0x1000_0000
인 매핑으로 바꿈
전체 MMIO와 한 RAM 영역의 끝부분, GameCube 이후 시스템에서는 다른 RAM 영역의 시작 부분까지 포함함
Wii U의 물리 주소 0xD000_0000-0xEFFF_FFFF
는 Radeon R7xx GPU의 HDP 에 연결되므로, 향후 이 블록을 사용할 경우 매핑을 바꿀 수 있음
HDP는 스위즐링이나 엔디언 변환을 적용한 물리 메모리 뷰를 제공해 GPU 전용 형식의 텍스처를 선형 프레임버퍼처럼 보이게 할 수 있음
Trampoline의 매핑 초기화 함수 버전 차이 도 처리함
초기 버전은 페이지 수를 16비트로, 후기 버전은 32비트로 다뤄 구버전을 감지하고 함수를 후킹함
구버전이 0x8000_0000
이상 물리 메모리에 무조건 생성하는 1:1 매핑은 앞서 만든 매핑과 충돌하므로 제거함
Macintosh 하드웨어 전제와 장치 트리 수정
특정 Macintosh 하드웨어를 전제한 초기화 코드 를 패치함
모든 PowerPC Macintosh에 있던 마이크로컨트롤러의 존재를 나타내는 일부 비트 플래그 설정을 제거함
특정 하드웨어 타이머로 버스 주파수를 다시 계산하는 동작을 수정함
이 시스템에는 없는 PCI 연결 리틀 엔디언 인터럽트 컨트롤러의 레지스터 쓰기와 보정 코드를 수정함
모든 코드가 메모리에 로드된 뒤 추가 패치를 적용하도록, 커널 초기화 코드로 넘어가는 마지막 호출을 후킹 함
장치 트리 도 Trampoline이 받아들일 형태로 조정함
인터럽트 컨트롤러는 인식 가능한 기존 리틀 엔디언 장치로 위장함. 레지스터 수준에서 ArtX 계열의 Flipper 인터럽트 컨트롤러와 가장 가까운 장치임
Wii U의 Flipper 계열 컨트롤러는 추가 PowerPC 코어를 지원하도록 일부 변경돼 있음
프레임버퍼 주소를 0xExxx_xxxx
매핑의 비캐시 가상 주소 로 바꿈
가짜 Mac99 호환 전원 관리 장치를 추가해 Trampoline이 전원 관리 드라이버를 준비하게 하고, 나중에 이를 교체함
커널, SuperMario, 네이티브 코드 패치
커널 자체에서는 선택된 인터럽트 컨트롤러 드라이버 를 Flipper에 맞게 수정하며, 사용하지 않는 다른 드라이버 하나의 공간을 활용함
원래 컨트롤러의 레거시 모드는 인터럽트 발생뿐 아니라 인터럽트 상태가 바뀔 때마다 PowerPC 인터럽트를 발생시킴
이 차이를 처리하려고 커널에서 발생한 인터럽트를 마스킹하고, 각 드라이버의 인터럽트 처리기에서 나중에 마스킹을 해제함
SuperMario m68k 코드 에서는 네이티브 인터럽트 컨트롤러 레지스터에 직접 접근하는 경로를 수정함
오디오 인터럽트를 켜고 끄는 함수 포인터는 기존 테이블에 있던 스텁을 이용해 무동작 처리함
부팅 초기에 ADB와 전원 관리 마이크로컨트롤러를 초기화하는 함수는 장치 존재 여부를 검사하지 않아, 장치가 없으면 낮은 주소 영역의 메모리를 훼손함
하드웨어 인터럽트 초기화 함수에는 직렬 포트 1의 코드를 복사하면서 점프 레이블을 바꾸지 않은 버그가 있어, 직렬 포트 2가 없으면 무한 루프에 빠짐
PowerPC 네이티브 실행 코드 의 인터럽트 컨트롤러 직접 접근도 수정함
USBShimKeyboard
초기화 코드는 USB 컨트롤러가 없는 경우를 처리하지 못해 m68k 에뮬레이터 내부에서 NULL 포인터를 호출함
전원 관리 드라이버는 현재 BlueBox의 스텁 드라이버 로 완전히 교체했으며, 추후 정상적인 종료와 재시작을 지원하는 자체 드라이버를 작성할 계획임
이 패치들로 TBXI가 깜빡이는 플로피 아이콘 까지 부팅됨
Elliott Nunn의 virtio 드라이버를 참고해 디스플레이 드라이버를 작성하고 화면을 올바르게 표시함
NT용 드라이버를 바탕으로 GameCube 컨트롤러 포트 드라이버를 이식해 USB 없이 마우스 커서를 움직이게 함
디스크 형식과 가상 SCSI 드라이버
EXI 장치용 블록 입출력 드라이버 구현을 시작했으나, 디스크 배치와 드라이버 구조를 결정하는 단계에서 작업이 정체됨
이후 CHRP용 Mac OS 덤프가 공개되자, 후기 TBXI 이미지에서 이를 부팅하도록 하는 패치 작업으로 옮겨감
GameCube의 RAM은 Mac OS 8.0 최소 요구량에도 못 미치므로 , 7.x 실행이 유용할 것으로 판단함
다른 프로젝트까지 진행하다가 거의 1년 뒤 돌아와, 원하는 디스크 형식을 OpenBIOS에 구현함
저장 장치를 SCSI처럼 보이게 하는 드라이버 를 작성함. 클래식 Mac OS의 일부 SATA 컨트롤러 드라이버도 같은 방식을 사용했음
디스크 자체에서 읽어 오는 디스크 드라이버를 신형 방식으로 로드 하도록 m68k 코드를 추가 패치함
이 드라이버는 파티션이 있는 블록 장치 위에 실제 디스크 장치를 구현함
구형 방식은 첫 PowerPC 시스템 출시 무렵 이미 사실상 구식이었으며, 가상 SCSI 드라이버도 구형 호출을 지원하지 않음
구형 드라이버로 로드하려다 충돌한 원인은 이 미지원 호출 때문일 가능성이 있음
광학 디스크 드라이버의 분산/수집(scatter-gather) 읽기 도 지원해야 했음
이 드라이버는 2048바이트 또는 2352바이트 섹터의 블록 장치에서 512바이트 섹터를 에뮬레이션하며, 버퍼 3개를 지정한 읽기 요청을 사용함
하위 SCSI 드라이버가 분산/수집을 지원하는지 확인하지 않으므로, 가상 SCSI 드라이버에 해당 읽기 기능을 구현함
부팅 장치 판별과 비정렬 버퍼 오류
계속 깜빡이는 플로피 아이콘이 나타난 원인은 StartLib!GetStartupDevice
의 부팅 장치 판별 과정에 있었음
함수가 기대하는 장치 트리 구조는 드라이버 초기화 코드에서 수정함
내장 SCSI 장치가 따로 있다는 가정도 있어, 장치 트리를 포함한 내부 구조 세 곳의 인덱스를 0이 아닌 값으로 바꿔 올바른 코드 경로를 타게 함
이후 Happy Mac 아이콘 이 나타났지만, HFS 부트 섹터에서 오류가 나며 부팅이 중단됨
수정한 Dolphin의 EXI-IDE 장치에서 테스트하던 중 자체 드라이버의 버그를 발견함
IDE PIO 전송은 16비트 워드 단위인데, 코드가 하위 4비트가 1인 완전히 비정렬된 홀수 버퍼 주소를 받을 것으로 예상하지 못했음
이런 주소에서는 EXI DMA를 시도하지 않도록 저수준 드라이버를 수정함
버그가 발생하면 한 바이트가 기록되지 않고 이후 데이터가 한 바이트씩 어긋남
리소스 포크 헤더를 읽는 중 유효성 검사가 실패해 원인을 좁히기 쉬웠으며, RAM을 덤프해 디스크 이미지의 예상 데이터와 비교하며 디버깅함
Dolphin과 실제 Wii의 부팅 결과
수정한 Dolphin에서 Mac OS 9.2.2 가 부팅을 시작했으나 매우 느렸고, 약 1시간 뒤 충돌함
이어 시험한 7.6은 더 이른 단계에서 충돌함
MacsBug 로딩이 원인일 것으로 보고 제거하자, 약 20분 뒤 데스크톱 에 도달함
다음 날 실제 하드웨어에서 SPI를 통한 SD 카드 접근 으로 시험하자 Mac OS 7.6이 약 40초 만에 부팅됨
클래식 Mac OS에서는 전송 중 CPU 전체를 점유 할 수 있으며, 사실상 다른 선택지도 없음
비동기 전송을 나타내는 값을 반환하면 호출 측이 완료될 때까지 인터럽트를 기다리는 반복문으로 바쁜 대기를 수행함
이 대기 루프는 시스템에 존재하는 모든 컨트롤러를 확인함
간단한 충돌 처리기를 추가해 조사한 결과, MacsBug 충돌은 에뮬레이션 오류 였으며 실제 하드웨어에서는 발생하지 않음
Mac OS 9.2.2 부팅 충돌은 Open Transport 와 관련돼 있었고, Extensions 폴더에서 제거하자 정상 부팅됨
직렬 장치와 네트워크 장치가 전혀 없는 상태를 Open Transport가 처리하지 못하는 것으로 추측하지만, 원인은 확정하지 않음
남은 하드웨어 지원과 실험
포트는 아직 공개 배포할 수준과는 거리가 멂
다음 순서는 Wii SD 컨트롤러 , USB 컨트롤러 지원, Wii U 부팅 구현임
USB 관련 역공학은 일부 진행함
바이브 코딩으로 작성된 EHCI 드라이버가 존재하지만, 주로 역공학을 돕는 용도로 활용할 수 있을 것으로 봄
향후 일부 RAM 제한을 넘어서는 패치 도 실험하고 싶어 함
Tenon Power MachTen 을 이 환경에서 실행할 수 있는지는 아직 알 수 없음
댓글과 토론