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

IOSU syscalls

From WiiUBrew
Revision as of 23:35, 11 September 2015 by Naehrwert (talk | contribs)
Jump to navigation Jump to search

There are 2 types of syscalls:

1. Syscalls using undefined ARM instruction.

2. Syscalls using ARM syscall instruction.

Syscalls (via undefined instructions)

Similarly to the Wii's IOS, the IOSU uses a syscall table that is stored toward 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             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

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 currently has 0x94 available syscalls (the number of installed syscalls can vary between system versions).

NOTE: Official syscall names begin with "IOS_", the rest are merely educated guesses.

ID # Internal name Description Return value
0x00 int IOS_CreateThread(u32 (*proc)(void* arg), void* arg, u32* stack_top, u32 stacksize, int priority, BOOL detached) Creates a thread (in paused state) New threadid or error (negative value)
0x01 int thread_join(int threadid, u32 *returned_value) Waits for a thread to finish executing 0 on success
0x02 int thread_cancel(int threadid, u32 unk) Cancels an active thread 0 on success
0x03 int get_tid() Get the current thread's ID Current threadid
0x04
0x05 int get_pid() Get the current process' ID Current processid
0x06 int get_process_name(int pid, char *out_buffer, u32 out_size) Get the specified process' name string 0 on success
0x07 int thread_resume(int threadid) Resume the specified thread 0 on success
0x08 int thread_suspend(int threadid) Suspend the specified thread 0 on success
0x09 int thread_yield() Yield execution to any higher priority threads 0 on success
0x0A int IOS_GetThreadPriority(int threadid) Get the priority of the specified thread The thread's priority or error (negative value)
0x0B int IOS_SetThreadPriority(int threadid, int priority) Set the priority of the specified thread 0 on success
0x0C int IOS_CreateMessageQueue(u32 *ptr, u32 n_msgs) Create a queue at ptr, for n_msgs messages The queue ID
0x0D int IOS_DestroyMessageQueue(int queueid) Destroy a message queue 0 on success
0x0E int IOS_SendMessage(int queueid, u32 message, u32 flags) Add a message to the end queue 0 on success
0x0F int IOS_JamMessage(int queueid, u32 message, u32 flags) Add a message to the front of a queue 0 on success
0x10 int IOS_ReceiveMessage(int queueid, u32 *message, u32 flags) Fetch a message from the front of a queue 0 on success
0x11 int IOS_HandleEvent(int device, int queueid, int message) Register queueid as a handler for interrupts generated by device (sends message to queueid when device's interrupt is triggered) 0 on success
0x12 int unregister_event_handler(int device) Unregister handler for device 0 on success
0x13 int IOS_CreateTimer(int time_us, int repeat_time_us, int queueid, u32 message) Create a timer that sends a message to a queue after the elapsed period(s) Timerid or error (negative value)
0x14 int IOS_RestartTimer(int timerid, int time_us, int repeat_time_us) Restart a timer using the specified period(s) 0 on success
0x15 int IOS_StopTimer(int timerid) Pauses the specified timer 0 on success
0x16 int IOS_DestroyTimer(int timerid) Destroys the specified timer 0 on success
0x17
0x18 int time_now()
0x19 IOS_GetUpTimeStruct(???)
0x1A IOS_GetUpTime64(???)
0x1B
0x1C IOS_GetAbsTimeCalendar(???)
0x1D IOS_GetAbsTime64(???)
0x1E IOS_GetAbsTimeStruct(???)
0x1F
0x20
0x21 int check_jtag() Get the current status of the JTAG 0 if JTAG is enabled or -4 if disabled
0x22
0x23 int heap_create(void *ptr, int size) Create a new heap at ptr of size bytes The heapid or error (negative value)
0x24 int IOS_CreateLocalProcessHeap(void *ptr, int size) Create a new local process heap of size bytes The heap ID or error (negative value)
0x25 int IOS_CreateCrossProcessHeap(int size) Create a new cross process heap of size bytes The heap ID or error (negative value)
0x26 int heap_destroy(int heapid) Destroy the specified heap 0 on success
0x27 void* IOS_Alloc(int heapid, u32 size) Allocate size bytes from the specified heap Pointer to memory
0x28 void* heap_alloc_aligned(int heapid, u32 size, u32 align) Allocate size bytes from the specified heap with the requested alignment Pointer to aligned memory
0x29 void IOS_Free(int heapid, void *ptr) Release allocated memory back to the heap 0 on success
0x2A
0x2B
0x2C
0x2D BOOL device_register(const char* device, int queueid) Registers device to the device tree, so it can be opened (from Starbuck and PPC) 0 on success
0x2E
0x2F
0x30
0x31
0x32 int query_featureid(int featureid, int out_size, void *out_buffer)
0x33 int IOS_Open(const char* device, int mode) Similar to IOS_Open on PPC, except now internal to the IOSU system Returns an fd or error (negative)
0x34 int IOS_Close(int fd) Close a previously opened fd 0 on success
0x35 int IOS_Read(int fd, void *buf, u32 len) Read len bytes from fd into buf The number of bytes read or error
0x36 int IOS_Write(int fd, const void *buf, u32 len) Write len bytes to fd from buf The number of bytes written or error
0x37 int IOS_Seek(int fd, int offset, int origin) Seek to offset relative to origin The new absolute offset or error
0x38 int IOS_Ioctl(int fd, u32 request, void *input_buffer, u32 input_buffer_len, void *output_buffer, u32 output_buffer_len) Perform the requested IOCTL Return value from IOCTL
0x39 int IOS_Ioctlv(int fd, u32 request, u32 vector_count_in, u32 vector_count_out, struct iovec *vector) Perform the requested IOCTL Return value from IOCTL
0x3A int IOS_OpenAsync(const char* device, int mode, int queueid, ipcmessage *message) Async implementation of IOS_Open 0 on success, ipcmessage is sent to the queue with the command's return value
0x3B int IOS_CloseAsync(int fd, int queueid, ipcmessage *message) Async implementation of IOS_Close 0 on success
0x3C int IOS_ReadAsync(int fd, void *buf, u32 len, int queueid, ipcmessage *message) Async implementation of IOS_Read 0 on success
0x3D int IOS_WriteAsync(int fd, const void *buf, u32 len, int queueid, ipcmessage *message) Async implementation of IOS_Write 0 on success
0x3E int IOS_SeekAsync(int fd, int offset int origin, int queueid, ipcmessage *message) Async implementation of IOS_Seek 0 on success
0x3F int IOS_IoctlAsync(int fd, u32 request, void *input_buffer, u32 input_buffer_len, void *output_buffer, u32 output_buffer_len, int queueid, ipcmessage *message) Async implementation of IOS_Ioctl 0 on success
0x40 int IOS_IoctlvAsync(int fd, u32 request, u32 vector_count_in, u32 vector_count_out, struct iovec *vector, int queueid, ipcmessage *message) Async implementation of IOS_Ioctlv 0 on success
0x41 open_as_async
0x42 write_as_async
0x43 ipc_resume
0x44 ipc_suspend
0x45 ipc_svcmsg
0x46 ipc_resume_async
0x47 ipc_suspend_async
0x48 ipc_svcmsg_async
0x49 IOS_ResourceReply(???)
0x4A
0x4B
0x4C
0x4D
0x4E
0x4F
0x50 IOS_ClearandEnable(???)
0x51 access_iobuf_pool(???)
0x52
0x53
0x54
0x55
0x56
0x57
0x58
0x59
0x5A
0x5B int IOS_InvalidateDCache(void *ptr, unsigned int len)
0x5C
0x5D disable_memory_protection
0x5E
0x5F
0x60
0x61 IOS_CreateSemaphore(???)
0x62 IOS_WaitSemaphore(???)
0x63 IOS_SignalSemaphore(???)
0x64 IOS_DestroySemaphore(???)
0x65
0x66
0x67
0x68
0x69
0x6A get_iop_cpu_utilization(???)
0x6B
0x6C IOS_ThreadProfileCommand(???)
0x6D get_thread_utilization(???)
0x6E
0x6F
0x70
0x71 get_iobuf_utilization(???)
0x72 get_message_utilization(???)
0x73 get_active_resources(???)
0x74
0x75 get_timer_utilization(???)
0x76 get_semaphore_utilization(???)
0x77
0x78
0x79
0x7A
0x7B
0x7C
0x7D
0x7E
0x7F panic(???)
0x80 crash(???)
0x81
0x82
0x83
0x84
0x85
0x86
0x87
0x88
0x89
0x8A
0x8B
0x8C
0x8D
0x8E get_resource_violations(???)
0x8F
0x90
0x91
0x92
0x93

Syscalls (via ARM syscall instruction)

These types of syscalls are created with the ARM syscall instruction. The exception handler is empty and just do nothing and returns. These syscalls are RealView semihosting operations that allow communication with a debugger.
Currently only syscall 0x04 is still used in production versions of IOSU.

MOVS r0, #syscall_number
SVC 0xAB

Register r0 takes the syscall number.
Register r1 takes the first parameter.

ID # Internal name Description Return value
0x04 write(const char *string) Prints a null-terminated debug message None
0x05 unused
0x06 unused
0x07 unused
0x08 unused
0x09 unused
0x0A unused
0x0C unused
0x0D unused
0x0E unused
0x0F unused
0x10 unused
0x11 unused
0x12 unused
0x13 unused
0x15 unused
0x16 unused
0x30 unused
0x31 unused