· 7 min read ·

The PowerPC Coincidence That Made Mac OS X Run on a Nintendo Wii

Source: hackernews

Bryan Keller’s writeup on porting Mac OS X to the Nintendo Wii landed on Hacker News this week and immediately gathered nearly two thousand points. The reaction makes sense. The project sounds absurd on its surface: a game console from 2006 running an operating system designed for desktop workstations. But the more you know about the hardware involved, the less surprising the feasibility becomes, and the more impressive the execution looks.

The key is the CPU.

Broadway and the PowerPC 750 Lineage

The Wii’s main processor, codenamed Broadway, is an IBM PowerPC 750CL running at 729 MHz. That places it squarely in the same architectural family as the chips Apple used in consumer Macs from the late 1990s through the mid-2000s. The iBook G3, the PowerBook G3, the original iMac — all of them used variants of the PowerPC 750. Apple’s transition to Intel in 2006 made this whole lineage feel ancient, but the ISA compatibility never went away. Broadway is still a 32-bit, big-endian PowerPC core executing the same instruction set that Darwin/XNU was compiled against for nearly a decade of Mac releases.

Mac OS X ran on PowerPC from 10.0 Cheetah in 2001 through 10.5 Leopard in 2007. Apple’s last PowerPC-supporting release, Leopard, required a G4 minimum — the G3 was dropped — but the kernel code still compiled for the 750-class architecture. More importantly, Apple open-sourced Darwin, including the XNU kernel, throughout this period. The PPC-specific code lives in osfmk/ppc/ in the XNU source tree, and Apple’s open-source releases make XNU 1228 (corresponding to 10.5.x) available to anyone willing to dig.

So the building blocks were there: an open-source kernel with a mature PPC port, a target CPU that speaks the right ISA, and a homebrew community that had spent years reverse-engineering every register on the board. What remained was stitching them together across a gap that the hardware makes wide.

What the Boot Path Actually Requires

On a real PowerPC Mac, the boot sequence runs through Open Firmware. Apple’s BootX bootloader reads the mach_kernel binary, constructs a device tree describing the hardware, sets up initial BAT (Block Address Translation) register mappings, and hands control to XNU’s _start entry point. The kernel then calls ppc_init(), finishes setting up the hash page table (HTAB) for virtual memory, and begins the Mach bootstrap sequence.

The Wii has none of this. There is no Open Firmware. There is no BootX. The Wii boots into Nintendo’s own firmware, which loads IOS — a collection of ARM microkernel modules running on a separate ARM926EJ-S core embedded inside the Hollywood GPU chip, codenamed Starlet. This Starlet core runs at roughly 243 MHz and mediates almost all I/O: disc access, USB, NAND flash, SD card, Wi-Fi, and Bluetooth. The main Broadway CPU communicates with Starlet through an IPC mechanism that Nintendo never documented publicly; the homebrew community reverse-engineered it over years of work.

The entry point for any third-party code on a Wii is either the Homebrew Channel (a launcher installed via exploit) or BootMii, which can run as a boot2 replacement and gives near-total control of the hardware before Nintendo’s own firmware does anything interesting. A kernel ELF loaded through BootMii is roughly analogous to what Open Firmware would hand to BootX on a real Mac, minus the device tree and the initialization work that Open Firmware would have already done.

That missing device tree is one of the central engineering problems. XNU discovers hardware through a flattened device tree blob that describes memory regions, CPU properties, interrupt controllers, and peripheral buses. For a Mac, Open Firmware generates this automatically. For the Wii, it has to be fabricated by hand, encoding the correct physical addresses for MEM1 and MEM2, the Broadway CPU node with its cache sizes and clock speed, and enough of the bus topology that the kernel does not panic trying to find things that are not there.

The Memory Map Problem

The Wii’s RAM layout is not contiguous. MEM1 is 24 MB of 1T-SRAM starting at physical address 0x00000000 — fast, low-latency, directly accessible by both the CPU and the GPU. MEM2 is 64 MB of GDDR3 SDRAM starting at 0x10000000, slower but larger, added to give the Wii more headroom than the GameCube’s 24 MB. Total addressable RAM: 88 MB, but split across a physical gap.

XNU on PPC expects to set up BAT registers covering its memory regions during early boot, before the full hash page table is operational. The 32-bit PPC BAT registers support up to 256 MB blocks and can cover both MEM1 and MEM2 with separate entries, but the kernel’s physical map (pmap) layer — the code in pmap.c that manages the HTAB — needs to know about both regions and treat them correctly. Getting this right without a reference platform means reading every relevant line of osfmk/ppc/pmap.c carefully, then cross-referencing against the WiiBrew wiki’s memory map documentation.

PowerPC exception vectors add another wrinkle. On a PPC 750, hardware exceptions (TLB miss, data access, instruction access, system call, and so on) vector to fixed physical addresses: 0x0100, 0x0200, 0x0300, and so on. The kernel’s exception handlers in locore.s must reside at those exact addresses in physical memory. Since TLB miss handling on the PPC 750 is software-managed — the hardware raises an exception and the OS refills the TLB from the hash table — getting the miss handlers wrong means the system never survives its first page fault. This is the kind of thing that produces a black screen and nothing else until you get it exactly right.

The Debt to gc-linux and the Homebrew Community

Keller’s port does not exist in a vacuum. The gc-linux project, which ported Linux 2.4 and later 2.6 to the GameCube and Wii, proved that a full general-purpose OS could run on this hardware. The GameCube’s Gekko CPU is the direct predecessor to Broadway — essentially the same PPC 750CXe core at 485 MHz — so the gc-linux work established the basic approach: load a kernel ELF through a homebrew entry point, fabricate a device tree, map the memory regions, write a minimal framebuffer driver against Hollywood’s registers, and route I/O through Starlet’s IPC interface.

The libogc library, which underlies most Wii homebrew, documents or implements almost every piece of Wii hardware interaction a porting effort needs. Its source contains register definitions for Hollywood, the Starlet IPC protocol, the SD and USB stacks, and the GX graphics interface. The WiiBrew wiki fills in everything else: clock frequencies, memory-mapped I/O addresses, the structure of the Wii’s NAND filesystem, the Starlet IOS module system.

None of this work was done for the Mac OS X port specifically. It accumulated over more than fifteen years of people taking apart a game console because they were curious. Projects like this are what that curiosity enables.

What XNU Requires That Linux Does Not

Linux on Wii is a more tractable problem than XNU on Wii, for reasons that go beyond the kernel being more familiar. Linux’s PowerPC port is actively maintained, targets a wide range of embedded and server hardware, and has infrastructure for handling unusual memory layouts and non-standard boot protocols. The arch/powerpc/ tree in Linux is built to be adapted.

XNU’s PPC port, by contrast, was written for Apple hardware specifically and has not been maintained since 2007. It assumes Open Firmware or something that closely mimics it. The I/O Kit driver model — an object-oriented C++ framework for hardware drivers — means that getting any device working requires writing a proper IOService subclass, not just a flat C driver. Getting even a basic framebuffer working requires either a real IOFramebuffer driver or careful surgery on the kernel’s early console code.

The other constraint is AltiVec. The G4 and G5 Macs that ran Leopard had AltiVec (VMX) SIMD units, and some kernel code — particularly in the crypto and memory copy paths — uses AltiVec intrinsics. Broadway has no AltiVec. It has paired-singles, a Wii/GameCube-specific SIMD extension for pairs of single-precision floats, which is completely different. Any kernel path that touches AltiVec needs to be conditionalized or replaced. The PPC 750CL does support the full 32-bit PowerPC base ISA, so most code runs fine; the AltiVec paths are the exception.

Why This Matters Beyond the Novelty

Ports like this are frequently dismissed as pointless because the result is not useful in any practical sense. Mac OS X on a Wii is not going to replace anyone’s workstation. But the value of a project like this is not in the shipped product; it is in the knowledge it produces and the techniques it forces into existence.

Keller’s port required someone to read the XNU PPC boot path carefully enough to understand what it genuinely requires versus what it assumes because Apple’s hardware always provided it. It required fabricating a device tree that satisfies XNU’s expectations without any of the infrastructure that normally generates one. It required bridging two eras of hardware that were never meant to meet.

That kind of archaeology matters. Apple’s PPC code is not going to be maintained by anyone, but understanding how a 2007-era hybrid microkernel boots on a RISC processor is the kind of low-level knowledge that transfers. The people who built PS3 Linux, who maintained gc-linux, who wrote the Wii’s Starlet IPC documentation on WiiBrew — they were not building toward something. They were just paying close attention to how hardware works, and writing it down.

The result, occasionally, is that someone can boot Mac OS X on a Nintendo Wii nineteen years after Apple stopped caring about the architecture it runs on.

Was this interesting?