2013年,一个大二学生在网上发帖说想干一件事——把Mac OS X移植到任天堂Wii上。

没人鸟他。

8年后的2021年,有人在Reddit上认真回复:"这件事发生的概率是零。"

AI配图

又过了5年。

2026年4月8日,这个大二学生(现在已经是资深工程师了)在GitHub Pages上发了一篇文章,标题简单到不像话——

"I ported Mac OS X to the Nintendo Wii"

苹果公司在2001年发布的操作系统,跑在任天堂2006年发布的游戏机上。

中间隔了25年。

中间隔着两家公司、两种产品哲学、无数行代码。

但它就是跑起来了。


一个"零概率"项目的起点

Bryan Keller第一次动这个念头是在2013年。

那时候他还是个大学生,对底层开发几乎一无所知。把Mac OS X这种级别的系统移植到一台游戏机上?这想法就像是说"我想把飞机引擎装到自行车上"——技术上不是不可能,但正常人不会这么想。

这一想,就想了10年。

日常工作已经够复杂了,没必要再给自己找事。但2025年,他看到Windows NT被移植到Wii上,突然又坐不住了。

"就算我经验不足搞失败了,至少也能学点东西。"

就这么一句话,他开始干。

他给自己定了个规矩:写自己的bootloader,而不是移植Open Firmware或者BootX。为什么?因为Mac OS X一旦跑起来,根本不依赖这两者。多余的代码只会增加复杂度。

而他只需要让系统跑在一台特定的机器上——Wii。


88MB内存,够吗?

先看硬件。

Wii用的是PowerPC 750CL处理器。这颗芯片的血统很纯——它是G3 iBook和部分G3 iMac所用处理器的后代。CPU层面,没问题。

关键是内存。

Wii的内存配置很奇葩:88MB,分成两部分。24MB是1T-SRAM(MEM1),速度快但容量小;64MB是GDDR3 SDRAM(MEM2),慢但容量大。

而Mac OS X 10.0 Cheetah官方要求多少?

128MB。

差了40MB,将近一半。

换别人可能就放弃了。但Bryan做了个测试——用QEMU模拟64MB内存启动Cetah。居然能跑。

"那行,先这么着。"

boot_args结构体里要填device tree,他就硬编码了一个。bootloader要加载kernel,他就自己写了解析Mach-O文件的代码。

每一步都是坑,每一步都像在黑暗中摸索。


屏幕黑了,然后呢?

第一次跳转到kernel的时候,屏幕黑了。

串口调试输出也停了。

这意味着什么?Kernel可能正在跑,也可能已经崩了。没有任何反馈。

怎么知道进行到哪了?

Bryan想了个损招——改kernel代码,让它控制Wii前面板的LED灯

在PowerPC汇编里,往特定内存地址写值就能点亮LED。他把kernel里各个函数的地址和源码交叉对照,找到合适的位置,替换成LED控制指令。

然后观察LED亮不亮。

亮到哪一步,就知道跑到哪一步。

这个过程他画了张流程图:

1. start.s: start
2. start.s: allStart
3. start.s: nextPVR
...
10. ppc_init.c: ppcInit
11. pe_init.c: PE_INIT_PLATFORM
12. device_tree.c: find_entry (crash with 300 exception)

跑到第12步,崩了。

原因是device tree没传对。


自己造一个设备树

AI配图

device tree是什么?

想象一棵倒过来的树。树根代表整台机器,子节点代表CPU、内存、显卡、USB控制器等各种硬件。操作系统靠这棵树"认识"自己身上有哪些零件。

在真正的Mac上,Open Firmware会在启动时自动扫描硬件、生成这棵树。但Wii没有Open Firmware,而且Wii的硬件结构完全不一样——它用的是一块叫Hollywood的系统级芯片,用IPC和ARM协处理器(代号Starlet)通信。

没有现成的,那就自己造。

Bryan直接从Wii Linux项目抄——不对,是"借鉴"。他把device tree硬编码进bootloader里,核心就三个节点:

/
├── cpus
│ └── PowerPC,750
└── memory

就这俩。CPU和内存。

其他的,后面再补。

填好device tree指针,boot_args结构体一塞——过了。

kernel不崩了,开始往下跑。

然后卡在"Still waiting for root device"。


写驱动,从零开始

Mac OS X的驱动模型叫IOKit。Bryan之前没接触过这东西,花了好一阵子才搞明白里面的弯弯绕。

简单说,IOKit有两类东西:DriverNub

Driver管具体设备,比如一块网卡。Nub是个"接口",让Driver能连到系统总线上。

在真正的Mac上,PCI总线由IOPCIBridge驱动扫描,发现一块网卡,就创建一个IOPCIDevice Nub。网卡的Driver看到这个Nub,附着上去,就能通信了。

但Wii不用PCI。

它用Hollywood SoC,定制芯片,没有现成的IOKit驱动家族可用。

那就自己写。

Bryan设计了一套自己的驱动架构:

NintendoWiiHollywood(主驱动)
├── NintendoWiiHollywoodDevice(Nub)
│ ├── NintendoWiiSDCard(SD卡驱动)
│ └── NintendoWiiFramebuffer(显卡驱动)

AI配图

每一个子设备都是一个Nub,每一个Nub都可以挂新的Driver。

先从SD卡开始写。

SD卡驱动要实现IOBlockStorageDevice的一大堆虚方法。大部分都是硬编码返回值——厂商字符串、块大小、最大传输量之类的。真正难的是读写操作。

Wii的SD卡通过Starlet协处理器上的MINI程序控制。Bryan要在PowerPC端写特定的内存地址发命令,MINI执行完再把结果写到另一块内存。

这中间有个坑:缓存

SD卡读出来的数据可能还留在cache里没刷到RAM,PowerPC读的时候读的是cache里的旧数据。

解决方案:用非缓存的内存区域做缓冲区。


颜色是洋红色的

SD卡能动了。

接下来是显卡。

Mac OS X的GUI需要一个真正的帧缓冲驱动。Bryan写了NintendoWiiFramebuffer,继承自IOFramebuffer。

但有个问题——颜色全变了。

洋红色。所有的颜色都是洋红色。

为什么?

Wii的视频编码器是为模拟电视信号优化的,它expect的是YUV格式的像素数据。但Mac OS X写的是RGB

一个要YUV,一个给RGB。

颜色能不诡异吗?

解决方案:双缓冲。

一块RGB帧缓冲给Mac OS X用,一块YUV帧缓冲给Wii硬件用。每秒60次,把RGB转成YUV写进去。

这活儿Wii Linux项目很多年前就干过。Bryan直接照搬思路。

颜色终于正常了。

Mac OS X的图标、菜单、Finder——都出来了。

但有个问题:没法操作

没有键盘,没有鼠标。


USB这道坎

Wii的后置USB口是USB 1.1 OHCI标准。Bryan本想直接用Mac OS X自带的AppleUSBOHCI驱动。

结果撞墙三道。

第一道Mac OS X 10.0(Cheetah)的IOUSBFamily源码没开源。10.2(Jaguar)之后的才有。没有源码,出了问题没法调试。

第二道AppleUSBOHCI的驱动配置要求provider必须是IOPCIDevice。Wii不用PCI,根本不会创建这种Nub。匹配不上,驱动根本不启动。

第三道就算强行让它启动,还有字节序的问题。AppleUSBOHCI在软件层做字节序转换,但Wii的硬件层已经做过一次了。双重转换,数据全乱。

怎么办?

第一道坎:Bryan上IRC求助。在一个古早的CVS仓库里找到了Cheetah时代的IOUSBFamily源码。

第二道坎:写了个假的IOPCIDevice Nub,骗过驱动匹配。

第三道坎:用Ghidra反汇编,一行一行找字节交换指令,注释掉。

"手打的AppleUSBOHCI二进制脆弱到几乎不可能维护,而且几乎肯定是错的。"

他自己在文章里写的。

但最后居然跑通了。

键盘亮了,鼠标能动了。

Wii变成了一台Mac。


经济舱里的kernel panic

读文章的时候注意到一张图——

一个经济舱座位,小桌板上放着MacBook,屏幕上是串口调试输出。

注释写的是:"在修复USB bug的时候"

另一张照片——夏威夷的酒店里,Wii接在电视上,屏幕上是Mac OS X的桌面。

他带着Wii去旅行,因为"项目正到关键时刻,停不下来"。


一个"不可能"的故事

文章开头,Bryan专门引用了那条Reddit评论:

"这件事发生的概率是零。"

"Feeling encouraged."

他用了一个词:encouraged

被"鼓励"到了。

这就是整篇文章的张力所在。

一个人,十几年的念头,断断续续的推进。没有团队,没有预算,没有任何商业目的。

只有一个问题:能不能做到

最后他做到了。

"那些看起来遥不可及的项目,恰恰是值得去做的。"


文章写于2026年4月。


【锐评】:这年头敢在GitHub Pages发这种纯技术长文的人不多了,更难得的是他把"如何把不可能变成可能"写得像侦探小说一样好看。技术细节足够硬,故事节奏足够爽,结尾那句"encouraged"简直是点睛之笔。

参考链接:
https://bryankeller.github.io/2026/04/08/porting-mac-os-x-nintendo-wii.html