IOS/Syscalls

From WiiUBrew
< IOS
Jump to navigation Jump to search

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.).

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.

Syscall Table

The following syscall table is for the latest version of IOSU (5.5.0 onwards). Syscall IDs can vary based on IOSU version.

Names starting with IOS_ are official names. The rest are only educated guesses.

ID Name Description
0x00 IOSThreadId IOS_CreateThread(u32 entry, void *arg, void *stack, u32 stackSize, u32 priority, u32 attributes)
0x01 IOSError IOS_JoinThread(IOSThreadId id, void **val)
0x02 IOSError IOS_DestroyThread(IOSThreadId id, void *val)
0x03 IOSThreadId IOS_GetThreadId(void)
0x04 void* GetCurrentThreadLocalStorage(void)
0x05 IOSProcessId IOS_GetProcessId(void)
0x06 IOSError GetProcessName(IOSProcessId pid, char *name)
0x07 IOSError IOS_StartThread(IOSThreadId id)
0x08 IOSError IOS_StopThread(IOSThreadId id)
0x09 void IOS_YieldThread(void)
0x0A u32 IOS_GetThreadPriority(IOSThreadId id)
0x0B IOSError IOS_SetThreadPriority(IOSThreadId id, u32 priority)
0x0C IOSMessageQueueId IOS_CreateMessageQueue(IOSMessage *msgarray, u32 count)
0x0D IOSError IOS_DestroyMessageQueue(IOSMessageQueueId mq)
0x0E IOSError IOS_SendMessage(IOSMessageQueueId mq, IOSMessage msg, u32 flag)
0x0F IOSError IOS_JamMessage(IOSMessageQueueId mq, IOSMessage msg, u32 flag)
0x10 IOSError IOS_ReceiveMessage(IOSMessageQueueId mq, IOSMessage* msg, u32 flag)
0x11 IOSError IOS_HandleEvent(IOSEvent event, IOSMessageQueueId mq, IOSMessage mesg)
0x12 IOSError IOS_UnhandleEvent(IOSEvent event)
0x13 IOSTimerId IOS_CreateTimer(IOSTime value, IOSTime interval, IOSMessageQueueId mq, IOSMessage mesg)
0x14 IOSError IOS_RestartTimer(IOSTimerId id, IOSTime time, IOSTime interval)
0x15 IOSError IOS_StopTimer(IOSTimerId id)
0x16 OSError IOS_DestroyTimer(IOSTimerId id)
0x17 IOSTime GetUpTimer(void) Returns the number of microseconds elapsed since boot as an u32.
0x18 u32 IOS_GetTimer(void) Returns the raw tick count from the HW_TIMER register.
0x19 IOSError IOS_GetUpTimeStruct(IOSTimeStruct *out) Returns the time elapsed since boot in struct format.
0x1A IOSError IOS_GetUpTime64(u64 *out) Returns the time elapsed since boot as an u64.
0x1B IOSError SetRtcCounter(IOSTimeStruct *in) Sets the time provided by the RTC in struct format.
0x1C IOSError IOS_GetAbsTimeCalendar(IOSTimeCalendar *out) Returns the absolute time (up time + RTC) in calendar format.
0x1D IOSError IOS_GetAbsTime64]](u64 *out) Returns the absolute time (up time + RTC) as an u64.
0x1E IOSError IOS_GetAbsTimeStruct(IOSTimeStruct *out) Returns the absolute time (up time + RTC) in struct format.
0x1F IOSError EnablePanicOnException]](IOSProcessId pid, bool enable) 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.
0x20 IOSError IsDevelopment(void)
0x21 IOSError IsJTAGEnabled(void)
0x22 IOSError ReadOTP(u32 wordIndex, void *out_buf, u32 size) Read data from the eFuses. This can only be used from the IOS-CRYPTO process.
0x23 IOSHeapId IOS_CreateHeap(void *ptr, u32 size)
0x24 IOSHeapId IOS_CreateLocalProcessHeap(void *ptr, u32 size)
0x25 IOSHeapId IOS_CreateCrossProcessHeap(u32 size)
0x26 IOSError IOS_DestroyHeap(IOSHeapId id)
0x27 void* IOS_Alloc(IOSHeapId id, u32 size)
0x28 void* IOS_AllocAligned(IOSHeapId id, u32 size, u32 alignment)
0x29 IOSError IOS_Free(IOSHeapId id, void *ptr)
0x2A IOSError FreeAndClear(IOSHeapId id, void *ptr)
0x2B IOSError Realloc(IOSHeapId id, void *ptr, u32 size)
0x2C IOSError IOS_RegisterResourceManager(const char* path, IOSMessageQueueId mq)
0x2D IOSError AssociateResourceManager(const char* path, u32 id) 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.
0x2E IOSError SetResourceManagerMaxIoVectors(const char* path, u32 max_vectors)
0x2F IOSError SetClientCapabilities(IOSProcessId pid, u32 fid, u32 *capabilities)
0x30 IOSError ClearClientCapabilities(IOSProcessId pid)
0x31 IOSError GetClientCapabilities(IOSProcessId pid, u32 fid, u32 *capabilities)
0x32 IOSError QueryClientCapabilities(u32 fid, u32 num, IOSResourceManager *out)
0x33 IOSFd IOS_Open(const char* pathname, u32 flags)
0x34 IOSError IOS_Close(IOSFd fd)
0x35 s32 IOS_Read(IOSFd fd, void *buf, u32 length)
0x36 s32 IOS_Write(IOSFd fd, void *buf, u32 length)
0x37 s32 IOS_Seek(IOSFd fd, s32 offset, u32 origin)
0x38 IOSError IOS_Ioctl(IOSFd fd, s32 cmd, void *input, u32 input_size, void *output, u32 output_size)
0x39 IOSError IOS_Ioctlv(IOSFd fd, s32 cmd, u32 readCount, u32 writeCount, IOSIoVector *vector)
0x3A IOSFd IOS_OpenAsync(const char* path, u32 flags, IOSMessageQueueId mqid, IOSResourceRequest *reply)
0x3B IOSError IOS_CloseAsync(IOSFd fd, IOSMessageQueueId mqid, IOSResourceRequest *reply)
0x3C s32 IOS_ReadAsync(IOSFd fd, void *buf, u32 length, IOSMessageQueueId mqid, IOSResourceRequest *reply)
0x3D s32 IOS_WriteAsync(IOSFd fd, void *buf, u32 length, IOSMessageQueueId mqid, IOSResourceRequest *reply)
0x3E s32 IOS_SeekAsync(IOSFd fd, s32 offset, u32 origin, IOSMessageQueueId mqid, IOSResourceRequest *reply)
0x3F IOSError IOS_IoctlAsync(IOSFd fd, s32 cmd, void *input, u32 inputLen, void *output, u32 outputLen, IOSMessageQueueId mqid, IOSResourceRequest *reply)
0x40 IOSError IOS_IoctlvAsync(IOSFd fd, s32 cmd, u32 readCount, u32 writeCount, IOSIoVector *vector, IOSMessageQueueId mqid, IOSResourceRequest *reply)
0x41 IOSError OpenAsAsync(const char* pathname, u32 flags, IOSMessageQueueId mqid, IOSResourceRequest *reply, IOSProcessId pid, IOSNodeId node_id)
0x42 IOSError WriteAsAsync(IOSFd fd, void *buf, u32 len, IOSMessageQueueId mqid, IOSResourceRequest *reply, IOSProcessId pid, IOSNodeId node_id)
0x43 IOSError Resume(IOSFd fd, SystemMode mode, PowerFlags flags)
0x44 IOSError Suspend(IOSFd fd, SystemMode mode, PowerFlags flags)
0x45 IOSError SvcMsg(IOSFd fd, u32 unk0, u32 unk1, u32 unk2, u32 unk3)
0x46 IOSError ResumeAsync(IOSFd fd, SystemMode mode, PowerFlags flags, IOSMessageQueueId mqid, IOSResourceRequest *reply)
0x47 IOSError SuspendAsync(IOSFd fd, SystemMode mode, PowerFlags flags, IOSMessageQueueId mqid, IOSResourceRequest *reply)
0x48 IOSError SvcMsgAsync(IOSFd fd, u32 unk0, u32 unk1, u32 unk2, u32 unk3, IOSMessageQueueId mqid, IOSResourceRequest *reply)
0x49 IOSError IOS_ResourceReply(IOSResourceRequest *response, IOSError status)
0x4A IOSError SetProcessTitle(IOSProcessId pid, u64 tid, u32 gid)
0x4B IOSError GetProcessTitle(IOSProcessId pid, u64 *tid, u32 *gid)
0x4C IOSError IOS_FlushMem(int flushGroup) flushGroup being one of MEM_WB_CLIENTS
0x4D IOSError IOS_FlushMemAsync(int flushGroup) flushGroup being one of MEM_WB_CLIENTS
0x4E IOSError IOS_GetMemWriteStatus(int client) client being one of AHM_RB_CLIENTS
0x4F IOSError IOS_InvalidateRdb(int readBuffer) readBuffer being one of AHM_RB_CLIENTS
0x50 IOSError IOS_ClearAndEnable(u32 id)
0x5B void IOS_InvalidateDCache(void *ptr, u32 length)
0x52 void IOS_FlushDCache(void *ptr, u32 length)
0x53 IOSError IOS_LaunchOS(BootOSImageHeader *os_image) 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.
0x54 void IOS_GetOSVersion(u32 *major, u16 *minor)
0x55 void IOS_GetBootVersion(u32 *major, u16 *minor)
0x56 void* IOS_VirtualToPhysical(void *address)
0x57 IOSSemaphoreId IOS_CreateSemaphore(u32 max_count, u32 initial_count)
0x58 IOSError IOS_WaitSemaphore(IOSSemaphoreId id, bool try_wait)
0x59 IOSError IOS_SignalSemaphore(IOSSemaphoreId id)
0x5A IOSError IOS_DestroySemaphore(IOSSemaphoreId id)
0x5B IOSError InitializeIpc(void)
0x5C IOSError SetBspReady(void)
0x5D IOSError CheckIOPAddressRange(void *address, u32 size, u32 rw_flags) Checks an IOSU address range for read/write permissions.
0x5E IOSError CheckPPCAddressRange(void *address, u32 size) Checks if a PPC address range is registered in the IOSU's address table.
0x5F void PPCPrepareMEM1(void) Fills range 0x00000000 to 0x00002000 in MEM1 with empty PPC branches.
0x60 u32 IOS_GetCpuUtilization(void)
0x61 IOSError GetThreadStackInfo(IOSThreadId id, IOSThreadStackInfo *out)
0x62 IOSError ThreadProfileCommand(IOSThreadProfileCommand cmd, void *data)
Command Value Description
100
101 ProfileEndEx
102
103 ProfileStart
104
105 SamplingProfileResume
106 SamplingProfileEnd
107 SamplingProfileStart
108
109 SamplingProfileMark
110
111
0x63 IOSError GetThreadUtilization(IOSThreadUtilization *out)
0x64 IOSError GetThreadProfile(IOSThreadId id, IOSThreadProfile *out)
0x65 IOSError GetThreadProfiles(u32 max_count, IOSThreadProfile *out)
0x66 IOSError GetMessageUtilization(IOSMessageUtilization *out
0x67 IOSError GetResourceUtilization(IOSResourceAggregateUtilization* out, bool clear)
0x68 IOSError GetProcessResourceUtilization(IOSResourcePerProcessUtilization* out, IOSProcessId pid, bool clear)
0x69 IOSError IOS_GetTimerUtilization(IOSTimerUtilization *out)
0x6A IOSError IOS_GetSemaphoreUtilization(IOSSemaphoreUtilization *out)
0x6B IOSError GetHeapProfile(IOSHeapId id, IOSHeapProfile *profile)
0x6C IOSError IOS_SetIOP2xState(bool enable)
0x6D IOSError SetPpcPlatformInfo(OSPlatformInfo *info)
0x6E void ReadDebugReg(void) Reads LT_SYSCFG1.
0x6F void ClearDebugReg(void) Clears LT_SYSCFG1.
0x70 void WriteDebugReg(u32 val) Writes to LT_SYSCFG1.
0x71 u32 CheckDebugReg(u32 flag) ANDs flag with set LT_SYSCFG1.
0x72 void Shutdown(bool flag) Flag 0 is for standby, 1 resets hardware.
0x73 void IOS_Panic(char *panic_desc, u32 panic_desc_size)
0x74 void Reset(void)
0x75 void SetPanicBehavioir(u32 mode)
0x76 IOSError SetSyslogBuffer(void *log_buf)
0x77 IOSError LoadPPCKernel(u32 address, u32 size) Maps the PPC kernel image memory: address == 0x08000000, size == 0x00120000
0x78 IOSError LoadPPCApplication(u32 mem_id, u32 addr1, u32 size1, u32 addr2, u32 size2) Maps the PPC user application memory: mem_id == 0x02, addr1 == 0x00, size1 == 0x00, addr2 == 0x28000000, size2 == 0xA8000000
0x79 IOSError SetSecurityLevel(IOSSecurityLevel level)
0x7A IOSSecurityLevel GetSecurityLevel(void)
0x7B IOSError GetOpenResourceHandles(u32 max_count, IOSOpenResourceHandle *out, IOSProcessId pid)
0x7C IOSError SetMasterTitleSdkVersion(u32 version)
0x7D u32 GetMasterTitleSdkVersion(void)
0x7E IOSError IsCrossProcessHeap(void *ptr, u32 size)
0x7F IOSError HandleDebugInterrupt(const char *dbg_sts, u32 dbg_sts_size, IOSMessageQueueId mqid, IOSMessage message)
0x80 IOSError UnhandleDebugInterrupt(IOSMessageQueueId mqid, bool panic)
0x81 IOSError NullFunction(void) Null function. Returns 0.
0x82 IOSError GetResourceViolations(u32 max_count, IOSResourceManager *out)
0x83 u32 StaleClientHandlesAndUnregisterResourceManager(char *path)
0x84 IOSError EnableResourceSecurity(bool enable)
0x85 IOSError GetPendingResourceRequests(u32 max_count, IOSPendingResourceRequest *out, IOSProcessId pid)
0x86 IOSError LoadIOS(void)
0x87 void ExiReset(void)

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 0xAB

Register 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