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

IOSU syscalls

From WiiUBrew
Revision as of 22:11, 5 October 2015 by Hykem (talk | contribs) (More syscalls)
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 void* access_ipc_buffer_pool() Gets the per-thread IPC buffer pool's address The IPC buffer pool address value
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 u32 get_timestamp() Get the current timestamp The current timestamp value
0x18 u32 time_now() Fetch the current value of the Starbuck's timer The current value of the timer register
0x19 IOS_GetUpTimeStruct(???)
0x1A int IOS_GetUpTime64(u64 *out_buf) Returns the current time in wide format 0 on success
0x1B int set_rtc_counter(u64 *in_buf) Sets the RTC counter used by MCP (can only be called by MCP) 0 on success
0x1C IOS_GetAbsTimeCalendar(???)
0x1D IOS_GetAbsTime64(???)
0x1E IOS_GetAbsTimeStruct(???)
0x1F
0x20 int check_otp() Checks if the first word in bank 1 is 0x8000000 0 on success
0x21 int check_jtag() Get the current status of the JTAG 0 if JTAG is enabled or -4 if disabled
0x22 int read_otp(int index, void *out_buf, u32 size) Read data from the OTP 0 on success
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 void heap_free_and_clear(int heapid, void *ptr) Same as IOS_Free, but clears the contents of ptr 0 on success
0x2B int heap_expand(int heapid, void *ptr, u32 size) Expands an allocated memory block by size bytes 0 on success
0x2C int device_register(const char* device, int queueid) Registers device to the device tree, so it can be opened (from ARM and PPC) 0 on success
0x2D int device_associate(const char* device, int internal_id) Associates a device to the specified internal IOS ID 0 on success
0x2E int device_set_flags(const char* device, u32 flags) Sets some flags in the device's internal structure 0 on success
0x2F int set_client_capabilities(int client_pid, int feature_id, u32 *masks) Sets the client's capability masks/permissions (can only be called by MCP) 0 on success
0x30 int clear_client_capabilities(int client_pid) Clears the client's capability masks/permissions (can only be called by MCP) 0 on success
0x31 int query_client_capabilities(int client_pid, int feature_id, void *out_buffer) Gets the client's capability masks/permissions (out_buffer gets 0x08 bytes; mask1 and mask2) 0 on success
0x32 int query_feature_id(int feature_id, int out_count, void *out_buffer) Retrieves information associated with a feature_id (out_buffer receives out_count * 0x34 bytes structures with the client pid, busy close violations count, active TXN count and open handles count) 0 on success
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 int IOS_ResourceReply(void *ipc_handle, u32 result) Reply back through the IPC handle 0 on success
0x4A
0x4B
0x4C
0x4D
0x4E
0x4F
0x50 IOS_ClearandEnable(???)
0x51 int access_iobuf_pool(int unk) Unused Always 0
0x52 struct iobuf *alloc_iobuf(int unk, u32 buf_size) Allocate an iobuf NULL on error
0x53 int free_iobuf(struct iobuf *iob) Free an allocated iobuf 0 on success
0x54 void iobuf_log_header_info() Unused Nothing
0x55 void iobuf_log_buffer_info() Unused Nothing
0x56 void *extend_iobuf(struct iobuf *iob, unsigned short num) Extend the data in the buffer by num bytes Returns a pointer to extended area
0x57 void *IOS_PushIob(struct iobuf *iob, unsigned short num) Move head pointer num bytes towards the buffer end Returns old head pointer
0x58 void *IOS_PullIob(struct iobuf *iob, unsigned short num) Move head pointer num bytes towards the buffer start Returns old head pointer
0x59 int verify_iobuf(struct iobuf *iob) Verify if the argument points to an iobuf 0 on success
0x5A
0x5B void IOS_InvalidateDCache(void *ptr, unsigned int len) Invalidate data cache
0x5C void IOS_FlushDCache(void *ptr, unsigned int len) Flush data cache
0x5D disable_memory_protection(???)
0x5E
0x5F
0x60
0x61 IOS_CreateSemaphore(???)
0x62 IOS_WaitSemaphore(???)
0x63 IOS_SignalSemaphore(???)
0x64 IOS_DestroySemaphore(???)
0x65
0x66
0x67
0x68 get_ppc_log_region(???)
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_aggregate_resource_utilization(???)
0x74 get_per_process_resource_utilization(???)
0x75 get_timer_utilization(???)
0x76 get_semaphore_utilization(???)
0x77 get_heap_profile(???)
0x78
0x79
0x7A
0x7B
0x7C
0x7D
0x7E
0x7F panic(???)
0x80 crash(???)
0x81
0x82
0x83
0x84
0x85
0x86
0x87 int get_open_handles(int out_count, void *out_buffer, int pid) Finds open resource handles for the specified pid (out_buffer receives out_count * 0x2C bytes structures with the handle number, handle path and more) 0 on success
0x88
0x89
0x8A get_dynamic_heap_access(???)
0x8B
0x8C
0x8D
0x8E get_resource_violations(???)
0x8F
0x90
0x91 get_pending_resource_requests(???)
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
0x01 unused
0x02 unused
0x03 unused
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