我最爱的 PowerMac 是任天堂 Wii

Lobsters Hottest 新闻

摘要

一位开发者详细介绍了其正在进行的项目——将经典 Mac OS 移植到任天堂基于 ArtX 的 PowerPC 硬件(GameCube、Wii、Wii U)上,成功在 Wii 上进入桌面环境,这很可能是自 CHRP 克隆机时代以来首次在 Apple 之外实现这一目标。文章涵盖了 OpenBIOS 移植、EXI 总线磁盘驱动以及启动方面的种种挑战。

<p><a href="https://lobste.rs/s/siebde/my_favourite_powermac_is_nintendo_wii">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/10/29 17:43

# 我最喜欢的 PowerMac 是一台 Nintendo Wii 来源:https://virtuallyfun.com/2026/10/29/my-favourite-powermac-is-a-nintendo-wii/ *(这是一篇由 Rairii 撰写的客座文章)* ![](https://virtuallyfun.com/wp-content/uploads/2026/10/bootscreen76-1-640x480.jpg) Mac OS 7.6 在 Wii 上启动 ![](https://virtuallyfun.com/wp-content/uploads/2026/10/bootscreen922-640x480.jpg) Mac OS 9.2.2 在 Wii 上启动 今天我的一个项目达成了一个漂亮的里程碑:我将经典 Mac OS 移植到 PowerPC 系统的工作——我亲切地称之为 ArtX 芯片组(Nintendo GameCube、Wii,最终还有 Wii U;GameCube 的 Flipper 集成芯片组在很大程度上是由 ArtX 设计的,因为在 ATI 收购该公司时它实际上已经完成了,而 Wii 的 Vegas(以及其后来的修订版 Bollywood)和 Wii U 的 Latte 则实际上是其直系后继者)——首次进入了桌面环境,这很可能是自 CHRP 克隆机时代以来,Apple 之外的人第一次在新系统上将经典 Mac OS 带到桌面。虽然距离可以公开发布还差得远,但我想谈谈到目前为止这个项目中遇到的挑战。 但首先,为什么要将经典 Mac OS 移植到这种硬件上呢?我之前当然已经移植过 NT,在那项工作中我获得了一些 PowerPC Mac 笔记本电脑,后来我也给它们移植了 NT——一个移植上的工作会改善其他的,以此类推。这让我熟悉了经典 Mac OS,而且我爱上了它的"jank"(这种从 1980 年代延续至今的 hack 之上再堆 hack 的方式,绝对可以称之为 "jank")。更不用说 TBXI 中 m68k 部分的名字叫做 "SuperMario",而且在整个 PowerPC 时代都是如此。我怀疑某个开发者在 1990 年代初是不是一个粉丝? 另外要说明的是:我于 2025 年 6 月 22 日启动了这个项目(当时我 fork 了上游的 openbios),没有使用任何编码代理或大语言模型,所有编码、逆向和调试工作都是我自己完成的。我做这些项目是为了乐趣和学习,如果我使用了"AI"那就不好玩了,我也什么都学不到。 让我们从初始引导开始。"New World"经典 Mac OS 从一个叫做 "Trampoline" 的引导加载程序开始,它运行在 Open Firmware 环境中。所以我需要移植 OpenBIOS。幸运的是,大约同一时期 Goldfish64 开始了他自己在 Wii 上的 Mac OS X 移植工作,他做了一个 OpenBIOS 移植,我可以从中借用一些驱动,但由于各种原因我并不想直接使用他的移植(他只针对 Wii/Wii U,而我还想针对 GameCube)。我还决定复用一些现有的代码来简化驱动开发(具体来说是显示驱动),因此我将现有的 NT ARC 固件加载器改为加载大端序 ELF。 我需要少量的磁盘驱动来进行初始引导,所以我决定移植我自己的两个 EXI 总线设备驱动(这只是 Nintendo 和 Macronix 对 SPI 的叫法):"SD Gecko"(这只是 GameCube 记忆卡插槽的直通转接器,允许通过 SPI 访问 SD 卡)和 "EXI-IDE"(我的驱动实际上并不完全符合真实硬件,而是符合我在我的 Dolphin 分支中不精确的模拟实现,以便在模拟器中进行测试并利用其底层调试支持)。 我不确定想使用什么样的磁盘格式(在我早期的 NT 移植中,这些驱动完全在 FAT 文件系统上的磁盘映像中运行,因为需要兼容现有的从 FAT 文件系统加载可执行文件的自制程序加载器,但这自然会受限于 FAT32 的 4GB 映像限制,而经典 Mac OS 的较新版本需要更多空间),所以对于初始测试,我直接将 "Mac OS ROM" TBXI 文件放在 FAT 文件系统上作为`\ppc\bootinfo.txt`供 OpenBIOS 在启动时加载。 有了这些我就能让 Trampoline 运行起来了。我决定尽可能在接近运行时的时间点对映像应用补丁,这样最终可以使用基本上未经修改的现有 CD 映像。 我遇到的第一个问题是 Trampoline 对物理地址空间布局做了一些假设,而这些假设在这个系统上不成立。缓冲区的物理地址被计算为一个无效地址,所以我将其修补为一个保证有效的地址,同时也修补了相应的设置内核内存块列表/页表项的代码。 此外,Trampoline 期望从`0x8000_0000`开始的物理地址对应于内存映射 I/O(在该代码运行的现有系统上,这对应于 PCI 总线地址空间)。在这里并非如此,事实上在 Wii U 上,这个地址对应的是一部分 RAM。还有一个在这些系统上会失效的假设——物理地址空间中 RAM 区域之间存在空洞,其中一些被内存映射 I/O 部分填充。 我的修复方法是修补内核内存块列表中这个 MMIO 映射的初始化,改为将物理地址`0x0100_0000`(位于某个 RAM 区域中间)映射到虚拟地址`0xE000_0000`,长度为`0x1000_0000`。这恰好映射了整个 MMIO 区域,加上一个 RAM 区域的末尾和(对于 GameCube 之后的系统)另一个 RAM 区域的开头。(我将来可能会更改这一点,因为在 Wii U 上,物理地址范围`0xD000_0000-0xEFFF_FFFF`被映射到 Radeon R7xx GPU 的一个叫做 "HDP" 的部分,它可以用来以特定的 swizzling 和/或字节序转换映射物理内存的一个视图,使得某种 GPU 特定格式中的纹理可以呈现为线性帧缓冲。这取决于我是否需要使用这个块。)Trampoline 中用于初始化映射的函数在某个时间点发生了变化,我最终检测到了旧版本并 hook 了该函数来解决这个问题(早期版本使用 16 位页计数,后来的版本使用 32 位)。此外,Trampoline 的较旧版本会为`0x8000_0000`以上的物理内存建立无条件的 1:1 映射,这需要移除,因为它们与前面建立的映射冲突。 接下来是各种针对特定硬件的补丁。包括:修补掉一些对应于所有 PowerPC Macintosh 硬件上都存在的微控制器的标志位设置、尝试使用特定硬件定时器重新计算总线频率,以及与特定中断控制器设备相关的各种寄存器写入和修正(它是小端序的,因为它在 PCI 总线上,当然在这里不存在)。 最后,跳转到已加载的内核初始化代码的最终调用被 hook,以便在所有内容加载到内存后进行额外的补丁。 此外,设备树必须做一些修改才能达到 Trampoline 可以接受的形式。中断控制器被伪装成被识别的类型之一(上面提到的小端序那种,因为在寄存器层面它最接近所有 ArtX 芯片组上都存在的 Flipper 中断控制器,尽管在 Wii U 上它被做了一些修改以支持额外的 PowerPC 核心)。设备树中帧缓冲区的地址被改为非缓存虚拟地址(在`0Exxx_xxxx`映射中),最后在设备树中添加了一个假的 Mac99 兼容电源管理设备,这样 Trampoline 会为其准备一个电源管理驱动,之后可以被替换。 如上所述,内核初始化被 hook 以便进行额外的补丁。在内核方面,只需要一个补丁:内核包含多个中断控制器驱动,选中的那个被修补以匹配 Flipper 中断控制器,牺牲了一个未使用的驱动来获得更多空间。主要区别在于,被期望的中断控制器(其驱动已被修补)有一个传统模式,它会在中断变化时(不只是在中断触发时)产生一个 PowerPC 中断,所以这需要通过在内核中屏蔽触发的中断然后在驱动的中断处理程序中稍后取消屏蔽来解决。 在 "SuperMario" m68k 代码和 PowerPC 原生可执行文件中还做了额外的补丁。m68k 代码中有各种直接读写原生中断控制器寄存器的代码路径,这些需要被修补。启用和禁用音频中断的函数指针需要被 stub 掉(该表中已经有一个指向 stub 的条目,这很有帮助)。一个在启动早期初始化 ADB 和电源管理微控制器的函数不检查硬件是否实际存在,如果不存在就会破坏部分低内存。一个初始化硬件中断的函数有一个因复制粘贴错误导致的 bug,原意是如果硬件不存在就跳过串口 2 的中断初始化代码,但开发者从串口 1 复制粘贴代码时忘记修改跳转标签,如果串口 2 不存在就会导致无限循环。至于原生代码,有更多读写中断控制器寄存器的代码需要正确修补。USBShimKeyboard 驱动的初始化代码无法处理不存在 USB 控制器的情况,在这种情况下会在 m68k 模拟器内部调用 NULL 指针。上面提到的电源管理驱动也被完全替换(目前我使用 BlueBox 中的 stub 驱动,但计划之后自己编写以添加对关机和重启的适当支持)。 所有这些足以让 TBXI 启动到闪烁的软盘图标——之后我编写了一个显示驱动(感谢 Elliott Nunn 的 virtio 驱动,它非常有帮助)以便我能正确看到它,接着是一个 GameCube 手柄端口的驱动(从我的 NT 驱动移植而来)这样我就可以不用 USB 来移动鼠标光标了。 在这个阶段我开始实现一个块 IO 驱动(针对 EXI 设备),但最终卡在了思考如何处理磁盘格式的布局以及驱动该如何工作上。然后 CHRP 版本的 Mac OS 被 dump 出来了,我被分心去修补后来的 TBXI 映像来启动它(https://github.com/Wack0/universal-tbxi-patchset),想着在连运行 8.0 最低配置所需的 RAM 都不够的 GameCube 上运行 7.x 会很有用,之后我又被其他项目分心了。将近一年后我回来继续这个项目,在 OpenBIOS 中实现了我偏好的磁盘格式,并决定 hack 一个伪装 SCSI 的驱动(一些其他驱动也这样做,最著名的是经典 Mac OS 中各种 SATA 控制器的驱动)。在编写伪装 SCSI 驱动时我也发现了一些问题:我不得不在 m68k 代码中添加另一个补丁来强制以较新的类型而非较旧的类型加载磁盘驱动(我说的是认真的,一个从磁盘本身加载的驱动,基本上是在某个已分区的块设备之上实现实际的磁盘设备),较旧的类型在第一代 PowerPC 系统发布时就已经过时了,而且我的伪装 SCSI 驱动甚至不支持旧式的调用方式,这可能就是它尝试作为较旧类型驱动加载时崩溃的原因。还发现了一个有趣的怪癖:光盘驱动(从块设备本身加载)通过发出一个设置了 3 个分散-聚集缓冲区的读取调用来在 2048 字节或 2352 字节扇区的块设备上模拟 512 字节扇区,但它从未检查底层 SCSI 驱动是否实际支持分散-聚集,所以我在读取路径上实现了这个支持。 不过我仍然看到闪烁的软盘图标,一些调试告诉我什么被拒绝了——一个 PowerPC 函数`StartLib!GetStartupDevice`被调用来获取启动设备,它对设备树以及存在某种需要单独处理的内置 SCSI 设备做了一些假设。第一个问题很简单(在我的驱动初始化代码中修复设备树),第二个更有意思,我不得不深入内部结构在 3 个不同地方(包括设备树)修复一个索引,确保它非零从而执行正确的代码路径。 完成这些后我第一次看到了令人愉快的 Mac 图标,但随后被 HFS 引导扇区拒绝了(出错了然后返回了)。结果发现这是我自己的驱动的一个 bug:我在 Dolphin 中用一个 hack 的 EXI-IDE 设备进行调试;IDE 设备的 PIO 模式读写数据以 16 位字为单位处理,我没有预料到我的代码会被传入一个完全未对齐的奇数缓冲区地址(低 4 位等于 1),所以我不得不修改我的底层驱动,对这样的地址甚至不尝试 EXI DMA。这个 bug 的表现是一个字节实际上未能写出,剩余数据偏移了一个字节;至少在读取资源分支头时发生了这种情况,失败的是数据的有效性检查,这让调试变得容易得多(我最终 dump 了 RAM 并与我使用的磁盘映像中的预期数据进行了比对)。 之后,Mac OS 9.2.2 开始在我的 hack 的 Dolphin 分支中启动,速度非常慢。它花了一个小时才最终崩溃,然后我尝试了 7.6,也崩溃了,但更早。我意识到它可能是在尝试加载 MacsBug 时崩溃的,删除了它,大约 20 分钟后我看到了桌面。 ![](https://virtuallyfun.com/wp-content/uploads/2026/10/76-640x480.jpg) Mac OS 7.6 在我 hack 的 Dolphin 分支中启动 第二天早上我在真实硬件上进行了测试(使用 SPI 上的 SD 卡)。这基本上在 40 秒内就启动了 7.6,而这应该是 SD 卡*最慢*的访问模式!不过我之前的经验是为 SPI 上的 SD 卡编写 NT 驱动,也许那更像是一个异常值。看看[这个视频](https://youtu.be/BrcZ2-I0CbQ?t=197),使用这样的块设备在 GameCube 上安装 NT,并注意 NT 文本模式安装中的文件拷贝被加速了 64 倍——它非常非常慢。这里的区别在于我在执行传输时可以独占整个 CPU——事实上没有其他选择,如果我返回一个值指定传输是异步的,调用者会继续在一个循环中忙等中断直到传输完成(尽管忙等会检查系统上所有存在的控制器)。 后来我添加了一个 hack 的崩溃处理器来尝试调试 MacsBug 的情况……结果发现是一个模拟错误,在真实硬件上加载 MacsBug 时没有发生这种崩溃。然后我发现了 Mac OS 9.2.2 启动时崩溃的原因是 Open Transport,从 Extensions 文件夹中删除它后就完美启动了。我猜测 Open Transport 无法处理完全不存在串口或网络设备的情况。 如我所说,我的移植距离可以发布还差得远。接下来将是启用 Wii 的 SD 控制器,然后是 USB 控制器(我已经做了一些相关的逆向工作,我知道现在有一个 vibecoded 的 EHCI 驱动,那可能主要只对逆向工作有帮助),然后是在 Wii U 上启用这个移植。在某个时候我想尝试一些补丁来至少绕过部分内存屏障。

相似文章

Windows NT 用于 GameCube/Wii

Hacker News Top

该项目将 Windows NT 移植到任天堂 GameCube 和 Wii 主机,支持多种输入设备和驱动程序。它是开源的,可在 GitHub 上获取。

我打造了一个袖珍Macintosh

Jeff Geerling

使用运行Pico Micro Mac固件的Raspberry Pi Pico打造了一个袖珍Macintosh,具备VGA输出和USB键盘/鼠标。

ConsoleMini

Product Hunt

ConsoleMini 把 Mac mini 变成客厅里的复古/PlayStation 风格游戏机。