IOS
IOS (unofficially known as IOSU for distinguishing between the Wii and Wii U variants) is the operating system running on the Starbuck coprocessor in Wii U mode. It is the Wii U equivalent of the IOS on the Wii and, while similar in some aspects, is a complete rewrite with many changes.
While the kernel implements memory, process and thread management, device drivers and security handlers run as processes in the ARM user mode. These processes, called resource managers (RMs), can register as request handlers for resources, which are represented as nodes under "/dev" in a virtual filesystem. They communicate with each other through the kernel, using standard Unix file operations (open/close/read/write/seek/ioctl/ioctlv).
The IOSU firmware image file ("fw.img") is stored as an Ancast image which, when decrypted, contains three regions: a header, an ELF loader and the actual operating system image as an ELF binary.
Header
This just contains the 0x100-byte struct BootOSImageHeader.
BootOSImageHeader
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x4 | HdrSize (always 0x100) | 
| 0x4 | 0x4 | LoaderSize | 
| 0x8 | 0x4 | ImageSize | 
| 0xC | 0x4 | DdrInit | 
| 0x10 | 0xF0 | Pad | 
Loader
Each time the IOSU starts, the ELF loader is the first portion of code that runs in order to make preparations for the actual IOSU binary. During the console's initial boot, boot1 is responsible for fetching the "fw.img" file from NAND, verifying, decrypting and launching it (cold boot). However, IOS-MCP also has to do this when handling a system restart (warm boot) for which it follows a similar path but, ultimately, uses the LaunchOS system call in order to disable memory protections and jump to the IOSU's ELF loader code.
The loader does the following:
- Clears it's own stack;
- Sets 0x20 in HW_SRNPROT register, if not set already;
- Fetches e_phnum from the IOSU's ELF header;
- Loops through the IOSU's ELF program header structs;
- For each program marked with PT_LOAD, copies it's code into the target physical memory;
- Wipes the IOSU's ELF binary from MEM1;
- Wipes itself from MEM1 (excluding the then running subroutine);
- Jumps to 0xFFFF0000 (IOSU kernel boot).
Kernel
After being parsed by it's own ELF loader, the IOSU's kernel is launched from the Wii U's SRAM (0xFFFF0000). IOSU's kernel follows a standard ARM microkernel architecture:
// IOSU kernel entry-point
// ARM vector table (firmware 5.5.1)
start()  // 0xFFFF0000
{
  // Reset handler
  pc <- sub_FFFF0060
	
  // Undefined handler
  pc <- loc_812DD6C
	
  // SWI handler
  pc <- sub_812DD20
	
  // Prefetch handler
  pc <- sub_812E74C
	
  // Abort handler
  pc <- sub_812E720
	
  // NULL
  pc <- loc_FFFF0040
	
  // IRQ handler
  pc <- loc_FFFF0044
	
  // FIQ handler
  pc <- loc_FFFF0048
}
Execution follows into the reset handler:
// Reset handler (firmware 5.5.1)
sub_FFFF0060()
{
  r0 <- 0
	
  // Invalidate ICache
  MCR p15, 0, R0,c7,c5, 0
	
  // Invalidate DCache
  MCR p15, 0, R0,c7,c6, 0
	
  // Read control register
  MRC p15, 0, R0,c1,c0, 0
	
  // Set replacement strategy to Round-Robin
  r0 <- r0 | 0x1000
	
  // Enable alignment fault checking
  r0 <- r0 | 0x2
	
  // Write control register
  MCR p15, 0, R0,c1,c0, 0
	
  // Clear the IOS-KERNEL stack
  memset_range(stack_start, stack_end, 0, 0x04);
	
  // Disable boot0 mapping
  r0 <- 0x0D80018C   // HW_SPARE1
  r1 <- 0x00(HW_SPARE1)
  r1 <- r1 | 0x1000
  0x00(HW_SPARE1) <- r1
	
  // MSR CPSR_c, #0xD3 -> Enter supervisor mode, FIQ/IRQ disabled
  // SP == 0xFFFF0904
  init_svc_stack(0xFFFF0904);
	
  // MSR CPSR_c, #0xD2 -> Enter IRQ mode, FIQ/IRQ disabled
  // SP == 0xFFFF1104
  init_irq_stack(0xFFFF1104);
	
  // MSR CPSR_c, #0xD1 -> Enter FIQ mode, FIQ/IRQ disabled
  // SP == 0xFFFF1504
  init_fiq_stack(0xFFFF1504);
	
  // MSR CPSR_c, #0xD7 -> Enter abort mode, FIQ/IRQ disabled
  // SP == 0xFFFF0D04
  init_abort_stack(0xFFFF0D04);
	
  // MSR CPSR_c, #0xDB -> Enter undefined mode, FIQ/IRQ disabled
  // SP == 0xFFFF1904
  init_undefined_stack(0xFFFF1904);
	
  // MSR CPSR_c, #0xDF -> Enter system mode, FIQ/IRQ disabled
  // SP == 0xFFFF1904
  init_user_stack(0xFFFF1904);
	
  // Jump to MEM0 check
  lr <- pc
  pc <- sub_FFFFDA38
  while(1);
}
MEM0's integrity is checked before going any further:
// Check MEM0 for IOS-KERNEL (firmware 5.5.1)
sub_FFFFDA38()
{
  r1 <- 0x08143008  // IOSU kernel data region
  r3 <- 0xA5A51212
	
  r2 <- 0x00(0x08143008)
	
  // Deadlock
  if (0x00(0x08143008) != 0xA5A51212)
  {
     r3 <- 0xDEAD1111
     sp <- 0xDEAD1111
     while(1);
  }
  r12 <- 0xFFFF0500	// IOSU boot heap region
  r2 <- 0x00(0xFFFF0500)
	
  // Deadlock
  if (0x00(0xFFFF0500) != 0xA5A51212)
  {
     r3 <- 0xDEAD1111
     sp <- 0xDEAD1111
     while(1);
  }
	
  // Set init magic
  r2 <- 0x5A5AEDED
  0x00(0xFFFF0500) <- 0x5A5AEDED
  0x00(0x08143008) <- 0x5A5AEDED
	
  // Flush AHB for Starbuck
  ahbMemFlush(0);
  ahb_flush_to(1);
	
  // Load IOS_KERNEL
  r2 <- sub_8121B18
  sub_8121B18();
	
  // Deadlock
  r3 <- 0xDEAD2222
  sp <- 0xDEAD2222
  while(1);	
}
And, finally, execution switches over to MEM0 where the IOS-KERNEL module will be running:
// Load IOS-KERNEL (firmware 5.5.1)
sub_8121B18()
{
  // Read LT_DEBUG register
  // and store it's value at 0x08150000
  sub_8120970();
	
  // Clear LT_DEBUG register
  sub_8120988();
	
  // Do a bitwise AND with the LT_DEBUG value
  r0 <- 0x80000000
  r0 <- sub_81209B8(0x80000000);
	
  // If LT_DEBUG is 0x80000000
  // the hardware is using RealView
  if (r0 != 0)
  {
    r4 <- (sp + 0x04)
    r3 <- 0
    0x00(sp) <- 0
		
    // Wait for user input
    // to start the kernel
    while (r3 != 0x01)
    {
	r0 <- "\n\n\n\n\n\n\n\n\n\n"
	debug_printf("\n\n\n\n\n\n\n\n\n\n");
			
	r0 <- "Enter '1' to proceed with kernel startup. "
	debug_printf("Enter '1' to proceed with kernel startup. ");
			
	r0 <- "%d"
        r1 <- sp
	debug_read("%d", sp);			
	
       r3 <- 0x00(sp)
    }
  }
	
  // Initialize the MMU and map memory regions
  sub_8120C58();
	
  // Reset GPIOs and IRQs
  sub_8120510();
	
  // Setup IRQ handlers
  sub_8120488();
	
  // Clear and set some kernel structures
  sub_812B308();
	
  // Setup iobuf
  sub_81235E8();
	
  // Re-map shared_user_ro
  sub_81294AC();
	
  // Clear IOS_KERNEL module's thread stack and run it
  sub_812CD08();
	
  return;
}
At this point, the IOS-KERNEL module is running on it's own thread and becomes responsible for launching and controlling all the other IOSU modules. The kernel is responsible for tasks such as as IPC handling, permissions' control, resource managers (/dev nodes) and much more.
System calls are handled through the ARM undefined handler and mapped into their respective kernel functions.
There are 2 types of syscalls:
- Syscalls using undefined ARM instruction
- Syscalls using ARM syscall instruction
Syscalls (via undefined instructions)
Similarly to the Wii's IOS, the IOSU uses a syscall table that is stored towards the end of the kernel area inside the main ARM binary (fw.img).
The second vector is the invalid instruction handler, which is used to implement syscalls:
fw:FFFF0000 LDR PC, =_reset fw:FFFF0004 LDR PC, =starbuck_syscall_handler
The Starbuck syscall handler:
starbuck_syscall_handler
   STMFA           SP, {R0-LR}^
   MRS             R8, SPSR
   STR             R8, [SP]
   STR             LR, [SP,#0x40]
   LDR             R10, [LR,#-4]   ; R10 = E7F0XXXX  (the invalid instruction)
   BIC             R9, R10, #0xFF00
   LDR             R8, =0xE7F000F0   ; Syscall base
   CMP             R9, R8            ; Were any bits set other than the syscall number
   BNE             invalid_syscall
   MOV             R10, R10,ASR#8
   AND             R10, R10, #0xFF
   CMP             R10, #0x94        ; Max index of syscall (can possibly vary)
   BGT             return_to_caller
   MOV             R8, SP
   MOV             R11, #0x1F
   MSR             CPSR_c, R11       ; Switch to system mode and disable FIQ/IRQ
   
   LDR             R9, [R8,#0x48]    ; Added in 5.5.0: Check for invalid stack
   CMP             SP, R9
   BLCS            bad_stack
   LDR             R11, [R8,#0x4C]
   SUB             R9, R9, R11
   CMP             SP, R9
   BCC             bad_stack
   
   LDR             R8, [R8,#0x44]
   LDR             R11, =syscall_stack_arg_counts
   LDR             R11, [R11,R10,LSL#2]  ; Number of args on stack for this syscall
   ADD             SP, SP, R11,LSL#2
get_stack_arg                             
   CMP             R11, #0
   BEQ             find_syscall_and_jump
   LDR             R9, [SP,#-4]!	 ; Copy argument value
   STR             R9, [R8,#-4]!
   SUB             R11, R11, #1
   B               get_stack_arg
find_syscall_and_jump
   MOV             SP, R8
   LDR             R11, =syscall_table
   LDR             R11, [R11,R10,LSL#2]
   MOV             LR, PC
   BX              R11
return_to_caller
   MOV             R11, #0xDB   ; Switch to undefined mode and re-enable FIQ/IRQ
   MSR             CPSR_c, R11
   LDR             R11, [SP]
   MSR             SPSR_cxsf, R11
   MOV             LR, R0
   LDMED           SP, {R0-LR}^
   NOP
   MOV             R0, LR
   LDR             LR, [SP,#0x40]
   MOVS            PC, LR	      ; Return
invalid_syscall
   LDR             SP, =current_thread_ctx_addr
   LDR             SP, [SP]
   STR             LR, [SP,#0x40]
   ADD             SP, SP, #0x40
   STMFD           SP, {R0-LR}^
   SUB             R0, SP, #0x40
   MOV             LR, #6	 ; STATE_FAULTED
   STR             LR, [R0,#0x50]
   LDR             SP, =debug_args_addr
   BL              debug_print  ; Illegal Instruction:tid=%d,pid=%d,pc=0x%08x,sp=0x%08x
   B               schedule_yield
bad_stack
   BL      disable_interrupts
   LDR     R0, =current_thread_ctx_addr
   LDR     R0, [R0]
   MOV     LR, #6               ; STATE_FAULTED
   STR     LR, [R0,#0x50]
   MOV     R1, SP
   MOV     R2, R10
   LDR     SP, =debug_args_addr
   BL      debug_print_bad_stack ; Bad stack upon making system call:tid=%d,pid=%d,sp=0x%08x,sysCallNum=%d\n
   B       schedule_yield
Syscalls are invoked by way of the invalid instruction handler; syscalls take the form 0xE7F000F0 | (syscall_num << 8). (E.g. E7F000F0 is syscall 0, E7F036F0 is syscall 0x36, etc.).
The IOSU has 0x94 available syscalls with 5.3.2 (the number of installed syscalls can vary between system versions).
With 5.5.0 sp(user-mode/system-mode) is now bounds-checked right after the switch to system-mode. When out-of-bounds it will execute code similar to "invalid_syscall" described above. Hence, userland sp has to be within the current thread userland stackbottom/stacktop at the time a syscall is used, otherwise the fault code will be executed.
The following syscall numbers were last verified on 5.3.2 development OSv10 and 5.5.0 production OSv10. They may vary for newer/older versions or OSv9.
NOTE: Official syscall names begin with "IOS_", the rest are merely educated guesses.
| ID (Development) | ID (Production) | Return | Name | Arguments | 
|---|---|---|---|---|
| 0x00 | 0x00 | IOSThreadId | IOS_CreateThread | u32 (*entry)(void* arg), void* arg, void* stack, u32 stack_size, u32 priority, u32 attributes | 
| 0x01 | 0x01 | IOSError | JoinThread | IOSThreadId id, u32 **return_value | 
| 0x02 | 0x02 | IOSError | DestroyThread | IOSThreadId id, u32 *return_value | 
| 0x03 | 0x03 | IOSThreadId | GetThreadId | |
| 0x04 | 0x04 | void * | AccessIpcPool | |
| 0x05 | 0x05 | IOSProcessId | GetProcessId | |
| 0x06 | 0x06 | IOSError | GetProcessName | IOSProcessId pid, char *name | 
| 0x07 | 0x07 | IOSError | IOS_StartThread | IOSThreadId id | 
| 0x08 | 0x08 | IOSError | StopThread | IOSThreadId id | 
| 0x09 | 0x09 | void | YieldThread | |
| 0x0A | 0x0A | u32 | IOS_GetThreadPriority | IOSThreadId id | 
| 0x0B | 0x0B | IOSError | IOS_SetThreadPriority | IOSThreadId id, u32 priority | 
| 0x0C | 0x0C | IOSMessageQueueId | IOS_CreateMessageQueue | IOSMessage *ptr, u32 count | 
| 0x0D | 0x0D | IOSError | IOS_DestroyMessageQueue | IOSMessageQueueId mqid | 
| 0x0E | 0x0E | IOSError | IOS_SendMessage | IOSMessageQueueId mqid, IOSMessage message, u32 flags | 
| 0x0F | 0x0F | IOSError | IOS_JamMessage | IOSMessageQueueId mqid, IOSMessage message, u32 flags | 
| 0x10 | 0x10 | IOSError | IOS_ReceiveMessage | IOSMessageQueueId mqid, IOSMessage *message, u32 flags | 
| 0x11 | 0x11 | IOSError | IOS_HandleEvent | IOSEvent event, IOSMessageQueueId mqid, IOSMessage message | 
| 0x12 | 0x12 | IOSError | UnhandleEvent | IOSEvent event | 
| 0x13 | 0x13 | IOSTimerId | IOS_CreateTimer | IOSTime time, IOSTime interval, IOSMessageQueueId mqid, IOSMessage message | 
| 0x14 | 0x14 | IOSError | IOS_RestartTimer | IOSTimerId id, IOSTime time, IOSTime interval | 
| 0x15 | 0x15 | IOSError | IOS_StopTimer | IOSTimerId id | 
| 0x16 | 0x16 | IOSError | IOS_DestroyTimer | IOSTimerId id | 
| 0x17 | 0x17 | IOSTime | GetUpTimer | |
| 0x18 | 0x18 | u32 | GetTimer | |
| 0x19 | 0x19 | IOSError | IOS_GetUpTimeStruct | IOSTimeStruct *out | 
| 0x1A | 0x1A | IOSError | IOS_GetUpTime64 | u64 *out | 
| 0x1B | 0x1B | IOSError | SetRtcTimeStruct | IOSTimeStruct *in | 
| 0x1C | 0x1C | IOSError | IOS_GetAbsTimeCalendar | IOSTimeCalendar *out | 
| 0x1D | 0x1D | IOSError | IOS_GetAbsTime64 | u64 *out | 
| 0x1E | 0x1E | IOSError | IOS_GetAbsTimeStruct | IOSTimeStruct *out | 
| 0x1F | 0x1F | IOSError | EnablePanicOnException | IOSProcessId pid, bool enable | 
| 0x20 | 0x20 | IOSError | IsDevelopment | |
| 0x21 | 0x21 | IOSError | IsJtagEnabled | |
| 0x22 | 0x22 | IOSError | ReadEfuse | u32 word, void *out_buf, u32 size | 
| 0x23 | 0x23 | IOSHeapId | CreateHeap | void *ptr, u32 size | 
| 0x24 | 0x24 | IOSHeapId | IOS_CreateLocalProcessHeap | void *ptr, u32 size | 
| 0x25 | 0x25 | IOSHeapId | IOS_CreateCrossProcessHeap | int size | 
| 0x26 | 0x26 | IOSError | DestroyHeap | IOSHeapId id | 
| 0x27 | 0x27 | void* | IOS_Alloc | IOSHeapId id, u32 size | 
| 0x28 | 0x28 | void* | AllocAligned | IOSHeapId id, u32 size, u32 align | 
| 0x29 | 0x29 | IOSError | IOS_Free | IOSHeapId id, void *ptr | 
| 0x2A | 0x2A | IOSError | FreeAndClear | IOSHeapId id, void *ptr | 
| 0x2B | 0x2B | IOSError | ReAlloc | IOSHeapId id, void *ptr, u32 size | 
| 0x2C | 0x2C | IOSError | IOS_RegisterResourceManager | const char* path, IOSMessageQueueId mqid | 
| 0x2D | 0x2D | IOSError | AssociateResourceManager | const char* path, u32 id | 
| 0x2E | 0x2E | IOSError | SetResourceManagerMaxIoVectors | const char* path, u32 max_vectors | 
| 0x2F | 0x2F | IOSError | SetResourceClientCapabilities | IOSProcessId pid, u32 feature_id, u32 *caps | 
| 0x30 | 0x30 | IOSError | ClearResourceClientCapabilities | IOSProcessId pid | 
| 0x31 | 0x31 | IOSError | GetResourceClientCapabilities | IOSProcessId pid, u32 feature_id, u32 *caps | 
| 0x32 | 0x32 | IOSError | GetResourceManagers | u32 feature_id, u32 max_count, IOSResourceManager *out | 
| 0x33 | 0x33 | IOSFd | IOS_Open | const char* path, u32 flags | 
| 0x34 | 0x34 | IOSError | IOS_Close | IOSFd fd | 
| 0x35 | 0x35 | s32 | IOS_Read | IOSFd fd, void *buf, u32 len | 
| 0x36 | 0x36 | s32 | IOS_Write | IOSFd fd, void *buf, u32 len | 
| 0x37 | 0x37 | s32 | IOS_Seek | IOSFd fd, s32 offset, u32 origin | 
| 0x38 | 0x38 | IOSError | IOS_Ioctl | IOSFd fd, s32 cmd, void *input, u32 input_size, void *output, u32 output_size | 
| 0x39 | 0x39 | IOSError | IOS_Ioctlv | IOSFd fd, s32 cmd, u32 read_count, u32 write_count, IOSIoVector *vector | 
| 0x3A | 0x3A | IOSFd | IOS_OpenAsync | const char* path, u32 flags, IOSMessageQueueId mqid, IOSResourceRequest *reply | 
| 0x3B | 0x3B | IOSError | IOS_CloseAsync | IOSFd fd, IOSMessageQueueId mqid, IOSResourceRequest *reply | 
| 0x3C | 0x3C | s32 | IOS_ReadAsync | IOSFd fd, void *buf, u32 len, IOSMessageQueueId mqid, IOSResourceRequest *reply | 
| 0x3D | 0x3D | s32 | IOS_WriteAsync | IOSFd fd, void *buf, u32 len, IOSMessageQueueId mqid, IOSResourceRequest *reply | 
| 0x3E | 0x3E | s32 | IOS_SeekAsync | IOSFd fd, s32 offset, u32 origin, IOSMessageQueueId mqid, IOSResourceRequest *reply | 
| 0x3F | 0x3F | IOSError | IOS_IoctlAsync | IOSFd fd, s32 cmd, void *input, u32 input_size, void *output, u32 output_size, IOSMessageQueueId mqid, IOSResourceRequest *reply | 
| 0x40 | 0x40 | IOSError | IOS_IoctlvAsync | IOSFd fd, s32 cmd, u32 read_count, u32 write_count, IOSIoVector *vector, IOSMessageQueueId mqid, IOSResourceRequest *reply | 
| 0x41 | 0x41 | IOSError | OpenAsyncAs | const char* path, u32 flags, IOSMessageQueueId mqid, IOSResourceRequest *reply, IOSProcessId pid, IOSNodeId node_id | 
| 0x42 | 0x42 | IOSError | WriteAsyncAs | IOSFd fd, void *buf, u32 len, IOSMessageQueueId mqid, IOSResourceRequest *reply, IOSProcessId pid, IOSNodeId node_id | 
| 0x43 | 0x43 | IOSError | Resume | IOSFd fd, SystemMode mode, PowerFlags flags | 
| 0x44 | 0x44 | IOSError | Suspend | IOSFd fd, SystemMode mode, PowerFlags flags | 
| 0x45 | 0x45 | IOSError | SvcMsg | IOSFd fd, u32 unk0, u32 unk1, u32 unk2, u32 unk3 | 
| 0x46 | 0x46 | IOSError | ResumeAsync | IOSFd fd, SystemMode mode, PowerFlags flags, IOSMessageQueueId mqid, IOSResourceRequest *reply | 
| 0x47 | 0x47 | IOSError | SuspendAsync | IOSFd fd, SystemMode mode, PowerFlags flags, IOSMessageQueueId mqid, IOSResourceRequest *reply | 
| 0x48 | 0x48 | IOSError | SvcMsgAsync | IOSFd fd, u32 unk0, u32 unk1, u32 unk2, u32 unk3, IOSMessageQueueId mqid, IOSResourceRequest *reply | 
| 0x49 | 0x49 | IOSError | IOS_ResourceReply | IOSResourceTransaction *txn, IOSFd fd | 
| 0x4A | 0x4A | IOSError | SetUidGid | IOSProcessId pid, u32 uid_high, u32 uid_low, u32 gid | 
| 0x4B | 0x4B | IOSError | GetUidGid | IOSProcessId pid, u32 *uid, u32 *gid | 
| 0x4C | 0x4C | IOSError | IOS_FlushMem | MEM_WB_CLIENTS client | 
| 0x4D | 0x4D | IOSError | IOS_FlushMemAsync | MEM_WB_CLIENTS client | 
| 0x4E | 0x4E | IOSError | IOS_GetMemWriteStatus | int client | 
| 0x4F | 0x4F | IOSError | IOS_InvalidateRdb | AHM_RB_CLIENTS client | 
| 0x50 | 0x50 | IOSError | IOS_ClearAndEnableEvent | u32 id | 
| 0x51 | IOSError | AccessIobPool | u32 pool | |
| 0x52 | IOSIobuf * | AllocIob | u32 pool, u32 size | |
| 0x53 | IOSError | FreeIob | IOSIobuf *iob | |
| 0x54 | void | DebugDumpIobFreeHdrsList | ||
| 0x55 | void | DebugDumpIobFreeBufsList | ||
| 0x56 | u8 * | PutIob | IOSIobuf *iob, u16 len | |
| 0x57 | u8 * | IOS_PushIob | IOSIobuf *iob, u16 len | |
| 0x58 | u8 * | IOS_PullIob | IOSIobuf *iob, u16 len | |
| 0x59 | IOSError | IsValidIob | IOSIobuf *iob | |
| 0x5A | IOSIobuf * | CloneIob | IOSIobuf *iob | |
| 0x5B | 0x51 | void | IOS_InvalidateDCache | void *ptr, u32 len | 
| 0x5C | 0x52 | void | IOS_FlushDCache | void *ptr, u32 len | 
| 0x5D | 0x53 | IOSError | LaunchOS | BootOSImageHeader *os_image | 
| 0x5E | 0x54 | void | GetOSVersion | u32 *major, u16 *minor | 
| 0x5F | 0x55 | void | GetBootVersion | u32 *major, u16 *minor | 
| 0x60 | 0x56 | void * | IOS_VirtualToPhysical | void *address | 
| 0x61 | 0x57 | IOSSemaphoreId | IOS_CreateSemaphore | u32 max_count, u32 initial_count | 
| 0x62 | 0x58 | IOSError | IOS_WaitSemaphore | IOSSemaphoreId id, bool try_wait | 
| 0x63 | 0x59 | IOSError | IOS_SignalSemaphore | IOSSemaphoreId id | 
| 0x64 | 0x5A | IOSError | IOS_DestroySemaphore | IOSSemaphoreId id | 
| 0x65 | 0x5B | IOSError | InitializeIpc | |
| 0x66 | 0x5C | IOSError | SetBspReady | |
| 0x67 | 0x5D | IOSError | CheckIopBuffer | void *address, u32 size, u32 rw_flags | 
| 0x68 | 0x5E | IOSError | CheckPpcBuffer | void *address, u32 size | 
| 0x69 | 0x5F | void | InitializePpc | |
| 0x6A | 0x60 | u32 | IOS_GetCpuUtilization | |
| 0x6B | 0x61 | IOSError | GetThreadStackInfo | IOSThreadId id, IOSThreadStackInfo *out | 
| 0x6C | 0x62 | IOSError | IOS_ThreadProfileCommand | IOSThreadProfileCommand cmd, void *data | 
| 0x6D | 0x63 | IOSError | IOS_GetThreadUtilization | IOSThreadUtilization *out | 
| 0x6E | 0x64 | IOSError | GetThreadProfile | IOSThreadId id, IOSThreadProfile *out | 
| 0x6F | 0x65 | IOSError | GetThreadProfiles | u32 max_count, IOSThreadProfile *out | 
| 0x70 | IOSError | GetIobContext | u32 id, IOSIobContext *out | |
| 0x71 | u32 | IOS_GetIobPoolsUtilization | u32 max_count, IOSIobPoolsUtilization *out | |
| 0x72 | 0x66 | IOSError | IOS_GetMessageUtilization | IOSMessageUtilization *out | 
| 0x73 | 0x67 | IOSError | GetResourceAggregateUtilization | IOSResourceAggregateUtilization* out, bool clear | 
| 0x74 | 0x68 | IOSError | GetResourcePerProcessUtilization | IOSResourcePerProcessUtilization* out, IOSProcessId pid, bool clear | 
| 0x75 | 0x69 | IOSError | IOS_GetTimerUtilization | IOSTimerUtilization *out | 
| 0x76 | 0x6A | IOSError | IOS_GetSemaphoreUtilization | IOSSemaphoreUtilization *out | 
| 0x77 | 0x6B | IOSError | GetHeapProfile | IOSHeapId id, IOSHeapProfile *profile | 
| 0x78 | 0x6C | IOSError | IOS_SetIOP2xMode | bool enable | 
| 0x79 | 0x6D | IOSError | SetPpcPlatformInfo | OSPlatformInfo *info | 
| 0x7A | 0x6E | void | LoadSystemConfiguration | |
| 0x7B | 0x6F | void | ClearSystemConfiguration | |
| 0x7C | 0x70 | void | SetSystemConfiguration | u32 syscfg | 
| 0x7D | 0x71 | u32 | IsSystemConfigurationEnabled | u32 flag | 
| 0x7E | 0x72 | void | Standby | bool unk | 
| 0x7F | 0x73 | void | IOS_Panic | char *panic_desc, u32 panic_desc_size | 
| 0x80 | 0x74 | void | Shutdown | |
| 0x81 | 0x75 | void | EnableResetOnPanic | u32 mode | 
| 0x82 | 0x76 | IOSError | SetSyslogBuffer | void *log_buf | 
| 0x83 | 0x77 | IOSError | LoadPpcKernel | u32 address, u32 size | 
| 0x84 | 0x78 | IOSError | LoadPpcApplication | u32 mem_id, u32 addr1, u32 size1, u32 addr2, u32 size2 | 
| 0x85 | 0x79 | IOSError | SetSecurityLevel | IOSSecurityLevel level | 
| 0x86 | 0x7A | IOSSecurityLevel | GetSecurityLevel | |
| 0x87 | 0x7B | IOSError | GetOpenResourceHandles | u32 max_count, IOSOpenResourceHandle *out, IOSProcessId pid | 
| 0x88 | 0x7C | IOSError | SetMainTitleSdkVersion | u32 version | 
| 0x89 | 0x7D | u32 | GetMainTitleSdkVersion | |
| 0x8A | 0x7E | IOSError | IsCrossProcessHeap | void *ptr, u32 size | 
| 0x8B | 0x7F | IOSError | HandleDebugInterrupt | const char *dbg_sts, u32 dbg_sts_size, IOSMessageQueueId mqid, IOSMessage message | 
| 0x8C | 0x80 | IOSError | UnhandleDebugInterrupt | IOSMessageQueueId mqid, bool panic | 
| 0x8D | 0x81 | IOSError | ||
| 0x8E | 0x82 | IOSError | GetViolatingResourceManagers | u32 max_count, IOSResourceManager *out | 
| 0x8F | 0x83 | u32 | MakeResourceClientHandlesStale | char *path | 
| 0x90 | 0x84 | IOSError | EnableResourceSecurity | bool enable | 
| 0x91 | 0x85 | IOSError | GetPendingResourceRequests | u32 max_count, IOSPendingResourceRequest *out, IOSProcessId pid | 
| 0x92 | 0x86 | IOSError | InitializeIOS | |
| 0x93 | 0x87 | void | Enable4SecondsOffTimer | 
GetUpTimer
Returns the number of microseconds elapsed since boot as an u32.
GetTimer
Returns the raw tick count from the HW_TIMER register.
IOS_GetUpTimeStruct
Returns the time elapsed since boot in struct format.
IOS_GetUpTimeStruct
Returns the time elapsed since boot as an u64.
SetRtcTimeStruct
Sets the time provided by the RTC in struct format.
IOS_GetAbsTimeCalendar
Returns the absolute time (up time + RTC) in calendar format.
IOS_GetAbsTime64
Returns the absolute time (up time + RTC) as an u64.
IOS_GetAbsTimeStruct
Returns the absolute time (up time + RTC) in struct format.
EnablePanicOnException
Enables/disables raising a panic when an exception occurs in the specified process. IOS-MCP can call this with any IOSProcessId while other processes must use their own IOSProcessId. Only IOS processes can be targeted and IOS-KERNEL is always forced back to the enabled state.
ReadEfuse
Read data from the eFuses. This can only be used from the IOS-CRYPTO process.
AssociateResourceManager
Associates a resource manager to the specified group ID. This ID appears to correspond to the cos.xml permissions groupid? This syscall isn't used with devices that don't require any permissions(and are PowerPC-accessible) it seems. It appears when this ID isn't listed in the cos.xml groupids at all, the device is ARM-only.
LaunchOS
Disables memory protection, cleans up executable memory areas and jumps to the specified OS image. This can only be called by MCP and will infinite loop on return.
CheckIopBuffer
Checks an IOSU address range for read/write permissions.
CheckPpcBuffer
Checks if a PPC address range is registered in the IOSU's address table.
InitializePpc
Fills range 0x00000000 to 0x00002000 in MEM1 with empty PPC branches.
LoadSystemConfiguration
Stores the value from LT_SYSCFG1 register in the IOSU heap.
ClearSystemConfiguration
Clears the LT_SYSCFG1 register.
SetSystemConfiguration
Sets the value of the LT_SYSCFG1 register.
IsSystemConfigurationEnabled
Checks if the supplied flag is enabled in the LT_SYSCFG1 register copy on the IOSU heap.
SetResetOnPanic
Changes the system behavior on panic.
LoadPpcKernel
Maps the PPC kernel image memory: address == 0x08000000 size == 0x00120000
LoadPpcApplication
Maps the PPC user application memory: mem_id == 0x02 addr1 == 0x00 size1 == 0x00 addr2 == 0x28000000 size2 == 0xA8000000
InitializeIOS
Maps the IOS kernel image memory.
Enable4SecondsOffTimer
Programs the RTC off timer with RTC_COUNTER + 4 seconds and enables it.
Syscalls (via syscall instruction)
These types of syscalls are created with the thumb syscall instruction. When the u16 from retaddr-0x2 matches 0xdfab(intended as thumb "svc 0xab" but ARM "svc 0xdfab" would pass too), it will just return from the exception-handler, otherwise it will do the same thing described here for exceptions. These syscalls are RealView semihosting operations that allow communication with a debugger.
Currently only syscall 0x04 is still used in production versions of IOSU. Syscall 0x06 is only used for a scanf call in some kind of debug configuration, with the following prompt: "Enter '1' to proceed with kernel startup."
MOVS r0, #syscall_number
SVC 0xABRegister r0 takes the syscall number.
Register r1 takes the first parameter.
| ID | Return | Name | Arguments | 
|---|---|---|---|
| 0x01 | __sys_open | ||
| 0x02 | __sys_close | ||
| 0x03 | __sys_writec | ||
| 0x04 | __sys_write0 | ||
| 0x05 | __sys_write | ||
| 0x06 | __sys_read | ||
| 0x07 | __sys_readc | ||
| 0x08 | __sys_iserror | ||
| 0x09 | __sys_istty | ||
| 0x0A | __sys_seek | ||
| 0x0C | __sys_flen | ||
| 0x0D | __sys_tmpnam | ||
| 0x0E | __sys_remove | ||
| 0x0F | __sys_rename | ||
| 0x10 | __sys_clocK | ||
| 0x11 | __sys_time | ||
| 0x12 | __sys_system | ||
| 0x13 | __sys_errno | ||
| 0x15 | __sys_get_cmdline | ||
| 0x16 | __sys_heapinfo | ||
| 0x30 | __sys_elapsed | ||
| 0x31 | __sys_tickfreq | 
__sys_write0
Prints a null-terminated debug message.
__sys_read
Reads input from debugger stdin.
IOSMemoryRegion
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x4 | Paddr | 
| 0x4 | 0x4 | Vaddr | 
| 0x8 | 0x4 | Size | 
| 0xC | 0x4 | Domain | 
| 0x10 | 0x4 | Ap | 
| 0x14 | 0x4 | Cached | 
IOSContext
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x4 | Cpsr | 
| 0x4 | 0x4 | R0 | 
| 0x8 | 0x4 | R1 | 
| 0xC | 0x4 | R2 | 
| 0x10 | 0x4 | R3 | 
| 0x14 | 0x4 | R4 | 
| 0x18 | 0x4 | R5 | 
| 0x1C | 0x4 | R6 | 
| 0x20 | 0x4 | R7 | 
| 0x24 | 0x4 | R8 | 
| 0x28 | 0x4 | R9 | 
| 0x2C | 0x4 | R10 | 
| 0x30 | 0x4 | R11 | 
| 0x34 | 0x4 | R12 | 
| 0x38 | 0x4 | R13 | 
| 0x3C | 0x4 | Lr | 
IOSThread
The IOSU is able to create and handle up to 0xB4 threads. Each thread has a corresponding internal structure stored in kernel SRAM (0xFFFF4D78 in firmware 5.5.1).
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x40 | Context | 
| 0x40 | 0x4 | Pc | 
| 0x44 | 0x4 | Next | 
| 0x48 | 0x4 | InitPriority | 
| 0x4C | 0x4 | Priority | 
| 0x50 | 0x4 | State | 
| 0x54 | 0x4 | Pid | 
| 0x58 | 0x4 | Tid | 
| 0x5C | 0x4 | Attributes | 
| 0x60 | 0x4 | ExitValue | 
| 0x64 | 0x4 | JoinQueue | 
| 0x68 | 0x4 | Queue | 
| 0x6C | 0x38 | |
| 0xA4 | 0x4 | Sp | 
| 0xA8 | 0x8 | |
| 0xB0 | 0x4 | SysStackBase | 
| 0xB4 | 0x4 | UsrStackBase | 
| 0xB8 | 0x4 | UsrStackSize | 
| 0xBC | 0x4 | IpcBufferPool | 
| 0xC0 | 0x4 | ScheduledCount | 
| 0xC4 | 0x4 | ScheduledTime | 
State
| Value | Description | 
|---|---|
| 0 | Available | 
| 1 | Ready | 
| 2 | Running | 
| 3 | Stopped | 
| 4 | Waiting | 
| 5 | Dead | 
| 6 | Faulted | 
| 7 | Unknown | 
IOSThreadStackInfo
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x4 | SysStackBase | 
| 0x4 | 0x4 | SysStackSize | 
| 0x8 | 0x4 | SysStackUsedSize | 
| 0xC | 0x4 | UsrStackBase | 
| 0x10 | 0x4 | UsrStackSize | 
| 0x14 | 0x4 | UsrStackUsedSize | 
IOSThreadUtilization
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x4 | MaxThreads | 
| 0x4 | 0x4 | AllocatedThreads | 
| 0x8 | 0x4 | MaxAllocatedThreads | 
| 0xC | 0x4 | FaultedThreads | 
IOSThreadProfile
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x4 | Tid | 
| 0x4 | 0x4 | Pid | 
| 0x8 | 0x4 | Priority | 
| 0xC | 0x4 | State | 
| 0x10 | 0x4 | ScheduledCount | 
| 0x14 | 0x4 | TotalScheduledCount | 
| 0x18 | 0x4 | ScheduledTime | 
| 0x1C | 0x4 | TotalScheduledTime | 
| 0x20 | 0x4 | |
| 0x24 | 0x4 | Sp | 
| 0x28 | 0x4 | 
IOSThreadTrace
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x4 | Total | 
| 0x4 | 0x4 | Idx | 
| 0x8 | 0x4 | TimerVal | 
| 0xC | 0x4 | TimerBase | 
| 0x10 | 0x8 | UpTime | 
| 0x18 | 0x4 | Flags | 
| 0x1C | 0x1 * 180 | Pids | 
IOSThreadProfileCommand
| Value | Description | 
|---|---|
| 100 | |
| 101 | ProfileEndEx | 
| 102 | |
| 103 | ProfileStart | 
| 104 | |
| 105 | SamplingProfileResume | 
| 106 | SamplingProfileEnd | 
| 107 | SamplingProfileStart | 
| 108 | |
| 109 | SamplingProfileMark | 
| 110 | |
| 111 | 
IOSMessage
This is a s32.
IOSMessageQueueId
This is an u32.
IOSMessageQueue
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x4 | EmptyQueue | 
| 0x4 | 0x4 | FullQueue | 
| 0x8 | 0x4 | Count | 
| 0xC | 0x4 | Rptr | 
| 0x10 | 0x4 | Size | 
| 0x14 | 0x4 | Buffer | 
| 0x18 | 0x4 | Id | 
| 0x1C | 0x1 | Owner | 
| 0x1D | 0x1 | HasEvent | 
| 0x1E | 0x2 | 
IOSMessageUtilization
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x4 | MaxCount | 
| 0x4 | 0x4 | AllocatedCount | 
| 0x8 | 0x4 | MaxAllocatedCount | 
| 0xC | 0x2 * 14 | PerPidUtilization | 
IOSEvent
This is an u32.
IOSEventState
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x4 | MessageQueue | 
| 0x4 | 0x4 | Message | 
| 0x8 | 0x4 | Owner | 
| 0xC | 0x4 | 
IOSFd
This is an u32.
IOSResource
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x20 | Path | 
| 0x20 | 0x4 | MqId | 
| 0x24 | 0x4 | RegisteredResourcesManager | 
| 0x28 | 0x4 | FeatureId | 
| 0x2C | 0x2 | PathLen | 
| 0x2E | 0x2 | |
| 0x30 | 0x2 | |
| 0x32 | 0x2 | ActiveTxnCount | 
| 0x34 | 0x2 | OpenHandles | 
| 0x36 | 0x2 | |
| 0x38 | 0x2 | |
| 0x3A | 0x2 | BusyCloseViolations | 
| 0x3C | 0x2 | MaxIoVectors | 
| 0x3E | 0x2 | 
IOSResourceHandle
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x4 | ServerHandle | 
| 0x4 | 0x4 | ClientFd | 
| 0x8 | 0x4 | Resource | 
| 0xC | 0x1 | State | 
| 0xD | 0x3 | Reserved | 
IOSResourceCapability
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x4 | FeatureId | 
| 0x4 | 0x4 | Mask0 | 
| 0x8 | 0x4 | Mask1 | 
IOSResourceRequest
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x4 | Cmd | 
| 0x4 | 0x4 | ClientHandle | 
| 0x8 | 0x4 | ServerHandle | 
| 0xC | 0x4 | Flags | 
| 0x10 | 0x4 | ClientNodeId | 
| 0x14 | 0x4 | ClientPid | 
| 0x18 | 0x4 | ClientUniqueIdHigh | 
| 0x1C | 0x4 | ClientUniqueIdLow | 
| 0x20 | 0x4 | ClientGroupId | 
| 0x24 | 0x14 | Args | 
IOSResourceTransaction
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x38 | Req | 
| 0x38 | 0x4 | Mq | 
| 0x3C | 0x4 | MqId | 
| 0x40 | 0x4 | Reply | 
| 0x44 | 0x4 | RegisteredResourcesManager | 
| 0x48 | 0x4 | Resource | 
| 0x4C | 0x4 | ClientFd | 
| 0x50 | 0x4 | |
| 0x54 | 0x4 | Path | 
| 0x58 | 0x5C | 
IOSRegisteredResourcesManager
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x4 | UniqueIdHigh | 
| 0x4 | 0x4 | UniqueIdLow | 
| 0x8 | 0x4 | GroupId | 
| 0xC | 0x4 | Owner | 
| 0x10 | 0x4 | OpenHandles | 
| 0x14 | 0x4 | OpenHandlesWaterline | 
| 0x18 | 0x4 | MaxOpenHandles | 
| 0x1C | 0x10 * 96 | Handles | 
| 0x61C | 0x4 | ActiveTxns | 
| 0x620 | 0x4 | ActiveTxnWaterline | 
| 0x624 | 0x4 | TotalTxnAllocFailures | 
| 0x628 | 0x4 | MaxActiveTxns | 
| 0x62C | 0xC * 20 | Capabilities | 
| 0x71C | 0x4 | RegisteredResources | 
| 0x720 | 0x4 | MaxRegisteredResources | 
| 0x724 | 0x4 | InvalidResourceReplies | 
IOSActiveResourcesManager
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x2 | ActiveResources | 
| 0x2 | 0x2 | ActiveResourcesWaterline | 
| 0x4 | 0x2 | |
| 0x6 | 0x2 | |
| 0x8 | 0x2 | CurrentResource | 
| 0xA | 0x2 | MaxResources | 
| 0xC | 0x40 * 96 | Resources | 
IOSResourceTransactionsManager
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x2 | TotalActiveTxns | 
| 0x2 | 0x2 | TotalActiveTxnsWaterline | 
| 0x4 | 0x2 | TotalTxnAllocFailures | 
| 0x6 | 0x2 | CurrentTxn | 
| 0x8 | 0x2 | |
| 0xA | 0x2 | MaxTotalActiveTxns | 
| 0xC | 0xB4 * 256 | Txns | 
IOSResourceManager
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x20 | Path | 
| 0x20 | 0x4 | FeatureId | 
| 0x24 | 0x4 | Owner | 
| 0x28 | 0x4 | BusyCloseViolations | 
| 0x2C | 0x4 | ActiveTxnCount | 
| 0x30 | 0x4 | OpenHandles | 
IOSResourceAggregateUtilization
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x4 | ActiveResources | 
| 0x4 | 0x4 | ActiveResourcesWaterline | 
| 0x8 | 0x4 | MaxResources | 
| 0xC | 0x4 | TotalActiveTxns | 
| 0x10 | 0x4 | TotalActiveTxnsWaterline | 
| 0x14 | 0x4 | TotalTxnAllocFailures | 
| 0x18 | 0x4 | MaxTotalActiveTxns | 
IOSResourcePerProcessUtilization
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x4 | Owner | 
| 0x4 | 0x4 | OpenHandles | 
| 0x8 | 0x4 | OpenHandlesWaterline | 
| 0xC | 0x4 | MaxOpenHandles | 
| 0x10 | 0x4 | ActiveTxns | 
| 0x14 | 0x4 | ActiveTxnWaterline | 
| 0x18 | 0x4 | TotalTxnAllocFailures | 
| 0x1C | 0x4 | MaxActiveTxns | 
| 0x20 | 0x4 | RegisteredResources | 
| 0x24 | 0x4 | MaxRegisteredResources | 
| 0x28 | 0x4 | InvalidResourceReplies | 
IOSOpenResourceHandle
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x4 | Pid | 
| 0x4 | 0x4 | ClientFd | 
| 0x8 | 0x4 | ServerHandle | 
| 0xC | 0x20 | Path | 
IOSPendingResourceRequest
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x4 | ClientReplyAddress | 
| 0x4 | 0x4 | Owner | 
| 0x8 | 0x4 | Host | 
| 0xC | 0x4 | ClientFd | 
| 0x10 | 0x38 | Req | 
| 0x48 | 0x20 | Path | 
IOSHeap
The IOSU is able to create and handle up to 0x30 heaps. Each heap has a corresponding descriptor structure stored in the kernel's BSS section (0x08150008 in firmware 5.5.1).
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x4 | Base | 
| 0x4 | 0x4 | Owner | 
| 0x8 | 0x4 | Size | 
| 0xC | 0x4 | FreeList | 
| 0x10 | 0x4 | AllocErrors | 
| 0x14 | 0x4 | FreeErrors | 
| 0x18 | 0x4 | ReAllocErrors | 
| 0x1C | 0x4 | InvalidChunks | 
| 0x20 | 0x4 | Flags | 
| 0x24 | 0x4 | TotalAllocatedSize | 
| 0x28 | 0x4 | LargestAllocatedSize | 
| 0x2C | 0x4 | AllocatedChunks | 
| 0x30 | 0x4 | FreeChunks | 
| 0x34 | 0x4 | FreeUnusedChunkErrors | 
| 0x38 | 0x4 | AllocInvalidHeapErrors | 
| 0x3C | 0x4 | AllocInvalidHeapId | 
All accesses to heaps are verified using owner PID and active PID. Heaps are referenced using IDs that are used as indices into the heap descriptor array. There are 3 special heap IDs:
| Value | Description | 
|---|---|
| 0x0001 | Shared heap | 
| 0xCAFE | Local process heap for active PID | 
| 0xCAFF | Cross process heap for active PID | 
Access to special heap IDs is redirected to the appropriate heap.
Each process can allocate a cross process heap for multiple processes to use and a local process heap for itself. These are kept tracked of using two arrays following the heap descriptor array in kernel BSS:
int32 local_process_heaps[14]; int32 cross_process_heaps[14];
They are initialized to IOS_ERROR_INVALID within the IOSU kernel and are set to the appropriate heap ID when created using IOS_CreateLocalProcessHeap or IOS_CreateCrossProcessHeap. There may only be one cross/local process heap for each PID.
Each heap descriptor contains a flag field that contains information about the heap:
0x1: Local process heap 0x2: Cross process heap
Each heap is created from memory of the shared heap. It is initialized as one big seperate memory chunk.
When memory is allocated to a heap, the linked list (terminated using nullptr's) is traversed to find a large enough chunk, chunks are split and back and forward pointers are cleared for the allocated chunk. When a chunk is allocated aligned, a chunk bigger than the needed one may be allocated. Inside this chunk, a second heap chunk is set up in a fashion that the beginning of the memory block described by this "inner" chunk is aligned according to the specified alignment. It's magic is set to 0xBABE0002 and the back pointer is set to the chunk containing it. These inner chunks can not be expanded.
IOSChunk
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x4 | Status | 
| 0x4 | 0x4 | Size | 
| 0x8 | 0x4 | PrevFree | 
| 0xC | 0x4 | NextFree | 
Status
| Value | Description | 
|---|---|
| 0xBABE0000 | Chunk is free | 
| 0xBABE0001 | Chunks is used | 
| 0xBABE0002 | Chunk is inner chunk and used | 
IOSHeapProfile
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x4 | Owner | 
| 0x4 | 0x4 | Base | 
| 0x8 | 0x4 | Size | 
| 0xC | 0x4 | FreeChunks | 
| 0x10 | 0x4 | LargestChunkSize | 
| 0x14 | 0x4 | SmallestChunkSize | 
| 0x18 | 0x4 | TotalFreeSize | 
| 0x1C | 0x4 | AllocErrors | 
| 0x20 | 0x4 | FreeErrors | 
| 0x24 | 0x4 | ReAllocErrors | 
| 0x28 | 0x4 | CorruptChunks | 
| 0x2C | 0x4 | InvalidChunks | 
| 0x30 | 0x4 | Flags | 
IOSTimeStruct
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x4 | Microsecond | 
| 0x4 | 0x4 | Second | 
IOSTimeCalendar
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x4 | Year | 
| 0x4 | 0x4 | Month | 
| 0x8 | 0x4 | Day | 
| 0xC | 0x4 | Hour | 
| 0x10 | 0x4 | Minute | 
| 0x14 | 0x4 | Second | 
| 0x18 | 0x4 | Microsecond | 
IOSTimerUtilization
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x4 | MaxCount | 
| 0x4 | 0x4 | AllocatedCount | 
| 0x8 | 0x4 | MaxAllocatedCount | 
| 0xC | 0x2 * 14 | PerPidUtilization | 
IOSSemaphoreUtilization
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x4 | MaxCount | 
| 0x4 | 0x4 | AllocatedCount | 
| 0x8 | 0x4 | MaxAllocatedCount | 
| 0xC | 0x2 * 14 | PerPidUtilization | 
IOSIpcServer
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x4 | IsEnabled | 
| 0x4 | 0x4 | NodeId | 
| 0x8 | 0x4 | ClientNodeIdx | 
| 0xC | 0x4 | Event | 
| 0x10 | 0x4 | Message | 
| 0x14 | 0x34 | |
| 0x48 | 0x4 | IpcIopCtrlReg | 
| 0x4C | 0x4 | IpcPpcMsgReg | 
| 0x50 | 0x4 | IpcIopMsgReg | 
| 0x54 | 0x4 | ActiveReplies | 
| 0x58 | 0x4 | |
| 0x5C | 0x4 | CurrentReplyIdx | 
| 0x60 | 0x38 * 128 | Replies | 
| 0x260 | 0x4 | ActiveRequests | 
| 0x264 | 0x4 | IsInAckPending | 
| 0x268 | 0x4 | HasPendingRequests | 
| 0x26C | 0x4 | InvalidRequestAddressErrors | 
| 0x270 | 0x4 | InvalidRequestClientPidErrors | 
| 0x274 | 0x4 | ReadErrors | 
| 0x278 | 0x4 | WriteErrors | 
| 0x27C | 0x4 | SeekErrors | 
| 0x280 | 0x4 | IoctlErrors | 
| 0x284 | 0x4 | IoctlvErrors | 
| 0x288 | 0x4 | OpenErrors | 
| 0x28C | 0x4 | CloseErrors | 
| 0x290 | 0x4 | |
| 0x294 | 0x4 | ActiveRequestsWaterline | 
| 0x298 | 0x4 | ActiveRepliesWaterline | 
| 0x29C | 0x4 | PendingRequests | 
| 0x2A0 | 0x4 | RepliedRequests | 
IOSProcessId
| Value | Description | 
|---|---|
| 0 | IOS-KERNEL | 
| 1 | IOS-MCP | 
| 2 | IOS-BSP | 
| 3 | IOS-CRYPTO | 
| 4 | IOS-USB | 
| 5 | IOS-FS | 
| 6 | IOS-PAD | 
| 7 | IOS-NET | 
| 8 | IOS-ACP | 
| 9 | IOS-NSEC | 
| 10 | IOS-AUXIL | 
| 11 | IOS-NIM-BOSS | 
| 12 | IOS-FPD | 
| 13 | IOS-TEST | 
| 14 | COS-KERNEL | 
| 15 | COS-ROOT | 
| 16 | COS-02 | 
| 17 | COS-03 | 
| 18 | COS-OVERLAY | 
| 19 | COS-HBM | 
| 20 | COS-ERROR | 
| 21 | COS-MASTER | 
IOSNodeId
| Value | Description | 
|---|---|
| 0 | IOS_NODE_INTERNAL | 
| 1 | IOS_NODE_EXTERNAL0 | 
| 2 | IOS_NODE_EXTERNAL1 | 
| 3 | IOS_NODE_EXTERNAL2 | 
IOSCmdId
| Value | Description | 
|---|---|
| 0 | IOS_COMMAND_INVALID | 
| 1 | IOS_OPEN | 
| 2 | IOS_CLOSE | 
| 3 | IOS_READ | 
| 4 | IOS_WRITE | 
| 5 | IOS_SEEK | 
| 6 | IOS_IOCTL | 
| 7 | IOS_IOCTLV | 
| 8 | IOS_REPLY | 
| 9 | IOS_IPC_MSG0 | 
| 10 | IOS_IPC_MSG1 | 
| 11 | IOS_IPC_MSG2 | 
| 12 | IOS_SUSPEND | 
| 13 | IOS_RESUME | 
| 14 | IOS_SVCMSG | 
IOSSecurityLevel
| Value | Description | 
|---|---|
| 0 | None | 
| 10 | Test | 
| 20 | Dev | 
| 30 | Prod | 
IOSError
| Value | Description | 
|---|---|
| 0 | IOS_ERROR_OK | 
| -1 | IOS_ERROR_ACCESS | 
| -2 | IOS_ERROR_EXISTS | 
| -3 | IOS_ERROR_INTR | 
| -4 | IOS_ERROR_INVALID | 
| -5 | IOS_ERROR_MAX | 
| -6 | IOS_ERROR_NOEXISTS | 
| -7 | IOS_ERROR_QEMPTY | 
| -8 | IOS_ERROR_QFULL | 
| -9 | IOS_ERROR_UNKNOWN | 
| -10 | IOS_ERROR_NOTREADY | 
| -11 | IOS_ERROR_ECC | 
| -12 | IOS_ERROR_ECC_CRIT | 
| -13 | IOS_ERROR_BADBLOCK | 
| -14 | IOS_ERROR_INVALID_OBJTYPE | 
| -15 | IOS_ERROR_INVALID_RNG | 
| -16 | IOS_ERROR_INVALID_FLAG | 
| -17 | IOS_ERROR_INVALID_FORMAT | 
| -18 | IOS_ERROR_INVALID_VERSION | 
| -19 | IOS_ERROR_INVALID_SIGNER | 
| -20 | IOS_ERROR_FAIL_CHECKVALUE | 
| -21 | IOS_ERROR_FAIL_INTERNAL | 
| -22 | IOS_ERROR_FAIL_ALLOC | 
| -23 | IOS_ERROR_INVALID_SIZE | 
| -24 | IOS_ERROR_NO_LINK | 
| -25 | IOS_ERROR_AN_FAILED | 
| -26 | IOS_ERROR_MAX_SEM_COUNT | 
| -27 | IOS_ERROR_SEM_UNAVAILABLE | 
| -28 | IOS_ERROR_INVALID_HANDLE | 
| -29 | IOS_ERROR_INVALID_ARG | 
| -30 | IOS_ERROR_NO_RESOURCE | 
| -31 | IOS_ERROR_BUSY | 
| -32 | IOS_ERROR_TIMEOUT | 
| -33 | IOS_ERROR_ALIGNMENT | 
| -34 | IOS_ERROR_BSP | 
| -35 | IOS_ERROR_DATA_PENDING | 
| -36 | IOS_ERROR_EXPIRED | 
| -37 | IOS_ERROR_NO_R_ACCESS | 
| -38 | IOS_ERROR_NO_W_ACCESS | 
| -39 | IOS_ERROR_NO_RW_ACCESS | 
| -40 | IOS_ERROR_CLIENT_TXN_LIMIT | 
| -41 | IOS_ERROR_STALE_HANDLE | 
| -42 | IOS_ERROR_UNKNOWN_VALUE | 
MEM_WB_CLIENTS
| Value | Description | 
|---|---|
| 0 | IOS_WB_IOD | 
| 1 | IOS_WB_AIM | 
| 2 | IOS_WB_FLA | 
| 3 | IOS_WB_AES | 
| 4 | IOS_WB_SHA | 
| 5 | IOS_WB_EHCI | 
| 6 | IOS_WB_OHCI0 | 
| 7 | IOS_WB_OHCI1 | 
| 8 | IOS_WB_SD0 | 
| 9 | IOS_WB_SD1 | 
| 10 | IOS_WB_SD2 | 
| 11 | IOS_WB_SD3 | 
| 12 | IOS_WB_EHC1 | 
| 13 | IOS_WB_OHCI10 | 
| 14 | IOS_WB_EHC2 | 
| 15 | IOS_WB_OHCI20 | 
| 16 | IOS_WB_SATA | 
| 17 | IOS_WB_AESS | 
| 18 | IOS_WB_SHAS | 
| 19 | IOS_WB_DMAA | 
| 20 | IOS_WB_DMAB | 
| 21 | IOS_WB_DMAC | 
| 22 | IOS_WB_ALL | 
AHM_RB_CLIENTS
| Value | Description | 
|---|---|
| 0 | IOS_RB_IOD | 
| 1 | IOS_RB_IOI | 
| 2 | IOS_RB_AIM | 
| 3 | IOS_RB_FLA | 
| 4 | IOS_RB_AES | 
| 5 | IOS_RB_SHA | 
| 6 | IOS_RB_EHCI | 
| 7 | IOS_RB_OHCI0 | 
| 8 | IOS_RB_OHCI1 | 
| 9 | IOS_RB_SD0 | 
| 10 | IOS_RB_SD1 | 
| 11 | IOS_RB_SD2 | 
| 12 | IOS_RB_SD3 | 
| 13 | IOS_RB_EHC1 | 
| 14 | IOS_RB_OHCI10 | 
| 15 | IOS_RB_EHC2 | 
| 16 | IOS_RB_OHCI20 | 
| 17 | IOS_RB_SATA | 
| 18 | IOS_RB_AESS | 
| 19 | IOS_RB_SHAS | 
Auxiliary Vectors
The IOSU elf has a PH_NOTES section which contains a so called "mrg file". This "mrg file" contains auxiliary vectors for IOSU modules.
The vectors are parsed by IOS-KERNEL, before launching the modules.
The first 0xc bytes of the notes section make up a Elf32_Nhdr. After that there are 6 auxv_t for each module (14 in 5.5.X).
The following auxiliary vector types are used:
| Value | Name | Description | 
|---|---|---|
| 0x09 | AT_ENTRY | Entry point address | 
| 0x0B | AT_UID | Module ID | 
| 0x7D | AT_PRIORITY | Main thread priority | 
| 0x7E | AT_STACK_SIZE | Main thread stack size | 
| 0x7F | AT_STACK_ADDR | Main thread stack address | 
| 0x80 | AT_MEM_PERM_MASK | Memory permission mask | 
Auxiliary vectors from 5.5.X:
AT_UID: 0 AT_ENTRY: 0xFFFF0000 AT_PRIORITY: 0x0 AT_STACK_SIZE: 0x0 AT_STACK_ADDR: 0x00000000 AT_MEM_PERM_MASK: 0x00000000
AT_UID: 1 AT_ENTRY: 0x05056718 AT_PRIORITY: 0x7C AT_STACK_SIZE: 0x2000 AT_STACK_ADDR: 0x050BA4A0 AT_MEM_PERM_MASK: 0x000C0030
AT_UID: 2 AT_ENTRY: 0xE600F848 AT_PRIORITY: 0x7D AT_STACK_SIZE: 0x1000 AT_STACK_ADDR: 0xE7000000 AT_MEM_PERM_MASK: 0x00100000
AT_UID: 3 AT_ENTRY: 0x04015EA4 AT_PRIORITY: 0x7B AT_STACK_SIZE: 0x1000 AT_STACK_ADDR: 0x04028628 AT_MEM_PERM_MASK: 0x000C0030
AT_UID: 4 AT_ENTRY: 0x1012E9E8 AT_PRIORITY: 0x6B AT_STACK_SIZE: 0x4000 AT_STACK_ADDR: 0x104B92C8 AT_MEM_PERM_MASK: 0x00038600
AT_UID: 5 AT_ENTRY: 0x107F6830 AT_PRIORITY: 0x55 AT_STACK_SIZE: 0x4000 AT_STACK_ADDR: 0x1114117C AT_MEM_PERM_MASK: 0x001C5870
AT_UID: 6 AT_ENTRY: 0x11F82D94 AT_PRIORITY: 0x75 AT_STACK_SIZE: 0x2000 AT_STACK_ADDR: 0x1214AB4C AT_MEM_PERM_MASK: 0x00008180
AT_UID: 7 AT_ENTRY: 0x123E4174 AT_PRIORITY: 0x50 AT_STACK_SIZE: 0x4000 AT_STACK_ADDR: 0x12804498 AT_MEM_PERM_MASK: 0x00002000
AT_UID: 11 AT_ENTRY: 0xE22602FC AT_PRIORITY: 0x32 AT_STACK_SIZE: 0x4000 AT_STACK_ADDR: 0xE22CB000 AT_MEM_PERM_MASK: 0x00000000
AT_UID: 9 AT_ENTRY: 0xE108E930 AT_PRIORITY: 0x32 AT_STACK_SIZE: 0x1000 AT_STACK_ADDR: 0xE12E71A4 AT_MEM_PERM_MASK: 0x00000000
AT_UID: 12 AT_ENTRY: 0xE3166B34 AT_PRIORITY: 0x32 AT_STACK_SIZE: 0x4000 AT_STACK_ADDR: 0xE31AF000 AT_MEM_PERM_MASK: 0x00000000
AT_UID: 8 AT_ENTRY: 0xE00D8290 AT_PRIORITY: 0x32 AT_STACK_SIZE: 0x4000 AT_STACK_ADDR: 0xE0125390 AT_MEM_PERM_MASK: 0x00000000
AT_UID: 10 AT_ENTRY: 0xE500D720 AT_PRIORITY: 0x46 AT_STACK_SIZE: 0x4000 AT_STACK_ADDR: 0xE506A900 AT_MEM_PERM_MASK: 0x00000000
AT_UID: 13 AT_ENTRY: 0xE40168A4 AT_PRIORITY: 0x4B AT_STACK_SIZE: 0x2000 AT_STACK_ADDR: 0xE415623C AT_MEM_PERM_MASK: 0x00000000
Exception Handling
The data-abort and prefetch-abort exception handlers will first check whether a certain flag is clear(flagsfield & (1<<PID)). When that bit is clear and the PID is <=13(highest IOSU PID value that exists), it will just return from the function then do a context-switch. Otherwise, iosPanic() is called.
IPC
PowerPC code is able to call IOSU drivers through an IPC interface. It uses the same call interface as IOSU does internally. Userspace code submits IOSU requests with the IPCKDriver_SubmitRequest() syscall in the Cafe OS kernel. The kernel includes information to identify which Cafe OS process sent the request, allowing IOSU to check permissions on a per-app basis. Requests are contained in a struct, sent through a hardware interface, and marshalled by the IOSU kernel to a target process. An example of IOSU IPC from the PowerPC can be found here.
IPC request struct (size = 0x48, align = 0x20) 0x00: CMD (1=open, 2=close, 3=read, 4=write, 5=seek, 6=ioctl, 7=ioctlv) 0x04: Reply to client 0x08: Client FD 0x0C: Flags (always 0) 0x10: Client CPU (0=ARM internal, 1-3=PPC cores 0-2) 0x14: Client PID (PFID in older versions, RAMPID more recently?) 0x18: Client group ID (Title ID, upper) 0x1C: Client group ID (Title ID, lower) 0x20: Server handle (written by IOSU) 0x24: Arg0 0x28: Arg1 0x2C: Arg2 0x30: Arg3 0x34: Arg4 0x38: CMD (previous) 0x3C: Client FD (previous) 0x40: Virt0 (PPC virtual addresses to be translated) 0x44: Virt1 (PPC virtual addresses to be translated)
IPC commands 0x00 -> IOS_COMMAND_INVALID 0x01 -> IOS_OPEN 0x02 -> IOS_CLOSE 0x03 -> IOS_READ 0x04 -> IOS_WRITE 0x05 -> IOS_SEEK 0x06 -> IOS_IOCTL 0x07 -> IOS_IOCTLV 0x08 -> IOS_REPLY (internal to IOSU) 0x09 -> IOS_IPC_MSG0 (internal to IOSU) 0x0A -> IOS_IPC_MSG1 (internal to IOSU) 0x0B -> IOS_IPC_MSG2 (internal to IOSU) 0x0C -> IOS_SUSPEND (internal to IOSU) 0x0D -> IOS_RESUME (internal to IOSU) 0x0E -> IOS_SVCMSG (internal to IOSU)
IPC client PIDs On older versions of IOSU, it seems to match the PFID list. More recently, it appears to use the RAMPID. See the Cafe OS PID tables.
IPC arguments
Open CMD:   Client FD == 0
            Arg0 = name
            Arg1 = name_size
            Arg2 = mode (0 = none, 1 = read, 2 = write)
            Arg3-Arg4 = u64 permissions_bitmask for the target IOSU process, loaded by the target IOSU process during fd init. With PPC this originates from the cos.xml of the source process.
Close CMD:  Client FD != 0
Read CMD:   Client FD != 0
            Arg0 = outPtr
            Arg1 = outLen
Write CMD:  Client FD != 0
            Arg0 = inPtr
            Arg1 = inLen
Seek CMD:   Client FD != 0
            Arg0 = where
            Arg1 = whence
IOCtl CMD:  Client FD != 0
            Arg0 = cmd
            Arg1 = inPtr
            Arg2 = inLen
            Arg3 = outPtr
            Arg4 = outLen
IOCtlv CMD: Client FD != 0
            Arg0 = cmd
            Arg1 = readCount
            Arg2 = writeCount
            Arg3 = vector
Modules
Similarly to the Wii, IOS modules roughly map to processes and drivers inside the kernel.
IOS-CRYPTO
Cryptography services.
- /dev/crypto - Cryptography API
IOS-MCP
Master title operations such as title launching and cafe2wii booting.
- /dev/mcp - Master title launching (also encapsulates ES from the Wii)
- /dev/mcp_recovery - Master title launching (recovery mode)
- /dev/volflush - Volume cache flushing service
- /dev/pm - Power management
- /dev/syslog - System logging
- /dev/usb_syslog - USB system logging
- /dev/dk_syslog - DevKit system logging
- /dev/ppc_app - PPC application service
- /dev/ppc_kernel - PPC kernel service
IOS-USB
USB controllers and devices.
- /dev/usbproc1 - USB internal process
- /dev/usbproc2 - USB internal recovery process
- /dev/uhs/0 - USB host stack (external ports)
- /dev/usb_cdc - USB communications device class
- /dev/usb_hid - USB human interface device
- /dev/usb_uac - USB audio class
- /dev/usb_midi - USB musical instrument digital interface
IOS-FS
File system services.
- /dev/fsa - Virtual file system API
- /dev/dk - DevKit file system API
- /dev/odm - Optical disk manager
- /dev/ramdisk_svc - RAM disk service
- /dev/ums - USB mass storage
- /dev/df - Disk format
- /dev/atfs - Optical disk file system
- /dev/isfs - Internal storage file system
- /dev/wfs - Wii file system
- /dev/pcfs - PC file system (only available in development or test modes)
- /dev/rbfs - Raw file system
- /dev/fat - FAT file system
- /dev/fla - Flash file system
- /dev/ahcimgr - Advanced host controller interface manager
- /dev/shdd - SATA hard disk drive
- /dev/md - Raw memory device
- /dev/scfm - SLC cache for MLC
- /dev/mmc - eMMC storage
- /dev/timetrace - File IO time tracer
IOS-PAD
Gamepad controllers and devices.
- /dev/uhs/1 - USB host stack (internal devices)
- /dev/ccr_io - Gamepad main service
- /dev/ccr_cdc - Gamepad RPC (CDC = Communications Device Class)
- /dev/ccr_hid - Gamepad input (HID = Human Interface Device)
- /dev/ccr_nfc - Gamepad NFC reader
- /dev/ccr_uac - Gamepad microphone (UAC = USB Audio Class)
- /dev/ccr_uvc - Gamepad camera (UVC = USB Video Class)
- /dev/usb/btrm - Bluetooth module (for Wii Remote and Pro Controller)
- /dev/usb/early_btrm - Secondary Bluetooth module
IOS-NET
Network services.
- /dev/network - Network main service
- /dev/socket - BSD sockets API
- /dev/ifnet - Network interface
- /dev/net/ifmgr - Network interface manager
- /dev/net/ifmgr/wd - Wireless device?
- /dev/net/ifmgr/ncl - Network configuration
- /dev/net/ifmgr/usbeth - Ethernet over USB
- /dev/ifuds - UDS interface
- /dev/udscntrl - UDS control. Used by nn_uds.rpl(see here).
- /dev/wl0 - Wireless interface
- /dev/wifidata - WiFi data test (send/receive raw data frames)
- /dev/wifi24 - WiFi driver
- /dev/ac_main - Auto Connection, used by nn_ac.rpl.
- /dev/ndm - Network daemons
- /dev/dlp - 3DS Download Play hosting, used by nn_dlp.rpl.
IOS-ACP
User level application management.
- /dev/acpproc - Application management internal process
- /dev/acp_main - Application management main service
- /dev/emd - Eco management dameon?
- /dev/pdm - Play data manager? (stores applications' statistics)
- /dev/nnsm - Nintendo Network service manager?
- /dev/nnmisc - Nintendo Network miscellaneous?
IOS-NSEC
Network security services. This uses OpenSSL, "OpenSSL 1.0.0f 4 Jan 2012".
- /dev/nsec - Network security
- /dev/nsec/nss - Network security services
- /dev/nsec/nssl - Network SSL API
IOS-NIM-BOSS
Nintendo's proprietary online services such as update installations. This uses statically-linked libcurl.
IOS-FPD
Nintendo's proprietary friend system. This uses statically-linked libcurl.
IOS-TEST
Debugging and testing services.
- /dev/testproc1 - Test process
- /dev/testproc2 - Test process
- /dev/iopsh - IOP shell?
- /dev/cbl - Cafe OS block log
- /debug/prof - Profiler (development mode only)
- /test/ppcprotviol - PPC protocol violation (test mode only)
- /test/sp - System profiler (test mode only)
- /test/test_rm - Resource manager test (test mode only)
IOS-AUXIL
Auxiliary services.
- /dev/auxilproc - Auxiliary service's internal process
- /dev/im - Home menu
- /dev/usr_cfg - User configuration
IOS-BSP
Hardware.
- /dev/bsp - Board support package? (hardware interface)
Others
These are not real /dev nodes. Instead, they represent internal mappings of system volumes created by the IOS-FS process as part of the virtual file system API's initialization.
The virtual file system API is able to map more than one instance of such volumes, whence why the final node name always has an integer representing it's instance (e.g.: 01).
- /dev/si01 - ?????
- /dev/slccmpt01 - NAND SLC (vWii compatible)
- /dev/slc01 - NAND SLC
- /dev/ramdisk01 - RAM disk
- /dev/mlc01 - NAND MLC
- /dev/hfio01 - Host file IO
- /dev/odd01 - Optical disk drive
- /dev/sdcard01 - SD card
- /dev/sd01 - ?????
- /dev/usb01 - USB device
- /dev/mlcorig01 - NAND MLC original? (Used for board types ID and IH instead of mlc, disables scfm)
- /dev/unknown01 - Unrecognized
Virtual Memory Map
| Virtual address range | Physical address range | Size | Description | 
|---|---|---|---|
| 0x04000000 - 0x04030000 | 0x08280000 - 0x082B0000 | 0x30000 | IOS-CRYPTO | 
| 0x05000000 - 0x050C0000 | 0x081C0000 - 0x08280000 | 0xC0000 | IOS-MCP | 
| 0x05100000 - 0x05120000 | 0x13D80000 - 0x13DA0000 | 0x20000 | IOS-MCP (development and recovery mode) | 
| 0x08120000 - 0x081C0000 | 0x08120000 - 0x081C0000 | 0xA0000 | IOS-KERNEL | 
| 0x10000000 - 0x10100000 | 0x10000000 - 0x10100000 | 0x100000 | PRSH/PRST | 
| 0x10100000 - 0x104D0000 | 0x10100000 - 0x104D0000 | 0x3D0000 | IOS-USB | 
| 0x10700000 - 0x11C40000 | 0x10700000 - 0x11C40000 | 0x1540000 | IOS-FS (5.5.1 production) | 
| 0x10800000 - 0x11EE0000 | 0x10800000 - 0x11EE0000 | 0x16E0000 | IOS-FS (5.3.2 development) | 
| 0x11F00000 - 0x12160000 | 0x11F00000 - 0x12160000 | 0x260000 | IOS-PAD | 
| 0x12300000 - 0x12890000 | 0x12300000 - 0x12890000 | 0x590000 | IOS-NET | 
| 0x1D000000 - 0x1FB00000 | 0x1D000000 - 0x1FB00000 | 0x2B00000 | Global heap | 
| 0x1FB00000 - 0x1FE00000 | 0x1FB00000 - 0x1FE00000 | 0x300000 | Global IOB (input/output block) | 
| 0x1FE00000 - 0x1FE20000 | 0x1FE00000 - 0x1FE20000 | 0x40000 | IOS-MCP (shared region) | 
| 0x1FE40000 - 0x20000000 | 0x1FE40000 - 0x20000000 | 0x1C0000 | IOS-MCP (setup region) | 
| 0x20000000 - 0x28000000 | 0x20000000 - 0x28000000 | 0x8000000 | RAMDISK | 
| 0xE0000000 - 0xE0270000 | 0x12900000 - 0x12B70000 | 0x270000 | IOS-ACP | 
| 0xE1000000 - 0xE12F0000 | 0x12BC0000 - 0x12EB0000 | 0x2F0000 | IOS-NSEC | 
| 0xE2000000 - 0xE26D0000 | 0x12EC0000 - 0x13590000 | 0x6D0000 | IOS-NIM-BOSS | 
| 0xE3000000 - 0xE3300000 | 0x13640000 - 0x13940000 | 0x300000 | IOS-FPD | 
| 0xE4000000 - 0xE4160000 | 0x13A40000 - 0x13BA0000 | 0x160000 | IOS-TEST | 
| 0xE5000000 - 0xE5070000 | 0x13C00000 - 0x13C70000 | 0x70000 | IOS-AUXIL | 
| 0xE6000000 - 0xE6050000 | 0x13CC0000 - 0x13D80000 | 0xC0000 | IOS-BSP | 
| 0xE7000000 - 0xE7001000 | |||
| 0xEFF00000 - 0xEFF08000 | 0xFFF00000 - 0xFFF08000 | 0x8000 | C2W (cafe2wii) boot heap | 
| 0xFFFF0000 - 0xFFFFFFFF | 0xFFFF0000 - 0xFFFFFFFF | 0x10000 | Kernel SRAM / C2W (cafe2wii) | 
The Starbuck MMU itself only has R/W permissions for data/instruction memory access, no XN. However, there is XN implemented via separate hardware registers at 0x0d8b0XXX. The register relative-offset is calculated with the physaddr of the memory being protected. Each u32 register corresponds to a different block of physical memory. Among other things, this controls whether the ARM is allowed to access the memory for instruction-access, and in what ARM-mode(userland/privileged) the instruction-access is permitted.
Hence, userland .text is only executable from userland. From userland, the only executable memory is the process .text. In privileged-mode, the only executable memory is the main kernel .text(0x08120000) and 0xffff0000(the latter is also RWX).