============================= IOS/boot2 boot process ============================= - es_main() is called - ES registers /dev/es resource manager - gets its own process ID and sets GID to 0 (kernel) - uses syscall 0x47. the first argument (which appears to mean whether IOS is modular) is set to 3 for IOSes if that value is higher than 2 => modular / normal IOS: - ES uses syscall 0x4d to get its own version (based on the value at 0x3140) - loads modules for that version - opens /sys/launch.sys * if /sys/launch.sys exists: - reads /sys/launch.sys into 2 buffers (8 bytes for the title ID, 0xd8 bytes for the ticket view) - reads the TMD - calls syscall 0x59 (load PPC) with r0 = (pointer to TMD + 0x1ba) -- this points to the reserved field in the TMD - calls ES_Launch - goes into message receive loop * otherwise (ret = -106): - opens /sys/disc.sys * if /sys/disc.sys exists: - ES gets file stats for /sys/disc.sys to get its size (ioctl 0xb, 8 bytes of output, no input) - reads it completely (title ID?), closes the file - calls syscall 0x59 (load PPC) with r0 = (pointer to read buffer + 0xe0 (title ID + tikview) + 0x1ba) -- again, this points to a reserved field in the TMD - deletes /sys/disc.sys - goes into message receive loop * otherwise (ret = -106): - ES calls syscall 0x59 (load PPC) with r0 = 0x2010E540 - goes into message receive loop * on any error, the boot process will halt if that value is lower than 2 => monolithic / boot2: - /sys/boot.sys stuff: - ES checks whether /sys/boot.sys exists * if it exists, IOS does some additional things: - ES opens /sys/boot.sys, reads 4 bytes from it, then closes it - ES opens /dev/boot2, calls ioctl 0x3 (input buffer: 4 bytes from /sys/boot.sys, no output) - if the ioctl succeeded, /sys/boot.sys is deleted - ES checks the system bus clock * if it's 162 (GC mode, set by BC), it launches MIOS (1-101) * otherwise, it launches the system menu (1-2) - goes into message receive loop ============================= Active title ============================= IOS stores the active title in a structure like this: struct ESActiveTitle { Ticket* ticket; TMDHeader* tmd; u32 active; }; ES_DIVerify and ES_Launch can modify es_active_title used by most ES_Di* ioctlvs (which are not specific to the DI, but are used for the active title), etc. (no title => ES_EINVAL) SetUID takes a title ID, gets a TMD view, and sets the GID for PID 15 according to the TMD field ES_DIVerify, ES_Launch sets it as well ============================= ES_DIVerify ============================= - called from the DI driver during a partition open with the TMD and ticket - creates the entry in uid.sys, data directory, etc. (haven't confirmed this in depth, but this is what Dolphin does and it appears to match with what IOS does) - sets GID (syscall) according to group ID in TMD - deletes /sys/space.sys - deletes /sys/launch.sys - writes the title ID + ticket view (ES_DIGetTicketView) to /sys/disc.sys (only if IOS > 27) ============================= ES_Launch ============================= the ES_Launch ioctlv calls ES_Launch(u32 title_type, u32 title_identifier, TicketView* view, u32 unknown) ES_Launch: - if the title type is 00000001 and the title to launch is not the system menu, boot_ios() - otherwise, it's a PPC title: - deletes /sys/launch.sys if it exists and creates /sys/space.sys - reads TMD, determines required IOS version * if IOS was already reloaded: boot_ppc() * otherwise: - ES deletes /sys/space.sys and /sys/disc.sys - reads TMD, writes title ID + ticket view to /sys/launch.sys - reloads into new IOS (even if it is the same version) - new IOS boots - -1017 (ES_EINVAL) if the required vectors are not passed - -1028 (ES_ENOENT) if the ticket does not exist (this is called from es_launch) boot_ios (syscall): - writes to 0x3140 for the new IOS - IOS restarts into new kernel, acks - new IOS boots and takes over boot_ppc (syscall): - writes 0xdeadbeef to 0x3160 (init semaphore) - writes code to the EXI boot buffer - sets up magic constants in memory - bootstraps the PPC - writes 0x0 to 0x3160 (ready) reinit_ipc (syscall): - "set IPC access rights" - argument may be some kind of salt? (according to debug message) - reinits IPC (writes bits 111000 to 0xd80000c, which sets the ack flag) ============================= ES_Launch according to marcan ============================= Indeed, LaunchTitle has special treatment for system titles. I think the logic goes like this (it's been a while since I looked at it): - If the first half is >1, then it's a channel - If the titleID is 1-2, then it's the system menu ( a channel ) (also gets special privs) - If the titleID is 1-3 to 1-ff (255), then it's an IOS - If the titleID is 1-100 or 1-101 then it's BC or MIOS and it mostly gets loaded as an IOS. The main difference is between IOS-like and channel-like title IDs. IOSes get loaded as is, while channels have their IOS version checked. If the same, it just loads the channel. If different, it sets a flag file in NAND with the titleID and ticket view and then loads the IOS specified in the channel TMD, which then proceeds to load the channel itself.