The CPU That Almost Made It Easy: Porting Mac OS X to the Nintendo Wii
Source: hackernews
Bryan Keller published a writeup this week on porting Mac OS X to the Nintendo Wii, and it got 1,880 points on Hacker News for a reason. On the surface it sounds like a stunt. Look closer and it is actually a compelling systems programming project, because the Wii’s CPU is not as foreign to Mac OS X as you might think. The real story is not the headline but the boot chain, the memory layout, and the ARM core that quietly controls everything.
The Hardware Coincidence That Makes This Possible
The Wii’s main CPU, codenamed Broadway, is a 729 MHz IBM PowerPC derivative based directly on the GameCube’s Gekko, which is itself a PowerPC 750CXe, better known as the G3. The G3 is precisely the chip that shipped in iMacs, PowerBook G3s, and the first iBooks. Mac OS X 10.0 through 10.2 ran on G3 hardware natively. Apple’s XNU kernel has PowerPC assembly support going back to those machines, and the G3 ABI, exception vector layout, and cache coherency model are all things the kernel already knew how to handle.
Broadway runs at 32-bit big-endian PowerPC with a paired-singles floating-point extension Nintendo added for graphics math. It has 32 KB each of L1 instruction and data cache, a 256 KB L2, and no AltiVec. That last point matters: XNU on G3 hardware already skips AltiVec initialization entirely, so the kernel’s low-level assembly paths are fine. The paired-singles extension is non-standard but XNU never touches it, so it sits dormant. From the kernel’s perspective, Broadway looks like a slightly unusual G3, which is almost exactly what it is.
This is the seam Keller exploited. The ISA compatibility does most of the work at the instruction level. Everything else is a fight.
The Boot Chain Problem
Mac OS X on PowerPC boots through Open Firmware, the IEEE 1275 standard that Apple used from the first Power Macs through the last G5 towers. The firmware builds a device tree, a hierarchical description of the hardware, and passes it to BootX, Apple’s second-stage bootloader. BootX reads the device tree, locates the Mach kernel on disk, maps it into memory, and jumps to it. XNU’s platform layer then walks that device tree to find RAM ranges, interrupt controllers, I/O buses, and clocks.
The Wii has none of this. Its boot ROM, embedded in the Hollywood chip, starts the Starlet, an ARM926EJ-S security processor running at 243 MHz. Starlet loads and verifies Nintendo’s IOS firmware from NAND, sets up hardware, and only then releases Broadway from reset. Broadway wakes up with a small trampoline in memory and no device tree in sight.
To get XNU running, that device tree has to be fabricated from whole cloth. The GameCube Linux project and its successor WiiLinux faced the same problem with the Linux kernel’s device tree, and they solved it by writing a custom bootloader that constructs a flattened device tree blob describing the Wii’s actual hardware before handing off to the kernel. Keller needed a comparable solution for the Mach boot path: either patch BootX to generate a synthetic Open Firmware tree from known Wii memory addresses, or patch XNU’s platform initialization to skip the device tree lookup entirely and hardcode the hardware layout.
Memory: Two Banks, Neither Where You Expect Them
PowerPC Macs map RAM starting at physical address 0x00000000, contiguously. The Wii does not. MEM1, the fast 24 MB block of 1T-SRAM embedded near the Hollywood chip, lives at 0x00000000. MEM2, the 64 MB of GDDR3 added for the Wii (the GameCube had no equivalent), sits at a separate physical base address, 0x10000000. Total addressable RAM is 88 MB across a non-contiguous layout.
XNU configures memory access early in boot using the PowerPC BAT registers, Block Address Translation entries that establish large, coarse-grained virtual-to-physical mappings before the full page table is set up. A stock kernel expects to find a single contiguous RAM region. The Wii requires two separate BAT entries and a memory descriptor list that accounts for the gap. Miss this step and the kernel triple-faults trying to access MEM2 addresses that are not mapped.
88 MB is also tight. Mac OS X 10.4 Tiger was the lightest full release; Apple listed 256 MB as the minimum for Tiger and in practice the kernel plus a minimal userspace claimed well over 100 MB. Running a stripped Darwin environment rather than the full Aqua stack is the only way to stay within the Wii’s memory ceiling, which means excising the window server, CoreGraphics, and most of the system frameworks before getting anywhere near a shell prompt.
The Starlet Problem
This is where the project gets genuinely difficult. The ARM Starlet is not a curiosity. It is the I/O controller for the entire machine. USB, Bluetooth, the SD card slot, the disc drive, NAND flash, the Wi-Fi chip, and the sensor bar interface all route through IOS, the firmware running on Starlet. Broadway cannot talk to any of these devices directly. It submits requests to IOS through a shared memory interface and interrupt mechanism, and IOS executes them on Starlet.
For a ported OS to do anything useful, either XNU must speak the IOS RPC protocol (which is undocumented by Nintendo, though the Wii homebrew community reverse-engineered it thoroughly), or the port has to write new kernel drivers that wrap IOS calls. IOKit, Apple’s driver framework, is architected around hardware buses, PCI, USB host controllers, ATA, and so on. None of those buses exist on the Wii in the form IOKit expects. Every driver is a dead end unless it is rewritten from scratch as an IOS client.
The WiiLinux project wrote Linux drivers for the IOS interface. Bringing Mac OS X to the same point requires equivalent work inside IOKit, a framework that was never designed to be ported to a custom RPC-based I/O model.
Prior Art and the Path Keller Walked
This is not the first time someone tried to run a real OS on Wii hardware. The GameCube Linux effort predates the Wii by years, and WiiLinux extended it. Both projects solved the bootloader problem and got to a working shell. The Dolphin emulator accurately emulates Broadway, Hollywood, and Starlet together, which gave Keller a debugging environment where register state and memory contents are fully inspectable without soldering anything.
On the Darwin side, the PureDarwin project spent years trying to run open-source Darwin builds on non-Apple hardware. They documented the XNU PowerPC platform layer in detail and established what Apple’s platform code assumes about hardware that nothing but a Mac actually provides. That documentation is exactly the kind of map you need when transplanting XNU to a foreign machine.
The devkitPPC toolchain from devkitPro gives you a GCC cross-compiler targeting powerpc-eabi, which is not the same ABI as Mac OS X’s PowerPC target but close enough to build test stubs that run on Broadway before the full kernel environment is ready.
What Getting Mac OS X “Running” Actually Means
In projects like this, “running” is a spectrum. The Wii’s memory ceiling and the IOKit driver problem make full Aqua out of the question. What is achievable, and what represents a genuine engineering milestone, is getting the XNU Mach kernel to boot to the point where it initializes virtual memory, spawns the kernel task, and drops into a debug prompt or single-user shell over a UART connection through one of the USB ports. That requires the synthetic device tree, the split-bank memory configuration, and enough of a framebuffer driver to confirm the kernel is alive, even if it is just scrolling kernel log output to the TV at 480i.
That milestone is what the GameCube Linux project considered their first real success, and it is the kind of thing that validates the entire porting effort. Everything beyond it, networking, storage, a usable userspace, is incremental from there.
The fact that Broadway is architecturally a G3 is the reason this was approachable at all. XNU’s PowerPC platform code was written for that CPU class. The ISA compatibility removes a huge category of problems. What remains is pure systems work: bootloaders, memory maps, and device drivers. That is the hard part of any OS port, and it is exactly what makes Keller’s project worth reading about.