Difference between revisions of "IOS/Syscalls"
m |
|||
Line 261: | Line 261: | ||
| 52 || syscall_52 | | 52 || syscall_52 | ||
|- | |- | ||
− | | 53 || syscall_53 || allows | + | | 53 || syscall_53 || allows Broadway to access otherwise protected hardware (e.g. SD, NAND,...) directly. can only be called from kernel context |
|- | |- | ||
| 54 || syscall_54 | | 54 || syscall_54 |
Revision as of 23:15, 26 August 2009
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(void *ptr, int n_msgs) | ||
b | message_queue_destroy(int queue) | ||
c | message_queue_send | ||
d | message_queue_send_now | ||
e | message_queue_receive(int queue, void *message, int flags) | ||
f | RegisterEventHandler(int device, int queue, int message) | ||
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(void *ptr, int size) | ||
17 | heap_destroy(int heap) | ||
18 | heap_alloc(int heap, int size) | ||
19 | heap_alloc_aligned(int heap, int size, int align) | ||
1a | heap_free(void *ptr) | ||
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 | s32 device_open(char* device, int mode) | Similar to IOS_Open on PPC, except now internal to the IOS system | Returns an fd |
1d | s32 device_close(s32 fd) | ||
1e | s32 device_read(s32 fd, void *buf, s32 len) | ||
1f | s32 device_write(s32 fd, void *buf, s32 len) | ||
20 | s32 device_seek(s32 fd, s32 where, s32 whence) | ||
21 | s32 device_ioctl(s32 fd, u32 request, void *input_buffer, u32 input_buffer_len, void *output_buffer, u32 output_buffer_len) | ||
22 | s32 device_ioctlv(s32 fd, u32 request, u32 bytes_in, u32 bytes_out, struct iovec *vector) | ||
23 | s32 device_open_async(char* device, int mode, void *callback) | ||
24 | s32 device_close_async(s32 fd, void *callback) | ||
25 | s32 device_read_async(s32 fd, void *buf, s32 len, void *callback) | ||
26 | s32 device_write_async(s32 fd, void *buf, s32 len, void *callback) | ||
27 | s32 device_seek_async(s32 fd, s32 where, s32 whence, void *callback) | ||
28 | s32 device_ioctl_async(s32 fd, u32 request, void *input_buffer, u32 input_buffer_len, void *output_buffer, u32 output_buffer_len, void *callback | ||
29 | s32 device_ioctlv_async(s32 fd, u32 request, u32 bytes_in, u32 bytes_out, struct iovec *vector, void *callback) | ||
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 (sdhc) | |
34 | software_IRQ(id) | enables hardware interrupts for device nr. id; check caller PID | |
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(u32 address, u32 size) | Flushes dcache and does magic bullshit (aka magic AHB operations) | |
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 | GetHollywoodRevision | ||
4b | kernel_debug_print | ||
4c | kernel_set_version | ||
4d | kernel_get_version | ||
4e | poke_E0_1 | ||
4f | virt_to_phys(void *ptr) | ||
50 | syscall_50 | ||
51 | syscall_51 | ||
52 | syscall_52 | ||
53 | syscall_53 | allows Broadway to access otherwise protected hardware (e.g. SD, NAND,...) directly. can only be called from kernel context | |
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 | do_something_with_tmd | ||
5c | IOSC_DeleteObject | ||
5d | set_public_key (7 arguments) | ||
5e | crypto_syscall_5e (7 arguments) | ||
5f | crypto_syscall_5f | ||
60 | crypto_syscall_60 | ||
61 | get_keyid | ||
62 | crypto_syscall_62 | ||
63 | get_key | Used to get entries from the keyring. R0 is key index: | |
0 ECC Private Key | |||
1 Console ID | |||
2 NAND AES Key | |||
3 NAND HMAC | |||
4 Common Key | |||
5 PRNG Seed (unused?) | |||
6 SD Key | |||
7 Boot2 version | |||
8 ? | |||
9 ? | |||
10 Filesystem metadata (SFFS) generation | |||
11 "Korean Common Key" | |||
64 | sha_async | ||
65 | sha | ||
66 | aes_async (7 args) | ||
67 | aes (5 args) | ||
68 | crypto_syscall_68 (7 args) | ||
69 | crypto_syscall_69 (5 args) | ||
6a | crypto_syscall_6a (7 args) | ||
6b | aes_decrypt(int keyid, void *iv, void *in, int len, void *out) | ||
6c | hmac_async | ||
6d | crypto_syscall_6d (8 args) | ||
6e | get_ng_cert (10 args) | ||
6f | key_set_permission_mask | ||
70 | crypto_syscall_70 | ||
71 | crypto_syscall_71 | ||
72 | crypto_syscall_72 | ||
73 | crypto_syscall_73 | ||
74 | crypto_syscall_74 | ||
75 | crypto_syscall_75 | ||
76 | crypto_syscall_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. |