Changes

6,342 bytes removed ,  02:11, 7 December 2024
Rewrite
Line 3: Line 3:  
The IOSU is an embedded operating system written by Nintendo, with a microkernel architecture. It contains a simple kernel that implements memory management and process and thread management. Device drivers and security handlers run as processes in the ARM user mode. These processes, called resource managers (RMs), can register as request handlers for resources, which are represented as nodes under /dev in a virtual filesystem. They communicate with each other through the kernel, using standard Unix file operations (open/close/read/write/seek/ioctl/ioctlv).
 
The IOSU is an embedded operating system written by Nintendo, with a microkernel architecture. It contains a simple kernel that implements memory management and process and thread management. Device drivers and security handlers run as processes in the ARM user mode. These processes, called resource managers (RMs), can register as request handlers for resources, which are represented as nodes under /dev in a virtual filesystem. They communicate with each other through the kernel, using standard Unix file operations (open/close/read/write/seek/ioctl/ioctlv).
   −
= ELF loader =
+
= Loader =
 
The IOSU firmware image file (fw.img), when decrypted, contains two distinguishable pieces of code: a small ELF loader and the actual firmware binary (ELF file).
 
The IOSU firmware image file (fw.img), when decrypted, contains two distinguishable pieces of code: a small ELF loader and the actual firmware binary (ELF file).
 
Each time the IOSU starts, the ELF loader is the first portion of code that runs in order to make preparations for the actual IOSU binary.
 
Each time the IOSU starts, the ELF loader is the first portion of code that runs in order to make preparations for the actual IOSU binary.
Line 238: Line 238:     
== Syscalls (via undefined instructions) ==
 
== 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).
+
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:
 
The second vector is the invalid instruction handler, which is used to implement syscalls:
Line 326: Line 326:     
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>
 
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>
 +
 +
The following syscall numbers were last verified on 5.3.2 development OSv10 and 5.5.0 production OSv10. They may vary for newer/older versions or OSv9.
    
NOTE: Official syscall names begin with "IOS_", the rest are merely educated guesses.
 
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"
 
{| class="wikitable"
 
|-
 
|-
! Debug ID# !! Retail ID# !! Internal name !! Description !! Return value
+
! ID (Production) !! ID (Development) !! Return !! Name !! Arguments
 
|-
 
|-
| 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)
+
| 0x00 || 0x00 || IOSThreadId || IOS_CreateThread || u32 (*proc)(void* arg), void* arg, void* stack_top, u32 stacksize, u32 priority, u32 flags
 
|-
 
|-
| 0x01 || 0x01 || int thread_join(int threadid, u32 *returned_value) || Waits for a thread to finish executing || 0 on success
+
| 0x01 || 0x01 || IOSError || JoinThread || IOSThreadId id, u32 *return_value
 
|-
 
|-
| 0x02 || 0x02 || int thread_cancel(int threadid, u32 return_value)  || Cancels an active thread. Threadid 0 will use the current thread. || 0 on success
+
| 0x02 || 0x02 || IOSError || DestroyThread || IOSThreadId id, u32 return_value
 
|-
 
|-
| 0x03 || 0x03 || int get_tid() || Get the current thread's ID || Current threadid
+
| 0x03 || 0x03 || IOSThreadId || GetThreadId ||  
 
|-
 
|-
| 0x04 || 0x04 || void* access_ipc_buffer_pool() || Gets the per-thread IPC buffer pool's address || The IPC buffer pool address value
+
| 0x04 || 0x04 || void * || AccessIpcPool ||
 
|-
 
|-
| 0x05 || 0x05 || int get_pid() || Get the current process' ID || Current processid
+
| 0x05 || 0x05 || IOSProcessId || GetProcessId ||  
 
|-
 
|-
| 0x06 || 0x06 || int get_process_name(int pid, char *out_buffer) || Get the specified process' name string || 0 on success
+
| 0x06 || 0x06 || IOSError || GetProcessName || IOSProcessId id, char *name
 
|-
 
|-
| 0x07 || 0x07 || int IOS_StartThread(int threadid) || Resume the specified thread || 0 on success
+
| 0x07 || 0x07 || IOSError || IOS_StartThread || IOSThreadId id
 
|-
 
|-
| 0x08 || 0x08 || int thread_suspend(int threadid) || Suspend the specified thread. Threadid 0 will use the current thread. || 0 on success
+
| 0x08 || 0x08 || IOSError || StopThread || IOSThreadId id
 
|-
 
|-
| 0x09 || 0x09 || int thread_yield() || Yield execution to any higher priority threads || 0 on success
+
| 0x09 || 0x09 || void || YieldThread ||
 
|-
 
|-
| 0x0A || 0x0A || int IOS_GetThreadPriority(int threadid) || Get the priority of the specified thread || The thread's priority or error (negative value)
+
| 0x0A || 0x0A || u32 || IOS_GetThreadPriority || IOSThreadId id
 
|-
 
|-
| 0x0B || 0x0B || int IOS_SetThreadPriority(int threadid, int priority) || Set the priority of the specified thread || 0 on success
+
| 0x0B || 0x0B || IOSError || IOS_SetThreadPriority || IOSThreadId id, u32 priority
 
|-
 
|-
| 0x0C || 0x0C || int IOS_CreateMessageQueue(u32 *ptr, u32 n_msgs) || Create a queue at ptr, for n_msgs messages || The queue ID
+
| 0x0C || 0x0C || IOSMessageQueueId || IOS_CreateMessageQueue || IOSMessage *ptr, u32 count
 
|-
 
|-
| 0x0D || 0x0D || int IOS_DestroyMessageQueue(int queueid) || Destroy a message queue || 0 on success
+
| 0x0D || 0x0D || IOSError || IOS_DestroyMessageQueue || IOSMessageQueueId id
 
|-
 
|-
| 0x0E || 0x0E || int IOS_SendMessage(int queueid, u32 message, u32 flags) || Add a message to the end queue || 0 on success
+
| 0x0E || 0x0E || IOSError || IOS_SendMessage || IOSMessageQueueId id, IOSMessage message, u32 flags
 
|-
 
|-
| 0x0F || 0x0F || int IOS_JamMessage(int queueid, u32 message, u32 flags) || Add a message to the front of a queue || 0 on success
+
| 0x0F || 0x0F || IOSError || IOS_JamMessage || IOSMessageQueueId id, IOSMessage message, u32 flags
 
|-
 
|-
| 0x10 || 0x10 || int IOS_ReceiveMessage(int queueid, u32 *message, u32 flags) || Fetch a message from the front of a queue || 0 on success
+
| 0x10 || 0x10 || IOSError || IOS_ReceiveMessage || IOSMessageQueueId id, IOSMessage *message, u32 flags
 
|-
 
|-
| 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
+
| 0x11 || 0x11 || IOSError || IOS_HandleEvent || IOSEvent event, IOSMessageQueueId id, IOSMessage message
 
|-
 
|-
| 0x12 || 0x12 || int unregister_event_handler(int device) || Unregister handler for device || 0 on success
+
| 0x12 || 0x12 || IOSError || UnhandleEvent || IOSEvent event
 
|-
 
|-
| 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)
+
| 0x13 || 0x13 || IOSTimerId || IOS_CreateTimer || IOSTime time_us, IOSTime repeat_time_us, IOSMessageQueueId id, IOSMessage message
 
|-
 
|-
| 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
+
| 0x14 || 0x14 || IOSError || IOS_RestartTimer || IOSTimerId id, IOSTime time_us, IOSTime repeat_time_us
 
|-
 
|-
| 0x15 || 0x15 || int IOS_StopTimer(int timerid) || Pauses the specified timer || 0 on success
+
| 0x15 || 0x15 || IOSError || IOS_StopTimer || IOSTimerId id
 
|-
 
|-
| 0x16 || 0x16 || int IOS_DestroyTimer(int timerid) || Destroys the specified timer || 0 on success
+
| 0x16 || 0x16 || IOSError || IOS_DestroyTimer || IOSTimerId id
 
|-
 
|-
| 0x17 || 0x17 || u32 get_timestamp() || Get the current timestamp || The current timestamp value
+
| 0x17 || 0x17 || u32 || GetTimeStamp ||  
 
|-
 
|-
| 0x18 || 0x18 || u32 time_now() || Fetch the current value of the Starbuck's timer || The current value of the timer register
+
| 0x18 || 0x18 || IOSTime || GetTimer ||
 
|-
 
|-
| 0x19 || 0x19 || int IOS_GetUpTimeStruct(???) || || 0 on success
+
| 0x19 || 0x19 || IOSError || IOS_GetUpTimeStruct ||
 
|-
 
|-
| 0x1A || 0x1A || int IOS_GetUpTime64(u64 *out_buf) || Returns the current time in wide format || 0 on success
+
| 0x1A || 0x1A || IOSError || IOS_GetUpTime64 || u64 *out_buf
 
|-
 
|-
| 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
+
| 0x1B || 0x1B || IOSError || SetUpTime64 || u64 *in_buf
 
|-
 
|-
| 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
+
| 0x1C || 0x1C || IOSError || IOS_GetAbsTimeCalendar || void *out_buf
 
|-
 
|-
| 0x1D || 0x1D || int IOS_GetAbsTime64(???) || || 0 on success
+
| 0x1D || 0x1D || IOSError || IOS_GetAbsTime64 ||  
 
|-
 
|-
| 0x1E || 0x1E || int IOS_GetAbsTimeStruct(???) || || 0 on success
+
| 0x1E || 0x1E || IOSError || IOS_GetAbsTimeStruct ||  
 
|-
 
|-
| 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.
+
| 0x1F || 0x1F || IOSError || [[#SetProcessPanic|SetProcessPanic]] || IOSProcessId id, u32 flag
 
|-
 
|-
| 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
+
| 0x20 || 0x20 || IOSError || IsDevelopment ||
 
|-
 
|-
| 0x21 || 0x21 || int check_jtag() || Get the current status of the JTAG || 0 if JTAG is enabled or -4 if disabled
+
| 0x21 || 0x21 || IOSError || IsJtag ||
 
|-
 
|-
| 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.
+
| 0x22 || 0x22 || IOSError || [[#ReadEfuse|ReadEfuse]] || u32 word, void *out_buf, u32 size
 
|-
 
|-
| 0x23 || 0x23 || int heap_create(void *ptr, int size) || Create a new heap at ptr of size bytes || The heapid or error (negative value)
+
| 0x23 || 0x23 || IOSHeapId || CreateHeap || void *ptr, u32 size
 
|-
 
|-
| 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)
+
| 0x24 || 0x24 || IOSHeapId || IOS_CreateLocalProcessHeap || void *ptr, u32 size
 
|-
 
|-
| 0x25 || 0x25 || int IOS_CreateCrossProcessHeap(int size) || Create a new cross process heap of size bytes || The heap ID or error (negative value)
+
| 0x25 || 0x25 || IOSHeapId || IOS_CreateCrossProcessHeap || int size
 
|-
 
|-
| 0x26 || 0x26 || int heap_destroy(int heapid) || Destroy the specified heap || 0 on success
+
| 0x26 || 0x26 || IOSError || DestroyHeap || IOSHeapId id
 
|-
 
|-
| 0x27 || 0x27 || void* IOS_Alloc(int heapid, u32 size) || Allocate size bytes from the specified heap || Pointer to memory
+
| 0x27 || 0x27 || void* || IOS_Alloc || IOSHeapId id, u32 size
 
|-
 
|-
| 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
+
| 0x28 || 0x28 || void* || AllocAligned || IOSHeapId id, u32 size, u32 align
 
|-
 
|-
| 0x29 || 0x29 || void IOS_Free(int heapid, void *ptr)  || Release allocated memory back to the heap || 0 on success
+
| 0x29 || 0x29 || IOSError || IOS_Free || IOSHeapId id, void *ptr
 
|-
 
|-
| 0x2A || 0x2A || void heap_free_and_clear(int heapid, void *ptr) || Same as IOS_Free, but clears the contents of ptr || 0 on success
+
| 0x2A || 0x2A || IOSError || FreeAndClear || IOSHeapId id, void *ptr
 
|-
 
|-
| 0x2B || 0x2B || int heap_expand(int heapid, void *ptr, u32 size) || Expands an allocated memory block by size bytes || 0 on success
+
| 0x2B || 0x2B || IOSError || Expand || IOSHeapId id, void *ptr, u32 size
 
|-
 
|-
| 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
+
| 0x2C || 0x2C || IOSError || IOS_RegisterResourceManager || const char* path, IOSMessageQueueId id
 
|-
 
|-
| 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
+
| 0x2D || 0x2D || IOSError || [[#SetResourceManagerPermissionGroup|SetResourceManagerPermissionGroup]] || const char* path, u32 id
 
|-
 
|-
| 0x2E || 0x2E || int device_set_flags(const char* device, u32 flags) || Sets some flags in the device's internal structure || 0 on success
+
| 0x2E || 0x2E || IOSError || SetResourceManagerFlags || const char* path, u32 flags
 
|-
 
|-
| 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
+
| 0x2F || 0x2F || IOSError || SetClientCapabilities || IOSProcessId id, u32 feature_id, u32 *masks
 
|-
 
|-
| 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
+
| 0x30 || 0x30 || IOSError || ClearClientCapabilities || IOSProcessId id
 
|-
 
|-
| 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
+
| 0x31 || 0x31 || IOSError || QueryClientCapabilities || IOSProcessId id, u32 feature_id, void *out_buffer
 
|-
 
|-
| 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
+
| 0x32 || 0x32 || IOSError || QueryFeatureId || u32 feature_id, int out_count, void *out_buffer
 
|-
 
|-
| 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)
+
| 0x33 || 0x33 || IOSFd || IOS_Open || const char* path, u32 flags
 
|-
 
|-
| 0x34 || 0x34 || int IOS_Close(int fd) || Close a previously opened fd || 0 on success
+
| 0x34 || 0x34 || IOSError || IOS_Close || IOSFd fd
 
|-
 
|-
| 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
+
| 0x35 || 0x35 || s32 || IOS_Read || IOSFd fd, void *buf, u32 len
 
|-
 
|-
| 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
+
| 0x36 || 0x36 || s32 || IOS_Write || IOSFd fd, void *buf, u32 len
 
|-
 
|-
| 0x37 || 0x37 || int IOS_Seek(int fd, int offset, int origin) || Seek to offset relative to origin || The new absolute offset or error
+
| 0x37 || 0x37 || s32 || IOS_Seek || IOSFd fd, s32 offset, u32 origin
 
|-
 
|-
| 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
+
| 0x38 || 0x38 || IOSError || IOS_Ioctl || IOSFd fd, s32 cmd, void *input_buffer, u32 input_buffer_len, void *output_buffer, u32 output_buffer_len
 
|-
 
|-
| 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
+
| 0x39 || 0x39 || IOSError || IOS_Ioctlv || IOSFd fd, s32 cmd, u32 vector_count_in, u32 vector_count_out, IOSIoVector *vector
 
|-
 
|-
| 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
+
| 0x3A || 0x3A || IOSFd || IOS_OpenAsync || const char* path, u32 flags, IOSMessageQueueId id, IOSResourceRequest *reply
 
|-
 
|-
| 0x3B || 0x3B || int IOS_CloseAsync(int fd, int queueid, ipcmessage *message) || Async implementation of IOS_Close || 0 on success
+
| 0x3B || 0x3B || IOSError || IOS_CloseAsync || IOSFd fd, IOSMessageQueueId id, IOSResourceRequest *reply
 
|-
 
|-
| 0x3C || 0x3C || int IOS_ReadAsync(int fd, void *buf, u32 len, int queueid, ipcmessage *message) || Async implementation of IOS_Read || 0 on success
+
| 0x3C || 0x3C || s32 || IOS_ReadAsync || IOSFd fd, void *buf, u32 len, IOSMessageQueueId id, IOSResourceRequest *reply
 
|-
 
|-
| 0x3D || 0x3D || int IOS_WriteAsync(int fd, const void *buf, u32 len, int queueid, ipcmessage *message) || Async implementation of IOS_Write || 0 on success
+
| 0x3D || 0x3D || s32 || IOS_WriteAsync || IOSFd fd, void *buf, u32 len, IOSMessageQueueId id, IOSResourceRequest *reply
 
|-
 
|-
| 0x3E || 0x3E || int IOS_SeekAsync(int fd, int offset, int origin, int queueid, ipcmessage *message) || Async implementation of IOS_Seek || 0 on success
+
| 0x3E || 0x3E || s32 || IOS_SeekAsync || IOSFd fd, s32 offset, u32 origin, IOSMessageQueueId id, IOSResourceRequest *reply
 
|-
 
|-
| 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
+
| 0x3F || 0x3F || IOSError || IOS_IoctlAsync || IOSFd fd, s32 cmd, void *input_buffer, u32 input_buffer_len, void *output_buffer, u32 output_buffer_len, IOSMessageQueueId id, IOSResourceRequest *reply
 
|-
 
|-
| 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
+
| 0x40 || 0x40 || IOSError || IOS_IoctlvAsync || IOSFd fd, s32 cmd, u32 vector_count_in, u32 vector_count_out, IOSIoVector *vector, IOSMessageQueueId id, IOSResourceRequest *reply
 
|-
 
|-
| 0x41 || 0x41 || int open_as_async(???) || ||
+
| 0x41 || 0x41 || IOSError || OpenAsAsync ||
 
|-
 
|-
| 0x42 || 0x42 || int write_as_async(???) || ||
+
| 0x42 || 0x42 || IOSError || WriteAsAsync ||
 
|-
 
|-
| 0x43 || 0x43 || int ipc_resume(???) || ||
+
| 0x43 || 0x43 || IOSError || IpcResume ||
 
|-
 
|-
| 0x44 || 0x44 || int ipc_suspend(???) || ||
+
| 0x44 || 0x44 || IOSError || IpcSuspend ||
 
|-
 
|-
| 0x45 || 0x45 || int ipc_svcmsg(???) || ||
+
| 0x45 || 0x45 || IOSError || IpcSvcMsg ||
 
|-
 
|-
| 0x46 || 0x46 || int ipc_resume_async(???) || ||
+
| 0x46 || 0x46 || IOSError || IpcResumeAsync ||
 
|-
 
|-
| 0x47 || 0x47 || int ipc_suspend_async(???) || ||
+
| 0x47 || 0x47 || IOSError || IpcSuspendAsync ||
 
|-
 
|-
| 0x48 || 0x48 || int ipc_svcmsg_async(???) || ||
+
| 0x48 || 0x48 || IOSError || IpcSvcMsgAsync ||
 
|-
 
|-
| 0x49 || 0x49 || int IOS_ResourceReply(void *ipc_handle, u32 result) || Reply back through the IPC handle || 0 on success
+
| 0x49 || 0x49 || IOSError || IOS_ResourceReply || IOSResourceRequest *reply, IOSError result
 
|-
 
|-
| 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
+
| 0x4A || 0x4A || IOSError || SetUidGid || IOSProcessId id, u32 uid, u32 gid, u32 unk
 
|-
 
|-
| 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
+
| 0x4B || 0x4B || IOSError || GetUidGid || IOSProcessId id, u32 *uid, u32 *gid
 
|-
 
|-
| 0x4C || 0x4C || int ahbMemFlush(int ahb_dev) || Performs some additional checks and calls ahb_flush_from || 0 on success
+
| 0x4C || 0x4C || IOSError || FlushMem || int group
 
|-
 
|-
| 0x4D || 0x4D || int ahb_flush_from(int ahb_dev) || Performs AHB memory flushing || 0 on success
+
| 0x4D || 0x4D || IOSError || InvalidateRdb || int rdb
 
|-
 
|-
| 0x4E || 0x4E || int ahb_flush_check(int ahb_dev) || Checks for valid device masks || 0 on success
+
| 0x4E || 0x4E || IOSError || AhbFlushCheck || u32 ahb_dev
 
|-
 
|-
| 0x4F || 0x4F || int ahb_flush_to(int ahb_dev) || Performs AHB memory flushing || 0 on success
+
| 0x4F || 0x4F || IOSError || AhbFlushTo || u32 ahb_dev
 
|-
 
|-
| 0x50 || 0x50 || int IOS_ClearandEnable(int id) || Enables hardware interrupts (IRQs) for the specified device || 0 on success
+
| 0x50 || 0x50 || IOSError || IOS_ClearandEnable || u32 id
 
|-
 
|-
| 0x51 ||  || int access_iobuf_pool(int unk) || Unused || Always 0
+
| 0x51 ||  || IOSError || AccessIobPool || u32 pool
 
|-
 
|-
| 0x52 ||  || struct iobuf *alloc_iobuf(int unk, u32 buf_size) || Allocate an iobuf || NULL on error
+
| 0x52 ||  || IOSIobuf * || AllocIob || u32 pool, u32 size
 
|-
 
|-
| 0x53 ||  || int free_iobuf(struct iobuf *iob) || Free an allocated iobuf || 0 on success
+
| 0x53 ||  || IOSError || FreeIob || IOSIobuf *iob
 
|-
 
|-
| 0x54 ||  || void iobuf_log_header_info() || Unused || Nothing
+
| 0x54 ||  || void || DebugDumpIobFreeHdrsList ||  
 
|-
 
|-
| 0x55 ||  || void iobuf_log_buffer_info() || Unused || Nothing
+
| 0x55 ||  || void || DebugDumpIobFreeBufsList ||  
 
|-
 
|-
| 0x56 ||  || void *extend_iobuf(struct iobuf *iob, unsigned short num) || Extend the data in the buffer by num bytes || Pointer to extended area
+
| 0x56 ||  || u8 * || PutIob || IOSIobuf *iob, u16 len
 
|-
 
|-
| 0x57 ||  || void *IOS_PushIob(struct iobuf *iob, unsigned short num) || Move head pointer num bytes towards the buffer end || Old head pointer
+
| 0x57 ||  || u8 * || IOS_PushIob || IOSIobuf *iob, u16 len
 
|-
 
|-
| 0x58 ||  || void *IOS_PullIob(struct iobuf *iob, unsigned short num) || Move head pointer num bytes towards the buffer start || Old head pointer
+
| 0x58 ||  || u8 * || IOS_PullIob || IOSIobuf *iob, u16 len
 
|-
 
|-
| 0x59 ||  || int verify_iobuf(struct iobuf *iob) || Verify if the argument points to an iobuf || 0 on success
+
| 0x59 ||  || IOSError || IsValidIob || IOSIobuf *iob
 
|-
 
|-
| 0x5A ||  || struct iobuf *copy_iobuf(struct iobuf *iob) || Copy an iobuf into the pool || Itself
+
| 0x5A ||  || IOSIobuf * || CloneIob || IOSIobuf *iob
 
|-
 
|-
| 0x5B || 0x51 || void IOS_InvalidateDCache(void *ptr, unsigned int len) || Invalidate data cache || Nothing
+
| 0x5B || 0x51 || void || IOS_InvalidateDCache || void *ptr, u32 len
 
|-
 
|-
| 0x5C || 0x52 || void IOS_FlushDCache(void *ptr, unsigned int len) || Flush data cache || Nothing
+
| 0x5C || 0x52 || void || IOS_FlushDCache || void *ptr, u32 len
 
|-
 
|-
| 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
+
| 0x5D || 0x53 || IOSError || [[#Launch|Launch]] || void *address
 
|-
 
|-
| 0x5E || 0x54 || int get_unk_flags1(u32 *out_buf1, u16 *out_buf2) || Gets (u32*)out_buf1 = 0x03; (u16*)out_buf2 = 0x00 || 0 on success
+
| 0x5E || 0x54 || void || GetOSVersion || u32 *major, u16 *minor
 
|-
 
|-
| 0x5F || 0x55 || int get_unk_flags2(u32 *out_buf1, u16 *out_buf2) || Gets (u32*)out_buf1 = 0x01; (u16*)out_buf2 = 0x00 || 0 on success
+
| 0x5F || 0x55 || void || GetBootVersion || u32 *major, u16 *minor
 
|-
 
|-
| 0x60 || 0x56 || void* virt_to_phys(void *address) || Translate a virtual address to physical || The translated address
+
| 0x60 || 0x56 || void * || VirtualToPhysical || void *address
 
|-
 
|-
| 0x61 || 0x57 || int IOS_CreateSemaphore(???) || ||
+
| 0x61 || 0x57 || IOSSemaphore || IOS_CreateSemaphore ||  
 
|-
 
|-
| 0x62 || 0x58 || int IOS_WaitSemaphore(???) || ||
+
| 0x62 || 0x58 || IOSError || IOS_WaitSemaphore ||
 
|-
 
|-
| 0x63 || 0x59 || int IOS_SignalSemaphore(???) || ||
+
| 0x63 || 0x59 || IOSError || IOS_SignalSemaphore ||
 
|-
 
|-
| 0x64 || 0x5A || int IOS_DestroySemaphore(???) || ||
+
| 0x64 || 0x5A || IOSError || IOS_DestroySemaphore ||
 
|-
 
|-
| 0x65 || 0x5B || int flush_ipc_server() || Resets the ARM IPC control register's flags || 0 on success
+
| 0x65 || 0x5B || IOSError || FlushIpc ||  
 
|-
 
|-
| 0x66 || 0x5C || int set_bsp_ready() || Tells the IOSU that BSP is ready || 0 on success
+
| 0x66 || 0x5C || IOSError || InitializeBsp ||
 
|-
 
|-
| 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
+
| 0x67 || 0x5D || IOSError || [[#ValidateIopAddressSpaceRange|ValidateIopAddressSpaceRange]] || void *address, u32 size, u32 rw_flags
 
|-
 
|-
| 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
+
| 0x68 || 0x5E || IOSError || [[#ValidatePpcAddressSpaceRange|ValidatePpcAddressSpaceRange]] || void *address, u32 size
 
|-
 
|-
| 0x69 || 0x5F || int init_mem1_ppc() || Fills range 0x00000000 to 0x00002000 in MEM1 with empty PPC branches || Always 0
+
| 0x69 || 0x5F || void || [[#InitializePpc|InitializePpc]] ||  
 
|-
 
|-
| 0x6A || 0x60 || int get_iop_cpu_utilization() || || IOP CPU utilization
+
| 0x6A || 0x60 || u32 || GetIopCpuUtilization ||
 
|-
 
|-
| 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
+
| 0x6B || 0x61 || IOSError || [[#GetThreadStackInfo|GetThreadStackInfo]] || IOSThreadId id, IOSThreadStackInfo *out_buf
 
|-
 
|-
| 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)
+
| 0x6C || 0x62 || IOSError || [[#IOS_ThreadProfileCommand|IOS_ThreadProfileCommand]] || u32 cmd, u32 unk
 
|-
 
|-
| 0x6D || 0x63 || int IOS_GetThreadUtilization(void *out_buf) || Dumps the current thread's utilization structure || 0 on success
+
| 0x6D || 0x63 || IOSError || IOS_GetThreadUtilization || IOSThreadUtilization *out_buf
 
|-
 
|-
| 0x6E || 0x64 || int dump_thread_context(int tid, u32 *out_buf) || Dumps the specified thread's context structure || 0 on success
+
| 0x6E || 0x64 || IOSError || GetThreadContext || IOSThreadId id, IOSThreadContext *out_buf
 
|-
 
|-
| 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
+
| 0x6F || 0x65 || u32 || GetThreadProfile || u32 count, IOSThreadProfile *out_buf
 
|-
 
|-
| 0x70 ||  || int dump_iobuf_context(int iobuf_id, u32 *out_buf) || Dumps the specified iobuf's context structure || 0 on success
+
| 0x70 ||  || IOSError || GetIobContext || u32 id, IOSIobContext *out_buf
 
|-
 
|-
| 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
+
| 0x71 ||  || u32 || IOS_GetIobPoolsUtilization || u32 count, u32 *out_buf
 
|-
 
|-
| 0x72 || 0x66 || int IOS_GetMessageUtilization(???) || || 0 on success
+
| 0x72 || 0x66 || IOSError || IOS_GetMessageUtilization ||
 
|-
 
|-
| 0x73 || 0x67 || int get_aggregate_resource_utilization(???) || || 0 on success
+
| 0x73 || 0x67 || IOSError || GetAggregateResourceUtilization ||
 
|-
 
|-
| 0x74 || 0x68 || int get_per_process_resource_utilization(???) || || 0 on success
+
| 0x74 || 0x68 || IOSError || GetPerProcessResourceUtilization ||  
 
|-
 
|-
| 0x75 || 0x69 || int IOS_GetTimerUtilization(???) || || 0 on success
+
| 0x75 || 0x69 || IOSError || IOS_GetTimerUtilization ||
 
|-
 
|-
| 0x76 || 0x6A || int IOS_GetSemaphoreUtilization(???) || || 0 on success
+
| 0x76 || 0x6A || IOSError || IOS_GetSemaphoreUtilization ||
 
|-
 
|-
| 0x77 || 0x6B || int get_heap_profile(???) || || 0 on success
+
| 0x77 || 0x6B || IOSError || GetHeapProfile ||
 
|-
 
|-
| 0x78 || 0x6C || int set_iop2x_state(u32 state) || Sets the state of an unknown feature from BSP || 0 on success
+
| 0x78 || 0x6C || IOSError || SetIopClockMultiplier || u32 mult
 
|-
 
|-
| 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
+
| 0x79 || 0x6D || IOSError || SetPpcBootParams || void *params
 
|-
 
|-
| 0x7A || 0x6E || void get_debug_register_value() || Stores the value from LT_DEBUG register in the IOSU heap || Nothing
+
| 0x7A || 0x6E || void || [[#LoadSystemConfiguration|LoadSystemConfiguration]] ||
 
|-
 
|-
| 0x7B || 0x6F || void clear_debug_register_value() || Clears the LT_DEBUG register || Nothing
+
| 0x7B || 0x6F || void || [[#ClearSystemConfiguration|ClearSystemConfiguration]] ||
 
|-
 
|-
| 0x7C || 0x70 || void set_debug_register_value(u32 value) || Sets the value of the LT_DEBUG register || Nothing
+
| 0x7C || 0x70 || void || [[#SetSystemConfiguration|SetSystemConfiguration]] || u32 syscfg
 
|-
 
|-
| 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
+
| 0x7D || 0x71 || u32 || [[#IsSystemConfigurationEnabled|IsSystemConfigurationEnabled]] || u32 flag
 
|-
 
|-
| 0x7E || 0x72 || void ios_shutdown(bool reset) || Issues a system shutdown or reset depending on the input arg || Nothing
+
| 0x7E || 0x72 || void || Shutdown || bool reset
 
|-
 
|-
| 0x7F || 0x73 || void ios_panic(char *panic_desc, u32 panic_desc_size) || Issues a system panic (with optional description string) || Nothing
+
| 0x7F || 0x73 || void || Panic || char *panic_desc, u32 panic_desc_size
 
|-
 
|-
| 0x80 || 0x74 || void ios_reset() || Issues a system reset || Nothing
+
| 0x80 || 0x74 || void || Reset ||
 
|-
 
|-
| 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
+
| 0x81 || 0x75 || void || [[#SetPanicBehavior|SetPanicBehavior]] || u32 flag
 
|-
 
|-
| 0x82 || 0x76 || int set_syslog_buffer(void *log_buf) || Sets up the system log buffer in the IOSU heap || 0 on success
+
| 0x82 || 0x76 || IOSError || SetSyslogBuffer || void *log_buf
 
|-
 
|-
| 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
+
| 0x83 || 0x77 || IOSError || [[#LoadPpcKernel|LoadPpcKernel]] || u32 address, u32 size
 
|-
 
|-
| 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
+
| 0x84 || 0x78 || IOSError || [[#LoadPpcApplication|LoadPpcApplication]] || u32 mem_id, u32 addr1, u32 size1, u32 addr2, u32 size2
 
|-
 
|-
| 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
+
| 0x85 || 0x79 || IOSError || SetSecurityLevel || IOSSecurityLevel level
 
|-
 
|-
| 0x86 || 0x7A || int get_security_level() || Gets the master title security level || The security level
+
| 0x86 || 0x7A || IOSSecurityLevel || GetSecurityLevel ||
 
|-
 
|-
| 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
+
| 0x87 || 0x7B || IOSError || GetOpenResourceHandles || u32 out_count, void *out_buffer, IOSProcessId id
 
|-
 
|-
| 0x88 || 0x7C || int set_main_title_sdk_version(int version) || Sets the master title's SDK/kernel version || 0 on success
+
| 0x88 || 0x7C || IOSError || SetMainTitleSdkVersion || u32 version
 
|-
 
|-
| 0x89 || 0x7D || int get_main_title_sdk_version() || Gets the master title's SDK/kernel version || The SDK/kernel version
+
| 0x89 || 0x7D || u32 || GetMainTitleSdkVersion ||
 
|-
 
|-
| 0x8A || 0x7E || int get_dynamic_heap_access(???) || || 0 on success
+
| 0x8A || 0x7E || IOSError || GetDynamicHeapAccess ||  
 
|-
 
|-
| 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
+
| 0x8B || 0x7F || IOSError || InitializeGpuConfiguration || void *out_buf, u32 size, IOSMessageQueueId id, u32 unk)
 
|-
 
|-
| 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
+
| 0x8C || 0x80 || IOSError || FinishGpuConfiguration || IOSMessageQueueId id, bool panic
 
|-
 
|-
| 0x8D || 0x81 || int return_null() || Unused || Always 0
+
| 0x8D || 0x81 || IOSError || ||  
 
|-
 
|-
| 0x8E || 0x82 || int get_resource_violations(???) || || 0 on success
+
| 0x8E || 0x82 || IOSError || GetResourceViolations ||
 
|-
 
|-
| 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
+
| 0x8F || 0x83 || u32 || GetClientHandles || char *dev_node
 
|-
 
|-
| 0x90 || 0x84 || int device_disable_registration(bool do_disable) || Prevents any future dev node from being registered || An error code (0xFFFFFFE3)
+
| 0x90 || 0x84 || IOSError || DisableDeviceRegistration || bool disable
 
|-
 
|-
| 0x91 || 0x85 || int get_pending_resource_requests(???) || || 0 on success
+
| 0x91 || 0x85 || IOSError || GetPendingResourceRequests ||
 
|-
 
|-
| 0x92 || 0x86 || int load_ios_kernel() || Maps the IOS Kernel image memory || 0 on success
+
| 0x92 || 0x86 || IOSError || [[#InitializeIOS|InitializeIOS]] ||  
 
|-
 
|-
| 0x93 || 0x87 || void exi_reset() || Resets the EXI for the PPC side || Nothing
+
| 0x93 || 0x87 || void || [[#ResetEXI|ResetEXI]] ||
 
|}
 
|}
 +
 +
=== SetProcessPanic ===
 +
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.
 +
 +
=== ReadEfuse ===
 +
Read data from the [[#Hardware/eFuse|eFuses]]. This can only be used from the IOS-CRYPTO process.
 +
 +
=== SetResourceManagerPermissionGroup ===
 +
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.
 +
 +
=== Launch ===
 +
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.
 +
 +
=== ValidateIopAddressSpaceRange ===
 +
Checks an IOSU address range for read/write permissions.
 +
 +
=== ValidatePpcAddressSpaceRange ===
 +
Checks if a PPC address range is registered in the IOSU's address table.
 +
 +
=== InitializePpc ===
 +
Fills range 0x00000000 to 0x00002000 in MEM1 with empty PPC branches
 +
 +
=== GetThreadStackInfo ===
 +
Gets information on the specified thread's stack:
 +
0x00(out_buf) == sys stack base
 +
0x04(out_buf) == sys stack size (0x400)
 +
0x08(out_buf) == sys stack used space
 +
0x0C(out_buf) == user stack base
 +
0x10(out_buf) == user stack size
 +
0x14(out_buf) == user stack used space
 +
 +
=== IOS_ThreadProfileCommand ===
 +
Issues a command to the thread profiling system. Valid commands are:
 +
67h : Start profiling
 +
64h : Stop profiling
 +
65h : Stop profiling interval (disabled on retail?)
 +
66h, 6Eh, 6Fh : Unknown
 +
 +
=== LoadSystemConfiguration ===
 +
Stores the value from LT_SYSCFG1 register in the IOSU heap.
 +
 +
=== ClearSystemConfiguration ===
 +
Clears the LT_SYSCFG1 register.
 +
 +
=== SetSystemConfiguration ===
 +
Sets the value of the LT_SYSCFG1 register.
 +
 +
=== IsSystemConfigurationEnabled ===
 +
Checks if the supplied flag is enabled in the LT_SYSCFG1 register copy on the IOSU heap.
 +
 +
=== SetPanicBehavior ===
 +
Changes the system behavior on panic:
 +
flag is 0 -> crash on panic
 +
flag is 1 -> reset on panic
 +
flag is 2 -> reset EXI as well
 +
 +
=== LoadPpcKernel ===
 +
Maps the PPC kernel image memory:
 +
address == 0x08000000
 +
size == 0x00120000
 +
 +
=== LoadPpcApplication ===
 +
Maps the PPC user application memory:
 +
mem_id == 0x02
 +
addr1 == 0x00
 +
size1 == 0x00
 +
addr2 == 0x28000000
 +
size2 == 0xA8000000
 +
 +
=== InitializeIOS ===
 +
Maps the IOS kernel image memory.
 +
 +
=== ResetEXI ===
 +
Resets the EXI for the PPC side.
    
== Syscalls (via syscall instruction) ==
 
== Syscalls (via syscall instruction) ==
Line 645: Line 719:  
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! ID # !! Internal name !! Description !! Return value
+
! ID !! Return !! Name !! Arguments
 
|-
 
|-
| 0x01 || __sys_open || unused  ||
+
| 0x01 || || __sys_open ||
 
|-
 
|-
| 0x02 || __sys_close || unused  ||
+
| 0x02 || || __sys_close ||
 
|-
 
|-
| 0x03 || __sys_writec || unused  ||
+
| 0x03 || || __sys_writec ||
 
|-
 
|-
| 0x04 || __sys_write0 || Prints a null-terminated debug message || None
+
| 0x04 || || [[#__sys_write0|__sys_write0]] ||
 
|-
 
|-
| 0x05 || __sys_write || unused  ||
+
| 0x05 || || __sys_write ||
 
|-
 
|-
| 0x06 || __sys_read || Reads input from debugger stdin  ||
+
| 0x06 || || [[#__sys_read|__sys_read]] ||
 
|-
 
|-
| 0x07 || __sys_readc || unused  ||
+
| 0x07 || || __sys_readc ||
 
|-
 
|-
| 0x08 || __sys_iserror || unused  ||
+
| 0x08 || || __sys_iserror ||
 
|-
 
|-
| 0x09 || __sys_istty || unused  ||
+
| 0x09 || || __sys_istty ||
 
|-
 
|-
| 0x0A || __sys_seek || unused  ||
+
| 0x0A || || __sys_seek ||
 
|-
 
|-
| 0x0C || __sys_flen || unused  ||
+
| 0x0C || || __sys_flen ||
 
|-
 
|-
| 0x0D || __sys_tmpnam || unused  ||
+
| 0x0D || || __sys_tmpnam ||
 
|-
 
|-
| 0x0E || __sys_remove || unused  ||
+
| 0x0E || || __sys_remove ||
 
|-
 
|-
| 0x0F || __sys_rename || unused  ||
+
| 0x0F || || __sys_rename ||
 
|-
 
|-
| 0x10 || __sys_clocK || unused  ||
+
| 0x10 || || __sys_clocK ||
 
|-
 
|-
| 0x11 || __sys_time || unused  ||
+
| 0x11 || || __sys_time ||
 
|-
 
|-
| 0x12 || __sys_system || unused  ||
+
| 0x12 || || __sys_system ||
 
|-
 
|-
| 0x13 || __sys_errno || unused  ||
+
| 0x13 || || __sys_errno ||
 
|-
 
|-
| 0x15 || __sys_get_cmdline || unused  ||
+
| 0x15 || || __sys_get_cmdline ||
 
|-
 
|-
| 0x16 || __sys_heapinfo || unused  ||
+
| 0x16 || || __sys_heapinfo ||
 
|-
 
|-
| 0x30 || __sys_elapsed || unused  ||
+
| 0x30 || || __sys_elapsed ||
 
|-
 
|-
| 0x31 || __sys_tickfreq || unused  ||
+
| 0x31 || || __sys_tickfreq ||
 
|}
 
|}
   −
== Auxiliary vectors ==
+
=== __sys_write0 ===
 +
Prints a null-terminated debug message.
 +
 
 +
=== __sys_read ===
 +
Reads input from debugger stdin.
 +
 
 +
== Auxiliary Vectors ==
 
The IOSU elf has a PH_NOTES section which contains a so called "mrg file".
 
The IOSU elf has a PH_NOTES section which contains a so called "mrg file".
 
This "mrg file" contains auxiliary vectors for IOSU modules.
 
This "mrg file" contains auxiliary vectors for IOSU modules.
Line 704: Line 784:  
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 +
! Value
 
! Name
 
! Name
! Value
   
! Description
 
! Description
 
|-
 
|-
 +
| 0x09
 
| AT_ENTRY
 
| AT_ENTRY
| 0x09
   
| Entry point address
 
| Entry point address
 
|-
 
|-
 +
| 0x0B
 
| AT_UID
 
| AT_UID
| 0x0b
   
| Module ID
 
| Module ID
 
|-
 
|-
 +
| 0x7D
 
| AT_PRIORITY
 
| AT_PRIORITY
| 0x7d
   
| Main thread priority
 
| Main thread priority
 
|-
 
|-
 +
| 0x7E
 
| AT_STACK_SIZE
 
| AT_STACK_SIZE
| 0x7e
   
| Main thread stack size
 
| Main thread stack size
 
|-
 
|-
 +
| 0x7F
 
| AT_STACK_ADDR
 
| AT_STACK_ADDR
| 0x7f
   
| Main thread stack address
 
| Main thread stack address
 
|-
 
|-
 +
| 0x80
 
| AT_MEM_PERM_MASK
 
| AT_MEM_PERM_MASK
| 0x80
+
| Memory permission mask
|
   
|}
 
|}
   Line 831: Line 911:  
   AT_STACK_ADDR:        0xE415623C
 
   AT_STACK_ADDR:        0xE415623C
 
   AT_MEM_PERM_MASK:      0x00000000
 
   AT_MEM_PERM_MASK:      0x00000000
 +
 +
== IOSContext ==
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset || Size || Description
 +
|-
 +
| 0x0 || 0x4 || Cpsr
 +
|-
 +
| 0x4 || 0x4 || R0
 +
|-
 +
| 0x8 || 0x4 || R1
 +
|-
 +
| 0xC || 0x4 || R2
 +
|-
 +
| 0x10 || 0x4 || R3
 +
|-
 +
| 0x14 || 0x4 || R4
 +
|-
 +
| 0x18 || 0x4 || R5
 +
|-
 +
| 0x1C || 0x4 || R6
 +
|-
 +
| 0x20 || 0x4 || R7
 +
|-
 +
| 0x24 || 0x4 || R8
 +
|-
 +
| 0x28 || 0x4 || R9
 +
|-
 +
| 0x2C || 0x4 || R10
 +
|-
 +
| 0x30 || 0x4 || R11
 +
|-
 +
| 0x34 || 0x4 || R12
 +
|-
 +
| 0x38 || 0x4 || R13
 +
|-
 +
| 0x3C || 0x4 || Lr
 +
|}
 +
 +
== IOSThread ==
 +
The IOSU is able to create and handle up to 0xB4 threads. Each thread has a corresponding internal structure stored in kernel SRAM (0xFFFF4D78 in firmware 5.5.1).
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset || Size || Description
 +
|-
 +
| 0x0 || 0x40 || [[#IOSContext|Context]]
 +
|-
 +
| 0x40 || 0x4 || Pc
 +
|-
 +
| 0x44 || 0x4 || [[#IOSThread|Next]]
 +
|-
 +
| 0x48 || 0x4 || InitPriority
 +
|-
 +
| 0x4C || 0x4 || Priority
 +
|-
 +
| 0x50 || 0x4 || [[#State|State]]
 +
|-
 +
| 0x54 || 0x4 || Pid
 +
|-
 +
| 0x58 || 0x4 || Tid
 +
|-
 +
| 0x5C || 0x4 || Attributes
 +
|-
 +
| 0x60 || 0x4 || ExitValue
 +
|-
 +
| 0x64 || 0x4 || [[#IOSThread|JoinQueue]]
 +
|-
 +
| 0x68 || 0x4 || [[#IOSThread|Queue]]
 +
|-
 +
| 0x6C || 0x38 ||
 +
|-
 +
| 0xA4 || 0x4 || Sp
 +
|-
 +
| 0xA8 || 0x8 ||
 +
|-
 +
| 0xB0 || 0x4 || SysStackAddress
 +
|-
 +
| 0xB4 || 0x4 || UserStackAddress
 +
|-
 +
| 0xB8 || 0x4 || UserStackSize
 +
|-
 +
| 0xBC || 0x4 || IpcBufferPool
 +
|-
 +
| 0xC0 || 0x4 || ProfiledCount
 +
|-
 +
| 0xC4 || 0x4 || ProfiledTime
 +
|}
 +
 +
=== State ===
 +
{| class="wikitable"
 +
|-
 +
! Value
 +
! Description
 +
|-
 +
| 0
 +
| Available
 +
|-
 +
| 1
 +
| Ready
 +
|-
 +
| 2
 +
| Running
 +
|-
 +
| 3
 +
| Stopped
 +
|-
 +
| 4
 +
| Waiting
 +
|-
 +
| 5
 +
| Dead
 +
|-
 +
| 6
 +
| Faulted
 +
|-
 +
| 7
 +
| Unknown
 +
|}
 +
 +
== IOSHeap ==
 +
The IOSU is able to create and handle up to 0x30 heaps. Each heap has a corresponding descriptor structure stored in the kernel's BSS section (0x08150008 in firmware 5.5.1).
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset || Size || Description
 +
|-
 +
| 0x0 || 0x4 || Base
 +
|-
 +
| 0x4 || 0x4 || Pid
 +
|-
 +
| 0x8 || 0x4 || Size
 +
|-
 +
| 0xC || 0x4 || FirstFree
 +
|-
 +
| 0x10 || 0x4 || ErrorCountOutOfMemory
 +
|-
 +
| 0x14 || 0x4 || ErrorCountFreeBlockNotInHeap
 +
|-
 +
| 0x18 || 0x4 || ErrorCountExpandInvalidBlock
 +
|-
 +
| 0x1C || 0x4 || ErrorCountCorruptedBlock
 +
|-
 +
| 0x20 || 0x4 || Flags
 +
|-
 +
| 0x24 || 0x4 || TotalAllocatedSize
 +
|-
 +
| 0x28 || 0x4 || LargestAllocatedSize
 +
|-
 +
| 0x2C || 0x4 || TotalAllocationCount
 +
|-
 +
| 0x30 || 0x4 || TotalFreedCount
 +
|-
 +
| 0x34 || 0x4 || ErrorCountFreeUnallocatedBlock
 +
|-
 +
| 0x38 || 0x4 || ErrorCountAllocInvalidHeap
 +
|-
 +
| 0x3C || 0x4 || Id
 +
|}
 +
 +
All accesses to heaps are verified using owner PID and active PID. Heaps are referenced using IDs that are used as indices into the heap descriptor array. There are 3 special heap IDs:
 +
{| class="wikitable"
 +
|-
 +
! Heap ID
 +
! Purpose
 +
|-
 +
| 0x0001
 +
| Shared heap
 +
|-
 +
| 0xCAFE
 +
| Local process heap for active PID
 +
|-
 +
| 0xCAFF
 +
| Cross process heap for active PID
 +
|}
 +
 +
Access to special heap IDs is redirected to the appropriate heap.
 +
 +
Each process can allocate a cross process heap for multiple processes to use and a local process heap for itself. These are kept tracked of using two arrays following the heap descriptor array in kernel BSS:
 +
 +
int32 local_process_heaps[14];
 +
int32 cross_process_heaps[14];
 +
 +
They are initialized to IOS_ERROR_INVALID within the IOSU kernel and are set to the appropriate heap ID when created using IOS_CreateLocalProcessHeap or IOS_CreateCrossProcessHeap. There may only be one cross/local process heap for each PID.
 +
 +
Each heap descriptor contains a flag field that contains information about the heap:
 +
0x1: Local process heap
 +
0x2: Cross process heap
 +
 +
Each heap is created from memory of the shared heap. It is initialized as one big seperate memory chunk. Memory chunks have the following structure:
 +
 +
// Heap chunk header
 +
struct
 +
{
 +
  0x00: magic
 +
  0x04: size
 +
  0x08: back
 +
  0x0C: next
 +
} heap_chunk_header_t;  // sizeof() = 0x10
 +
 +
There are 3 valid magic values:
 +
 +
{| class="wikitable"
 +
|-
 +
! Magic
 +
! Meaning
 +
|-
 +
| 0xBABE0000
 +
| Chunk is free
 +
|-
 +
| 0xBABE0001
 +
| Chunks is used
 +
|-
 +
| 0xBABE0002
 +
| Chunk is inner chunk and used
 +
|}
 +
 +
When memory is allocated to a heap, the linked list (terminated using nullptr's) is traversed to find a large enough chunk, chunks are split and back and forward pointers are cleared for the allocated chunk. When a chunk is allocated aligned, a chunk bigger than the needed one may be allocated. Inside this chunk, a second heap chunk is set up in a fashion that the beginning of the memory block described by this "inner" chunk is aligned according to the specified alignment. It's magic is set to 0xBABE0002 and the back pointer is set to the chunk containing it. These inner chunks can not be expanded.
 +
 +
== IOSError ==
 +
{| class="wikitable"
 +
|-
 +
! Value
 +
! Description
 +
|-
 +
| 0
 +
| IOS_ERROR_OK
 +
|-
 +
| -1
 +
| IOS_ERROR_ACCESS
 +
|-
 +
| -2
 +
| IOS_ERROR_EXISTS
 +
|-
 +
| -3
 +
| IOS_ERROR_INTR
 +
|-
 +
| -4
 +
| IOS_ERROR_INVALID
 +
|-
 +
| -5
 +
| IOS_ERROR_MAX
 +
|-
 +
| -6
 +
| IOS_ERROR_NOEXISTS
 +
|-
 +
| -7
 +
| IOS_ERROR_QEMPTY
 +
|-
 +
| -8
 +
| IOS_ERROR_QFULL
 +
|-
 +
| -9
 +
| IOS_ERROR_UNKNOWN
 +
|-
 +
| -10
 +
| IOS_ERROR_NOTREADY
 +
|-
 +
| -11
 +
| IOS_ERROR_ECC
 +
|-
 +
| -12
 +
| IOS_ERROR_ECC_CRIT
 +
|-
 +
| -13
 +
| IOS_ERROR_BADBLOCK
 +
|-
 +
| -14
 +
| IOS_ERROR_INVALID_OBJTYPE
 +
|-
 +
| -15
 +
| IOS_ERROR_INVALID_RNG
 +
|-
 +
| -16
 +
| IOS_ERROR_INVALID_FLAG
 +
|-
 +
| -17
 +
| IOS_ERROR_INVALID_FORMAT
 +
|-
 +
| -18
 +
| IOS_ERROR_INVALID_VERSION
 +
|-
 +
| -19
 +
| IOS_ERROR_INVALID_SIGNER
 +
|-
 +
| -20
 +
| IOS_ERROR_FAIL_CHECKVALUE
 +
|-
 +
| -21
 +
| IOS_ERROR_FAIL_INTERNAL
 +
|-
 +
| -22
 +
| IOS_ERROR_FAIL_ALLOC
 +
|-
 +
| -23
 +
| IOS_ERROR_INVALID_SIZE
 +
|-
 +
| -24
 +
| IOS_ERROR_NO_LINK
 +
|-
 +
| -25
 +
| IOS_ERROR_AN_FAILED
 +
|-
 +
| -26
 +
| IOS_ERROR_MAX_SEM_COUNT
 +
|-
 +
| -27
 +
| IOS_ERROR_SEM_UNAVAILABLE
 +
|-
 +
| -28
 +
| IOS_ERROR_INVALID_HANDLE
 +
|-
 +
| -29
 +
| IOS_ERROR_INVALID_ARG
 +
|-
 +
| -30
 +
| IOS_ERROR_NO_RESOURCE
 +
|-
 +
| -31
 +
| IOS_ERROR_BUSY
 +
|-
 +
| -32
 +
| IOS_ERROR_TIMEOUT
 +
|-
 +
| -33
 +
| IOS_ERROR_ALIGNMENT
 +
|-
 +
| -34
 +
| IOS_ERROR_BSP
 +
|-
 +
| -35
 +
| IOS_ERROR_DATA_PENDING
 +
|-
 +
| -36
 +
| IOS_ERROR_EXPIRED
 +
|-
 +
| -37
 +
| IOS_ERROR_NO_R_ACCESS
 +
|-
 +
| -38
 +
| IOS_ERROR_NO_W_ACCESS
 +
|-
 +
| -39
 +
| IOS_ERROR_NO_RW_ACCESS
 +
|-
 +
| -40
 +
| IOS_ERROR_CLIENT_TXN_LIMIT
 +
|-
 +
| -41
 +
| IOS_ERROR_STALE_HANDLE
 +
|-
 +
| -42
 +
| IOS_ERROR_UNKNOWN_VALUE
 +
|}
 +
 +
== Exception Handling ==
 +
The data-abort and prefetch-abort exception handlers will first check whether a certain flag is clear(flagsfield & (1<<PID)). When that bit is clear and the PID is <=13(highest IOSU PID value that exists), it will just return from the function then do a context-switch. Otherwise, iosPanic() is called.
 +
 +
= IPC =
 +
PowerPC code is able to call IOSU drivers through an IPC interface. It uses the same call interface as IOSU does internally. Userspace code submits IOSU requests with the IPCKDriver_SubmitRequest() [[Cafe_OS_Kernel_Syscalls|syscall]] in the Cafe OS kernel. The kernel includes information to identify which Cafe OS process sent the request, allowing IOSU to check permissions on a per-app basis. Requests are contained in a struct, sent through a [[Hardware/IPC|hardware interface]], and marshalled by the IOSU kernel to a target process. An example of IOSU IPC from the PowerPC can be found [https://github.com/darksideos/darkside-kernel/blob/wiiu/bal/src/platform/wiiu/ios.c here].
 +
 +
IPC request struct (size = 0x48, align = 0x20)
 +
 +
0x00: CMD (1=open, 2=close, 3=read, 4=write, 5=seek, 6=ioctl, 7=ioctlv)
 +
0x04: Reply to client
 +
0x08: Client FD
 +
0x0C: Flags (always 0)
 +
0x10: Client CPU (0=ARM internal, 1-3=PPC cores 0-2)
 +
0x14: Client PID (PFID in older versions, RAMPID more recently?)
 +
0x18: Client group ID (Title ID, upper)
 +
0x1C: Client group ID (Title ID, lower)
 +
0x20: Server handle (written by IOSU)
 +
0x24: Arg0
 +
0x28: Arg1
 +
0x2C: Arg2
 +
0x30: Arg3
 +
0x34: Arg4
 +
0x38: CMD (previous)
 +
0x3C: Client FD (previous)
 +
0x40: Virt0 (PPC virtual addresses to be translated)
 +
0x44: Virt1 (PPC virtual addresses to be translated)
 +
 +
IPC commands
 +
 +
0x00 -> IOS_COMMAND_INVALID
 +
0x01 -> IOS_OPEN
 +
0x02 -> IOS_CLOSE
 +
0x03 -> IOS_READ
 +
0x04 -> IOS_WRITE
 +
0x05 -> IOS_SEEK
 +
0x06 -> IOS_IOCTL
 +
0x07 -> IOS_IOCTLV
 +
0x08 -> IOS_REPLY (internal to IOSU)
 +
0x09 -> IOS_IPC_MSG0 (internal to IOSU)
 +
0x0A -> IOS_IPC_MSG1 (internal to IOSU)
 +
0x0B -> IOS_IPC_MSG2 (internal to IOSU)
 +
0x0C -> IOS_SUSPEND (internal to IOSU)
 +
0x0D -> IOS_RESUME (internal to IOSU)
 +
0x0E -> IOS_SVCMSG (internal to IOSU)
 +
 +
IPC client PIDs
 +
 +
On older versions of IOSU, it seems to match the PFID list. More recently, it appears to use the RAMPID. See the [http://wiiubrew.org/wiki/Cafe_OS#Processes Cafe OS PID tables].
 +
 +
IPC arguments
 +
 +
Open CMD:  Client FD == 0
 +
            Arg0 = name
 +
            Arg1 = name_size
 +
            Arg2 = mode (0 = none, 1 = read, 2 = write)
 +
            Arg3-Arg4 = u64 permissions_bitmask for the target IOSU process, loaded by the target IOSU process during fd init. With PPC this originates from the cos.xml of the source process.
 +
 +
Close CMD:  Client FD != 0
 +
 +
Read CMD:  Client FD != 0
 +
            Arg0 = outPtr
 +
            Arg1 = outLen
 +
 +
Write CMD:  Client FD != 0
 +
            Arg0 = inPtr
 +
            Arg1 = inLen
 +
 +
Seek CMD:  Client FD != 0
 +
            Arg0 = where
 +
            Arg1 = whence
 +
 +
IOCtl CMD:  Client FD != 0
 +
            Arg0 = cmd
 +
            Arg1 = inPtr
 +
            Arg2 = inLen
 +
            Arg3 = outPtr
 +
            Arg4 = outLen
 +
 +
IOCtlv CMD: Client FD != 0
 +
            Arg0 = cmd
 +
            Arg1 = readCount
 +
            Arg2 = writeCount
 +
            Arg3 = vector
    
= Modules =
 
= Modules =
Line 949: Line 1,467:  
*[[:/dev/isfs]] - Internal storage file system
 
*[[:/dev/isfs]] - Internal storage file system
 
*[[:/dev/wfs]] - Wii file system
 
*[[:/dev/wfs]] - Wii file system
*[[:/dev/pcfs]] - PC file system (only available in DEBUG or TEST mode)
+
*[[:/dev/pcfs]] - PC file system (only available in development or test modes)
 
*[[:/dev/rbfs]] - Raw file system
 
*[[:/dev/rbfs]] - Raw file system
 
*[[:/dev/fat]] - FAT file system
 
*[[:/dev/fat]] - FAT file system
Line 1,028: Line 1,546:  
*[[:/dev/iopsh]] - IOP shell?
 
*[[:/dev/iopsh]] - IOP shell?
 
*[[:/dev/cbl]] - Cafe OS block log
 
*[[:/dev/cbl]] - Cafe OS block log
*[[:/debug/prof]] - Profiler (DEBUG mode only)
+
*[[:/debug/prof]] - Profiler (development mode only)
*[[:/test/ppcprotviol]] - PPC protocol violation (TEST mode only)
+
*[[:/test/ppcprotviol]] - PPC protocol violation (test mode only)
*[[:/test/sp]] - System profiler (TEST mode only)
+
*[[:/test/sp]] - System profiler (test mode only)
*[[:/test/test_rm]] - Resource manager test (TEST mode only)
+
*[[:/test/test_rm]] - Resource manager test (test mode only)
    
== IOS-AUXIL ==
 
== IOS-AUXIL ==
Line 1,061: Line 1,579:  
*[[:/dev/mlcorig01]] - NAND MLC original? (Used for board types ID and IH instead of mlc, disables scfm)
 
*[[:/dev/mlcorig01]] - NAND MLC original? (Used for board types ID and IH instead of mlc, disables scfm)
 
*[[:/dev/unknown01]] - Unrecognized
 
*[[:/dev/unknown01]] - Unrecognized
  −
= Threads =
  −
The IOSU is able to create and handle up to 0xB4 threads. Each thread has a corresponding internal structure stored in kernel SRAM (0xFFFF4D78 in firmware 5.5.1).
  −
  −
// Thread struct in memory
  −
struct
  −
{
  −
  0x00: saved_cpsr
  −
  0x04: saved_r0
  −
  0x08: saved_r1
  −
  0x0C: saved_r2
  −
  0x10: saved_r3
  −
  0x14: saved_r4
  −
  0x18: saved_r5
  −
  0x1C: saved_r6
  −
  0x20: saved_r7
  −
  0x24: saved_r8
  −
  0x28: saved_r9
  −
  0x2C: saved_r10
  −
  0x30: saved_r11
  −
  0x34: saved_r12
  −
  0x38: saved_r13
  −
  0x3C: saved_lr
  −
  0x40: thread_pc
  −
  0x44: thread_queue_next
  −
  0x48: thread_min_priority
  −
  0x4C: thread_max_priority
  −
  0x50: thread_state
  −
  0x54: owner_pid
  −
  0x58: thread_id
  −
  0x5C: flags
  −
  0x60: exit_value
  −
  0x64: join_thread_queue_head
  −
  0x68: current_thread_queue
  −
  0x6C: ?????
  −
  0x70: ?????
  −
  0x74: ?????
  −
  0x78: ?????
  −
  0x7C: ?????
  −
  0x80: ?????
  −
  0x84: ?????
  −
  0x88: ?????
  −
  0x8C: ?????
  −
  0x90: ?????
  −
  0x94: ?????
  −
  0x98: ?????
  −
  0x9C: ?????
  −
  0xA0: ?????
  −
  0xA4: thread_sp
  −
  0xA8: ?????
  −
  0xAC: ?????
  −
  0xB0: sys_stack_addr
  −
  0xB4: user_stack_addr
  −
  0xB8: user_stack_size
  −
  0xBC: ipc_buffer_pool
  −
  0xC0: profiled_count
  −
  0xC4: profiled_time
  −
} thread_t;  // sizeof() = 0xC8
  −
  −
Thread states
  −
  −
0x00 -> Available
  −
0x01 -> Ready
  −
0x02 -> Running
  −
0x03 -> Stopped
  −
0x04 -> Waiting
  −
0x05 -> Dead
  −
0x06 -> Faulted
  −
0x07 -> Unknown
  −
  −
Bit 2 in the flags determines whether or not the thread has an IPC buffer pool.
  −
  −
= Heaps =
  −
The IOSU is able to create and handle up to 0x30 heaps. Each heap has a corresponding descriptor structure stored in the kernel's BSS section (0x08150008 in firmware 5.5.1).
  −
  −
// Heap descriptor
  −
struct
  −
{
  −
  0x00: base
  −
  0x04: owner_pid
  −
  0x08: size
  −
  0x0C: first_free
  −
  0x10: error_count_out_of_memory
  −
  0x14: error_count_free_block_not_in_heap
  −
  0x18: error_count_expand_invalid_block
  −
  0x1C: error_count_corrupted_block
  −
  0x20: flags
  −
  0x24: total_allocated_size
  −
  0x28: largest_allocated_size
  −
  0x2C: total_allocation_count
  −
  0x30: total_freed_count
  −
  0x34: error_count_free_unallocated_block
  −
  0x38: error_count_alloc_invalid_heap
  −
  0x3C: heap_id
  −
} heap_descriptor_t;  // sizeof() = 0x40
  −
  −
All accesses to heaps are verified using owner PID and active PID. Heaps are referenced using IDs that are used as indices into the heap descriptor array. There are 3 special heap IDs:
  −
{| class="wikitable"
  −
|-
  −
! Heap ID
  −
! Purpose
  −
|-
  −
| 0x0001
  −
| Shared heap
  −
|-
  −
| 0xCAFE
  −
| Local process heap for active PID
  −
|-
  −
| 0xCAFF
  −
| Cross process heap for active PID
  −
|}
  −
  −
Access to special heap IDs is redirected to the appropriate heap.
  −
  −
Each process can allocate a cross process heap for multiple processes to use and a local process heap for itself. These are kept tracked of using two arrays following the heap descriptor array in kernel BSS:
  −
  −
int32 local_process_heaps[14];
  −
int32 cross_process_heaps[14];
  −
  −
They are initialized to IOS_ERROR_INVALID within the IOSU kernel and are set to the appropriate heap ID when created using IOS_CreateLocalProcessHeap or IOS_CreateCrossProcessHeap. There may only be one cross/local process heap for each PID.
  −
  −
Each heap descriptor contains a flag field that contains information about the heap:
  −
0x1: Local process heap
  −
0x2: Cross process heap
  −
  −
Each heap is created from memory of the shared heap. It is initialized as one big seperate memory chunk. Memory chunks have the following structure:
  −
  −
// Heap chunk header
  −
struct
  −
{
  −
  0x00: magic
  −
  0x04: size
  −
  0x08: back
  −
  0x0C: next
  −
} heap_chunk_header_t;  // sizeof() = 0x10
  −
  −
There are 3 valid magic values:
  −
  −
{| class="wikitable"
  −
|-
  −
! Magic
  −
! Meaning
  −
|-
  −
| 0xBABE0000
  −
| Chunk is free
  −
|-
  −
| 0xBABE0001
  −
| Chunks is used
  −
|-
  −
| 0xBABE0002
  −
| Chunk is inner chunk and used
  −
|}
  −
  −
When memory is allocated to a heap, the linked list (terminated using nullptr's) is traversed to find a large enough chunk, chunks are split and back and forward pointers are cleared for the allocated chunk. When a chunk is allocated aligned, a chunk bigger than the needed one may be allocated. Inside this chunk, a second heap chunk is set up in a fashion that the beginning of the memory block described by this "inner" chunk is aligned according to the specified alignment. It's magic is set to 0xBABE0002 and the back pointer is set to the chunk containing it. These inner chunks can not be expanded.
  −
  −
= IPC =
  −
PowerPC code is able to call IOSU drivers through an IPC interface. It uses the same call interface as IOSU does internally. Userspace code submits IOSU requests with the IPCKDriver_SubmitRequest() [[Cafe_OS_Kernel_Syscalls|syscall]] in the Cafe OS kernel. The kernel includes information to identify which Cafe OS process sent the request, allowing IOSU to check permissions on a per-app basis. Requests are contained in a struct, sent through a [[Hardware/IPC|hardware interface]], and marshalled by the IOSU kernel to a target process. An example of IOSU IPC from the PowerPC can be found [https://github.com/darksideos/darkside-kernel/blob/wiiu/bal/src/platform/wiiu/ios.c here].
  −
  −
IPC request struct (size = 0x48, align = 0x20)
  −
  −
0x00: CMD (1=open, 2=close, 3=read, 4=write, 5=seek, 6=ioctl, 7=ioctlv)
  −
0x04: Reply to client
  −
0x08: Client FD
  −
0x0C: Flags (always 0)
  −
0x10: Client CPU (0=ARM internal, 1-3=PPC cores 0-2)
  −
0x14: Client PID (PFID in older versions, RAMPID more recently?)
  −
0x18: Client group ID (Title ID, upper)
  −
0x1C: Client group ID (Title ID, lower)
  −
0x20: Server handle (written by IOSU)
  −
0x24: Arg0
  −
0x28: Arg1
  −
0x2C: Arg2
  −
0x30: Arg3
  −
0x34: Arg4
  −
0x38: CMD (previous)
  −
0x3C: Client FD (previous)
  −
0x40: Virt0 (PPC virtual addresses to be translated)
  −
0x44: Virt1 (PPC virtual addresses to be translated)
  −
  −
IPC commands
  −
  −
0x00 -> IOS_COMMAND_INVALID
  −
0x01 -> IOS_OPEN
  −
0x02 -> IOS_CLOSE
  −
0x03 -> IOS_READ
  −
0x04 -> IOS_WRITE
  −
0x05 -> IOS_SEEK
  −
0x06 -> IOS_IOCTL
  −
0x07 -> IOS_IOCTLV
  −
0x08 -> IOS_REPLY (internal to IOSU)
  −
0x09 -> IOS_IPC_MSG0 (internal to IOSU)
  −
0x0A -> IOS_IPC_MSG1 (internal to IOSU)
  −
0x0B -> IOS_IPC_MSG2 (internal to IOSU)
  −
0x0C -> IOS_SUSPEND (internal to IOSU)
  −
0x0D -> IOS_RESUME (internal to IOSU)
  −
0x0E -> IOS_SVCMSG (internal to IOSU)
  −
  −
IPC client PIDs
  −
  −
On older versions of IOSU, it seems to match the PFID list. More recently, it appears to use the RAMPID. See the [http://wiiubrew.org/wiki/Cafe_OS#Processes Cafe OS PID tables].
  −
  −
IPC arguments
  −
  −
Open CMD:  Client FD == 0
  −
            Arg0 = name
  −
            Arg1 = name_size
  −
            Arg2 = mode (0 = none, 1 = read, 2 = write)
  −
            Arg3-Arg4 = u64 permissions_bitmask for the target IOSU process, loaded by the target IOSU process during fd init. With PPC this originates from the cos.xml of the source process.
  −
  −
Close CMD:  Client FD != 0
  −
  −
Read CMD:  Client FD != 0
  −
            Arg0 = outPtr
  −
            Arg1 = outLen
  −
  −
Write CMD:  Client FD != 0
  −
            Arg0 = inPtr
  −
            Arg1 = inLen
  −
  −
Seek CMD:  Client FD != 0
  −
            Arg0 = where
  −
            Arg1 = whence
  −
  −
IOCtl CMD:  Client FD != 0
  −
            Arg0 = cmd
  −
            Arg1 = inPtr
  −
            Arg2 = inLen
  −
            Arg3 = outPtr
  −
            Arg4 = outLen
  −
  −
IOCtlv CMD: Client FD != 0
  −
            Arg0 = cmd
  −
            Arg1 = readCount
  −
            Arg2 = writeCount
  −
            Arg3 = vector
  −
  −
= Error codes =
  −
  −
Kernel errors
  −
  −
0x00000000 -> IOS_ERROR_OK
  −
0xFFFFFFFF -> IOS_ERROR_ACCESS
  −
0xFFFFFFFE -> IOS_ERROR_EXISTS
  −
0xFFFFFFFD -> IOS_ERROR_INTR
  −
0xFFFFFFFC -> IOS_ERROR_INVALID
  −
0xFFFFFFFB -> IOS_ERROR_MAX
  −
0xFFFFFFFA -> IOS_ERROR_NOEXISTS
  −
0xFFFFFFF9 -> IOS_ERROR_QEMPTY
  −
0xFFFFFFF8 -> IOS_ERROR_QFULL
  −
0xFFFFFFF7 -> IOS_ERROR_UNKNOWN
  −
0xFFFFFFF6 -> IOS_ERROR_NOTREADY
  −
0xFFFFFFF5 -> IOS_ERROR_ECC
  −
0xFFFFFFF4 -> IOS_ERROR_ECC_CRIT
  −
0xFFFFFFF3 -> IOS_ERROR_BADBLOCK
  −
0xFFFFFFF2 -> IOS_ERROR_INVALID_OBJTYPE
  −
0xFFFFFFF1 -> IOS_ERROR_INVALID_RNG
  −
0xFFFFFFF0 -> IOS_ERROR_INVALID_FLAG
  −
0xFFFFFFEF -> IOS_ERROR_INVALID_FORMAT
  −
0xFFFFFFEE -> IOS_ERROR_INVALID_VERSION
  −
0xFFFFFFED -> IOS_ERROR_INVALID_SIGNER
  −
0xFFFFFFEC -> IOS_ERROR_FAIL_CHECKVALUE
  −
0xFFFFFFEB -> IOS_ERROR_FAIL_INTERNAL
  −
0xFFFFFFEA -> IOS_ERROR_FAIL_ALLOC
  −
0xFFFFFFE9 -> IOS_ERROR_INVALID_SIZE
  −
0xFFFFFFE8 -> IOS_ERROR_NO_LINK
  −
0xFFFFFFE7 -> IOS_ERROR_AN_FAILED
  −
0xFFFFFFE6 -> IOS_ERROR_MAX_SEM_COUNT
  −
0xFFFFFFE5 -> IOS_ERROR_SEM_UNAVAILABLE
  −
0xFFFFFFE4 -> IOS_ERROR_INVALID_HANDLE
  −
0xFFFFFFE3 -> IOS_ERROR_INVALID_ARG
  −
0xFFFFFFE2 -> IOS_ERROR_NO_RESOURCE
  −
0xFFFFFFE1 -> IOS_ERROR_BUSY
  −
0xFFFFFFE0 -> IOS_ERROR_TIMEOUT
  −
0xFFFFFFDF -> IOS_ERROR_ALIGNMENT
  −
0xFFFFFFDE -> IOS_ERROR_BSP
  −
0xFFFFFFDD -> IOS_ERROR_DATA_PENDING
  −
0xFFFFFFDC -> IOS_ERROR_EXPIRED
  −
0xFFFFFFDB -> IOS_ERROR_NO_R_ACCESS
  −
0xFFFFFFDA -> IOS_ERROR_NO_W_ACCESS
  −
0xFFFFFFD9 -> IOS_ERROR_NO_RW_ACCESS
  −
0xFFFFFFD8 -> IOS_ERROR_CLIENT_TXN_LIMIT
  −
0xFFFFFFD7 -> IOS_ERROR_STALE_HANDLE
  −
0xFFFFFFD6 -> IOS_ERROR_UNKNOWN_VALUE
      
= Virtual Memory Map =
 
= Virtual Memory Map =
Line 1,366: Line 1,601:  
| 0x13D80000 - 0x13DA0000
 
| 0x13D80000 - 0x13DA0000
 
| 0x20000
 
| 0x20000
| IOS-MCP (debug and recovery mode)
+
| IOS-MCP (development and recovery mode)
 
|-
 
|-
 
| 0x08120000 - 0x081C0000
 
| 0x08120000 - 0x081C0000
Line 1,386: Line 1,621:  
| 0x10700000 - 0x11C40000
 
| 0x10700000 - 0x11C40000
 
| 0x1540000
 
| 0x1540000
| IOS-FS (5.5.1 retail)
+
| IOS-FS (5.5.1 production)
 
|-
 
|-
 
| 0x10800000 - 0x11EE0000
 
| 0x10800000 - 0x11EE0000
 
| 0x10800000 - 0x11EE0000
 
| 0x10800000 - 0x11EE0000
 
| 0x16E0000
 
| 0x16E0000
| IOS-FS (5.3.2 debug)
+
| IOS-FS (5.3.2 development)
 
|-
 
|-
 
| 0x11F00000 - 0x12160000
 
| 0x11F00000 - 0x12160000
Line 1,482: Line 1,717:     
Hence, userland .text is ''only'' executable from userland. From userland, the ''only'' executable memory is the process .text. In privileged-mode, the ''only'' executable memory is the main kernel .text(0x08120000) and 0xffff0000(the latter is also RWX).
 
Hence, userland .text is ''only'' executable from userland. From userland, the ''only'' executable memory is the process .text. In privileged-mode, the ''only'' executable memory is the main kernel .text(0x08120000) and 0xffff0000(the latter is also RWX).
  −
= Exception handling =
  −
The data-abort and prefetch-abort exception handlers will first check whether a certain flag is clear(flagsfield & (1<<PID)). When that bit is clear and the PID is <=13(highest IOSU PID value that exists), it will just return from the function then do a context-switch. Otherwise, iosPanic() is called.