IOS/Syscalls
This is an old revision of this page, as edited by Comex (talk | contribs) at 02:31, 25 February 2009. It may differ significantly from the current revision. |
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 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 LOAD 0x023b5d 0xffff8a00 0xffff8a00 0x00000 0x071e8 RW 0x20
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:FFFF1894 starlet_syscall_handler ; CODE XREF: start�j kernel:FFFF1894 E9 CD 7F FF STMFA SP, {R0-LR}^ kernel:FFFF1898 E1 4F 80 00 MRS R8, SPSR kernel:FFFF189C E5 8D 80 00 STR R8, [SP,#arg_0] kernel:FFFF18A0 E5 8D E0 40 STR LR, [SP,#arg_40] kernel:FFFF18A4 E5 1E A0 04 LDR R10, [LR,#-4] kernel:FFFF18A8 E3 CA 9D 7F BIC R9, R10, #0x1FC0 kernel:FFFF18AC E5 9F 84 9C LDR R8, =0xE6000010 kernel:FFFF18B0 E3 C9 90 20 BIC R9, R9, #0x20 kernel:FFFF18B4 E1 59 00 08 CMP R9, R8 kernel:FFFF18B8 1A 00 00 1F BNE loc_FFFF193C kernel:FFFF18BC E1 A0 A2 CA MOV R10, R10,ASR#5 kernel:FFFF18C0 E2 0A A0 FF AND R10, R10, #0xFF kernel:FFFF18C4 E3 5A 00 75 CMP R10, #0x75 ; 'u' kernel:FFFF18C8 CA 00 00 11 BGT loc_FFFF1914 kernel:FFFF18CC E1 A0 80 0D MOV R8, SP kernel:FFFF18D0 E3 A0 B0 1F MOV R11, #0x1F kernel:FFFF18D4 E1 21 F0 0B MSR CPSR_c, R11 kernel:FFFF18D8 E5 98 80 44 LDR R8, [R8,#arg_44] kernel:FFFF18DC E5 9F B4 70 LDR R11, =syscall_flags_maybe kernel:FFFF18E0 E7 9B B1 0A LDR R11, [R11,R10,LSL#2] kernel:FFFF18E4 E0 8D D1 0B ADD SP, SP, R11,LSL#2 kernel:FFFF18E8 kernel:FFFF18E8 loc_FFFF18E8 ; CODE XREF: starlet_syscall_handler+68�j kernel:FFFF18E8 E3 5B 00 00 CMP R11, #0 kernel:FFFF18EC 0A 00 00 03 BEQ loc_FFFF1900 kernel:FFFF18F0 E5 3D 90 04 LDR R9, [SP,#var_4]! kernel:FFFF18F4 E5 28 90 04 STR R9, [R8,#-4]! kernel:FFFF18F8 E2 4B B0 01 SUB R11, R11, #1 kernel:FFFF18FC EA FF FF F9 B loc_FFFF18E8 kernel:FFFF1900 loc_FFFF1900 ; CODE XREF: starlet_syscall_handler+58�j kernel:FFFF1900 E1 A0 D0 08 MOV SP, R8 kernel:FFFF1904 E5 9F B4 4C LDR R11, =syscall_base kernel:FFFF1908 E7 9B B1 0A LDR R11, [R11,R10,LSL#2] kernel:FFFF190C E1 A0 E0 0F MOV LR, PC kernel:FFFF1910 E1 2F FF 1B BX R11 kernel:FFFF1914 loc_FFFF1914 ; CODE XREF: starlet_syscall_handler+34�j kernel:FFFF1914 E3 A0 B0 DB MOV R11, #0xDB ; '¦' kernel:FFFF1918 E1 21 F0 0B MSR CPSR_c, R11 kernel:FFFF191C E5 9D B0 00 LDR R11, [SP,#arg_0] kernel:FFFF1920 E1 6F F0 0B MSR SPSR_cxsf, R11 kernel:FFFF1924 E1 A0 E0 00 MOV LR, R0 kernel:FFFF1928 E9 DD 7F FF LDMED SP, {R0-LR}^ kernel:FFFF192C E1 A0 00 00 NOP kernel:FFFF1930 E1 A0 00 0E MOV R0, LR kernel:FFFF1934 E5 9D E0 40 LDR LR, [SP,#arg_40] kernel:FFFF1938 E1 B0 F0 0E MOVS PC, LR kernel:FFFF193C loc_FFFF193C ; CODE XREF: starlet_syscall_handler+24�j kernel:FFFF193C E5 9F D4 18 LDR SP, =current_thread_context kernel:FFFF1940 E5 9D D0 00 LDR SP, [SP,#arg_0] kernel:FFFF1944 E5 8D E0 40 STR LR, [SP,#arg_40] kernel:FFFF1948 E3 A0 E0 06 MOV LR, #6 kernel:FFFF194C E5 8D E0 50 STR LR, [SP,#arg_50] kernel:FFFF1950 E2 8D D0 04 ADD SP, SP, #4 kernel:FFFF1954 E9 4D 7F FF STMFD SP, {R0-LR}^ kernel:FFFF1958 E1 4F B0 00 MRS R11, SPSR kernel:FFFF195C E5 0D B0 04 STR R11, [SP,#-4+arg_0] kernel:FFFF1960 EA 00 00 C9 B schedule kernel:FFFF1960 ; 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.)
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!)
ID # | Internal name | Description | Return value |
---|---|---|---|
0 | u32 thread_create( u32 (*proc)(void* arg), u8 priority, u32* stack, u32 stacksize, void* arg, BOOL autostart) | Creates a thread | Returns threadid |
1 | thread_join | ||
2 | thread_cancel( u32 threadid, u32 ? ) | ||
3 | get_tid | ||
4 | get_pid | ||
5 | thread_continue | ||
6 | thread_stop( u32 threadid ) | ||
7 | thread_yield | ||
8 | thread_get_priority | ||
9 | thread_set_priority | ||
a | message_queue_create | ||
b | message_queue_destroy | ||
c | message_queue_send | ||
d | message_queue_send_now | ||
e | message_queue_receive | ||
f | RegisterEventHandler | ||
10 | UnregisterEventHandler | ||
11 | IOS_CreateTimer(int time, int wtf, int message_queue, int message) | ||
12 | IOS_RestartTimer | ||
13 | IOS_StopTimer | ||
14 | IOS_DestroyTimer | ||
15 | timer_now | ||
16 | heap_create | ||
17 | heap_destroy | ||
18 | heap_alloc | ||
19 | heap_alloc_aligned | ||
1a | heap_free | ||
1b | BOOL device_register(char* device, u32 messagequeue) | Registers device to the device tree, so it can be opened (from Starlet and PPC) | Returns 0 on success, else error |
1c | u32 device_open(char* device, int mode) | Similar to IOS_Open on PPC, except now internal to the IOS system | Returns an fd |
1d | device_close | ||
1e | device_read | ||
1f | device_write | ||
20 | device_seek | ||
21 | device_ioctl | ||
22 | device_ioctlv(int fd, int request, int bytes_in, int bytes_out, struct iovec *vector) | ||
23 | device_open_async | ||
24 | device_close_async | ||
25 | device_read_async | ||
26 | device_write_async | ||
27 | device_seek_async | ||
28 | device_ioctl_async | ||
29 | device_ioctlv_async | ||
2a | int IOS_ResourceReply( struct ios_ressource_request *request, int retval) | return from a cmd on a ressource | |
2b | SetUID | ||
2c | get_hmac_queue_for_pid | ||
2d | SetGID | ||
2e | lookup_GID_maybe | ||
2f | cc_ahbMemFlush | ||
30 | syscall_ahbMemFlush_wrapper | ||
31 | software_IRQ_31 | seems to enable hardware interrupts for device nr 31 | |
32 | software_irq_18 | seems to enable hardware interrupts for device nr 18 | |
33 | software_IRQ_7_or_8(id) | seems to enable hardware interrupts for device nr 7 if id==0, else device nr 8 | |
34 | software_IRQ(id) | seems to enable hardware interrupts for device nr. id | |
35 | access_iobuf_pool(arg1) | 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 | ||
3f | void sync_before_read(u32 address, u32 size) | Invalidates dcache, and something (probably related to flushing memory) | |
40 | sync_after_write | ||
41 | ppc_boot | ||
42 | ios_boot | ||
43 | syscall_43 | ||
44 | int syscall_assert_di_reset | Clears bit 10 of 0xD800194 | Returns 0 on success, -1 on error |
45 | int syscall_deassert_di_reset | Enables bit 10 of 0xD800194 | Returns 0 on success, -1 on error |
46 | BOOL syscall_check_di_reset | Checks bit 10 of 0xD800194 | Returns 1 on reset asserted, 0 on (deasserted or error) |
47 | zero_r0_r1 | ||
48 | set_r0_1_r1_0 | ||
49 | get_boot_vector | ||
4a | syscall_4a | ||
4b | kernel_debug_print | ||
4c | kernel_set_version | ||
4d | kernel_get_version | ||
4e | poke_E0_1 | ||
4f | virt_to_phys | ||
50 | syscall_50 | ||
51 | syscall_51 | ||
52 | syscall_52 | ||
53 | syscall_53 | ||
54 | syscall_54 | ||
55 | get_bc_flag | ||
56 | poke_gpios | ||
57 | syscall_57 | ||
58 | call_poke_debug_port | ||
59 | create_key | ||
5a | destroy_key | ||
5b | es_syscall_5b | ||
5c | es_syscall_5c | ||
5d | set_public_key | ||
5e | es_syscall_5e | ||
5f | es_syscall_5f | ||
60 | es_syscall_60 | ||
61 | get_keyid | ||
62 | es_syscall_62 | ||
63 | es_syscall_63 | ||
64 | sha_async | ||
65 | sha | ||
66 | aes_async | ||
67 | aes | ||
68 | es_syscall_68 | ||
69 | es_syscall_69 | ||
6a | es_syscall_6a | ||
6b | hmac | ||
6c | hmac_async | ||
6d | es_syscall_6d | ||
6e | get_ng_cert | ||
6f | key_set_permission_mask | ||
70 | es_syscall_70 | ||
71 | es_syscall_71 | ||
72 | es_syscall_72 | ||
73 | es_syscall_73 | ||
74 | es_syscall_74 | ||
75 | ?? | ||
76 | ?? |
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 syscalls are still used in distributed IOS versions:
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. | unknown. |