Preserve formatted NAND boot and Wii Remote pairing, add DMA/SRAM conformance tests and a Wii comparison probe. Keep P1 profiling tools and native update A/B evidence; reject the unhelpful targeted SRAM shortcut.
561 lines
42 KiB
Markdown
561 lines
42 KiB
Markdown
# Wii IOS LLE / Starlet
|
||
|
||
This experimental mode replaces Dolphin's IOS HLE kernel with an emulated ARM926EJ-S (Starlet)
|
||
and executes the console-specific Wii firmware from local dumps. It is disabled by default. The
|
||
validated path now reaches the original IOS title launch, `IOS_StartPPC`, the EXI Broadway boot
|
||
stub, release of both Broadway reset lines, and execution of the IOS-loaded PowerPC title image in
|
||
Dolphin's normal Broadway core. The end-to-end path has rendered the original French System Menu
|
||
health-and-safety screen through Dolphin's Direct3D 11 backend. The original IOS80 Bluetooth stack
|
||
has also accepted an emulated paired Wii Remote, completed both L2CAP HID channels, exchanged the
|
||
Menu's setup reports, and delivered sustained input reports. Later validation launched the
|
||
Homebrew Channel through an original IOS58 reload, ran an unmodified HackMii Installer through
|
||
LetterBomb, and reached the original BootMii menu from its boot2 installation.
|
||
|
||
The implementation never writes to `nand.bin`. The whole `dumps/` directory is ignored by Git so
|
||
that boot ROMs, console keys, and NAND contents cannot accidentally be committed.
|
||
|
||
## Configuration
|
||
|
||
For the opt-in virtual USB Ethernet adapter and user-mode NAT, see
|
||
[Wii LLE Ethernet](Wii_LLE_Ethernet.md). It is independent of IOS HLE networking.
|
||
|
||
Add the following values to Dolphin's main configuration:
|
||
|
||
```ini
|
||
[Core]
|
||
WiiIOSLLE = True
|
||
CPUThread = True
|
||
|
||
[General]
|
||
WiiIOSLLEDumpPath = C:/absolute/path/to/dumps
|
||
```
|
||
|
||
Detailed JIT memory profiling is optional and disabled by default. To collect slow-access
|
||
regions, SRAM page counts and sampled hot addresses, set `WiiStarletJITMemoryProfiling = True`
|
||
under `[Core]` before starting emulation. The launch script exposes the same choice through
|
||
`-ProfileJitMemory` and explicitly disables it when that switch is absent. Aggregate slow-read,
|
||
slow-write and instruction counters remain active in both modes. A log field of
|
||
`memory-profile=false` means the detailed region counts are unavailable, not that there were no
|
||
accesses. The setting is fixed for the core's lifetime and does not alter guest memory, timing,
|
||
interrupts, or NAND persistence. It is host instrumentation and is not serialized in savestates.
|
||
|
||
The selected directory must contain the three matching files from one console:
|
||
|
||
| File | Exact size | Purpose |
|
||
|---|---:|---|
|
||
| `boot0.bin` | `0x2000` bytes | Immutable Starlet reset ROM |
|
||
| `keys.bin` | `0x400` bytes | BootMii-format OTP/key dump |
|
||
| `nand.bin` | `0x21000000` or `0x21000400` bytes | Raw NAND with spare/ECC, optionally followed by the BootMii keys footer |
|
||
|
||
For a `0x21000400`-byte BootMii dump, Dolphin compares the OTP and SEEPROM portions of the appended
|
||
footer with the separate `keys.bin`. A mismatch is rejected before any firmware executes. The
|
||
footer is validation metadata and is never exposed as NAND pages.
|
||
|
||
If validation fails, Dolphin reports the reason and stops the LLE boot. It never falls back to IOS
|
||
HLE while the mode is selected, because silently switching kernels would invalidate hardware and
|
||
exploit testing. The dump path and file data are not logged.
|
||
|
||
To request a normal NAND boot in Dolphin NoGUI, select the System Menu title ID. In LLE mode this is
|
||
a boot-chain selector, not a direct HLE title launch:
|
||
|
||
```text
|
||
DolphinNoGUI --nand_title 0000000100000002
|
||
```
|
||
|
||
The host does not look up or inject the System Menu TMD/content for this path. boot2 and the original
|
||
IOS select, authenticate, load, and start the title from the raw NAND. Other direct NAND-title,
|
||
WAD, and DOL/ELF launch requests remain rejected in LLE mode.
|
||
|
||
## Execution path
|
||
|
||
```text
|
||
Dolphin CoreTiming (Broadway clock domain, 729 MHz)
|
||
|
|
||
+-- active: 12,288 Broadway cycles --> 4,096 Starlet cycles (243 MHz)
|
||
+-- WFI idle: 72,900 Broadway cycles --> 24,300 Starlet cycles
|
||
|
|
||
v
|
||
ARMv5TE interpreter or x64 JIT
|
||
+ software TLB/I-cache
|
||
|
|
||
+-------------------------------+------------------------------+
|
||
| | |
|
||
boot0 ROM SRAM / MEM1 / MEM2 Hollywood MMIO
|
||
0xffff0000 shared memory NAND, AES, SHA, OTP, timer,
|
||
IRQ and IPC mailboxes
|
||
|
|
||
v
|
||
original IOS `/dev/*`
|
||
(when IOS is reached)
|
||
```
|
||
|
||
On reset, Dolphin parks Broadway on a host-only branch while CoreTiming continues to run; no word in
|
||
MEM1 is overwritten to create that loop. Starlet owns the normal boot sequence. Writes to
|
||
`HW_RESETS` reproduce the console's SRESET/HRESET transitions. The 64-byte EXI boot buffer written by IOS
|
||
at `0x0d806840` is exposed to Broadway at its real high reset vector, `0xfff00100`, once
|
||
`DIFLAGS_BOOT_CODE` enables the mapping. Releasing both reset lines resets the Broadway
|
||
register/cache state and executes those original instructions. The observed stub sets `SRR0` to
|
||
`0x3400` and reaches it through `rfi`; the code there establishes the BAT/MSR state and branches to
|
||
the IOS-loaded title entry at `0x81000000`. There is no host-side jump to either address. Direct
|
||
disc BS2, DOL/ELF, WAD, and arbitrary NAND-title launch paths are deliberately not mixed with this
|
||
mode because they depend on IOS HLE. Selecting the System Menu is the one exception: it starts the
|
||
raw NAND boot chain and does not directly launch the selected title.
|
||
|
||
PPC-to-Starlet commands use the existing Wii IPC registers. In LLE mode, an X1 request asserts the
|
||
Starlet IPC interrupt instead of calling `IOS::HLE::Kernel::EnqueueIPCRequest`. ARM replies and
|
||
acknowledgements update the same mailbox/control state and can interrupt Broadway. Consequently,
|
||
`/dev/fs`, `/dev/es`, and the other resource managers are intended to be created and executed by
|
||
the original IOS image—not reimplemented as LLE-specific HLE services.
|
||
|
||
The X1/X2 and Y1/Y2 producer bits are hardware latches rather than ordinary writable fields. A
|
||
producer write of zero leaves its pending bit unchanged; only the peer's write-one-to-clear bit
|
||
acknowledges it. This matters for back-to-back traffic: libogc can acknowledge one IOS reply with
|
||
X2 and immediately submit the next request with X1 before Starlet is scheduled again.
|
||
|
||
## Implemented hardware
|
||
|
||
### Freshly formatted NAND and controller pairing
|
||
|
||
Automatic Wii Remote pairing is optional at startup when `/shared2/sys/SYSCONF` or
|
||
its `BT.DINF` entry is absent. This permits boot0/BootMii to run after a formatter
|
||
without the host creating configuration files or restoring data from an older
|
||
SFFS superblock. Native Wii software remains responsible for initializing its NAND;
|
||
the emulated remotes use their default identities until pairing is established.
|
||
Existing pairing records are still reused or populated as before. Unreadable NAND,
|
||
malformed directories/configuration and failed journal writes remain errors.
|
||
This removes a host-side startup blocker; it does not guarantee that the formatter
|
||
installed a complete, bootable Wii system.
|
||
|
||
When native first-boot setup creates a new SYSCONF after formatting, a full Dolphin
|
||
restart lets the existing startup pairing routine populate its empty BT.DINF.
|
||
The write must use the native SFFS authentication layout: the complete 20-byte HMAC
|
||
starts at spare byte 1 of cluster page 6, with a second copy split between page 6
|
||
bytes 21-32 and page 7 bytes 1-8. Bad-block markers and unrelated spare bytes are
|
||
preserved, and ECC is regenerated for the ciphertext. The pairing regression test
|
||
checks both HMAC copies and spare/ECC preservation; valid decryption alone does not
|
||
prove IOS will accept the modified file.
|
||
|
||
### Devices and execution
|
||
|
||
- ARM and Thumb instruction interpretation needed by the observed boot, including banked CPU
|
||
modes, user-bank block transfers, SPSRs, high Starlet exception vectors, IRQ/FIQ entry,
|
||
ARM/Thumb interworking, ARMv5TE branches/multiplies, and CP15 registers.
|
||
- Initial ARM926 MMU translation for sections, coarse/fine page tables, and FCSE process IDs. A
|
||
generation-tagged 1 KiB software TLB caches resolved translations and is invalidated by the
|
||
original CP15 control/table/process-ID/TLB-maintenance writes.
|
||
- A physically tagged 64 KiB instruction cache avoids repeated bus fetches in hot IOS loops. CP15
|
||
`c7` maintenance invalidates it in O(1) through generation tags. ARM926 wait-for-interrupt stops
|
||
instruction issue, fast-forwards device time, and wakes on an asserted IRQ/FIQ even when masked.
|
||
- Native aligned 16-/32-bit reads translate a virtual address once and directly access boot ROM,
|
||
SRAM, MEM1, or MEM2. Direct writes remain enabled for MEM1/MEM2, while SRAM writes deliberately
|
||
retain byte-lane dispatch: treating a multi-byte SRAM store as one host write corrupted the
|
||
IOS-to-System-Menu handoff and produced the Wii fatal-error screen. Active execution advances
|
||
timer, NAND, OHCI, and Wiimote clocks once per 4,096-cycle scheduler slice instead of once per
|
||
interpreted instruction; external IRQ delivery remains bounded to about 16.9 microseconds and
|
||
WFI polling to 100 microseconds.
|
||
- An x86-64 Starlet JIT translates the observed ARM and Thumb integer, branch, interworking and
|
||
memory-transfer subset. Its inline generation-tagged TLB and direct fastmem paths cover ordinary
|
||
MEM1/MEM2 accesses plus a measured, direction-specific subset of single SRAM reads. Every SRAM
|
||
write and MMIO access still uses the exact bus. Aligned Thumb loads/stores can call that bus
|
||
directly from native code, including 8-/16-/32-bit and signed reads, without re-decoding the
|
||
instruction or returning through the dispatcher. Unaligned Thumb accesses retain interpreter
|
||
semantics, including rotated word loads and halfwords crossing a translation boundary.
|
||
Protected boot0 overlays and invalid SRAM apertures remain enforced by the bus.
|
||
- Big-endian Starlet address space, 96 KiB of physical SRAM (64 KiB bank A plus 32 KiB bank B)
|
||
exposed through the hardware's unusual 128 KiB windows, plus shared MEM1/MEM2 access.
|
||
Device DMA uses the physical A/B bank layout at `0x0d400000`, independent of the CPU's
|
||
`HW_SRNPROT.SM` bank swap. Applying the CPU mapping twice discarded AES output in IOS's SRAM
|
||
stack and left `IOSC_GenerateRand` callers retrying during the Shop SSL handshake. The common
|
||
DMA accessors cover AES, SHA, NAND, SD/SDIO and OHCI without changing CPU aliases or boot0
|
||
protection. Known-answer AES/SHA tests and bank-boundary tests reproduce the old defect.
|
||
See MINI's [CPU-to-DMA address conversion](https://github.com/fail0verflow/mini/blob/master/memory.c).
|
||
- Raw NAND reads, chip identification/status, Wii ECC generation, ECC-enabled page programming
|
||
(including the calculated-ECC DMA side buffer and random spare input), and 64-page block erase.
|
||
Programming obeys the NAND 1-to-0 bit rule.
|
||
- NAND and SEEPROM writes are session-local copy-on-write data. They participate in save states and
|
||
are discarded on a fresh emulated reset; the dump and `keys.bin` remain opened/read as immutable
|
||
source material.
|
||
- AES-CBC encrypt/decrypt DMA with the hardware key/IV FIFOs, SHA-1 compression, and the OTP
|
||
boot1-hash reads used by boot0.
|
||
- The 19.2 MHz Hollywood timer/alarm comparator, including immediate matches when programmed to
|
||
the current counter value, separate write-one-to-clear acknowledgement, completion causes, and
|
||
Starlet IRQ/FIQ masks.
|
||
- BootMii SEEPROM data exposed through the original 93C56-style GPIO serial protocol, including
|
||
read, write-enable/disable, word write/erase, and whole-array write/erase commands in COW memory.
|
||
- Hollywood's Starlet GPIO bank, including enable/output/direction/input, ownership, straps,
|
||
interrupt level/mask, and write-one-to-clear interrupt flags. POWER and EJECT have their idle
|
||
levels and the EEPROM MISO pin remains connected to the existing serial model. Writes to the
|
||
public BootMii diagnostic byte on GPIO bits 23:16 are logged as stage codes with the Starlet PC;
|
||
this observes the firmware's own progress/panic channel without modifying its control flow.
|
||
- Immediate AHM memory-flush acknowledgement, the indirect DDR/SEQ/BIST register banks used by
|
||
boot1 training, and the hardware-controlled boot0 ROM overlay/SRAM-bank swap.
|
||
- PPC/ARM IPC mailboxes, Starlet-side access to both control registers, and Broadway
|
||
SRESET/HRESET hold/release transitions.
|
||
- The Starlet EXI window at `0x0d806800` is forwarded to Dolphin's existing EXI controller at
|
||
`0x0d006800`, while the adjacent reset-vector aperture remains backed by Starlet memory. This
|
||
exposes the original EXI device state and transfer completion semantics used by MINI.
|
||
- The Broadway Serial Interface keeps an outgoing request latch separate from the readable
|
||
response RAM. Starting another transfer without rewriting communication RAM therefore repeats
|
||
the previous command, matching the controller probing performed by BootMii's `ppcboot.elf`.
|
||
- External SD host-controller and card path at `0x0d070000`: reversed-little-endian SDHCI
|
||
capabilities/version, card-detect state, self-clearing software reset, internal-clock
|
||
stabilization, write-one-to-clear interrupt status, the IOS initialization command subset,
|
||
and simple block DMA to Dolphin's copy-on-write-configured `WiiSD.raw` image. The implemented
|
||
commands cover identification/selection, OCR/CID/CSD/SCR, block-size setup, status, and
|
||
single/multiple-block reads and writes against Dolphin's copy-on-write SD image.
|
||
- The Starlet DI window at `0x0d806000` is forwarded to Dolphin's existing drive-interface MMIO
|
||
implementation (the `0x0d006000` hardware block), including byte-lane accesses and Hollywood DI
|
||
interrupt source `0x200`. This lets the original `/dev/di` resource manager service the System
|
||
Menu's post-health-screen cover/status commands instead of timing out and creating
|
||
`/shared2/test2/dvderror.dat`.
|
||
- Initial OpenHCI 1.0 host-controller path at `0x0d050000`/`0x0d060000`: controller reset and
|
||
functional states, interrupt status/enable/disable, 1 ms frame clock, HCCA frame/done-head
|
||
writeback, control/bulk/periodic list traversal, little-endian ED/TD DMA, and root-hub
|
||
power/connect/reset/change semantics routed through Hollywood IRQs 5 and 6. OHCI0 currently has
|
||
two empty external ports; OHCI1 exposes the internal `057e:0305` Bluetooth module and its USB
|
||
device/configuration/interface/endpoint descriptors. The emulated reset descriptor advertises a
|
||
nonzero two-unit power-on-to-power-good delay (4 ms in OpenHCI units), which the original driver
|
||
consumes through the original IOS timer service before scanning the hub. Standard endpoint-zero
|
||
enumeration is implemented without synthesizing an IOS IPC reply. The internal BCM2045 model
|
||
handles the HCI command/event subset used while IOS80 initializes Bluetooth, plus ACL transport
|
||
to Dolphin's existing remote-side L2CAP/HID implementation. It reuses trusted remote identities
|
||
already present in the dumped `BT.DINF` without logging their addresses. If no usable identity
|
||
exists, a session-only fallback pairing is installed by decrypting, updating, HMAC-authenticating,
|
||
ECC-correcting, and re-encrypting the affected SFFS cluster in the raw NAND COW overlay. The
|
||
final LLE-side remote devices are rebound to Dolphin's configured input sources after their NAND
|
||
identities are installed. ACL delivery waits for the connection-complete event, but unrelated
|
||
HCI events no longer block the second HID channel and deadlock the L2CAP handshake. The source
|
||
NAND remains unchanged.
|
||
- Hollywood `HW_USBFRCRST` reset-domain behavior across an IOS reload. When the original kernel
|
||
asserts a USB force-reset line, EHCI and both OHCI controllers return to their hardware reset
|
||
images before the replacement IOS drivers inspect them. This prevents operational state left by
|
||
IOS80 from making IOS58 reject OHCI0 before it can issue its own host-controller reset.
|
||
- The internal Wi-Fi SDIO host at `0x0d080000`/`0x0d880000`, including SDIO CMD5/7/52/53,
|
||
byte/word PIO and DMA transfers, CCCR/FBR/CIS data, clock and interrupt state, and the BCM4318
|
||
function-1 backplane aperture. The minimal Sonics core set exposes ChipCommon, D11, PCI and SDIO
|
||
IDs, the D11 bus-width aliases, G-PHY/radio identity, and the Wii board/MAC/antenna CIS values
|
||
required by the original Broadcom WL module. IOS80 completes hardware attach and registers its
|
||
original `/dev/wl`; no host network connection or packet-level 802.11 model is provided yet.
|
||
- The EXI Broadway boot buffer and its `0xfff00100` reset-vector mapping. The actual IOS-written PPC
|
||
stub is decoded and executed by Dolphin's normal Broadway core.
|
||
- Save-state serialization of ARM, SRAM, device, IPC, and scheduler state.
|
||
|
||
## Validated milestone
|
||
|
||
An isolated boot probe using the local, mutually matching dumps has executed this original chain:
|
||
|
||
1. `boot0` read 47 raw NAND pages, checked their ECC, decrypted boot1 with the emulated AES engine,
|
||
hashed it with the emulated SHA engine, compared the result with the console OTP value, and
|
||
transferred control to boot1.
|
||
2. boot1 trained the emulated memory controller, read and authenticated boot2, ran its ELF loader,
|
||
swapped the SRAM banks, removed the boot0 overlay, and entered the boot2/IOS image at
|
||
`0xffff0000`.
|
||
3. The IOS kernel changed from ARM to Thumb through an interworking `LDR pc`, built its translation
|
||
table at physical `0x13850000`, set its domain access register, and enabled the MMU with control
|
||
value `0x1087`.
|
||
4. The kernel entered its physical MEM2 code, mapped and ran module code at virtual
|
||
`0x20000000`/`0x20100000`, dispatched the firmware's intentional undefined-instruction system
|
||
calls through the high SRAM vectors, and performed thousands of real thread context switches.
|
||
5. boot2 created and encrypted `/tmp/launch.sys`, renamed it to `/sys/launch.sys`, and invoked the
|
||
original `ios_boot` syscall. The reloaded IOS80 mounted the newly written, HMAC- and ECC-valid
|
||
SFFS superblock and registered its original `/`, `/dev/boot2`, `/dev/es`, `/dev/di`, `/dev/stm/*`,
|
||
`/dev/usb/oh0`, `/dev/usb/oh1`, and `/dev/flash` resource managers.
|
||
6. IOS80 reopened `/sys/launch.sys`, loaded the requested title data, deleted the consumed launch
|
||
record, updated `/sys/space.sys`, and called `IOS_StartPPC`. The syscall completed successfully,
|
||
IOS populated the 64-byte EXI boot buffer, and both Broadway reset lines were released.
|
||
7. Before releasing reset, IOS had populated both the low-memory bootstrap at physical `0x3400`
|
||
and the title image backing virtual `0x81000000`. Mnemonic-only inspection confirmed a coherent
|
||
reset-stub chain (`rfi` to `0x3400`, BAT/MSR setup, then branch to the title entry) without
|
||
printing firmware bytes.
|
||
8. A full MSVC-built `DolphinNoGUI` run, using an isolated user directory and the System Menu boot
|
||
selector, executed the same chain through Dolphin's normal CoreTiming scheduler. It crossed the
|
||
1, 10, and 100 million ARM-instruction milestones, released Broadway through the EXI vector,
|
||
executed the title's BAT/HID setup, then continued through PowerPC system calls, external
|
||
interrupts, and periodic decrementer exceptions. The HLE Wii filesystem setup is explicitly
|
||
skipped when Starlet is active, preventing it from dereferencing or mutating an IOS HLE kernel
|
||
that intentionally does not exist in this mode.
|
||
9. The original PowerPC IPC client closed its initial 32 descriptor slots, opened the IOS80
|
||
resource managers `/dev/es`, `/dev/stm/immediate`, `/dev/stm/eventhook`, `/dev/fs`, and
|
||
`/dev/di`, and received ARM-generated acknowledgements and replies for sustained back-to-back
|
||
requests. The original filesystem stack read `SYSCONF`, `setting.txt`, `state.dat`,
|
||
`NANDBOOTINFO`, `loader.ini`, and a multi-megabyte System Menu content from the raw NAND. The
|
||
subsequently loaded PowerPC code reopened its IOS services and continued through IPC,
|
||
decrementer, external-interrupt, syscall, and floating-point-unavailable exception handling.
|
||
10. Complete runs with both an empty slot and a configured 128 MiB `WiiSD.raw` image reproduced the
|
||
same boot, multi-megabyte NAND load, second-stage IPC, and persistent PowerPC execution without
|
||
a regression. Synthetic tests validate reset/clock/status behavior and empty-slot command
|
||
timeout, while the inserted-card run validates discovery stability. The Menu had not yet
|
||
reached a `/dev/sdio/slot0` data request before blocking on USB, so original-IOS command-response
|
||
ordering and DMA remain to be proven end to end. That run observed the original title opening
|
||
`/dev/usb/oh1/57e/305`. A synthetic OHCI regression now proves endpoint-zero descriptor DMA,
|
||
done-head writeback, and WDH delivery; original-IOS enumeration is being validated separately
|
||
because root-hub discovery and device protocol timing remain incomplete.
|
||
11. An instrumented IOS80 run initialized both original OHCI drivers, read the emulated
|
||
`POTPGT=2` value, powered OHCI1 port 1, and waited 4 ms through the original IOS timer queue
|
||
before performing its initial empty-port scan. After initialization, the delayed internal
|
||
device attachment asserted Hollywood source 6. The original interrupt handler read and
|
||
acknowledged `RHSC`, sent its private root-hub-change message, and the original resource-manager
|
||
task dispatched it. That task observed `CSC|CCS`, acknowledged the connection change, initiated
|
||
a port reset, waited through its original 2 ms timer path, then observed `CCS|PES|PRSC` and
|
||
acknowledged reset completion. The same original driver then completed USB descriptor
|
||
enumeration and initialized the BCM2045 through HCI command/event traffic.
|
||
12. The IOS80 Broadcom WL module enumerated the emulated BCM4318 Sonics cores, passed its 32-/16-bit
|
||
D11 aperture tests, identified the G-PHY and BCM2050 radio, consumed the Wii CIS board and
|
||
antenna data, and registered `/dev/wl`. This allowed the original KD/NCD services to answer the
|
||
System Menu's `/dev/net/kd/request` and `/dev/net/kd/time` calls.
|
||
13. A headless Direct3D 11 run loaded the remaining System Menu resources through the original ES,
|
||
FS, DI and network resource managers, initialized VI/GX, and captured consecutive rendered
|
||
frames. The validated frame is the official French “Attention – Santé et sécurité” screen,
|
||
proving visible System Menu startup after the original IOS boot and Broadway release.
|
||
14. A subsequent run selected two trusted Wii Remote identities from the raw NAND `BT.DINF`, then
|
||
let the original IOS80 WUD and OHCI1 drivers perform the BCM2045 initialization and incoming
|
||
connection path. IOS accepted the first L2CAP connection response instead of returning
|
||
`L2CAP_SECURITY_BLOCK`, completed the HID control and interrupt channels, issued its normal
|
||
LED/report-mode/extension setup traffic, and received sustained `A1 37` input reports. No IOS
|
||
IPC resource manager or `/dev/usb/oh1` request was synthesized by the host.
|
||
15. A controller-driven run sent the health-screen `A` report through those original IOS80 HID
|
||
channels, completed the original `/dev/di` status path, and rendered the populated French Wii
|
||
Menu channel grid. The previous fatal-error path and `dvderror.dat` creation did not recur.
|
||
16. Performance work replaced byte-at-a-time instruction/MMU reads, per-instruction device clocking,
|
||
and repeated page-table/code fetches with safe native-width reads and MEM1/MEM2 writes, sliced
|
||
device advancement, a software TLB, and an instruction cache. SRAM writes keep their original
|
||
byte-lane path after an end-to-end regression test showed that the direct host-width shortcut
|
||
reached Broadway quickly but made the System Menu display its fatal-error screen. This benchmark
|
||
covers the ARM-active boot path.
|
||
17. Interactive profiling measured the populated Wii Menu at 13.00 FPS and 18% speed before the
|
||
final scheduler optimization. The dominant path was the original IOS Thumb scheduler loop
|
||
`LDR [Rn] -> CMP #0 -> BEQ`, which polls a shared RAM word while no thread is runnable. The ARM
|
||
core now recognizes that general side-effect-free shape only when the polled physical address
|
||
is RAM or SRAM, advances device time without replaying millions of identical instructions, and
|
||
rechecks the word or any unmasked interrupt every 100 microseconds of Wii time. MMIO polling is
|
||
never skipped. A clean Direct3D 11 run then held 100% emulation speed and 59.91 FPS on the same
|
||
populated Menu screen.
|
||
18. Launching the installed Homebrew Channel from that Menu exercised a real IOS reload from IOS80
|
||
to IOS58. The original kernel asserted `HW_USBFRCRST`; the replacement IOS registered and
|
||
initialized `/dev/usb/oh0`, `/dev/usb/ehc`, `/dev/usb/usb`, and `/dev/usb/ven`, then released
|
||
Broadway into the channel. HBC rendered its normal interface at 59.94 FPS without modifying its
|
||
executable or bypassing the reload.
|
||
19. LetterBomb loaded an unmodified HackMii Installer v1.2 from the virtual SD card. The installer
|
||
enumerated the NAND titles, selected and launched IOS58 revision `0x1820`, completed its
|
||
preparation and signature-checking work, displayed `Press 1 to continue`, accepted the emulated
|
||
Wii Remote input, and opened the HackMii installation menu. No HackMii binary, timer, syscall, or
|
||
detection check was patched. Its preparation phase is currently much slower than on hardware
|
||
because ARM-heavy IOS transients still run through the Starlet interpreter.
|
||
20. The dump's existing BootMii-as-boot2 installation intercepted a cold boot and loaded its
|
||
original `armboot.bin`/MINI from the virtual SD card. MINI initialized the emulated GPIO and
|
||
EXI paths, published its EXI Broadway boot vector, released Broadway, and ran the original
|
||
`ppcboot.elf`. The interactive four-icon BootMii menu rendered without a host-side firmware
|
||
jump, a patched BootMii binary, or a synthesized SI reply.
|
||
21. BootMii exposed two remaining Broadway hardware differences. Its VI setup writes the vertical
|
||
and horizontal beam-position registers; ignoring those writes let Dolphin's half-line counter
|
||
escape the active field and prevented the next VI interrupt. The beam writes now reposition the
|
||
emulated raster and field wrapping tolerates an out-of-range position. BootMii also clears the
|
||
PI interrupt-cause register before polling the front-panel controls. The reset-button bit is a
|
||
live active-low input, not an acknowledgeable interrupt latch, so PI acknowledgements now
|
||
preserve it. This removed the false held-RESET state that selected the Wii icon and issued
|
||
`IPC_BOOT2_RUN(1, 2)` immediately. Cold-boot BootMii and HBC -> IOS254 -> MINI -> BootMii both
|
||
remain in the original interactive menu, and keyboard-backed GameCube navigation was validated
|
||
without modifying `armboot.bin`, `ppcboot.elf`, or `bootmii.ini`.
|
||
22. Directional JIT profiling separated slow SRAM reads from writes and counted them per 4 KiB
|
||
aperture page. During the IOS-to-Menu phase, about 71% of slow SRAM accesses were writes;
|
||
pages `0x00` and `0x19` dominated those writes, while page `0x1e` dominated the remaining
|
||
reads. Single reads from the previously validated `0x00`/`0x12`/`0x14`/`0x19` pages and the
|
||
newly measured `0x1e` page now use guarded split-bank fastmem. Direct writes to `0x00`/`0x19`
|
||
passed synthetic bounds and canary tests but reproducibly stopped BootMii at its public
|
||
`hardware setup begin` GPIO marker, so every SRAM write was restored to the exact bus path.
|
||
The resulting build passed all 61 targeted Starlet/JIT tests and a fresh cold-boot regression:
|
||
BootMii completed hardware setup, the Wii selection re-entered NAND boot2, original IOS released
|
||
Broadway 54.1 seconds later, and the populated System Menu rendered without a crash or firmware
|
||
patch. The still-dominant exact writes are a measured coherency problem, not permission to skip
|
||
their bus semantics.
|
||
|
||
The probe never prints ROM, NAND, key, or firmware instruction bytes. The committed unit suite
|
||
covers ARM-to-Thumb loads into PC, high Starlet exception vectors, privileged `LDM ... ^` user-bank
|
||
transfers, latched bidirectional IPC control bits, the PI reset-button state surviving interrupt
|
||
acknowledgements, empty-slot SDHCI reset/clock/status behavior,
|
||
timer equal/future comparator matches with independent IRQ write-one-to-clear acknowledgement,
|
||
OHCI power-good/root-hub state, and a complete three-TD USB device-descriptor transaction. Targeted
|
||
development probes additionally exercised NAND read/program/erase and program-time ECC, SEEPROM
|
||
COW behavior, and AES-CBC encrypt/decrypt FIFO semantics. A separate differential harness compared
|
||
330,000 randomized
|
||
aligned ARM and Thumb cases against an ARM926-configured Unicorn 2.1.4 instance without a mismatch;
|
||
ARMv5 rotated unaligned word loads were tested separately because modern Unicorn models different
|
||
semantics.
|
||
|
||
This proves the original
|
||
`boot0 -> boot1 -> boot2 -> IOS kernel/modules -> title launch -> IOS_StartPPC -> Broadway release`
|
||
path is executing rather than being bypassed by Dolphin. At 120 million interpreted ARM/Thumb
|
||
instructions the probe observed no undefined ARM instruction outside IOS's syscall encoding, only
|
||
the three pre-existing bad-ECC pages in the source dump, a valid EXI reset vector, and
|
||
`HW_RESETS == 0xffffffff`.
|
||
|
||
The current end-to-end boundary is a rendered, controller-connected and post-health-screen System
|
||
Menu with its populated channel grid, followed by a successful original IOS80-to-IOS58 reload, a
|
||
rendered Homebrew Channel, LetterBomb reaching the interactive HackMii Installer menu, and both
|
||
cold-boot and IOS254 launches reaching a stable, navigable original BootMii UI through MINI and
|
||
`ppcboot.elf`. The path sustains PPC-to-original-IOS filesystem, DI, Bluetooth HID, SDIO/Wi-Fi and
|
||
network-service traffic. The stabilized Menu has been measured at 59.91 FPS and HBC at 59.94 FPS.
|
||
It proves the emulated first Wii Remote's pairing, L2CAP setup, command exchange and input-report
|
||
path, but not every extension, multiple-controller scenario, reconnection edge case, packet-level
|
||
networking, resource manager, or timing-sensitive exploit.
|
||
|
||
## Remaining blockers
|
||
|
||
The next firmware stages need substantially more hardware fidelity:
|
||
|
||
- ARM926 translation faults/aborts, domain and page permissions, replacement-policy fidelity, and
|
||
exact cache-maintenance timing. Address translation and functional TLB/I-cache invalidation exist,
|
||
but these protection and cycle-level details remain incomplete.
|
||
- Remaining memory-controller/AHB coherency behavior needed after the Broadway handoff and by
|
||
shared-memory DMA devices.
|
||
- NAND command latency, bad-block/wear behavior, error injection, and less common command variants.
|
||
The common IOS read/program/erase/ECC path is COW, but it is not yet a cycle-accurate flash model.
|
||
- Remaining GPIO inputs/interrupt behavior and external devices connected to those pins.
|
||
- DI, remaining SD command/response fidelity and insertion events, USB EHCI, packet-level Wi-Fi,
|
||
remaining Bluetooth/Wii Remote extensions, multi-controller and reconnection behavior, and their
|
||
DMA/interrupt timing. External SD block DMA, Wi-Fi SDIO/D11 attach, OHCI ED/TD DMA, USB
|
||
enumeration, Bluetooth HCI/ACL, and one paired remote's L2CAP/HID input path are implemented.
|
||
- Remaining IOS reload/reset edge cases, device timing, and scheduler accuracy needed by
|
||
timing-sensitive original exploits.
|
||
- Performance: the Menu's original IOS idle path runs at full speed through safe RAM/SRAM poll
|
||
fast-forwarding, and the x64 Starlet JIT now executes most ordinary ARM/Thumb instructions
|
||
natively. Boot and transient driver workloads still cross many architectural side exits for
|
||
MMIO, CP15 operations and the not-yet-native instruction subset. Those exits must be reduced by
|
||
proven instruction translations or register-specific MMIO stubs, never by treating every device
|
||
access as a resumable C helper.
|
||
|
||
Until those items are implemented, this is an end-to-end experimental LLE implementation rather
|
||
than a drop-in replacement for Dolphin's mature IOS HLE mode.
|
||
|
||
## Public implementation references
|
||
|
||
- [fail0verflow/mini](https://github.com/fail0verflow/mini) for public Starlet hardware constants,
|
||
SRAM swapping, MMU setup, and the boot2 ELF-loader shape.
|
||
- [InvoxiPlayGames/Uniicorn-Wii](https://github.com/InvoxiPlayGames/Uniicorn-Wii) for an independent
|
||
public Starlet/boot-chain emulator and high-vector behavior.
|
||
- [WiiBrew External Interface](https://www.wiibrew.org/wiki/Hardware/External_Interface) for the
|
||
documented EXI boot-buffer and Broadway reset-vector address mapping.
|
||
- [WiiBrew GPIOs](https://www.wiibrew.org/wiki/Hardware/Hollywood/GPIOs) and
|
||
[Serial Interface](https://www.wiibrew.org/wiki/Hardware/Serial_Interface) for the public GPIO
|
||
register and SI communication-RAM behavior.
|
||
- [WiiBrew NAND Interface](https://www.wiibrew.org/wiki/Hardware/NAND_Interface) and
|
||
[NAND layout](https://www.wiibrew.org/wiki/Hardware/NAND) for the command register, DMA buffers,
|
||
chip geometry, and supported device IDs.
|
||
- [WiiBrew Hollywood IRQs](https://www.wiibrew.org/wiki/Hollywood/IRQs) for the Starlet IRQ/FIQ
|
||
routing registers and interrupt-source assignments.
|
||
- [Linux Wii device tree](https://github.com/torvalds/linux/blob/master/arch/powerpc/boot/dts/wii.dts)
|
||
and [WiiBrew USB host controller](https://wiibrew.org/wiki/Hardware/USB_Host_Controller) for the
|
||
two OHCI register windows and Hollywood interrupt assignments.
|
||
- [OpenHCI 1.0a](https://www.cs.usfca.edu/~cruse/cs698s10/hcir1_0a.pdf) for controller, HCCA,
|
||
endpoint/transfer descriptor, root-hub, power-good-delay, and interrupt semantics.
|
||
- [WiiBrew IOS syscalls](https://www.wiibrew.org/wiki/IOS/Syscalls) and
|
||
[IOS kernel](https://www.wiibrew.org/wiki/IOS/Kernel) for the public timer/alarm and message-queue
|
||
interfaces used while correlating the original driver's control flow.
|
||
- [ARM926EJ-S Technical Reference Manual](https://developer.arm.com/documentation/ddi0198/latest/)
|
||
for ARMv5TE, CP15, banked-register, exception, and interworking semantics.
|
||
|
||
## JIT correctness and BootMii performance model
|
||
|
||
BootMii is two distinct Starlet programs before its Broadway UI appears. The boot2-style loader
|
||
performs Hollywood setup, mounts the external SD controller and loads `/bootmii/armboot.bin`.
|
||
MINI then configures the ARM926 MMU/caches and IRQs, initializes NAND, IPC and SDHC, loads
|
||
`/bootmii/ppcboot.elf`, writes the Broadway EXI reset stub, releases the reset lines and finally
|
||
sleeps in its IPC loop. MINI has no Wi-Fi stack. Consequently, Wi-Fi SDIO traffic observed later
|
||
belongs to Nintendo IOS/System Menu startup and is not a valid optimization target for a black
|
||
screen inside BootMii.
|
||
|
||
The public loader also gives deterministic stage telemetry. `debug_output()` writes one byte to
|
||
GPIO bits 23:16: `42/43/44` cover entry, stack and BSS setup; `F0/F1` enter and finish loader setup;
|
||
`F2/F3` select and hand off the SD payload; `C8/C9` fall back and hand off to NAND boot2; `E3/E4`
|
||
are ELF-loader panics. A panic then alternates its error byte with zero around repeated 500 ms
|
||
timer delays. Therefore a trace fixed at the loader's `udelay` loop for millions of scheduler
|
||
slices is a panic, not evidence that SDHC or the GUI merely needs more time.
|
||
|
||
The JIT follows the same invariant used by Dolphin's Broadway JIT and QEMU TCG: a slow access can
|
||
resume inside a translated block only when all guest architectural state at that instruction is
|
||
recoverable and the helper cannot change scheduling, interrupt, translation or code-cache state.
|
||
Dolphin flushes registers before its safe slow loads/stores and checks memory exceptions; QEMU
|
||
records a host-PC to guest-PC/state map so faults restore the precise instruction boundary. The
|
||
Starlet JIT does not yet have that per-instruction recovery metadata. Generic MMIO therefore exits
|
||
to the dispatcher. Future performance work can specialize proven side-effect-free registers
|
||
(for example read-only status or timer reads), while complex writes, IRQ acknowledgements, IPC and
|
||
reset transitions must remain exits.
|
||
|
||
The ARM926 manual is also explicit about the boundaries relevant here: wait-for-interrupt drains
|
||
the write buffer and sleeps until IRQ/FIQ/debug; disabling and re-enabling the MMU preserves TLB
|
||
contents; D-cache clean, write-buffer drain, I-cache invalidation and TLB invalidation are separate
|
||
CP15 operations. Collapsing all `c7` maintenance into a code-cache flush is both inaccurate and
|
||
slow, while ignoring the instruction-cache operations breaks self-modifying boot code.
|
||
|
||
### IOS syscall execution and evaluated acceleration strategies
|
||
|
||
IOS has two superficially similar software-exception ABIs. Normal kernel calls are deliberately
|
||
undefined ARM words of the form `0xE6000010 | (syscall_number << 5)`. The Undefined vector saves
|
||
the complete thread context, extracts bits 12:5, switches to System mode and dispatches through the
|
||
IOS-version-specific syscall table. ARM/Thumb `SVC 0xAB` is a separate RealView semihosting ABI;
|
||
production IOS retains essentially only debug-string output (`r0 = 4`, string in `r1`). Replacing
|
||
either path with host-side IOS HLE would skip the original scheduler, message queues, permission
|
||
checks and exploit-relevant kernel behavior, so LLE keeps the guest handlers. The JIT only enters
|
||
the architecturally correct Undefined/Supervisor exception directly, avoiding a redundant generic
|
||
instruction-decoder fallback.
|
||
|
||
The acceleration options were evaluated as follows:
|
||
|
||
| Method | Expected value here | Decision |
|
||
|---|---|---|
|
||
| Per-instruction interpreter | Reference accuracy, very low throughput | Keep as the exact fallback/oracle only |
|
||
| IOS syscall HLE | Very fast for ordinary titles | Reject for original IOS and exploit compatibility |
|
||
| QEMU TCG/Unicorn ARM core | Mature ARM system translation | Valuable reference, but integrating Dolphin memory, Hollywood MMIO, CoreTiming, precise cache invalidation and dual-CPU IPC would duplicate most of the current machine model |
|
||
| LLVM/whole-function recompilation | Strong global optimization | Excessive compile latency and difficult precise MMIO/exception recovery during boot and self-modifying code |
|
||
| Custom basic-block JIT | Shares Dolphin memory and timing directly | Selected; continue with measured native coverage and exact side exits |
|
||
| Native ARM predication | Removes common IOS conditional-ALU fallbacks | Implemented for every already-validated data-processing form |
|
||
| Native Undefined/SVC entry | Removes decoder fallback at each software exception | Implemented without bypassing the guest kernel handler |
|
||
| Direct block chaining | Removes dispatcher lookup on hot edges | Next high-value CPU optimization, provided TLB/I-cache invalidation unlinks every affected edge |
|
||
| Wider register allocation / traces | Reduces repeated guest-register loads and stores | Medium-term; add only after branch/memory profiles identify stable hot traces |
|
||
| Register-specific MMIO fast paths | Can remove very hot safe status reads | Only after sampled effective-address traces; generic MMIO continuation is forbidden |
|
||
|
||
This ordering follows the same split documented by
|
||
[QEMU TCG](https://github.com/qemu/qemu/blob/master/docs/devel/tcg.rst): RAM/ROM accesses use cached
|
||
host offsets, MMIO calls device code, and direct block chains must be removable when translated
|
||
pages change. The current microbenchmark reaches roughly two billion simple translated ARM
|
||
instructions per host second, while complete IOS traces are orders of magnitude slower. The raw
|
||
x86 emitter is therefore not the limiting component; remaining work is native coverage, side-exit
|
||
frequency, guest scheduling/idle detection and device-access cost.
|
||
|
||
## Code map
|
||
|
||
| Area | Files |
|
||
|---|---|
|
||
| ARM CPU | `Core/IOS/Starlet/ARMCore.{h,cpp}` |
|
||
| x86-64 ARM/Thumb JIT | `Core/IOS/Starlet/ARMJitX64.{h,cpp}` |
|
||
| Starlet scheduler/lifetime | `Core/IOS/Starlet/Starlet.{h,cpp}` |
|
||
| Address space and devices | `Core/IOS/Starlet/StarletMemory.{h,cpp}` |
|
||
| Bluetooth pairing and Wii Remote HID | `Core/IOS/USB/Bluetooth/{BTBase,WiimoteDevice}.{h,cpp}` |
|
||
| IPC and Broadway reset | `Core/HW/WII_IPC.{h,cpp}` |
|
||
| Broadway VI and front-panel state | `Core/HW/VideoInterface.cpp`, `Core/HW/ProcessorInterface.{h,cpp}` |
|
||
| Mode selection/lifetime | `Core/HW/HW.cpp`, `Core/System.{h,cpp}` |
|
||
| Boot-path separation | `Core/Boot/Boot.cpp`, `Core/ConfigManager.cpp`, `Core/Core.cpp` |
|
||
| Configuration | `Core/Config/MainSettings.{h,cpp}` |
|
||
| Starlet CPU/device unit tests | `UnitTests/Core/IOS/Starlet/ARMCoreTest.cpp` |
|
||
|
||
## Conformance work
|
||
|
||
The current priority is behavioral agreement with a real Wii, not a fixed FPS
|
||
target. [`Tools/WiiConformanceProbe`](../Tools/WiiConformanceProbe/README.md)
|
||
builds one PPC homebrew binary to run against native IOS on both systems and
|
||
compares numbered return codes and outputs. Keep the probe binary identical,
|
||
record the IOS revision and starting NAND state, and label physical-Wii versus
|
||
emulator captures explicitly. Local captures are not automatically treated as
|
||
hardware ground truth. When a result differs, add a minimal deterministic unit
|
||
test for the relevant IPC, memory, timing, or device behavior before changing
|
||
the emulator. Performance optimizations must preserve those observations and
|
||
the BootMii → Wii boot path.
|
||
|
||
## Safe development rules
|
||
|
||
1. Treat all dumps as private console material and never print keys or ROM/NAND bytes in logs.
|
||
2. Keep `nand.bin` read-only; implement writes only in a separate copy-on-write overlay.
|
||
3. Test new devices first with synthetic data, then with address/PC traces that reveal no secrets.
|
||
4. Do not call IOS HLE from LLE code. Missing hardware should fail visibly instead of silently
|
||
changing the firmware behavior, especially while testing exploits.
|