Changes

13,485 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            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.).<br>
  −
The IOSU currently has 0x94 available syscalls (the number of installed syscalls can vary between system versions).<br><br>
  −
NOTE: Official syscall names begin with "IOS_", the rest are merely educated guesses.
  −
 
  −
{|border=1
  −
|-
  −
! 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 [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.
  −
 
  −
<source lang="c">
  −
MOVS r0, #syscall_number
  −
SVC 0xAB
  −
</source>
  −
 
  −
Register r0 takes the syscall number.<br>
  −
Register r1 takes the first parameter.
  −
 
  −
{|border=1
  −
|-
  −
! 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  ||
  −
|}