IOS: add x64 Starlet JIT with guarded fastmem
This commit is contained in:
+99
-7
@@ -63,8 +63,8 @@ Dolphin CoreTiming (Broadway clock domain, 729 MHz)
|
||||
+-- WFI idle: 72,900 Broadway cycles --> 24,300 Starlet cycles
|
||||
|
|
||||
v
|
||||
ARMv5TE interpreter
|
||||
+ software TLB/I-cache
|
||||
ARMv5TE interpreter or x64 JIT
|
||||
+ software TLB/I-cache
|
||||
|
|
||||
+-------------------------------+------------------------------+
|
||||
| | |
|
||||
@@ -118,6 +118,13 @@ X2 and immediately submit the next request with X1 before Starlet is scheduled a
|
||||
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, register-list transfer, TLB miss, MMIO access, protected boot0 overlay, invalid SRAM
|
||||
aperture or unsupported instruction remains an architectural side exit: registers are flushed,
|
||||
the exact interpreter/device operation runs, and the dispatcher re-samples IRQ/FIQ, IPC yield,
|
||||
CP15 and translation state before another native block executes.
|
||||
- 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.
|
||||
- Raw NAND reads, chip identification/status, Wii ECC generation, ECC-enabled page programming
|
||||
@@ -135,7 +142,9 @@ X2 and immediately submit the next request with X1 before Starlet is scheduled a
|
||||
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.
|
||||
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
|
||||
@@ -305,6 +314,18 @@ An isolated boot probe using the local, mutually matching dumps has executed thi
|
||||
`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
|
||||
@@ -354,10 +375,12 @@ The next firmware stages need substantially more hardware fidelity:
|
||||
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 now runs at full speed through safe RAM/SRAM poll
|
||||
fast-forwarding. ARM-heavy boot and transient driver workloads still use the interpreter and can
|
||||
take longer than real hardware; a block cache or ARM JIT remains the next performance frontier
|
||||
for sustained workloads that do not enter the scheduler's idle loop.
|
||||
- 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.
|
||||
@@ -389,11 +412,80 @@ than a drop-in replacement for Dolphin's mature IOS HLE mode.
|
||||
- [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}` |
|
||||
|
||||
Reference in New Issue
Block a user