Changes

26,820 bytes removed ,  03:07, 11 February 2024
Redirected page to IOS
Line 1: Line 1: āˆ’
{{stub}}
+
#REDIRECT [[IOS]]
āˆ’
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            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.).<br>
  āˆ’
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 [[IOSU#Exception_Handling|fault]] code will be executed.<br><br>
  āˆ’
 
  āˆ’
NOTE: Official syscall names begin with "IOS_", the rest are merely educated guesses.
  āˆ’
 
  āˆ’
These syscall numbers were last verified on 5.3.2 debug OSv10 and 5.5.0 retail OSv10. They may vary for newer/older versions or OSv9.
  āˆ’
{| class="wikitable"
  āˆ’
|-
  āˆ’
! Debug ID# !! Retail ID# !! Internal name !! Description !! Return value
  āˆ’
|-
  āˆ’
| 0x00 || 0x00 || int IOS_CreateThread(u32 (*proc)(void* arg), void* arg, u32* stack_top, u32 stacksize, int priority, u32 flags)  || Creates a thread (in paused state) || New threadid or error (negative value)
  āˆ’
|-
  āˆ’
| 0x01 || 0x01 || int thread_join(int threadid, u32 *returned_value) || Waits for a thread to finish executing || 0 on success
  āˆ’
|-
  āˆ’
| 0x02 || 0x02 || int thread_cancel(int threadid, u32 return_value)  || Cancels an active thread. Threadid 0 will use the current thread. || 0 on success
  āˆ’
|-
  āˆ’
| 0x03 || 0x03 || int get_tid() || Get the current thread's ID || Current threadid
  āˆ’
|-
  āˆ’
| 0x04 || 0x04 || void* access_ipc_buffer_pool() || Gets the per-thread IPC buffer pool's address || The IPC buffer pool address value
  āˆ’
|-
  āˆ’
| 0x05 || 0x05 || int get_pid() || Get the current process' ID || Current processid
  āˆ’
|-
  āˆ’
| 0x06 || 0x06 || int get_process_name(int pid, char *out_buffer) || Get the specified process' name string || 0 on success
  āˆ’
|-
  āˆ’
| 0x07 || 0x07 || int IOS_StartThread(int threadid) || Resume the specified thread || 0 on success
  āˆ’
|-
  āˆ’
| 0x08 || 0x08 || int thread_suspend(int threadid) || Suspend the specified thread. Threadid 0 will use the current thread. || 0 on success
  āˆ’
|-
  āˆ’
| 0x09 || 0x09 || int thread_yield() || Yield execution to any higher priority threads || 0 on success
  āˆ’
|-
  āˆ’
| 0x0A || 0x0A || int IOS_GetThreadPriority(int threadid) || Get the priority of the specified thread || The thread's priority or error (negative value)
  āˆ’
|-
  āˆ’
| 0x0B || 0x0B || int IOS_SetThreadPriority(int threadid, int priority) || Set the priority of the specified thread || 0 on success
  āˆ’
|-
  āˆ’
| 0x0C || 0x0C || int IOS_CreateMessageQueue(u32 *ptr, u32 n_msgs) || Create a queue at ptr, for n_msgs messages || The queue ID
  āˆ’
|-
  āˆ’
| 0x0D || 0x0D || int IOS_DestroyMessageQueue(int queueid) || Destroy a message queue || 0 on success
  āˆ’
|-
  āˆ’
| 0x0E || 0x0E || int IOS_SendMessage(int queueid, u32 message, u32 flags) || Add a message to the end queue || 0 on success
  āˆ’
|-
  āˆ’
| 0x0F || 0x0F || int IOS_JamMessage(int queueid, u32 message, u32 flags) || Add a message to the front of a queue || 0 on success
  āˆ’
|-
  āˆ’
| 0x10 || 0x10 || int IOS_ReceiveMessage(int queueid, u32 *message, u32 flags) || Fetch a message from the front of a queue || 0 on success
  āˆ’
|-
  āˆ’
| 0x11 || 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 || 0x12 || int unregister_event_handler(int device) || Unregister handler for device || 0 on success
  āˆ’
|-
  āˆ’
| 0x13 || 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 || 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 || 0x15 || int IOS_StopTimer(int timerid) || Pauses the specified timer || 0 on success
  āˆ’
|-
  āˆ’
| 0x16 || 0x16 || int IOS_DestroyTimer(int timerid) || Destroys the specified timer || 0 on success
  āˆ’
|-
  āˆ’
| 0x17 || 0x17 || u32 get_timestamp() || Get the current timestamp || The current timestamp value
  āˆ’
|-
  āˆ’
| 0x18 || 0x18 || u32 time_now() || Fetch the current value of the Starbuck's timer || The current value of the timer register
  āˆ’
|-
  āˆ’
| 0x19 || 0x19 || int IOS_GetUpTimeStruct(???) || || 0 on success
  āˆ’
|-
  āˆ’
| 0x1A || 0x1A || int IOS_GetUpTime64(u64 *out_buf) || Returns the current time in wide format || 0 on success
  āˆ’
|-
  āˆ’
| 0x1B || 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 || 0x1C || int IOS_GetAbsTimeCalendar(void *out_buf) || Returns the current date and time in a 0x18 sized struct (0x00: year; 0x04: day; 0x08: month; 0x0C: hour; 0x10: minute; 0x14: second) || 0 on success
  āˆ’
|-
  āˆ’
| 0x1D || 0x1D || int IOS_GetAbsTime64(???) || || 0 on success
  āˆ’
|-
  āˆ’
| 0x1E || 0x1E || int IOS_GetAbsTimeStruct(???) || || 0 on success
  āˆ’
|-
  āˆ’
| 0x1F || 0x1F || int set_fault_behavior(int pid, u32 flag) || Enables or disables raising a panic when a system fault occurs in the specified process. This is only usable from the IOS-MCP process. Once finished, this will always set the flag for PID0(IOS-KERNEL) to value 1. This is the same field mentioned [[IOSU|here]] for exception handling. || 0 on success, -1 when curpid is not 1, and -29 when the input pid is >13.
  āˆ’
|-
  āˆ’
| 0x20 || 0x20 || int check_debug_mode() || Checks if we are in debug mode by looking at a flag in the OTP || 0 if in debug mode
  āˆ’
|-
  āˆ’
| 0x21 || 0x21 || int check_jtag() || Get the current status of the JTAG || 0 if JTAG is enabled or -4 if disabled
  āˆ’
|-
  āˆ’
| 0x22 || 0x22 || int read_otp(u32 wordindex, void *out_buf, u32 size) || Read data from the OTP, this can only be used from the IOS-CRYPTO process. || 0 on success, -1 when IOSU's PID isn't 3.
  āˆ’
|-
  āˆ’
| 0x23 || 0x23 || int heap_create(void *ptr, int size) || Create a new heap at ptr of size bytes || The heapid or error (negative value)
  āˆ’
|-
  āˆ’
| 0x24 || 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 || 0x25 || int IOS_CreateCrossProcessHeap(int size) || Create a new cross process heap of size bytes || The heap ID or error (negative value)
  āˆ’
|-
  āˆ’
| 0x26 || 0x26 || int heap_destroy(int heapid) || Destroy the specified heap || 0 on success
  āˆ’
|-
  āˆ’
| 0x27 || 0x27 || void* IOS_Alloc(int heapid, u32 size) || Allocate size bytes from the specified heap || Pointer to memory
  āˆ’
|-
  āˆ’
| 0x28 || 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 || 0x29 || void IOS_Free(int heapid, void *ptr)  || Release allocated memory back to the heap || 0 on success
  āˆ’
|-
  āˆ’
| 0x2A || 0x2A || void heap_free_and_clear(int heapid, void *ptr) || Same as IOS_Free, but clears the contents of ptr || 0 on success
  āˆ’
|-
  āˆ’
| 0x2B || 0x2B || int heap_expand(int heapid, void *ptr, u32 size) || Expands an allocated memory block by size bytes || 0 on success
  āˆ’
|-
  āˆ’
| 0x2C || 0x2C || int IOS_RegisterResourceManager(const char* device, int queueid) || Registers device to the device tree, so it can be opened (from ARM and PPC) || 0 on success
  āˆ’
|-
  āˆ’
| 0x2D || 0x2D || int device_associate(const char* device, int internal_id) || Associates a device to the specified internal IOS 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. || 0 on success
  āˆ’
|-
  āˆ’
| 0x2E || 0x2E || int device_set_flags(const char* device, u32 flags) || Sets some flags in the device's internal structure || 0 on success
  āˆ’
|-
  āˆ’
| 0x2F || 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 || 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 || 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 || 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 || 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 || 0x34 || int IOS_Close(int fd) || Close a previously opened fd || 0 on success
  āˆ’
|-
  āˆ’
| 0x35 || 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 || 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 || 0x37 || int IOS_Seek(int fd, int offset, int origin) || Seek to offset relative to origin || The new absolute offset or error
  āˆ’
|-
  āˆ’
| 0x38 || 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 || 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 || 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 || 0x3B || int IOS_CloseAsync(int fd, int queueid, ipcmessage *message) || Async implementation of IOS_Close || 0 on success
  āˆ’
|-
  āˆ’
| 0x3C || 0x3C || int IOS_ReadAsync(int fd, void *buf, u32 len, int queueid, ipcmessage *message) || Async implementation of IOS_Read || 0 on success
  āˆ’
|-
  āˆ’
| 0x3D || 0x3D || int IOS_WriteAsync(int fd, const void *buf, u32 len, int queueid, ipcmessage *message) || Async implementation of IOS_Write || 0 on success
  āˆ’
|-
  āˆ’
| 0x3E || 0x3E || int IOS_SeekAsync(int fd, int offset, int origin, int queueid, ipcmessage *message) || Async implementation of IOS_Seek || 0 on success
  āˆ’
|-
  āˆ’
| 0x3F || 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 || 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 || 0x41 || int open_as_async(???) || ||
  āˆ’
|-
  āˆ’
| 0x42 || 0x42 || int write_as_async(???) || ||
  āˆ’
|-
  āˆ’
| 0x43 || 0x43 || int ipc_resume(???) || ||
  āˆ’
|-
  āˆ’
| 0x44 || 0x44 || int ipc_suspend(???) || ||
  āˆ’
|-
  āˆ’
| 0x45 || 0x45 || int ipc_svcmsg(???) || ||
  āˆ’
|-
  āˆ’
| 0x46 || 0x46 || int ipc_resume_async(???) || ||
  āˆ’
|-
  āˆ’
| 0x47 || 0x47 || int ipc_suspend_async(???) || ||
  āˆ’
|-
  āˆ’
| 0x48 || 0x48 || int ipc_svcmsg_async(???) || ||
  āˆ’
|-
  āˆ’
| 0x49 || 0x49 || int IOS_ResourceReply(void *ipc_handle, u32 result) || Reply back through the IPC handle || 0 on success
  āˆ’
|-
  āˆ’
| 0x4A || 0x4A || int set_proc_unk_params(int pid, u32 param1, u32 param2, u32 param3) || Sets some unknown parameters on the specified process' internal structure || 0 on success
  āˆ’
|-
  āˆ’
| 0x4B || 0x4B || int get_proc_unk_params(int pid, u32 *out_buf1, u32 *out_buf2) || Gets some unknown parameters from the specified process' internal structure || 0 on success
  āˆ’
|-
  āˆ’
| 0x4C || 0x4C || int ahbMemFlush(int ahb_dev) || Performs some additional checks and calls ahb_flush_from || 0 on success
  āˆ’
|-
  āˆ’
| 0x4D || 0x4D || int ahb_flush_from(int ahb_dev) || Performs AHB memory flushing || 0 on success
  āˆ’
|-
  āˆ’
| 0x4E || 0x4E || int ahb_flush_check(int ahb_dev) || Checks for valid device masks || 0 on success
  āˆ’
|-
  āˆ’
| 0x4F || 0x4F || int ahb_flush_to(int ahb_dev) || Performs AHB memory flushing || 0 on success
  āˆ’
|-
  āˆ’
| 0x50 || 0x50 || int IOS_ClearandEnable(int id) || Enables hardware interrupts (IRQs) for the specified device || 0 on success
  āˆ’
|-
  āˆ’
| 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 || Pointer to extended area
  āˆ’
|-
  āˆ’
| 0x57 ||  || void *IOS_PushIob(struct iobuf *iob, unsigned short num) || Move head pointer num bytes towards the buffer end || Old head pointer
  āˆ’
|-
  āˆ’
| 0x58 ||  || void *IOS_PullIob(struct iobuf *iob, unsigned short num) || Move head pointer num bytes towards the buffer start || Old head pointer
  āˆ’
|-
  āˆ’
| 0x59 ||  || int verify_iobuf(struct iobuf *iob) || Verify if the argument points to an iobuf || 0 on success
  āˆ’
|-
  āˆ’
| 0x5A ||  || struct iobuf *copy_iobuf(struct iobuf *iob) || Copy an iobuf into the pool || Itself
  āˆ’
|-
  āˆ’
| 0x5B || 0x51 || void IOS_InvalidateDCache(void *ptr, unsigned int len) || Invalidate data cache || Nothing
  āˆ’
|-
  āˆ’
| 0x5C || 0x52 || void IOS_FlushDCache(void *ptr, unsigned int len) || Flush data cache || Nothing
  āˆ’
|-
  āˆ’
| 0x5D || 0x53 || int execute_privileged(void *address) || Disables memory protection, cleans up executable memory areas and branches to the specified address. This can only be called by MCP, and will infinite loop on return || 0 on success
  āˆ’
|-
  āˆ’
| 0x5E || 0x54 || int get_unk_flags1(u32 *out_buf1, u16 *out_buf2) || Gets (u32*)out_buf1 = 0x03; (u16*)out_buf2 = 0x00 || 0 on success
  āˆ’
|-
  āˆ’
| 0x5F || 0x55 || int get_unk_flags2(u32 *out_buf1, u16 *out_buf2) || Gets (u32*)out_buf1 = 0x01; (u16*)out_buf2 = 0x00 || 0 on success
  āˆ’
|-
  āˆ’
| 0x60 || 0x56 || void* virt_to_phys(void *address) || Translate a virtual address to physical || The translated address
  āˆ’
|-
  āˆ’
| 0x61 || 0x57 || int IOS_CreateSemaphore(???) || ||
  āˆ’
|-
  āˆ’
| 0x62 || 0x58 || int IOS_WaitSemaphore(???) || ||
  āˆ’
|-
  āˆ’
| 0x63 || 0x59 || int IOS_SignalSemaphore(???) || ||
  āˆ’
|-
  āˆ’
| 0x64 || 0x5A || int IOS_DestroySemaphore(???) || ||
  āˆ’
|-
  āˆ’
| 0x65 || 0x5B || int flush_ipc_server() || Resets the ARM IPC control register's flags || 0 on success
  āˆ’
|-
  āˆ’
| 0x66 || 0x5C || int set_bsp_ready() || Tells the IOSU that BSP is ready || 0 on success
  āˆ’
|-
  āˆ’
| 0x67 || 0x5D || int check_ios_addr_range(void *address, u32 size, u32 rw_flags) || Checks an IOSU address range for read/write permissions || 0 on success
  āˆ’
|-
  āˆ’
| 0x68 || 0x5E || int check_ppc_addr_range(void *address, u32 size) || Checks if a PPC address range is registered in the IOSU's address table || 0 on success
  āˆ’
|-
  āˆ’
| 0x69 || 0x5F || int init_mem1_ppc() || Fills range 0x00000000 to 0x00002000 in MEM1 with empty PPC branches || Always 0
  āˆ’
|-
  āˆ’
| 0x6A || 0x60 || int get_iop_cpu_utilization() || || IOP CPU utilization
  āˆ’
|-
  āˆ’
| 0x6B || 0x61 || int get_thread_stack_info(int tid, u32 *out_buf) || Gets information on the specified thread's stack:<br>0x00(out_buf) == sys stack base<br> 0x04(out_buf) == sys stack size (0x400)<br>0x08(out_buf) == sys stack used space<br>0x0C(out_buf) == user stack base<br>0x10(out_buf) == user stack size<br>0x14(out_buf) == user stack used space || 0 on success
  āˆ’
|-
  āˆ’
| 0x6C || 0x62 || int IOS_ThreadProfileCommand(int command, u32 unk) || Issues a command to the thread profiling system. Valid commands are:<br>67h : Start profiling<br>64h : Stop profiling<br>65h : Stop profiling interval (disabled on retail?)<br>66h, 6Eh, 6Fh : Unknown || 0 on success, when in PROD mode unavailable (NOTREADY)
  āˆ’
|-
  āˆ’
| 0x6D || 0x63 || int IOS_GetThreadUtilization(void *out_buf) || Dumps the current thread's utilization structure || 0 on success
  āˆ’
|-
  āˆ’
| 0x6E || 0x64 || int dump_thread_context(int tid, u32 *out_buf) || Dumps the specified thread's context structure || 0 on success
  āˆ’
|-
  āˆ’
| 0x6F || 0x65 || int dump_thread_profile(int tid_count, u32 *out_buf) || Dumps profiling information for each thread up to a specified count || Number of dumped threads
  āˆ’
|-
  āˆ’
| 0x70 ||  || int dump_iobuf_context(int iobuf_id, u32 *out_buf) || Dumps the specified iobuf's context structure || 0 on success
  āˆ’
|-
  āˆ’
| 0x71 ||  || int IOS_GetIobPoolsUtilization(int iobuf_count, u32 *out_buf) || Dumps iobuf's pools utilization for each iobuf up to a specified count || Size of each used pool
  āˆ’
|-
  āˆ’
| 0x72 || 0x66 || int IOS_GetMessageUtilization(???) || || 0 on success
  āˆ’
|-
  āˆ’
| 0x73 || 0x67 || int get_aggregate_resource_utilization(???) || || 0 on success
  āˆ’
|-
  āˆ’
| 0x74 || 0x68 || int get_per_process_resource_utilization(???) || || 0 on success
  āˆ’
|-
  āˆ’
| 0x75 || 0x69 || int IOS_GetTimerUtilization(???) || || 0 on success
  āˆ’
|-
  āˆ’
| 0x76 || 0x6A || int IOS_GetSemaphoreUtilization(???) || || 0 on success
  āˆ’
|-
  āˆ’
| 0x77 || 0x6B || int get_heap_profile(???) || || 0 on success
  āˆ’
|-
  āˆ’
| 0x78 || 0x6C || int set_iop2x_state(u32 state) || Sets the state of an unknown feature from BSP || 0 on success
  āˆ’
|-
  āˆ’
| 0x79 || 0x6D || int set_ppc_boot_params(void *params) || Registers the supplied address as a pointer for setting up the PPC boot parameters || 0 on success
  āˆ’
|-
  āˆ’
| 0x7A || 0x6E || void get_debug_register_value() || Stores the value from LT_DEBUG register in the IOSU heap || Nothing
  āˆ’
|-
  āˆ’
| 0x7B || 0x6F || void clear_debug_register_value() || Clears the LT_DEBUG register || Nothing
  āˆ’
|-
  āˆ’
| 0x7C || 0x70 || void set_debug_register_value(u32 value) || Sets the value of the LT_DEBUG register || Nothing
  āˆ’
|-
  āˆ’
| 0x7D || 0x71 || int check_debug_flag(u32 flag) || Checks if the supplied flag is enabled in the LT_DEBUG register copy on the IOSU heap || The flag value if enabled or 0 if disabled
  āˆ’
|-
  āˆ’
| 0x7E || 0x72 || void ios_shutdown(bool reset) || Issues a system shutdown or reset depending on the input arg || Nothing
  āˆ’
|-
  āˆ’
| 0x7F || 0x73 || void ios_panic(char *panic_desc, u32 panic_desc_size) || Issues a system panic (with optional description string) || Nothing
  āˆ’
|-
  āˆ’
| 0x80 || 0x74 || void ios_reset() || Issues a system reset || Nothing
  āˆ’
|-
  āˆ’
| 0x81 || 0x75 || void set_panic_behavior(int flag) || Changes the system behavior on panic:<br>flag is 0 -> crash on panic<br>flag is 1 -> reset on panic<br>flag is 2 -> reset EXI as well || Nothing
  āˆ’
|-
  āˆ’
| 0x82 || 0x76 || int set_syslog_buffer(void *log_buf) || Sets up the system log buffer in the IOSU heap || 0 on success
  āˆ’
|-
  āˆ’
| 0x83 || 0x77 || int load_ppc_kernel(u32 address, u32 size) || Maps the PPC kernel image memory:<br>address == 0x08000000<br>size == 0x00120000 || 0 on success
  āˆ’
|-
  āˆ’
| 0x84 || 0x78 || int load_ppc_app(int mem_id, u32 addr1, u32 size1, u32 addr2, u32 size2) || Maps the PPC user application memory:<br>mem_id == 0x02<br>addr1 == 0x00<br>size1 == 0x00<br>addr2 == 0x28000000<br>size2 == 0xA8000000 || 0 on success
  āˆ’
|-
  āˆ’
| 0x85 || 0x79 || int set_security_level(int level) || Sets the master title security level:<br>0x1E is normal<br>0x0A is TEST<br>0x14 is unknown || 0 on success
  āˆ’
|-
  āˆ’
| 0x86 || 0x7A || int get_security_level() || Gets the master title security level || The security level
  āˆ’
|-
  āˆ’
| 0x87 || 0x7B || int get_open_resource_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 || 0x7C || int set_main_title_sdk_version(int version) || Sets the master title's SDK/kernel version || 0 on success
  āˆ’
|-
  āˆ’
| 0x89 || 0x7D || int get_main_title_sdk_version() || Gets the master title's SDK/kernel version || The SDK/kernel version
  āˆ’
|-
  āˆ’
| 0x8A || 0x7E || int get_dynamic_heap_access(???) || || 0 on success
  āˆ’
|-
  āˆ’
| 0x8B || 0x7F || int start_gpu_config_validation(void *out_buf, u32 size, int queue_id, int unk) || Validates the current GPU configuration using a message queue. Sends a pointer that is populated by the IOSU with the GPU configuration parameters (using GPIO) || 0 on success
  āˆ’
|-
  āˆ’
| 0x8C || 0x80 || int finish_gpu_config_validation(int queue_id, bool do_panic) || Resets the buffer sent to the IOSU and invalidates the associated queue ID. Also looks for any errors raised due to a bad configuration state and throws a panic if specifically told to do so || 0 on success
  āˆ’
|-
  āˆ’
| 0x8D || 0x81 || int return_null() || Unused || Always 0
  āˆ’
|-
  āˆ’
| 0x8E || 0x82 || int get_resource_violations(???) || || 0 on success
  āˆ’
|-
  āˆ’
| 0x8F || 0x83 || int device_get_client_handles(char *dev_node) || Returns the number of client handles created in the specified dev node || The number of active client handles
  āˆ’
|-
  āˆ’
| 0x90 || 0x84 || int device_disable_registration(bool do_disable) || Prevents any future dev node from being registered || An error code (0xFFFFFFE3)
  āˆ’
|-
  āˆ’
| 0x91 || 0x85 || int get_pending_resource_requests(???) || || 0 on success
  āˆ’
|-
  āˆ’
| 0x92 || 0x86 || int load_ios_kernel() || Maps the IOS Kernel image memory || 0 on success
  āˆ’
|-
  āˆ’
| 0x93 || 0x87 || void exi_reset() || Resets the EXI for the PPC side || Nothing
  āˆ’
|}
  āˆ’
 
  āˆ’
== 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 [[IOSU|here]] for exceptions. These syscalls are [http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0471c/Bgbjhiea.html RealView semihosting operations] that allow communication with a debugger.<br>
  āˆ’
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."
  āˆ’
 
  āˆ’
<source lang="c">
  āˆ’
MOVS r0, #syscall_number
  āˆ’
SVC 0xAB
  āˆ’
</source>
  āˆ’
 
  āˆ’
Register r0 takes the syscall number.<br>
  āˆ’
Register r1 takes the first parameter.
  āˆ’
 
  āˆ’
{| class="wikitable"
  āˆ’
|-
  āˆ’
! ID # !! Internal name !! Description !! Return value
  āˆ’
|-
  āˆ’
| 0x01 || __sys_open || unused  ||
  āˆ’
|-
  āˆ’
| 0x02 || __sys_close || unused  ||
  āˆ’
|-
  āˆ’
| 0x03 || __sys_writec || unused  ||
  āˆ’
|-
  āˆ’
| 0x04 || __sys_write0 || Prints a null-terminated debug message || None
  āˆ’
|-
  āˆ’
| 0x05 || __sys_write || unused  ||
  āˆ’
|-
  āˆ’
| 0x06 || __sys_read || Reads input from debugger stdin  ||
  āˆ’
|-
  āˆ’
| 0x07 || __sys_readc || unused  ||
  āˆ’
|-
  āˆ’
| 0x08 || __sys_iserror || unused  ||
  āˆ’
|-
  āˆ’
| 0x09 || __sys_istty || unused  ||
  āˆ’
|-
  āˆ’
| 0x0A || __sys_seek || unused  ||
  āˆ’
|-
  āˆ’
| 0x0C || __sys_flen || unused  ||
  āˆ’
|-
  āˆ’
| 0x0D || __sys_tmpnam || unused  ||
  āˆ’
|-
  āˆ’
| 0x0E || __sys_remove || unused  ||
  āˆ’
|-
  āˆ’
| 0x0F || __sys_rename || unused  ||
  āˆ’
|-
  āˆ’
| 0x10 || __sys_clocK || unused  ||
  āˆ’
|-
  āˆ’
| 0x11 || __sys_time || unused  ||
  āˆ’
|-
  āˆ’
| 0x12 || __sys_system || unused  ||
  āˆ’
|-
  āˆ’
| 0x13 || __sys_errno || unused  ||
  āˆ’
|-
  āˆ’
| 0x15 || __sys_get_cmdline || unused  ||
  āˆ’
|-
  āˆ’
| 0x16 || __sys_heapinfo || unused  ||
  āˆ’
|-
  āˆ’
| 0x30 || __sys_elapsed || unused  ||
  āˆ’
|-
  āˆ’
| 0x31 || __sys_tickfreq || unused  ||
  āˆ’
|}