IOS/Syscalls

From WiiBrew
< IOS
Jump to: navigation, 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 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 PPC to access IOS-protected (right word?) hardware directly
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.