IOS/Syscalls

From WiiBrew
< IOS
Jump to navigation Jump to search

There are 2 types of syscalls:

1. Syscalls using undefined ARM instruction.

2. Syscalls using ARM syscall instruction.

Syscalls (via undefined instructions)

Internally, IOS uses a syscall table that is stored toward the end of the main kernel binary. The exact address varies with version of IOS, but there are two methods to locate it:

ELF header:

The second-to-last program header is the syscall table. For example:

$ arm-eabi-readelf -l ~/wii/system_updates/boot2.elf  | tail -2
 LOAD           0x0230d5 0xffff7f60 0xffff7f60 0x00a88 0x00a88 RW  0x10   # syscall table
 LOAD           0x023b5d 0xffff8a00 0xffff8a00 0x00000 0x071e8 RW  0x20 # kernel BSS

or

elf_header:134C01A0 elf32_phdr < 1, 0x230D5, syscall_base, syscall_base, 0xA88, 0xA88,  6, 0x10>
elf_header:134C01C0 elf32_phdr < 1, 0x23B5D, current_thread_context, current_thread_context, 0, 0x71E8,  6, 0x20>

Syscall Handler: The second vector is the invalid instruction handler, which is used to implement syscalls:

kernel:FFFF0000               LDR     PC, =_reset
kernel:FFFF0004               LDR     PC, =starlet_syscall_handler

kernel:FFFF1F24             starlet_syscall_handler                 ; CODE XREF: start�j
kernel:FFFF1F24 E9 CD 7F FF                 STMFA   SP, {R0-LR}^
kernel:FFFF1F28 E1 4F 80 00                 MRS     R8, SPSR
kernel:FFFF1F2C E5 8D 80 00                 STR     R8, [SP,#spsr_register_save]
kernel:FFFF1F30 E5 8D E0 40                 STR     LR, [SP,#lr_register_save]
kernel:FFFF1F34 E5 1E A0 04                 LDR     R10, [LR,#-4]   ; R10 = E600XXXX  (the invalid instruction)
kernel:FFFF1F38 E3 CA 9D 7F                 BIC     R9, R10, #NOT 0xFFFFE03F
kernel:FFFF1F3C E5 9F 84 CC                 LDR     R8, =0xE6000010 ; syscall base
kernel:FFFF1F40 E3 C9 90 20                 BIC     R9, R9, #NOT 0xFFFFFFDF ; R9 = R10 & FFFFE01F
kernel:FFFF1F44 E1 59 00 08                 CMP     R9, R8          ; Were any bits set other than the syscall number
kernel:FFFF1F48 1A 00 00 1F                 BNE     invalid_syscall
kernel:FFFF1F4C E1 A0 A2 CA                 MOV     R10, R10,ASR#5  ; R10 = R10 >> 5
kernel:FFFF1F50 E2 0A A0 FF                 AND     R10, R10, #0xFF ; R10 = R10 & 0xFF
kernel:FFFF1F54 E3 5A 00 7A                 CMP     R10, #0x7A      ; max index of syscall (can vary for each IOS)
kernel:FFFF1F58 CA 00 00 11                 BGT     return_to_caller
kernel:FFFF1F5C E1 A0 80 0D                 MOV     R8, SP
kernel:FFFF1F60 E3 A0 B0 1F                 MOV     R11, #0b11111
kernel:FFFF1F64 E1 21 F0 0B                 MSR     CPSR_c, R11     ; switch to system mode, disable irq & fiq
kernel:FFFF1F68 E5 98 80 44                 LDR     R8, [R8,#sp_register_save]
kernel:FFFF1F6C E5 9F B4 A0                 LDR     R11, =syscall_stack_arg_counts
kernel:FFFF1F70 E7 9B B1 0A                 LDR     R11, [R11,R10,LSL#2] ; number of args on stack for this syscall
kernel:FFFF1F74 E0 8D D1 0B                 ADD     SP, SP, R11,LSL#2 ; SP += R11[R10 << 2]
kernel:FFFF1F78             get_stack_arg                            ; CODE XREF: start+1F8C�j
kernel:FFFF1F78 E3 5B 00 00                 CMP     R11, #0
kernel:FFFF1F7C 0A 00 00 03                 BEQ     find_syscall_and_jump
kernel:FFFF1F80 E5 3D 90 04                 LDR     R9, [SP,#-4]! ; copy argument value
kernel:FFFF1F84 E5 28 90 04                 STR     R9, [R8,#-4]!
kernel:FFFF1F88 E2 4B B0 01                 SUB     R11, R11, #1
kernel:FFFF1F8C EA FF FF F9                 B       get_stack_arg
kernel:FFFF1F90             find_syscall_and_jump                   ; CODE XREF: start+1F7C�j
kernel:FFFF1F90 E1 A0 D0 08                 MOV     SP, R8
kernel:FFFF1F94 E5 9F B4 7C                 LDR     R11, =syscall_table
kernel:FFFF1F98 E7 9B B1 0A                 LDR     R11, [R11,R10,LSL#2] ; syscall number * sizeof(dword) + syscall table offset
kernel:FFFF1F9C E1 A0 E0 0F                 MOV     LR, PC          ; save returning position
kernel:FFFF1FA0 E1 2F FF 1B                 BX      R11             ; jump to syscall implementation
kernel:FFFF1FA0                                                     ;
kernel:FFFF1FA0                                                     ; NOTE: every syscall function
kernel:FFFF1FA0                                                     ; ends with something like "bx lr"
kernel:FFFF1FA4
kernel:FFFF1FA4             return_to_caller                        ; CODE XREF: start+1F58�j
kernel:FFFF1FA4 E3 A0 B0 DB                 MOV     R11, #0xDB      ; switch to undefined mode + re-enable FIQ/IRQ
kernel:FFFF1FA8 E1 21 F0 0B                 MSR     CPSR_c, R11
kernel:FFFF1FAC E5 9D B0 00                 LDR     R11, [SP,#spsr_register_save]
kernel:FFFF1FB0 E1 6F F0 0B                 MSR     SPSR_cxsf, R11  ; restore spsr
kernel:FFFF1FB4 E1 A0 E0 00                 MOV     LR, R0
kernel:FFFF1FB8 E9 DD 7F FF                 LDMED   SP, {R0-LR}^
kernel:FFFF1FBC E1 A0 00 00                 NOP
kernel:FFFF1FC0 E1 A0 00 0E                 MOV     R0, LR
kernel:FFFF1FC4 E5 9D E0 40                 LDR     LR, [SP,#lr_register_save]
kernel:FFFF1FC8 E1 B0 F0 0E                 MOVS    PC, LR          ; return to caller
kernel:FFFF1FCC
kernel:FFFF1FCC             invalid_syscall                            ; CODE XREF: start+1F48�j
kernel:FFFF1FCC E5 9F D4 48                 LDR     SP, =current_thread_context_addr
kernel:FFFF1FD0 E5 9D D0 00                 LDR     SP, [SP,#spsr_register_save]
kernel:FFFF1FD4 E5 8D E0 40                 STR     LR, [SP,#lr_register_save]
kernel:FFFF1FD8 E3 A0 E0 06                 MOV     LR, #6 ; STATE_FAULTED
kernel:FFFF1FDC E5 8D E0 50                 STR     LR, [SP,#thread_state] ; segfault, invalid instruction
kernel:FFFF1FE0 E2 8D D0 04                 ADD     SP, SP, #4
kernel:FFFF1FE4 E9 4D 7F FF                 STMFD   SP, {R0-LR}^
kernel:FFFF1FE8 E1 4F B0 00                 MRS     R11, SPSR
kernel:FFFF1FEC E5 0D B0 04                 STR     R11, [SP,#-4+spsr_register_save]
kernel:FFFF1FF0 EA 00 00 D2                 B       schedule_yield
kernel:FFFF1FF0             ; End of function starlet_syscall_handler

Syscalls are invoked by way of the invalid instruction handler; syscalls take the form 0xE6000010 | (syscall_num << 5). (E.g. E6000010 is syscall 0, E60006D0 is syscall 0x36, etc.). IOS70 has 0x7A available syscalls.

tmbinc has written an IDAPython script which can take a database that has "syscall_base" defined, and transform the references to it into more meaningful things -- it is available here: IOS/Syscall IDAPython

(please feel free to contribute your own findings!)

Syscall Table

Names starting with IOS_ are official names. The rest are only educated guesses.

The exact numbers seem to vary between IOSes; for example, 0x5a is IOSC_DeleteObject in IOS9. The entire IOSC seems to be offset by 2; LaunchRM is probably one of the two syscalls added later, although the other is not known.

List of syscalls in IOS
ID # Internal name Description Return value
0 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)
1 int JoinThread(int threadid, u32 *returned_value) Waits for a thread to finish executing 0 on success
2 int CancelThread(int threadid, u32 return_value ) Ends a thread, called automatically when proc returns 0 on success
3 int IOS_GetThreadId() Get the current thread's ID Current threadid
4 int GetProcessId() Get the current process's ID Current processid
5 int IOS_StartThread(int threadid) Resume the specified thread 0 on success
6 int SuspendThread(int threadid) Suspend the specified thread 0 on success
7 void YieldThread(void) Yield execution to any higher priority threads
8 int IOS_GetThreadPriority(int threadid) Get the priority of the specified thread thread's priority or error (negative value)
9 int IOS_SetThreadPriority(int threadid, int priority) Set the priority of the specified thread 0 on success
a int IOS_CreateMessageQueue(IOSMessage *ptr, u32 n_msgs) Create a queue at ptr, for n_msgs messages. IOSMessage is a typedef for u32. The queue ID
b int IOS_DestroyMessageQueue(int queueid) Destroy a message queue 0 on success
c int IOS_SendMessage(int queueid, IOSMessage message, u32 flags) Add a message to the end queue 0 on success
d int IOS_JamMessage(int queueid, IOSMessage message, u32 flags) Add a message to the front of a queue 0 on success
e int IOS_ReceiveMessage(int queueid, IOSMessage *message, u32 flags) Fetch a message from the front of a queue 0 on success
f int IOS_HandleEvent(int device, int queueid, IOSMessage message) Register queueid as a handler for interrupts generated by device (sends message to queueid when device's interrupt is triggered) 0 on success
10 int UnregisterEventHandler(int device) Unregister handler for device 0 on success
11 int IOS_CreateTimer(int time_us, int repeat_time_us, int queueid, IOSMessage message) Create a timer that sends a message to a queue after the elapsed period(s) timerid or error (negative value)
12 int IOS_RestartTimer(int timerid, int time_us, int repeat_time_us) Restart a timer using the specified period(s) 0 on success
13 int IOS_StopTimer(int timerid) Pauses the specified timer 0 on success
14 int IOS_DestroyTimer(int timerid) Destroys the specified timer 0 on success
15 u32 time_now() Fetch the current value of starlet's timer The current value of the HW_TIMER register
16 int IOS_CreateHeap(void *ptr, int size) Create a new heap at ptr of size bytes heapid or error (negative value)
17 int IOS_DestroyHeap(int heapid) Destroy the specified heap 0 on success
18 void* IOS_Alloc(int heapid, u32 size) Allocate size bytes from the specified heap pointer to memory
19 void* IOS_AllocAligned(int heapid, u32 size, u32 align) Allocate size bytes from the specified heap with the requested alignment pointer to aligned memory
1a int IOS_Free(int heapid, void *ptr) Release allocated memory back to the heap 0 on success
1b int IOS_RegisterResourceManager(const char* device, int queueid) Registers device to the device tree, so it can be opened with IOS_Open (from Starlet and Broadway) using the device name. Typically starts with /dev, but / is also registered by FS to allow files to be opened directly. 0 on success
1c int IOS_Open(const char* path, int mode) Generates a file descriptor, and notifies the device if the path points to a device. The file descriptor
1d int IOS_Close(int fd) Close a previously opened fd 0 on success
1e int IOS_Read(int fd, void *buf, u32 len) Read len bytes from fd into buf The number of bytes read or error
1f int IOS_Write(int fd, const void *buf, u32 len) Write len bytes to fd from buf The number of bytes written or error
20 int IOS_Seek(int fd, int offset, int origin) Seek to offset relative to origin The new absolute offset or error
21 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
22 int IOS_Ioctlv(int fd, u32 request, u32 vector_count_in, u32 vector_count_out, IOVector *vector) Perform the requested IOCTL Return value from IOCTL
23 int IOS_OpenAsync(const char* device, int mode, int queueid, IOSRequest *message) Copy of IOS_Open that writes to a message queue. Unlike the other async IPC syscalls, this is not actually asynchronous, and only differs in the return method. 0 on success, ipcmessage is sent to the queue with the command's return value
24 int IOS_CloseAsync(int fd, int queueid, IOSRequest *message) Async implementation of IOS_Close 0 on success
25 int IOS_ReadAsync(int fd, void *buf, u32 len, int queueid, IOSRequest *message) Async implementation of IOS_Read
26 int IOS_WriteAsync(int fd, const void *buf, u32 len, int queueid, IOSRequest *message) Async implementation of IOS_Write
27 int IOS_SeekAsync(int fd, int offset, int origin, int queueid, IOSRequest *message) Async implementation of IOS_Seek
28 int IOS_IoctlAsync(int fd, u32 request, void *input_buffer, u32 input_buffer_len, void *output_buffer, u32 output_buffer_len, int queueid, IOSRequest *message) Async implementation of IOS_Ioctl
29 int IOS_IoctlvAsync(int fd, u32 request, u32 vector_count_in, u32 vector_count_out, IOVector *vector, int queueid, IOSRequest *message) Async implementation of IOS_Ioctlv
2a int IOS_ResourceReply( const IOSMessage *request, int retval) return from a cmd on a resource
2b int SetUid(u32 pid, u32 uid) Set the UID for a process (PID <= 0x13). This can only be used from the kernel or ES. IPC_SUCCESS on success, IPC_EACCES (permission denied if current PID > 0x1) or IPC_EINVAL (invalid PID)
2c IOSUid GetUid(void) Get the UID for the active process (based on the thread PID). UID (u32)
2d int SetGid(u32 pid, u16 gid) Set the GID for a process (PID <= 0x13). This can only be used from the kernel or ES. IPC_SUCCESS on success, IPC_EACCES (permission denied if current PID > 0x1) or IPC_EINVAL (invalid PID)
2e IOSGid GetGid(void) Get the GID for the active process (based on the thread PID). GID (u16)
2f int AHB_MemFlush(int ahb_dev)
30 int AHB_MemRBInvalidate(int ahb_dev)[check]
31 int ClearAndEnableIPCIOPIntr(void) Enables hardware interrupts for device 31 (IPC (Starlet)) (can only be used from the kernel or ES) 0 on success, -4 for no permission.
32 int ClearAndEnableDIIntr(void) Enables hardware interrupts for device 18 (DI) (can only be used from DI) 0 on success, -4 for no permission
33 int ClearAndEnableSDIntr(u8 hc) Enables hardware interrupts for device 7 (SDHC - must be SDI) if hc==0, else device 8 (802.11 Wireless - must be WL) 0 on success, -4 for no permission
34 int ClearAndEnableEvent(IOSEvent event) Enables hardware interrupts for the given device, with PID requirements (this is also used to syscalls 31 through 33):
event PID
4 (USB Host Controller) 6 (EHCI)
5 (USB Host Controller) 4 (OH0/OHCI0)
6 (USB Host Controller) 5 (OH1)
7 (SD Host Controller) 7 (SDI)
8 (802.11 Wireless) 11 (WL)
11 (Hollywood GPIOs (Starlet); also updates POWER (1) in HW_GPIO_INTFLAG) 14 (STM)
17 (Reset button) 14 (STM)
18 (Drive Interface) 3 (DI)
31 (IPC (Starlet)) 0 (Kernel or ES)
0 on success, -1 for unknown IRQ (not in that table), -4 for no permission
35 int AccessIobPool(u32 pool) no-op in IOS-35, arg1=0 returns always 0
36 struct iobuf *alloc_iobuf(arg1, sbuf) allocate an iobuf, arg1=0 (unknown), sbuf = buffer size return NULL on error
37 int free_iobuf(struct iobuf *buf) free an allocated iobuf
38 iobuf_log_header_info
39 iobuf_log_buffer_info
3a void *extend_iobuf(struct iobuf *iob, unsigned short num) extend the data in the buffer by num bytes returns pointer to extended area
3b void *IOS_PushIob(struct iobuf *iob, unsigned short num) move head pointer in io buffer num bytes towards the buffer end returns old head pointer
3c void *IOS_PullIob(struct iobuf *iob, unsigned short num) move head pointer in io buffer num bytes towards the buffer start
3d int verify_iobuf(struct iobuf *iob) verify if the argument points to an io buffer
3e syscall_3e Unknown; related to IO buffer functionality
3f void IOS_InvalidateDCache(void *address, u32 size) "sync_before_read" - Invalidates dcache, and something (probably related to flushing memory)
40 void IOS_FlushDCache(const void *address, u32 size) "sync_after_write" - Flushes dcache and does magic bullshit (aka magic AHB operations). If size is smaller or equal than 0x4000, it performs CP15 "Clean data cache line (MVA)" (c7, c10, 1) on each line, and otherwise, it performs CP15 "Test and clean" (c7, c10, 3)
41 IOS_StartPPC(const char *path) Loads a .dol or .elf file into memory and bootstraps the PPC
42 [[noreturn]] int ios_boot(const char* path, bool suspendBroadway, u32 version) Suspends the IPC thread, loads a new IOS kernel from the NAND to 0x10100000 in IOS59), then calls boot_new_ios_kernel(0x10100000, version). This can only be called from UID 0. Doesn't return if the boot succeeded; otherwise, an error code is returned.
43 [[noreturn]] int boot_new_ios_kernel(void* ios_binary_address, u32 new_version) Sets the version at 0x3140 to new_version and the IPC buffer range ("DDR settings") to the legacy range ("12M"), before branching to the new kernel. This can only be called from UID 0. -
44 int assert_di_reset() Clears bit 10 (DI) of HW_RESETS (can only be called from DI) Returns 0 on success, -1 on error
45 int deassert_di_reset() Enables bit 10 (DI) of HW_RESETS (can only be called from DI) Returns 0 on success, -1 on error
46 bool check_di_reset() Checks bit 10 (DI) of HW_RESETS (can only be called from DI) Returns 1 on reset asserted, 0 on deasserted or error
47 void get_kernel_flavor(u32 *type, u16 *unk) The implementation of this syscall differs between "flavors" of kernel and returns some identifiers. The IOSv58 kernel writes (*type=3, *unk=0). The boot2v4 kernel writes (*type=0, *unk_0), although types 0-2 all seem to be reserved for boot2.
48 void get_unk_flavor(u32 *type, u16 *unk) Potentially vestigial. Probably related to syscall 0x47 above. Always returns (*type=1, *unk=0).
49 u32 get_boot_vector() Returns a pointer (?) depending on the SRAM mirror bit in HW_MEMIRR.

Returns 0xffffff00 when the mirror bit is set. Returns 0x0d40ff00 when the mirror bit is unset.

4a u32 GetHollywoodId(void)
4b void kernel_debug_print(u32 flags) Prints various debug info (depending on flags) from the kernel
4c int SetLoMemOSVersion(u32 version) Stores version to 0x3140 (can only be called by ES) 0 on success
4d u32 GetLoMemOSVersion(void) Returns the current IOS version from 0x3140 (can only be called by ES) IOS version or 0 on error
4e int SetDiSpinup(u32 s) Sets or clears the DI_SPIN GPIO; if enable is 0 then the flag is set (disabling spinup); it is cleared otherwise. (Can only be called by DI) 0 on success, -1 on error
4f void *VirtualToPhysical(void *virt) Converts a virtual pointer to its physical equivalent
50 int SetDvdReadDisable(u8 disable) Enable/Disable DI DVD Video commands (can only be called from DI) 0 on success, -1 on error
51 u32 GetDvdReadDisable(void) Return status of DI DVD Video commands (can only be called from DI) 1 if disabled, 0 if enabled or error
52 int SetEnableAHBPI2DI(u8 enable) Sets bit 4 of HW_AIPPROT, clearing it if value is 0 and setting it otherwise. DI only seems to call it with false[check]. (Can only be called from DI) 0 on success, -1 on error
53 u8 GetEnableAHBPI2DI(void) Checks bit 4 of HW_AIPPROT (can only be called from DI) 1 if bit 4 of HW_AIPPROT is set, 0 if not set or error
54 int SetPPCACRPerms(u8 enable) Enable/Disable PPC AHBPROT setting (can only be called from ES) 0 on success, -1 on error
55 u32 GetBusSpeed(void) Returns the bus speed in megahertz: 162 in GC mode (if the bottom bit of HW_CLOCKS), and 243 in Wii mode typically, though the Wii value can vary based on HW_PLLSYS and HW_PLLSYSEXT.
56 int ACRRegWrite(u32 offset, u32 value) Set gpio reg to value (can only be called from STM) 0 on success, -1 on error
57 int DDRRegWrite(u32 offset, u32 value) Writes a 32-bit value to the specified Memory Controller register. Can only be called from the STM module. Returns 0 on success, -1 on error.
58 void OutputDebugPort(u8 value) Set GPIO lines 16-23 (DEBUG0-7, the debug port) to the provided value.
59 int SetIpcAccessRights(u8 *rights) Related to PPC IPC. Can only be called from the ES module. Called when bootstrapping PPC. 0 on success, negative for error.
5a int LaunchRM(const char *path) Load an ARM ELF [IOS module] and start a new thread. 0 on success, negative for error
5b IOSCError IOSC_CreateObject(u32* key_handle, IOSCObjectType type, IOSCObjectSubType subtype); Create a new keyring entry. key_handle is updated with a key handle to use with other IOSC calls. 0 on success, negative for error
5c IOSCError IOSC_DeleteObject(u32 key_handle) Remove a keyring entry 0 on success, negative for error
5d IOSCError IOSC_ImportSecretKey(IOSCSecretKeyHandle importedHandle, IOSCSecretKeyHandle verifyHandle, IOSCSecretKeyHandle decryptHandle, IOSCSecretKeySecurity flag, u8 * signbuffer, u8 * ivData, u8 * keybuffer); Sets the contents of a key handle. This is commonly used to import a built-in key handle (such as the common key). 0 on success, negative for error
5e IOSCError IOSC_ExportSecretKey(IOSCSecretKeyHandle exportedHandle, IOSCSecretKeyHandle signHandle, IOSCSecretKeyHandle encryptHandle, IOSCSecretKeySecurity security_flag, u8 * signbuffer, u8 * ivData, u8 * keybuffer); 0 on success, negative for error
5f IOSCError IOSC_ImportPublicKey(u8 * publicKeyData, u8 * exponent, IOSCPublicKeyHandle publicKeyHandle); Sets the contents of a signature. The imported public key must match publicKeyHandle's type. exponent is optional 4 bytes that can be attached 0 on success, negative for error
60 IOSCError IOSC_ExportPublicKey(u8 * publicKeyData, u8 * exponent, IOSCPublicKeyHandle publicKeyHandle); Gets the contents of a signature 0 on success, negative for error
61 IOSCError IOSC_ComputeSharedKey(IOSCSecretKeyHandle privateHandle, IOSCPublicKeyHandle publicHandle, IOSCSecretKeyHandle sharedHandle); Generates a new AES crypto key (sharedHandle) from an ecdh shared secret calculated from a sender's ECC key (publicHandle) and our own ECC key (privateHandle) 0 on success, negative for error
62 IOSCError IOSC_SetData(IOSCDataHandle dataHandle, u32 value); 0 on success, negative for error
63 IOSCError IOSC_GetData(IOSCDataHandle dataHandle, u32 * value); Fetch 4 bytes of userdata from the key 0 on success (userdata in data), negative for error
64 IOSCError IOSC_GetKeySize(u32 * keySize, IOSCKeyHandle handle); Return the key size 0 on success, negative for error
65 IOSCError IOSC_GetSignatureSize(u32 * signSize, int handle); Return the signature size 0 on success, negative for error
66 int IOSC_GenerateHashAsync(u8 * context, u8 * inputData, u32 inputSize, u32 chainingFlag, u8 * hashData, int message_queue_id, IOSRequest* reply); Calculate SHA1 hash of inputData. An IPC reply is sent to the message queue on completion. 0 on success
67 IOSCError IOSC_GenerateHash(u8 * context, u8 * inputData, u32 inputSize, u32 chainingFlag, u8 * hashData); Synchronous implementation of IOSC_GenerateHashAsync 0 on success
68 int IOSC_EncryptAsync(IOSCSecretKeyHandle encryptHandle, u8 * ivData, u8 * inputData, u32 inputSize, u8 * outputData, int message_queue_id, IOSRequest* reply) AES-encrypt inputSize bytes from inputData using encryptHandle and ivData (which gets updated) and write to outputData. An IPC reply is sent to the message queue on completion. 0 on success
69 IOSCError IOSC_Encrypt(IOSCSecretKeyHandle encryptHandle, u8 * ivData, u8 * inputData, u32 inputSize, u8 * outputData); Synchronous implementation of IOSC_EncryptAsync 0 on success
6a int IOSC_DecryptAsync(IOSCSecretKeyHandle decryptHandle, u8 * ivData, u8 * inputData, u32 inputSize, u8 * outputData, int message_queue_id, IOSRequest* request); AES-decrypt inputSize bytes from inputData using decryptHandle and ivData (which gets updated) and write to outputData. An IPC reply is sent to the message queue on completion. 0 on success
6b IOSCError IOSC_Decrypt(IOSCSecretKeyHandle decryptHandle, u8 * ivData, u8 * inputData, u32 inputSize, u8 * outputData); Synchronous implementation of IOSC_DecryptAsync 0 on success
6c IOSCError IOSC_VerifyPublicKeySign(u8 * inputData, u32 inputSize, IOSCPublicKeyHandle publicHandle, u8 * signData); 0 on success
6d IOSCError IOSC_GenerateBlockMAC(u8 * context, u8 * inputData, u32 inputSize, u8 * customData, u32 customDataSize, IOSCSecretKeyHandle signerHandle, u32 chainingFlag, u8 * signData); 0 on success
6e IOSCError IOSC_GenerateBlockMACAsync(u8 * context, u8 * inputData, u32 inputSize, u8 * customData, u32 customDataSize, IOSCSecretKeyHandle signerHandle, u32 chainingFlag, u8 * signData, int message_queue_id, IOSRequest* reply); Async version of IOSC_GenerateBlockMAC 0 on success
6f IOSCError IOSC_ImportCertificate(u8 * certData, IOSCPublicKeyHandle signerHandle, IOSCPublicKeyHandle publicKeyHandle); 0 on success
70 IOSCError IOSC_GetDeviceCertificate(IOSCEccSignedCert * certificate); Write 0x180 bytes of NG certificate to certificate 0 on success
71 IOSCError IOSC_SetOwnership(u32 handle, u32 users); Allow the PIDs set in mask to use this key 0 on success
72 IOSCError IOSC_GetOwnership(u32 handle, u32 * users); Get a mask of the PIDs allowed to use this key 0 on success
73 IOSCError IOSC_GenerateRand(u8 * randBytes, u32 numBytes); Write size bytes of random data to data 0 on success
74 IOSCError IOSC_GenerateKey(IOSCKeyHandle handle); Sets contents of handle to random data
75 IOSCError IOSC_GeneratePublicKeySign(u8 * hash, u32 hashLength, IOSCSecretKeyHandle signerHandle, u8 * eccSignature); Makes an ECC signature 0 on success
76 IOSCError IOSC_GenerateCertificate(IOSCSecretKeyHandle privateHandle, IOSCCertName certname, IOSCEccSignedCert * certificate); 0 on success
77 IOSCError IOSC_CheckDiHashes(u8 * destAddr, u8 * diskRdBuf, u32 h1Index, u32 h2Index, u8 * h3Ptr); can only be called from DI 0 on success, negative on error
78 IOSError SetProcessPriorities(ProcessPriority *newPriorities, u32 numProcesses) Updates the process priorities, which adjusts all of the thread priorities. Can only be called by ES. Returns 0 on success, negative on error
79 IOSError GetProcessPriorities(ProcessPriority *priorities, u32 numProcesses) Gets the current process priorities. Can only be called from ES. Returns negative on error.
7a syscall_7a
7b syscall_7b
7c syscall_7c

Syscalls (via ARM syscall instruction)

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

MOVS r0, #syscall_number
SVC 0xAB

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

ID # Internal name Description Return value
4 write(const char *string) Prints a null-terminated debug message. none.

IOSC built-in key handles

The above crypto commands use key/crypto object handles. These handles can be either from IOSC_CreateObject(which can then be initialized with IOSC_ImportSecretKey in the case of AES), or a built-in handle. The available built-in handles/ids are listed below.

Names starting with IOSC are official names which were found in the GPLed parts of IOS.

List of built-in key handles in IOS
ID Internal name Description
0 IOSC_DEV_SIGNING_KEY_HANDLE ECC-233 private key (source: xyzzy)
1 IOSC_DEV_ID_HANDLE Console ID
2 IOSC_FS_ENC_HANDLE NAND AES-128 key
3 IOSC_FS_MAC_HANDLE NAND HMAC
4 IOSC_COMMON_ENC_HANDLE Common key
5 IOSC_BACKUP_ENC_HANDLE PRNG seed (source: xyzzy)
6 IOSC_APP_ENC_HANDLE SD AES-128 key (source: xyzzy)
7 IOSC_BOOTOSVER_HANDLE boot2 version (4 bytes, updated by ES_ImportBoot with the low 32 bits from the TMD IOS title ID field)
8 IOSC_CACRLVER_HANDLE Unknown - Appears to be unused
9 IOSC_SIGNERCRLVER_HANDLE Unknown - Appears to be unused
10 IOSC_FSVER_HANDLE Unknown - Used in the FS driver - SEEPROM NAND generation?
11 IOSC_COMMON2_ENC_HANDLE Korean common key

Error codes

This list of IOS error codes should be complete for IOS59. Other codes that can technically be returned, but only indirectly (since ES makes use of the FS module and IOSC) are not included in an exhaustive manner in this list.

Error code Notes
0 No Error (Success)
-1 IPC_EACCES - Permission Denied
-2 IPC_EEXIST - File exists
-3 IPC_EINTR - Waiting operation was interrupted
-4 IPC_EINVAL - Invalid argument
-5 IPC_EMAX - Parameter was greater than a max number
-6 IPC_ENOENT - Not Found
-7 IPC_EQUEUEEMPTY - Queue is empty
-8 IPC_EQUEUEFULL - Queue is full
-9 IPC_ERETURN - noreturn function returned
-12 IPC_EIO - ECC error
-22 IPC_ENOMEM - Alloc failed during request