In memory of Ben “bushing” Byer, who passed away on Monday, February 8th, 2016.

Changes

Jump to navigation Jump to search
7,336 bytes added ,  20:02, 4 April 2016
Line 6: Line 6:  
==Architecture==
 
==Architecture==
 
IOSU is an embedded operating system written by Nintendo, with a microkernel architecture. It contains a simple kernel that implements memory management and 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).
 
IOSU is an embedded operating system written by Nintendo, with a microkernel architecture. It contains a simple kernel that implements memory management and 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).
 +
 +
===ELF loader===
 +
The IOSU firmware image file (fw.img), when decrypted, contains two distinguishable pieces of code: a small ELF loader and the actual firmware binary (ELF file).
 +
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 IOSU's image and launch it (cold boot). However, IOS-MCP also has to do this when handling a system restart (warm boot).
 +
The IOS-MCP module begins by clearing up MEM1 then fetches the fw.img file from NAND. It verifies the image's [[Ancast_Image|header]], decrypts it using the [[Encryption_Keys|Starbuck Ancast Key]] and finally makes use of the [[IOSU_Syscalls|execute_privileged]] system call in order to disable memory protections and jump to the IOSU's ELF loader code.
 +
 +
This loader then does the following:
 +
- Clear it's own small stack;
 +
- Set 0x20 in LT_MEMIRR register (if not set already);
 +
- Fetch e_phnum from the IOSU's ELF header;
 +
- Loop through the ELF's program header structs;
 +
- For each program marked with PT_LOAD, copy it's code into the target physical memory;
 +
- Wipe the IOSU's ELF binary from MEM1;
 +
- Wipe itself from MEM1 (excluding the then running subroutine);
 +
- Branch 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  // LT_BOOT0
 +
  r1 <- 0x00(LT_BOOT0)
 +
  r1 <- r1 | 0x1000
 +
  0x00(LT_BOOT0) <- 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.
 +
 +
===Threads===
 +
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).
 +
// Thread struct in memory
 +
struct
 +
{
 +
  0x00: saved_cpsr
 +
  0x04: saved_r0
 +
  0x08: saved_r1
 +
  0x0C: saved_r2
 +
  0x10: saved_r3
 +
  0x14: saved_r4
 +
  0x18: saved_r5
 +
  0x1C: saved_r6
 +
  0x20: saved_r7
 +
  0x24: saved_r8
 +
  0x28: saved_r9
 +
  0x2C: saved_r10
 +
  0x30: saved_r11
 +
  0x34: saved_r12
 +
  0x38: saved_r13
 +
  0x3C: saved_lr
 +
  0x40: thread_pc
 +
  0x44: ?????
 +
  0x48: thread_min_priority
 +
  0x4C: thread_max_priority
 +
  0x50: thread_state
 +
  0x54: owner_pid
 +
  0x58: thread_id
 +
  0x5C: ?????
 +
  0x60: ?????
 +
  0x64: ?????
 +
  0x68: ?????
 +
  0x6C: ?????
 +
  0x70: ?????
 +
  0x74: ?????
 +
  0x78: ?????
 +
  0x7C: ?????
 +
  0x80: ?????
 +
  0x84: ?????
 +
  0x88: ?????
 +
  0x8C: ?????
 +
  0x90: ?????
 +
  0x94: ?????
 +
  0x98: ?????
 +
  0x9C: ?????
 +
  0xA0: ?????
 +
  0xA4: thread_sp
 +
  0xA8: ?????
 +
  0xAC: ?????
 +
  0xB0: sys_stack_addr
 +
  0xB4: user_stack_addr
 +
  0xB8: user_stack_size
 +
  0xBC: ipc_buffer_pool
 +
  0xC0: ?????
 +
  0xC4: ?????
 +
} thread_t;  // sizeof() = 0xC8
 +
 +
Thread states
 +
 +
0x00 -> Available
 +
0x01 -> Ready
 +
0x02 -> Running
 +
0x03 -> Stopped
 +
0x04 -> Waiting
 +
0x05 -> Dead
 +
0x06 -> Faulted
 +
0x07 -> Unknown
    
===IPC===
 
===IPC===
28

edits

Navigation menu