MIOS

From WiiBrew
Jump to navigation Jump to search
MIOS
WiiDrawing.png
Technical info
TypeSpecial IOS


MIOS is a special version of IOS that runs when the Wii enters GameCube mode, specifically launched by boot2 if it detects the lowered clock speed set by BC (if syscall 55 returns 162). The same MIOS is used for all GameCube games and software. It has seen minimal updates in the Wii's lifetime.

MIOS contains a full copy of the GC IPL,[check] slightly modified for the Wii. It performs patching of some games when they load, presumably to enhance compatibility with problematic titles.

MIOS is responsible for reading and running apploaders, but not for configuring the streaming audio (DTK) buffer; the System Menu's BS2 sets that up in state 11. Neither BC nor MIOS reset the disc drive, as doing so would clear the buffer configuration.

Once a GameCube game starts, MIOS does not do much, as direct access to GameCube hardware is now enabled. The main function of MIOS at this point is to handle the front buttons on the Wii; pressing the power button at this point shuts down the GameCube game and launches boot2, which launches the System Menu to complete the shutdown. It does this by listening to IRQs 11 and 15, with GPIOs configured to trigger an interrupt on the press of the power button; on IRQ 11, it shuts down with the RSTB_CPU bit of HW_RESETS cleared, while the bit is set on IRQ 15. Oddly, boot2 only sets 0x80003164 (which the System Menu uses to decide to shut down) if RSTB_CPU is set, which means IRQ 15 must fire first.[check]

Version Table

Version ARM code size PPC code size Notes
v0 0x4620 0x2785c Present on Prelaunch System Menu consoles.
v1 0x4954 0x275bc Present on Launch Wiis as well as Korean Wiis (which lacked gamecube functionality).
v4 0x4988 0x277dc First release
v5 0x2659c Blocks Datel's GameCube discs for one ID
v8 0x4d58 Overwrites memory to prevent the Tweezer Attack.
v9 0x4f1c Parental controls support[check] (3.4)
v10 0x4ee4 Fixes IOS exploits fixed in 4.2

v5, v8, v9, and v10 all have the same PowerPC code, while v4, v1, and v0 all have different code. Every version other than v0 prints "--- GAMECUBE BOOTROM for REVOLUTION v1.1 ---" on startup (v0 prints "--- GAMECUBE BOOTROM for REVOLUTION v1.0 ---").

v4 does not contain the Datel-blocking code, nor does it contain the Tony Hawk's Pro Skater 3 patch. v1 does not patch PZL (though it does still patch GZL and GSR). v0 does not handle patches in any obviously different way from v1; however, among other things, it has the strings "Insert disk" and "Wrong disk" which do not appear in v1. The patches included in all versions have the same content in all versions.

All versions have different ARM code except for v4 and v5, which are identical. Versions prior to v8 print "Compat mode kernel thread init" and "Compat mode idle thread started" on startup and "Compat mode IOS..." elsewhere, while v8 prints "$IOSVersion: IOS: 03/13/08 17:11:05 64M $", v9 prints "$IOSVersion: IOS: 06/05/08 00:07:50 64M $", and v10 prints "$IOSVersion: IOS: 08/22/09 12:41:31 64M $".

Patches

For MIOS v10, there are two places where patches happen: 813011e8 (used as a callback to DVD commands) and 81301598 (used before closing the apploader).

After-read patches

Legend of Zelda

Applied to games with a GameID whose first 3 bytes are GZL (The Legend of Zelda: The Wind Waker), PZL (The Legend of Zelda: Collector's Edition), and GSR (Smuggler's Run: Warzones, for some reason). First, it makes several fixed copies:

  • 0x30 bytes (12 instructions) from 81301df0 to 80001800: a function that sets 80001830 to r3, 80001834 to r4, 80001838 to r5, and 8000183C, and returns 80001840
  • 0x100 bytes (64 instructions) from 81301e20 to 80001840: a (52-instruction) function that does the following, along with a partial copy of a patch for Tony Hawk that probably is unused:
void FUN_80001840
               (undefined4 uParm1,undefined4 uParm2,undefined4 uParm3,undefined4 uParm4,
               undefined4 uParm5,undefined4 uParm6,undefined4 uParm7,undefined4 uParm8)

{
  FUN_800019c0(DAT_80001830,DAT_80001830 + DAT_80001834);
  FUN_80001dc4(DAT_80001830,DAT_80001830 + DAT_80001834);
  FUN_80002200(DAT_80001830,DAT_80001830 + DAT_80001834);
  (*DAT_8000183c)(uParm1,uParm2,uParm3,uParm4,uParm5,uParm6,uParm7,uParm8);
  return;
}
  • 0x800 bytes (512 instructions) from 81301ff0 to 80001940: 3 functions: FUN_80001940 which does graphics-related things, and FUN_800019c0 and FUN_80001dc4 which appear to look for and replace certain instruction patterns. The latter two functions match other functions which are called by MIOS directly. FUN_80001940 appears to be a template for __GXSetVAT, as three instructions have their lower halves replaced (80001940 = 81200000 (lwz r9, 0x0), 80001944 = 39400000 (li r10, 0x0), and 800019b8 = 98090000 (stb r0, 0x0(r9))) before being copied over another location in memory.
  • 0x100 bytes (64 instructions) from 81302d50 to 80002200: a single function that is just an immediate blr, followed by the code for several different patching functions used by MIOS (copied by accident?). This address is written by several different patches, but doesn't seem to do anything here.

This is followed by calls to two functions that dynamically look for data to patch in the read data (there is also logging for how long the calls to these functions take).

  • FUN_81302ea4, which looks for the same instruction patterns as FUN_800019c0, but has additional logging which notes "Patch __GXSetVAT() from 0x%08X (pattern 1)" or "Patch __GXSetVAT() from 0x%08X (pattern 2)". This patches FUN_80001940 (to handle different addresses?[check]), then copies the entirety of FUN_80001940 (32 instructions/128 bytes) over some other function. The calling function logs "GX ----> Time: %4d [ms]".
  • FUN_813032fc, which looks for the same instruction patterns as FUN_80001dc4, but has additional logging which notes "Hook to Read() from 0x%08X (pattern 2)" or "Hook to Read() from 0x%08X (pattern 1)". This patches a single instruction when it finds the right one. The calling function logs "DVD ---> Time: %4d [ms]".

Tony Hawk's Pro Skater 3

Applies to games with a GameID whose first 4 bytes are GT3P, GT3F, or GT3D (the PAL/French/German versions of Tony Hawk's Pro Skater 3, but not the US or Japanese versions). First, it makes several fixed copies:

  • 0x30 bytes (12 instructions) from 81301df0 to 80001800: same as Legend of Zelda
  • 0x100 bytes (64 instructions) from 81301e20 to 80001840: a (52-instruction) function that does the following, along with a partial copy of a patch for Legend of Zelda that probably is unused:
void FUN_80001840
               (undefined4 uParm1,undefined4 uParm2,undefined4 uParm3,undefined4 uParm4,
               undefined4 uParm5,undefined4 uParm6,undefined4 uParm7,undefined4 uParm8)

{
  FUN_800019c0(DAT_80001830,DAT_80001830 + DAT_80001834);
  FUN_80001aac(DAT_80001830,DAT_80001830 + DAT_80001834); // only change from LOZ
  FUN_80002200(DAT_80001830,DAT_80001830 + DAT_80001834);
  (*DAT_8000183c)(uParm1,uParm2,uParm3,uParm4,uParm5,uParm6,uParm7,uParm8);
  return;
}
  • 0x800 bytes (512 instructions) from 81301ff0 to 80001940: 3 functions: FUN_80001940 which does graphics-related things, and FUN_800019c0 and FUN_80001aac which appear to look for and replace certain instruction patterns. 80001aa8 is a NOP, and everything after 80001e28 is unrelated code used by MIOS (only 1256 bytes or 314 instructions are actually used). The latter two functions match other functions which are called by MIOS directly. FUN_80001940 appears to be unused and matches the __GXSetVAT template for Zelda.
  • 0x100 bytes (64 instructions) from 81302d50 to 80002200: same as Legend of Zelda

This is followed by calls to two functions that dynamically look for data to patch in the read data (there is also logging for how long the calls to these functions take).

  • FUN_813036d4, which matches FUN_800019c0 apart from logging. Logs "Patch PAL 312H Noninterlace from 0x%08X". Depending on the GameID (read from 0xc0000000 instead of 0x80000000), it patches different addresses: for GT3P, 801f0946 is used; for GT3F, 801f12c6 is used; for GT3D, 801f1386 is used. 0x00210021 is written to that address, and 0x027001b0 is written to that address + 0x14 (e.g. 801f095a), as long as the address is within the range that was read. The calling function logs "VI ----> Time: %4d [ms]".
  • FUN_813032fc, which is the exact same function as used for Legend of Zelda. The calling function logs "DVD ---> Time: %4d [ms]".

Datel blocker

Although not strictly a patch, this function also checks that the parameters for reads issued by the apploader match expected values if the first 4 bytes of the GameID are GNHE (Both Datel and NHL Hitz 2002 use GameID GNHE5d, with an oddly lowercase final character). Since Datel's apploader uses different read locations from NHL Hitz 2002, this effectively blocks existing Datel discs (though it was trivially bypassed by them using a different GameID).

Expected reads
Memory Size Disc offset
812013C0 00000020 00000108
81201500 00000020 00000110
817FC8C0 00002000 00000110
812013E0 00000100 00007340
80003100 000023C0 00007380
80005580 001B1480 00007C70
800054C0 00000060 00074190
80005520 00000060 000741A8
801B6A00 000001E0 000741C0
801B6BE0 00000020 00074238
801B6C00 000015C0 00074240
801B81C0 0002EFA0 000747B0
802802E0 00001EC0 00080398
802836E0 00004340 00080B48
817FE8C0 00001740 00081C40

After these 15 reads, the function stops checking.

Other patches

These patches are applied right before the apploader is closed. All of them create FUN_80002200 with overly large copies; it's not clear how that code is called though.[check]

Pokémon Colosseum (Japan)

Applies to GC6J; "Patch to GC6J" is logged. NOPs 80005ca4 by writing 0x60000000 to it. Also copies 0x100 bytes (when only 16 would be needed) from 81302cd8 to 80002200, making FUN_80002200 a function that NOPs 80005ca4.

Pokémon Colosseum (USA)

Applies to GC6E; "Patch to GC6E" is logged. NOPs 80005614, 80005c20, 80005d2c, 80005d50, 80036598, 80036688, and 80036740. Also copies 0x100 bytes (when only 44 would be needed) from 81302ce8 to 80002200, making FUN_80002200 a function that NOPs those same addresses.

Pokémon Colosseum (Europe)

Applies to GC6P; "Patch to GC6E" (sic) is logged. NOPs 80005614, 80005d1c, 80005e24, 80005e48, 800387e4, 800388d4, and 8003898c. Also copies 0x100 bytes (when only 44 would be needed) from 81302d14 to 80002200, making FUN_80002200 a function that NOPs those same addresses.

Phantasy Star Online Episode I & II Plus

Applies to GPOJ when the disc version in the header is 5; "Patch to GCOJ ver.5" (sic) is logged. This applies to the second release of the Japanese version of Phantasy Star Online Episode I & II Plus (though the GPOJ GameID is also used by the original Phantasy Star Online Episode I & II, which has two releases with versions 2 and 3). Copies 0x100 bytes (when only 16 would be needed) from 81302d40 to 80002200, making FUN_80002200 a function that NOPs 8000f2cc. The patch itself does not NOP 8000f2cc.