พอร์ต Mac OS X 10.0 (Cheetah) ให้ทำงานบน Nintendo Wii ได้สำเร็จ
(bryankeller.github.io)- โปรเจ็กต์พอร์ตที่ทำให้ Mac OS X 10.0 (Cheetah) ทำงานแบบเนทีฟบน ฮาร์ดแวร์ฐาน PowerPC ของ Wii เสร็จสมบูรณ์
- ปรับแก้ เคอร์เนล Darwin/XNU ให้เข้ากับ Wii และเขียน บูตโหลดเดอร์, device tree, ไดรเวอร์ ขึ้นเองจนบูตเข้า GUI ได้สำเร็จ
- พัฒนา ไดรเวอร์ IOKit แบบคัสตอมที่รองรับ SD card, framebuffer, อุปกรณ์รับข้อมูลผ่าน USB จนระบบทำงานได้ครบถ้วน
- สะท้อนโครงสร้างเฉพาะของ Wii เช่น การแก้ปัญหาการชนกันของการตั้งค่า BAT, การสร้างชั้นไดรเวอร์สำหรับ Hollywood SoC, framebuffer แปลง RGB→YUV
- หลังจากพยายามมานานกว่าสิบปี ก็ทำให้ Mac OS X บูตเต็มรูปแบบและใช้งานได้บน Wii สำเร็จ พร้อมพิสูจน์คุณค่าของการท้าทายในโปรเจ็กต์ที่ดูเหมือนเป็นไปไม่ได้
ภาพรวมโปรเจ็กต์รัน Mac OS X บน Wii
- ดำเนินโปรเจ็กต์พอร์ต Mac OS X 10.0 (Cheetah) ให้รันแบบเนทีฟบน Nintendo Wii
- ก่อนหน้านี้ Wii เคยมีกรณีพอร์ต OS อย่าง Linux, NetBSD, Windows NT มาแล้ว และครั้งนี้ได้เพิ่ม Mac OS X เข้ามา
- ใช้ ฮาร์ดแวร์ฐาน PowerPC ของ Wii เพื่อรัน เคอร์เนล Darwin/XNU และเขียน ไดรเวอร์กับบูตโหลดเดอร์ ที่จำเป็นขึ้นเอง
- ผลลัพธ์คือสามารถบูต Wii เข้า สภาพแวดล้อม GUI ของ Mac OS X ได้สมบูรณ์ และรองรับอินพุตจากคีย์บอร์ดกับเมาส์
การตรวจสอบความเป็นไปได้
- CPU PowerPC 750CL ของ Wii เป็นรุ่นต่อจาก PowerPC 750CXe ที่ใช้ใน G3 iMac/iBook จึงไม่มีปัญหาเรื่องความเข้ากันได้ของ CPU
- RAM 88MB ของ Wii (MEM1 24MB + MEM2 64MB) น้อยกว่าข้อกำหนดทางการ (128MB) แต่ทดสอบด้วย QEMU แล้วยืนยันได้ว่ายังบูตได้แม้มีเพียง 64MB
- ฮาร์ดแวร์ที่รองรับมี USB Gecko (ดีบักผ่านซีเรียล), SD card, interrupt controller, วิดีโอเอาต์พุตผ่าน framebuffer, พอร์ต USB
- หากปรับแกนโอเพนซอร์สของ Mac OS X คือ Darwin (เคอร์เนล XNU, IOKit) ให้เข้ากับ Wii ได้ ก็มีโอกาสให้ชั้น GUI ด้านบนทำงานได้เช่นกัน
- Wii สามารถ รันโค้ดที่พัฒนาเอง ได้ผ่าน Homebrew Channel และ BootMii จึงเหมาะกับการทดลองพอร์ต
แนวทางการพอร์ต
- เลือกจาก 3 กลยุทธ์การบูต:
- พอร์ต Open Firmware
- พอร์ต BootX
- เขียนบูตโหลดเดอร์คัสตอมขึ้นเอง
- เขียนบูตโหลดเดอร์เฉพาะสำหรับ Wii ใหม่ เพื่อทำหน้าที่ เริ่มต้นฮาร์ดแวร์, โหลดเคอร์เนล, สร้าง device tree, ส่งต่อการควบคุมให้เคอร์เนล
- หลังเคอร์เนลเริ่มทำงาน โค้ดของบูตโหลดเดอร์ก็ไม่จำเป็นอีกต่อไป จากนั้นงานจึงเน้นไปที่ การแพตช์เคอร์เนลและเขียนไดรเวอร์
การเขียนบูตโหลดเดอร์
- ใช้โค้ดตัวอย่าง ppcskel เป็นฐาน แล้วเพิ่มการเริ่มต้นระบบของ Wii และความสามารถด้าน SD card, framebuffer, USB debugging
- โหลดเคอร์เนล XNU ซึ่งอยู่ในรูปแบบ Mach-O เข้าไปในหน่วยความจำ แล้วกระโดดไปยัง entry point ที่กำหนดเพื่อเริ่มทำงาน
- เพื่อยืนยันว่าเคอร์เนลเริ่มทำงานจริง มีการใส่ แพตช์ให้ LED กะพริบ เพื่อติดตามขั้นตอนการเข้าเคอร์เนล
- ย้อนรอยเส้นทางการทำงานของเคอร์เนลแล้วพบว่าเกิด 300 exception ในขั้น device_tree.c → จึงตระหนักว่าจำเป็นต้อง ส่ง device tree ให้เคอร์เนล
-
การสร้างและส่ง device tree
- สร้าง tree ขั้นต่ำแบบฮาร์ดโค้ด จากโครงสร้างฮาร์ดแวร์คงที่ของ Wii (
/cpus,/memory) - ใส่ pointer ของ device tree ไว้ในโครงสร้าง
boot_argsแล้วส่งให้เคอร์เนล - หลังจากนั้นเคอร์เนลก็รู้จัก tree ได้ถูกต้องและดำเนินการบูตต่อไป
- สร้าง tree ขั้นต่ำแบบฮาร์ดโค้ด จากโครงสร้างฮาร์ดแวร์คงที่ของ Wii (
การแพตช์เคอร์เนล
- การตั้งค่า BAT (Block Address Translation) ของ XNU ชนกับ memory map ของ Wii จึงจำเป็นต้องแก้ซอร์สของเคอร์เนล
- จัดเตรียมระบบบิลด์เคอร์เนลในสภาพแวดล้อม Mac OS X Cheetah guest (QEMU)
- หลัง แก้ BAT และเพิ่มการ redirect เอาต์พุตคอนโซลไปยัง USB Gecko ก็สามารถดีบักได้
- จากนั้น virtual memory, IOKit, BSD subsystem ก็เริ่มต้นได้ตามปกติ
- ในล็อกการบูตพบข้อความ “Still waiting for root device” → ยืนยันว่าจำเป็นต้องมี ไดรเวอร์ SD card
การเขียนไดรเวอร์
-
ทำความเข้าใจโครงสร้าง IOKit
- IOKit เป็นเฟรมเวิร์กส่วนขยายเคอร์เนลที่พัฒนาด้วย C++ และใช้โครงสร้างแบบ driver-nub เพื่อแทนลำดับชั้นของฮาร์ดแวร์
- ตัวอย่าง:
IOPCIBridge→IOPCIDevice→SomeEthernetCard→IOEthernetInterface - Wii ใช้โครงสร้าง SoC (Hollywood) ไม่ใช่ PCI bus จึงต้องมีไดรเวอร์คัสตอมมาแทน IOPCIFamily
-
ไดรเวอร์ Hollywood
- เขียนไดรเวอร์
NintendoWiiHollywoodให้จับคู่กับโหนด “hollywood” ใน device tree - สร้างและลงทะเบียน nub
NintendoWiiHollywoodDeviceเพื่อแทนฮาร์ดแวร์ชั้นล่าง - ทำให้ไดรเวอร์ของอุปกรณ์ย่อยอย่าง SD card สามารถเชื่อมต่อเข้ามาได้
- เขียนไดรเวอร์
-
ไดรเวอร์ SD card
- สืบทอดจาก
IOBlockStorageDeviceเพื่อทำการเข้าถึง SD card ของ Wii - ใช้ คำสั่ง IPC ของ MINI (Starlet coprocessor) (
IPC_SDMMC_SIZE,READ,WRITE) ในการสื่อสารกับ SD card - แก้ปัญหาเรื่องหน่วยความจำแบบแคชด้วยการใช้ บัฟเฟอร์หน่วยความจำแบบไม่แคช
- สร้าง
IOMedianub ได้สำเร็จ ทำให้ รู้จัก root filesystem และบูตได้สมบูรณ์ - ในล็อกการบูตยืนยันด้วย
BSD root: disk0s4
- สืบทอดจาก
-
ไดรเวอร์ framebuffer
- สืบทอดจาก
IOFramebufferและกำหนด พื้นที่ MEM1 (0x01700000) ของ Wii เป็น framebuffer - เพื่อรองรับทั้ง text console ตอนต้นและการสลับไป GUI จึงให้
isConsoleDevice()คืนค่าtrue - ฮาร์ดแวร์วิดีโอของ Wii ใช้ ฟอร์แมต YUV จึงสร้าง double framebuffer สำหรับแปลง RGB→YUV
- ใช้ลูปแปลงสีที่ 60Hz → แสดงผล GUI ด้วยสีที่ถูกต้องได้สำเร็จ
- สืบทอดจาก
-
รองรับอินพุตผ่าน USB
- พยายามใช้
AppleUSBOHCIเพื่อขับ คอนโทรลเลอร์ OHCI USB 1.1 ของ Wii - ปัญหา 1: ไม่มีซอร์สของ IOUSBFamily จึงดีบักไม่ได้
- ปัญหา 2: พึ่งพา IOPCIDevice จึงต้องเขียน
NintendoWiiHollywoodPCIDeviceปลอมสำหรับ Wii - ปัญหา 3: endianness ไม่ตรงกัน (Wii เป็น reversed-little-endian) จึงต้องเอาการ byte-swap แบบซอฟต์แวร์ออก
- หลังได้ซอร์ส IOUSBFamily สำหรับ Mac OS X Cheetah ผ่าน IRC ก็สามารถแก้ไขและบิลด์ได้สำเร็จ
- ผลลัพธ์คือ คีย์บอร์ดและเมาส์ USB ใช้งานได้ ทำให้ Wii ทำงานเป็นระบบ Mac OS X ที่สมบูรณ์
- พยายามใช้
การปรับปรุงบูตโหลดเดอร์และเคอร์เนล
-
การปรับปรุงบูตโหลดเดอร์
- เพิ่ม การค้นหาพาร์ทิชัน SD card และเมนูบูต พร้อมรองรับการพาร์ส Apple Partition Map (APM)
- โหลด kernel extension (kext) จากบูตโหลดเดอร์ แล้วลงทะเบียนไว้ในโหนด
/chosen/memory-map - ทำให้สามารถบูตจาก อิมเมจติดตั้ง Mac OS X ที่ไม่ต้องแก้ไข ได้
-
การทำเคอร์เนลให้ง่ายขึ้น
- ลดการแก้ไขเคอร์เนลเฉพาะ Wii ให้เหลือน้อยที่สุด:
- แก้การตั้งค่า BAT
- รับรู้ I/O address จากโหนด “hollywood”
- แก้ความสอดคล้องของแคชใน framebuffer
- แยกไดรเวอร์ออกจากเคอร์เนลเพื่อให้บิลด์ได้มีประสิทธิภาพขึ้นและดูแลรักษาได้ง่ายขึ้น
สรุป
- โปรเจ็กต์ที่วางแผนไว้ตั้งแต่สมัยมหาวิทยาลัยในปี 2013 ได้สำเร็จหลังผ่านไปกว่าสิบปี
- ได้แรงบันดาลใจจากกรณีพอร์ต Windows NT ลง Wii แล้วตัดสินใจลงมือท้าทาย
- สุดท้ายสามารถทำให้ Mac OS X 10.0 บูตเต็มรูปแบบและใช้งาน GUI บน Wii ได้
- ย้ำบทเรียนว่า “โปรเจ็กต์ที่ดูเหมือนเป็นไปไม่ได้ ยิ่งมีคุณค่าที่จะลองท้าทาย”
3 ความคิดเห็น
เป็นบทความที่น่าอ่าน พร้อมผู้เขียนที่ยอดเยี่ยมเลยนะ….
ในบรรดาคนที่คลั่งไคล้ ยังต้องยกให้สายฝรั่งเป็นที่สุด..
ความคิดเห็นจาก Hacker News
โปรเจ็กต์นี้เป็นงานที่ น่าทึ่งมาก ตัวบทความเองก็เขียนได้น่าติดตามจนอ่านเพลินจนจบ
โดยเฉพาะตรงที่บอกว่า “WindowServer แสดงอาการไม่พอใจ และเพื่อแก้ปัญหานี้จึงต้องเขียนไดรเวอร์ framebuffer ขึ้นมาเอง” ที่ประทับใจมาก
รู้สึกทึ่งที่ได้เห็นว่า ชั้น abstraction ของ I/O Kit ทำหน้าที่ของมันได้จริง ขอปรบมือให้เหล่านักพัฒนาของ NeXT
ฉันไม่มีประสบการณ์พัฒนาไดรเวอร์บนแพลตฟอร์มอื่นเลยเลยเทียบตรง ๆ ไม่ได้ แต่ในเชิงโครงสร้างมันก็ดูน่าสนใจมาก
เมื่อก่อนเคยมีนักพัฒนา NetBSD รัน PPC Darwin บนชั้นความเข้ากันได้ของ Mach/IOKit จนเปิด Xquartz ได้ด้วย ที่น่าสนใจคือ NetBSD เป็นฝ่ายแปลการเรียก IOKit
ยังรู้สึกไม่อยู่ว่าจะมี OS มากขนาดนี้รันบน Wii ได้
จริง ๆ แล้วความต่างระหว่าง abstraction ที่ดีกับแย่ มักขึ้นอยู่กับว่า มันถูกอธิบายไว้ดีแค่ไหน
ตัวงานวิศวกรรมก็น่าทึ่งอยู่แล้ว แต่สิ่งที่ประทับใจจริง ๆ คือผู้เขียนกำลัง พัฒนางานอยู่บนที่นั่งชั้นประหยัด
(ดูเพิ่มแล้ว รูปแรกเป็นรถบัส รูปที่สองเป็นเครื่องบิน)
ในฐานะ ผู้เขียนพอร์ต NetBSD Wii และ Wii U ผมขอแสดงความยินดีกับโปรเจ็กต์นี้จากใจจริง
ต่อจากนี้รอติดตามเลยว่าคุณแก้ปัญหาต่าง ๆ อย่างไรบ้าง
เมื่อก่อนฉันก็เคยเป็นแฟน Mac สายฮาร์ดคอร์ และเคยทำ “แอป iOS” ยุคแรก ๆ แบบไม่เป็นทางการด้วยการย้อนวิศวกรรม
แต่โปรเจ็กต์นี้เหนือกว่าสิ่งเหล่านั้นทั้งหมด ไม่ใช่แค่การรัน MacOS บน Wii ที่น่าทึ่งเท่านั้น ตัวบทความเองก็ ประณีตและน่าสนใจมาก
เพิ่งรู้ว่า RAM ของ Wii มีแค่ 88MB เท่านั้น ดีแล้วที่เกมพวกนั้นไม่ได้สร้างด้วย Electron
ข้อกำหนดขั้นต่ำของ Vista คือ 512MB แต่พีซีส่วนใหญ่ในตอนนั้นมีหน่วยความจำน้อยกว่านั้น
เดี๋ยวนี้จากที่ 8GB เริ่มไม่พอ กลายเป็น 16GB กำลังจะเป็นมาตรฐาน โลกเปลี่ยนไปมากจริง ๆ
ก่อนเริ่มโปรเจ็กต์ ฉันลองเช็กก่อนว่า “มันพอจะเป็นไปได้ไหม” แล้วไปเจอคอมเมนต์บน Reddit ปี 2021 ที่บอกว่า “โอกาสเป็นศูนย์เปอร์เซ็นต์”
เห็นแล้วกลับยิ่งมีแรงฮึด เลยเริ่มจากการวิเคราะห์ฮาร์ดแวร์ของ Wii มันตลกดีจริง ๆ
ผู้คนมักเหมารวมว่าสิ่งที่ “แทบเป็นไปไม่ได้” จะไม่มีวันเกิดขึ้นจริง พร้อมหลงคิดว่าตัวเองเป็นพวกสงสัยอย่างมีหลักการ
ก็เลยคิดว่า “จริงเหรอ?” แล้วคอนฟิกพอร์ต UART ใหม่เพื่อต่อ ESP32 เข้าไป
ปัญหาคือไม่มีใครพูดถึงแนวคิดเรื่องความประชดแบบเกิดจากความไม่รู้นัก
การนั่งอยู่บนที่นั่งชั้นประหยัดบนเครื่องบินพร้อมดีบัก kernel panic บน Wii ไปด้วยนั้น เป็นระดับของ สมาธิที่นึกภาพแทบไม่ออก
คนส่วนใหญ่แค่อ่านหนังสือบนเครื่องบินให้จบสักเล่มยังยากเลย
เป็นโปรเจ็กต์ที่เท่มาก ทำให้นึกถึง ยุคทองของการพัฒนาระดับล่าง
สมัยก่อนการ init VGA แล้ววาดพิกเซลลงไปเป็นเรื่องง่าย และชิปอย่าง 6502 ก็เข้าถึงได้ไม่ยาก
แต่ทุกวันนี้ระบบซับซ้อนขึ้นมากจนกำแพงในการเริ่มต้นสูงขึ้น
แถม AI ยังทำท่าเหมือนจะทำให้การพัฒนาง่ายลง แต่จริง ๆ แล้วกลับ ทำให้การเข้าถึงยากขึ้นอีก
ฉันเองก็กำลังพยายาม พอร์ต Mac OS 9 ไปลง Wii U อยู่เหมือนกัน
ดูโปรเจ็กต์นี้แล้วประทับใจมาก และทุกครั้งที่เริ่มคิดว่า “มันเป็นไปไม่ได้” ก็กลับได้กำลังใจขึ้นมาอีก
ตัวบทความยอดเยี่ยมมาก แต่การใส่วิดีโอ
.movผ่านแท็ก<video>มีปัญหาเรื่อง ความเข้ากันได้ของเบราว์เซอร์มันเล่นไม่ได้บน Chrome หรือ Firefox