Difference between revisions of "SVC"
Line 665: | Line 665: | ||
== svcGetInfo == | == svcGetInfo == | ||
+ | |||
+ | <div style="display: inline-block;"> | ||
+ | {| class="wikitable" border="1" | ||
+ | |- | ||
+ | ! Argument || Type || Name | ||
+ | |- | ||
+ | | (In) X1 || u64 || <code>Info ID</code> | ||
+ | |- | ||
+ | | (In) X2 || u64 || <code>Handle</code> | ||
+ | |- | ||
+ | | (In) X3 || u64 || <code>Info Sub ID</code> | ||
+ | |- | ||
+ | | (Out) W0 || [[#Result]] || <code>Ret</code> | ||
+ | |- | ||
+ | | (Out) X1 || u64 || <code>Out</code> | ||
+ | |} | ||
+ | </div> | ||
+ | |||
{| class=wikitable | {| class=wikitable | ||
! Handle type || Id0 || Id1 || Description | ! Handle type || Id0 || Id1 || Description | ||
Line 706: | Line 724: | ||
== svcDumpInfo == | == svcDumpInfo == | ||
+ | |||
+ | <div style="display: inline-block;"> | ||
+ | {| class="wikitable" border="1" | ||
+ | |- | ||
+ | ! Argument || Type || Name | ||
+ | |- | ||
+ | | (In) None || || | ||
+ | |- | ||
+ | | (Out) None || || | ||
+ | |} | ||
+ | </div> | ||
+ | |||
Does nothing, just returns with registers set to all-zero. | Does nothing, just returns with registers set to all-zero. | ||
== svcReadWriteRegister == | == svcReadWriteRegister == | ||
+ | |||
+ | <div style="display: inline-block;"> | ||
+ | {| class="wikitable" border="1" | ||
+ | |- | ||
+ | ! Argument || Type || Name | ||
+ | |- | ||
+ | | (In) X1 || u64 || <code>Reg Addr</code> | ||
+ | |- | ||
+ | | (In) W2 || u64 || <code>RW Mask</code> | ||
+ | |- | ||
+ | | (In) W3 || u64 || <code>In Value</code> | ||
+ | |- | ||
+ | | (Out) W0 || [[#Result]] || <code>Ret</code> | ||
+ | |- | ||
+ | | (Out) W1|| u64 || <code>Out Value</code> | ||
+ | |} | ||
+ | </div> | ||
+ | |||
Read/write IO registers with a hardcoded whitelist. Input address is physical-address and must be aligned to 4. | Read/write IO registers with a hardcoded whitelist. Input address is physical-address and must be aligned to 4. | ||
Line 727: | Line 775: | ||
== svcCreateSharedMemory == | == svcCreateSharedMemory == | ||
+ | |||
+ | <div style="display: inline-block;"> | ||
+ | {| class="wikitable" border="1" | ||
+ | |- | ||
+ | ! Argument || Type || Name | ||
+ | |- | ||
+ | | (In) W1 || u64 || <code>Size</code> | ||
+ | |- | ||
+ | | (In) W2 || u64 || <code>My Permissions</code> | ||
+ | |- | ||
+ | | (In) W3 || u64 || <code>Other Permissions</code> | ||
+ | |- | ||
+ | | (Out) W0 || [[#Result]] || <code>Ret</code> | ||
+ | |- | ||
+ | | (Out) W1|| u64 || <code>Shared Memory Handle</code> | ||
+ | |} | ||
+ | </div> | ||
+ | |||
Other perm can be used to enforce permission 1, 3, or 0x10000000 if don't care. | Other perm can be used to enforce permission 1, 3, or 0x10000000 if don't care. | ||
== svcMapTransferMemory == | == svcMapTransferMemory == | ||
+ | |||
+ | <div style="display: inline-block;"> | ||
+ | {| class="wikitable" border="1" | ||
+ | |- | ||
+ | ! Argument || Type || Name | ||
+ | |- | ||
+ | | (In) X0 || u64 || <code>Transfer Mem Handle</code> | ||
+ | |- | ||
+ | | (In) X1 || u64 || <code>Addr</code> | ||
+ | |- | ||
+ | | (In) X2 || u64 || <code>Size</code> | ||
+ | |- | ||
+ | | (In) W3 || u64 || <code>Permissions</code> | ||
+ | |- | ||
+ | | (Out) W0 || [[#Result]] || <code>Ret</code> | ||
+ | |} | ||
+ | </div> | ||
+ | |||
The newly mapped pages will have [[#MemoryState]] type 0xE. | The newly mapped pages will have [[#MemoryState]] type 0xE. | ||
Line 735: | Line 819: | ||
== svcUnmapTransferMemory == | == svcUnmapTransferMemory == | ||
+ | |||
+ | <div style="display: inline-block;"> | ||
+ | {| class="wikitable" border="1" | ||
+ | |- | ||
+ | ! Argument || Type || Name | ||
+ | |- | ||
+ | | (In) X0 || u64 || <code>Transfer Mem Handle</code> | ||
+ | |- | ||
+ | | (In) X1 || u64 || <code>Addr</code> | ||
+ | |- | ||
+ | | (In) X2 || u64 || <code>Size</code> | ||
+ | |- | ||
+ | | (Out) W0 || [[#Result]] || <code>Ret</code> | ||
+ | |} | ||
+ | </div> | ||
+ | |||
Size must match size given in map syscall, otherwise there's an invalid-size error. | Size must match size given in map syscall, otherwise there's an invalid-size error. | ||
== svcQueryPhysicalAddress == | == svcQueryPhysicalAddress == | ||
+ | |||
+ | <div style="display: inline-block;"> | ||
+ | {| class="wikitable" border="1" | ||
+ | |- | ||
+ | ! Argument || Type || Name | ||
+ | |- | ||
+ | | (In) X1 || u64 || <code>Addr</code> | ||
+ | |- | ||
+ | | (Out) W0 || [[#Result]]|| <code>Ret</code> | ||
+ | |- | ||
+ | | (Out) X1 || u64 || <code>Out0</code> | ||
+ | |- | ||
+ | | (Out) X2 || u64 || <code>Out1</code> | ||
+ | |- | ||
+ | | (Out) X3 || u64 || <code>Out2</code> | ||
+ | |} | ||
+ | </div> | ||
+ | |||
The inverse operation of [[#svcQueryIoMapping]]. | The inverse operation of [[#svcQueryIoMapping]]. | ||
== svcQueryIoMapping == | == svcQueryIoMapping == | ||
+ | |||
+ | <div style="display: inline-block;"> | ||
+ | {| class="wikitable" border="1" | ||
+ | |- | ||
+ | ! Argument || Type || Name | ||
+ | |- | ||
+ | | (In) X1 || u64 || <code>Physical Address</code> | ||
+ | |- | ||
+ | | (In) X2 || u64 || <code>Size</code> | ||
+ | |- | ||
+ | | (Out) W0 || [[#Result]] || <code>Ret</code> | ||
+ | |- | ||
+ | | (Out) X1 || u64 || <code>Virtual Address</code> | ||
+ | |} | ||
+ | </div> | ||
+ | |||
'''Description:''' Returns a virtual address mapped to a given IO range. | '''Description:''' Returns a virtual address mapped to a given IO range. | ||
== svcCreateDeviceAddressSpace == | == svcCreateDeviceAddressSpace == | ||
+ | |||
+ | <div style="display: inline-block;"> | ||
+ | {| class="wikitable" border="1" | ||
+ | |- | ||
+ | ! Argument || Type || Name | ||
+ | |- | ||
+ | | (In) X1 || u64 || <code>Device as Start Addr</code> | ||
+ | |- | ||
+ | | (In) X2 || u64 || <code>Device as End Addr</code> | ||
+ | |- | ||
+ | | (Out) W0 || [[#Result]] || <code>Ret</code> | ||
+ | |- | ||
+ | | (Out) W1 || u64 || <code>Device as Handle</code> | ||
+ | |} | ||
+ | </div> | ||
+ | |||
'''Description:''' Creates a virtual address space for binding device address spaces and returns a handle. | '''Description:''' Creates a virtual address space for binding device address spaces and returns a handle. | ||
Line 749: | Line 899: | ||
== svcAttachDeviceAddressSpace == | == svcAttachDeviceAddressSpace == | ||
+ | |||
+ | <div style="display: inline-block;"> | ||
+ | {| class="wikitable" border="1" | ||
+ | |- | ||
+ | ! Argument || Type || Name | ||
+ | |- | ||
+ | | (In) W0 || u64 || <code>Device</code> | ||
+ | |- | ||
+ | | (In) X1 || u64 || <code>Device as Handle</code> | ||
+ | |- | ||
+ | | (Out) W0 || [[#Result]] || <code>Ret</code> | ||
+ | |} | ||
+ | </div> | ||
+ | |||
'''Description:''' Attaches a device address space to a [[#DeviceName|device]]. | '''Description:''' Attaches a device address space to a [[#DeviceName|device]]. | ||
== svcDetachDeviceAddressSpace == | == svcDetachDeviceAddressSpace == | ||
+ | |||
+ | <div style="display: inline-block;"> | ||
+ | {| class="wikitable" border="1" | ||
+ | |- | ||
+ | ! Argument || Type || Name | ||
+ | |- | ||
+ | | (In) W0 || u64 || <code>Device</code> | ||
+ | |- | ||
+ | | (In) X1 || u64 || <code>Device as Handle</code> | ||
+ | |- | ||
+ | | (Out) W0 || [[#Result]] || <code>Ret</code> | ||
+ | |} | ||
+ | </div> | ||
+ | |||
'''Description:''' Detaches a device address space from a [[#DeviceName|device]]. | '''Description:''' Detaches a device address space from a [[#DeviceName|device]]. | ||
Revision as of 06:58, 14 October 2017
System calls
Id | Name | In | Out |
---|---|---|---|
0x1 | #svcSetHeapSize | W1=size | W0=result, X1=outaddr |
0x2 | #svcSetMemoryPermission | X0=addr, X1=size, W2=prot | W0=result |
0x3 | #svcSetMemoryAttribute | X0=addr, X1=size, W2=state0, W3=state1 | W0=result |
0x4 | #svcMapMemory | X0=dstaddr, X1=srcaddr, X2=size | W0=result |
0x5 | #svcUnmapMemory | X0=dstaddr, X1=srcaddr, X2=size | W0=result |
0x6 | #svcQueryMemory | X0=MemoryInfo*, X2=addr | W0=result, W1=PageInfo |
0x7 | #svcExitProcess | None | |
0x8 | #svcCreateThread | X1=entry, X2=arg, X3=stacktop, W4=prio, W5=processor_id | W0=result, W1=handle |
0x9 | #svcStartThread | W0=thread_handle | W0=result |
0xA | #svcExitThread | None | |
0xB | #svcSleepThread | X0=nano | W0=result |
0xC | #svcGetThreadPriority | W1=thread_handle | W0=result, W1=prio |
0xD | #svcSetThreadPriority | W0=thread_handle, W1=prio | W0=result |
0xE | #svcGetThreadCoreMask | W2=thread_handle | W0=result, W1=out, X2=out |
0xF | #svcSetThreadCoreMask | W0=thread_handle, W1=in, X2=in2 | W0=result |
0x10 | #svcGetCurrentProcessorNumber | None | W0/X0=cpuid |
0x11 | svcSignalEvent | W0=wevent_handle | W0=result |
0x12 | svcClearEvent | W0=wevent_or_revent_handle | W0=result |
0x13 | #svcMapSharedMemory | W0=shmem_handle, X1=addr, X2=size, W3=perm | W0=result |
0x14 | svcUnmapSharedMemory | W0=shmem_handle, X1=addr, X2=size | W0=result |
0x15 | #svcCreateTransferMemory | X1=addr, X2=size, W3=perm | W0=result, W1=tmem_handle |
0x16 | svcCloseHandle | W0=handle | W0=result |
0x17 | svcResetSignal | W0=revent_or_process_handle | W0=result |
0x18 | #svcWaitSynchronization | X1=handles_ptr, W2=num_handles. X3=timeout | W0=result, W1=handle_idx |
0x19 | svcCancelSynchronization | W0=thread_handle | W0=result |
0x1A | svcArbitrateLock | W0=cur_thread_handle, X1=ptr, W2=req_thread_handle | |
0x1B | svcArbitrateUnlock | X0=ptr | |
0x1C | svcWaitProcessWideKeyAtomic | X0=ptr0, X1=ptr, W2=thread_handle, X3=timeout | W0=result |
0x1D | svcSignalProcessWideKey | X0=ptr, W1=value | W0=result |
0x1E | svcGetSystemTick | None | X0={value of cntpct_el0} |
0x1F | svcConnectToNamedPort | X1=port_name_str | W0=result, W1=handle |
0x20 | svcSendSyncRequestLight | W0=light_session_handle, X1=? | W0=result |
0x21 | svcSendSyncRequest | X0=normal_session_handle | W0=result |
0x22 | #svcSendSyncRequestWithUserBuffer | X0=cmdbufptr, X1=size, X2=handle | W0=result |
0x23 | svcSendAsyncRequestWithUserBuffer | X1=cmdbufptr, X2=size, X3=handle | W0=result, W1=event_handle |
0x24 | svcGetProcessId | W0=thread_or_process_or_debug_handle | W0=result, X1=pid |
0x25 | svcGetThreadId | W0=thread_handle | W0=result, X1=out |
0x26 | svcBreak | X0,X1,X2=info | ? |
0x27 | svcOutputDebugString | X0=str, X1=size | W0=result |
0x28 | svcReturnFromException | X0=result | |
0x29 | #svcGetInfo | X1=info_id, X2=handle, X3=info_sub_id | W0=result, X1=out |
0x2A | svcFlushEntireDataCache | None | None |
0x2B | svcFlushDataCache | X0=addr, X1=size | W0=result |
0x2C | [3.0.0+] svcMapPhysicalMemory | ||
0x2D | [3.0.0+] svcUnmapPhysicalMemory | ||
0x2F | svcGetLastThreadInfo | None | W0=result, W1,W2,W3,W4=unk, W5=truncated_u64, W6=bool |
0x30 | svcGetResourceLimitLimitValue | W1=reslimit_handle, W2=#LimitableResource | W0=result, X1=value |
0x31 | svcGetResourceLimitCurrentValue | W1=reslimit_handle, W2=#LimitableResource | W0=result, X1=value |
0x32 | svcSetThreadActivity | W0=thread_handle, W1=bool | W0=result |
0x33 | svcGetThreadContext3 | W0=thread_handle, W1=#ThreadContext* | W0=result |
0x3C | svcDumpInfo | ||
0x40 | svcCreateSession | W2=is_light, X3=? | W0=result, W1=client_handle, W2=server_handle |
0x41 | svcAcceptSession | W1=port_handle | W0=result, W1=session_handle |
0x42 | svcReplyAndReceiveLight | W0=light_session_handle | W0=result, W1,W2,W3,W4,W5,W6,W7=out |
0x43 | svcReplyAndReceive | X1=ptr_handles, W2=num_handles, X3=replytarget_handle(0=none), X4=timeout | W0=result, W1=handle_idx |
0x44 | svcReplyAndReceiveWithUserBuffer | X1=buf, X2=sz, X3=ptr_handles, W4=num_handles, X5=replytarget_handle(0=none), X6=timeout | W0=result, W1=handle_idx |
0x45 | svcCreateEvent | None | W0=result, W1=client_handle ?, W2=server_handle ? |
0x4D | svcSleepSystem | None | None |
0x4E | #svcReadWriteRegister | X1=reg_addr, W2=rw_mask, W3=in_val | W0=result, W1=out_val |
0x4F | svcSetProcessActivity | W0=process_handle, W1=bool | W0=result |
0x50 | #svcCreateSharedMemory | W1=size, W2=myperm, W3=otherperm | W0=result, W1=shmem_handle |
0x51 | #svcMapTransferMemory | X0=tmem_handle, X1=addr, X2=size, W3=perm | W0=result |
0x52 | #svcUnmapTransferMemory | W0=tmemhandle, X1=addr, X2=size | W0=result |
0x53 | svcCreateInterruptEvent | X1=irq_id, W2=flag | W0=result, W1=handle |
0x54 | #svcQueryPhysicalAddress | X1=addr | W0=result, X1=out0, X2=out1, X3=out2 |
0x55 | #svcQueryIoMapping | X1=physaddr, X2=size | W0=result, X1=virtaddr |
0x56 | #svcCreateDeviceAddressSpace | X1=dev_as_start_addr, X2=dev_as_end_addr | W0=result, W1=dev_as_handle |
0x57 | #svcAttachDeviceAddressSpace | W0=device, X1=dev_as_handle | W0=result |
0x58 | #svcDetachDeviceAddressSpace | W0=device, X1=dev_as_handle | W0=result |
0x59 | #svcMapDeviceAddressSpaceByForce | W0=dev_as_handle, W1=proc_handle, X2=dev_map_addr, X3=dev_as_size, X4=dev_as_addr, W5=perm | W0=result |
0x5A | #svcMapDeviceAddressSpaceAligned | W0=dev_as_handle, W1=proc_handle, X2=dev_map_addr, X3=dev_as_size, X4=dev_as_addr, W5=perm | W0=result |
0x5B | svcMapDeviceAddressSpace | ||
0x5C | #svcUnmapDeviceAddressSpace | W0=dev_as_handle, W1=proc_handle, X2=dev_map_addr, X3=dev_as_size, X4=dev_as_addr | W0=result |
0x5D | svcInvalidateProcessDataCache | W0=process_handle, X1=addr, X2=size | W0=size |
0x5E | svcStoreProcessDataCache | W0=process_handle, X1=addr, X2=size | W0=size |
0x5F | svcFlushProcessDataCache | W0=process_handle, X1=addr, X2=size | W0=size |
0x60 | svcDebugActiveProcess | X1=pid | W0=result, W1=debug_handle |
0x61 | svcBreakDebugProcess | W0=debug_handle | W0=result |
0x62 | svcTerminateDebugProcess | W0=debug_handle | W0=result |
0x63 | svcGetDebugEvent | X0=DebugEventInfo*, W1=debug_handle | W0=result |
0x64 | svcContinueDebugEvent | W0=debug_handle, W1=flags, X2=? | W0=result |
0x65 | svcGetProcessList | X1=pids_out_ptr, W2=max_out | W0=result, W1=num_out |
0x66 | svcGetThreadList | X1=tids_out_ptr, W2=max_out, W3=debug_handle_or_zero | W0=result, X1=num_out |
0x67 | svcGetDebugThreadContext | X0=ThreadContext*, X1=debug_handle, X2=?, W3=? | W0=result |
0x68 | svcSetDebugThreadContext | ||
0x69 | svcQueryDebugProcessMemory | X0=#MemoryInfo*, X2=debug_handle, X3=addr | W0=result, W1=PageInfo |
0x6A | svcReadDebugProcessMemory | X0=buffer*, X1=debug_handle, X2=src_addr, X3=size | W0=result |
0x6B | svcWriteDebugProcessMemory | X0=debug_handle, X1=buffer*, X2=dst_addr, X3=size | W0=result |
0x6C | svcSetHardwareBreakPoint | ||
0x6D | svcGetDebugThreadParam | X2=debug_handle, X3=thread_id, W4=DebugThreadParam | W0=result, X1=out0, W2=out1 |
0x70 | svcCreatePort | ||
0x71 | svcManageNamedPort | X1=name_ptr, W2=max_sessions(?) | W0=result, W1=serverport_handle |
0x72 | svcConnectToPort | W1=clientport_handle | W0=result, W1=session_handle |
0x73 | svcSetProcessMemoryPermission | X0=addr, X1=size, W2=perm | W0=result |
0x74 | #svcMapProcessMemory | X0=srcaddr, W1=process_handle, X2=dstaddr, X3=size | W0=result |
0x75 | #svcUnmapProcessMemory | W0=process_handle, X1=dstaddr, X2=srcaddr, X3=size | W0=result |
0x76 | #svcQueryProcessMemory | X0=meminfo_ptr, W2=process_handle, X3=addr | W0=result, W1=pageinfo |
0x77 | #svcMapProcessCodeMemory | W0=process_handle, X2=dstaddr, X2=srcaddr, X3=size | W0=result |
0x78 | #svcUnmapProcessCodeMemory | W0=process_handle, X1=dstaddr, X2=srcaddr, X3=size | W0=result |
0x79 | #svcCreateProcess | X1=procinfo_ptr, X2=caps_ptr, W3=cap_num | W0=result, W1=process_handle |
0x7A | svcStartProcess | W0=process_handle, W1=main_thread_prio, W2=default_cpuid, W3=main_thread_stacksz | W0=result |
0x7B | svcTerminateProcess | W0=process_handle | W0=result |
0x7C | #svcGetProcessInfo | W0=process_handle | W0=result, X1=#ProcessState |
0x7D | svcCreateResourceLimit | None | W0=result, W1=reslimit_handle |
0x7E | svcSetResourceLimitLimitValue | W0=reslimit_handle, W1=#LimitableResource, X2=value | W0=result |
0x7F | svcCallSecureMonitor |
svcSetHeapSize
Argument | Type | Name |
---|---|---|
(In) W1 | u64 | Size
|
(Out) W0 | #Result | Ret
|
(Out) X1 | u64 | OutAddr
|
Description: Set the process heap to a given Size
. It can both extend and shrink the heap.
Size
must be a multiple of 0x2000000.
On success, the heap base-address (which is fixed by kernel, aslr'd) is written to OutAddr
.
[2.0.0+] Size
must be less than 0x18000000.
svcSetMemoryPermission
Argument | Type | Name |
---|---|---|
(In) X0 | u64 | Addr
|
(In) X1 | u64 | Size
|
(In) W2 | u64 | Prot
|
(Out) W0 | #Result | Ret
|
Description: Change permission of page-aligned memory region.
Bit2 of permission (exec) is not allowed. Setting write-only is not allowed either (bit1).
This can be used to move back and forth between ---, r-- and rw-.
svcSetMemoryAttribute
Argument | Type | Name |
---|---|---|
(In) X0 | u64 | Addr
|
(In) X1 | u64 | Size
|
(In) W2 | u64 | State0
|
(In) W3 | u64 | State1
|
(Out) W0 | #Result | Ret
|
Description: Change attribute of page-aligned memory region.
This is used to turn on/off caching for a given memory area. Useful when talking to devices such as the GPU.
What happens "under the hood" is the "Memory Attribute Indirection Register" index is changed from 2 to 3 in the MMU descriptor.
State0 | State1 | Action |
---|---|---|
0 | 0 | Clear bit3 in #MemoryAttribute. |
8 | 0 | Clear bit3 in #MemoryAttribute. |
8 | 8 | Set bit3 in #MemoryAttribute. |
svcMapMemory
Argument | Type | Name |
---|---|---|
(In) X0 | u64 | Dst
|
(In) X1 | u64 | Src
|
(In) X2 | u64 | Size
|
(Out) W0 | #Result | Ret
|
Description: Maps a memory range into a different range.
Mainly used for adding guard pages around stack.
Source range gets reprotected to --- (it can no longer be accessed), and bit0 is set in the source #MemoryAttribute.
If dstaddr >= LowerTreshold, the dst-range is enforced to be within the process' "MapRegion". Code can get the range of this region from #svcGetInfo id0=2,3.
In this case, the mapped memory will have state 0x5C3C0B
.
As long as (dstaddr+size) < LowerThreshold, then you can map anywhere but the mapped memory will have state 0x482907
instead.
LowerTreshold is 0x80000000 for 36-bit address spaces, and 0x40000000 for 32-bit ones.
[2.0.0+] Support for the 0x482907
mappings outside the "MapRegion" were removed.
svcUnmapMemory
Argument | Type | Name |
---|---|---|
(In) X0 | u64 | Dst
|
(In) X1 | u64 | Src
|
(In) X2 | u64 | Size
|
(Out) W0 | #Result | Ret
|
Description: Unmaps a region that was previously mapped with #svcMapMemory.
It's possible to unmap ranges partially, you don't need to unmap the entire range "in one go".
The srcaddr/dstaddr must match what was given when the pages were originally mapped.
svcQueryMemory
Argument | Type | Name |
---|---|---|
(In) X0 | MemoryInfo* | Mem Info
|
(In) X2 | u64 | Addr
|
(Out) W0 | #Result | Ret
|
(Out) W1 | PageInfo | Page Info
|
Description: Query information about an address. Will always fetch the lowest page-aligned mapping that contains the provided address.
Outputs a #MemoryInfo struct.
svcExitProcess
Argument | Type | Name |
---|---|---|
(In) None | ||
(Out) None |
Description: Exits the current process.
svcCreateThread
Argument | Type | Name |
---|---|---|
(In) X1 | u64 | Entry
|
(In) X2 | u64 | Arg
|
(In) X3 | u64 | Stack Top
|
(In) W4 | u64 | Priority
|
(In) W5 | u64 | Processor ID
|
(Out) W0 | #Result | Ret
|
(Out) W1 | Handle | Handle
|
Description: Create a thread in the current process.
Processor_id must be 0,1,2,3 or -2, where -2 uses the default cpuid for process.
svcStartThread
Argument | Type | Name |
---|---|---|
(In) W0 | u64 | Handle
|
(Out) None |
Description: Starts the thread for the provided handle.
svcExitThread
Argument | Type | Name |
---|---|---|
(In) None | ||
(Out) None |
Description: Exits the current thread.
svcSleepThread
Argument | Type | Name |
---|---|---|
(In) X1 | u64 | Nano
|
(Out) W0 | #Result | Ret
|
Description: Sleep for a specified amount of time, or yield thread.
Setting nano=0 means "yield thread".
svcGetThreadPriority
Argument | Type | Name |
---|---|---|
(In) W1 | u64 | Handle
|
(Out) W0 | #Result | Ret
|
(Out) W1 | u64 | Priority
|
Description: Get priority of provided thread handle.
svcSetThreadPriority
Argument | Type | Name |
---|---|---|
(In) W0 | u64 | Handle
|
(In) W1 | u64 | Priority
|
(Out) W0 | #Result | Ret
|
Description: Set priority of provided thread handle.
Priority is a number 0-0x3F. Lower value means higher priority.
svcGetThreadCoreMask
Argument | Type | Name |
---|---|---|
(In) W2 | u64 | Handle
|
(Out) W0 | #Result | Ret
|
(Out) W1 | u64 | Out
|
(Out) X2 | u64 | Out
|
Description: Get affinity mask of provided thread handle.
svcSetThreadCoreMask
Argument | Type | Name |
---|---|---|
(In) W0 | u64 | Handle
|
(In) W1 | u64 | In
|
(In) X2 | u64 | In
|
(Out) W0 | #Result | Ret
|
Description: Set affinity mask of provided thread handle.
svcGetCurrentProcessorNumber
Argument | Type | Name |
---|---|---|
(In) None | ||
(Out) W0/X0 | u64 | CPU ID
|
Description: Get which cpu is executing the current thread.
Cpu-id is an integer in the range 0-3.
Argument | Type | Name |
---|---|---|
(In) W0 | u64 | Mem Block Handle
|
(In) X1 | u64 | Addr
|
(In) X2 | u64 | Size
|
(In) W3 | u64 | Permissions
|
(Out) W0 | #Result | Ret
|
Maps the block supplied by the handle. The required permissions are different for the process that created the handle and all other processes.
Increases reference count for the KSharedMemory object. Thus in order to release the memory associated with the object, all handles to it must be closed and all mappings must be unmapped.
svcCreateTransferMemory
Argument | Type | Name |
---|---|---|
(In) X1 | u64 | Addr
|
(In) X2 | u64 | Size
|
(In) W3 | u64 | Permissions
|
(Out) W0 | #Result | Ret
|
(Out) W1 | u64 | Handle
|
This one reprotects the src block with perms you give it. It also sets bit0 into #MemoryAttribute.
Executable bit perm not allowed.
Closing all handles automatically causes the bit0 in #MemoryAttribute to clear, and the permission to reset.
svcWaitSynchronization
Argument | Type | Name |
---|---|---|
(In) X1 | u64 | Handles Pointer
|
(In) W2 | u64 | Number of Handles
|
(In) X3 | u64 | Timeout
|
(Out) W0 | #Result | Ret
|
(Out) W1 | u64 | Handle Index
|
Works with num_handles <= 0x40, error on num_handles == 0.
Does not accept 0xFFFF8001 or 0xFFFF8000 as handles.
svcSendSyncRequestWithUserBuffer
Argument | Type | Name |
---|---|---|
(In) X0 | u64 | Command Buffer Pointer
|
(In) X1 | u64 | Size
|
(In) X2 | u64 | Handle
|
(Out) W0 | #Result | Ret
|
Size must be 0x1000-aligned.
svcBreak
Argument | Type | Name |
---|---|---|
(In) X0 | u64 | |
(In) X1 | u64 | |
(In) X2 | u64 | Info
|
(Out) ? | ? | ?
|
When used on retail where inx0 bit31 is clear, the system will throw a fatal-error. Otherwise when bit31 is set, it will return 0.
svcGetInfo
Argument | Type | Name |
---|---|---|
(In) X1 | u64 | Info ID
|
(In) X2 | u64 | Handle
|
(In) X3 | u64 | Info Sub ID
|
(Out) W0 | #Result | Ret
|
(Out) X1 | u64 | Out
|
Handle type | Id0 | Id1 | Description |
---|---|---|---|
Process | 0 | 0 | AllowedCpuIdBitmask |
Process | 1 | 0 | AllowedThreadPrioBitmask |
Process | 2 | 0 | ReservedMapRegionBaseAddress |
Process | 3 | 0 | ReservedMapRegionSize |
Process | 4 | 0 | ReservedHeapRegionBaseAddress |
Process | 5 | 0 | ReservedHeapRegionSize |
Process | 6 | 0 | TotalMemoryUsage |
Process | 7 | 0 | TotalHeapUsage |
Zero | 8 | 0 | IsCurrentProcessBeingDebugged |
Zero | 9 | 0 | Returns ResourceLimit handle for current process. Used by PM. |
Zero | 10 | -1, {current coreid} | Unknown. Output data changes each time this SVC is used. Global and core-specific tick-count? |
Zero | 11 | 0-3 | RandomEntropy from current process. TRNG. Used to seed usermode PRNGs. |
Process | 12 | 0 | [2.0.0+] AddressSpaceStart |
Process | 13 | 0 | [2.0.0+] AddressSpaceSize |
Process | 14 | 0 | [2.0.0+] NewReservedRegionStartAddr |
Process | 15 | 0 | [2.0.0+] NewReservedRegionSize |
Process | 18 | 0 | [3.0.0+] Title-id. |
Thread | 0xF0000002 | 0 | Performance counter related. |
svcDumpInfo
Argument | Type | Name |
---|---|---|
(In) None | ||
(Out) None |
Does nothing, just returns with registers set to all-zero.
svcReadWriteRegister
Argument | Type | Name |
---|---|---|
(In) X1 | u64 | Reg Addr
|
(In) W2 | u64 | RW Mask
|
(In) W3 | u64 | In Value
|
(Out) W0 | #Result | Ret
|
(Out) W1 | u64 | Out Value
|
Read/write IO registers with a hardcoded whitelist. Input address is physical-address and must be aligned to 4.
rw_mask is 0 for reading and 0xffffffff for writing. You can also write individual bits by using a mask value.
You can only write to registers inside physical pages 0x70019000 (MC), 0x7001C000 (MC0), 0x7001D000 (MC1), and they all share the same whitelist.
The whitelist is same for writing as for reading.
The whitelist is:
0x054, 0x090, 0x094, 0x098, 0x09c, 0x0a0, 0x0a4, 0x0a8, 0x0ac, 0x0b0, 0x0b4, 0x0b8, 0x0bc, 0x0c0, 0x0c4, 0x0c8, 0x0d0, 0x0d4, 0x0d8, 0x0dc, 0x0e0, 0x100, 0x108, 0x10c, 0x118, 0x11c, 0x124, 0x128, 0x12c, 0x130, 0x134, 0x138, 0x13c, 0x158, 0x15c, 0x164, 0x168, 0x16c, 0x170, 0x174, 0x178, 0x17c, 0x200, 0x204, 0x2e4, 0x2e8, 0x2ec, 0x2f4, 0x2f8, 0x310, 0x314, 0x320, 0x328, 0x344, 0x348, 0x370, 0x374, 0x37c, 0x380, 0x390, 0x394, 0x398, 0x3ac, 0x3b8, 0x3bc, 0x3c0, 0x3c4, 0x3d8, 0x3e8, 0x41c, 0x420, 0x424, 0x428, 0x42c, 0x430, 0x44c, 0x47c, 0x480, 0x484, 0x50c, 0x554, 0x558, 0x55c, 0x670, 0x674, 0x690, 0x694, 0x698, 0x69c, 0x6a0, 0x6a4, 0x6c0, 0x6c4, 0x6f0, 0x6f4, 0x960, 0x970, 0x974, 0xa20, 0xa24, 0xb88, 0xb8c, 0xbc4, 0xbc8, 0xbcc, 0xbd0, 0xbd4, 0xbd8, 0xbdc, 0xbe0, 0xbe4, 0xbe8, 0xbec, 0xc00, 0xc5c, 0xcac
[2.0.0+] Whitelist was extended with 0x4c4, 0x4c8, 0x4cc, 0x584, 0x588, 0x58c.
[2.0.0+] The IO registers in range 0x7000E400 (PMC) size 0xC00 skip the whitelist, and do a TrustZone call using SMC Id1 0xC3000008(ReadWriteRegister).
Argument | Type | Name |
---|---|---|
(In) W1 | u64 | Size
|
(In) W2 | u64 | My Permissions
|
(In) W3 | u64 | Other Permissions
|
(Out) W0 | #Result | Ret
|
(Out) W1 | u64 | Shared Memory Handle
|
Other perm can be used to enforce permission 1, 3, or 0x10000000 if don't care.
svcMapTransferMemory
Argument | Type | Name |
---|---|---|
(In) X0 | u64 | Transfer Mem Handle
|
(In) X1 | u64 | Addr
|
(In) X2 | u64 | Size
|
(In) W3 | u64 | Permissions
|
(Out) W0 | #Result | Ret
|
The newly mapped pages will have #MemoryState type 0xE.
You must pass same size and permissions as given in svcCreateMemoryMirror, otherwise error.
svcUnmapTransferMemory
Argument | Type | Name |
---|---|---|
(In) X0 | u64 | Transfer Mem Handle
|
(In) X1 | u64 | Addr
|
(In) X2 | u64 | Size
|
(Out) W0 | #Result | Ret
|
Size must match size given in map syscall, otherwise there's an invalid-size error.
svcQueryPhysicalAddress
Argument | Type | Name |
---|---|---|
(In) X1 | u64 | Addr
|
(Out) W0 | #Result | Ret
|
(Out) X1 | u64 | Out0
|
(Out) X2 | u64 | Out1
|
(Out) X3 | u64 | Out2
|
The inverse operation of #svcQueryIoMapping.
svcQueryIoMapping
Argument | Type | Name |
---|---|---|
(In) X1 | u64 | Physical Address
|
(In) X2 | u64 | Size
|
(Out) W0 | #Result | Ret
|
(Out) X1 | u64 | Virtual Address
|
Description: Returns a virtual address mapped to a given IO range.
svcCreateDeviceAddressSpace
Argument | Type | Name |
---|---|---|
(In) X1 | u64 | Device as Start Addr
|
(In) X2 | u64 | Device as End Addr
|
(Out) W0 | #Result | Ret
|
(Out) W1 | u64 | Device as Handle
|
Description: Creates a virtual address space for binding device address spaces and returns a handle.
dev_as_start_addr is normally set to 0 and dev_as_end_addr is normally set to 0xFFFFFFFF.
svcAttachDeviceAddressSpace
Argument | Type | Name |
---|---|---|
(In) W0 | u64 | Device
|
(In) X1 | u64 | Device as Handle
|
(Out) W0 | #Result | Ret
|
Description: Attaches a device address space to a device.
svcDetachDeviceAddressSpace
Argument | Type | Name |
---|---|---|
(In) W0 | u64 | Device
|
(In) X1 | u64 | Device as Handle
|
(Out) W0 | #Result | Ret
|
Description: Detaches a device address space from a device.
svcMapDeviceAddressSpaceByForce
Description: Maps an attached device address space to an userspace address.
dev_map_addr is the userspace destination address, while dev_as_addr is the source address between dev_as_start_addr and dev_as_end_addr (passed to #svcCreateDeviceAddressSpace).
The userspace destination address must have the MapDeviceAllowed bit set. Bit IsDeviceMapped will be set after mapping.
svcMapDeviceAddressSpaceAligned
Description: Maps an attached device address space to an userspace address.
Same as #svcMapDeviceAddressSpaceByForce, but the userspace destination address must have the MapDeviceAlignedAllowed bit set instead.
svcUnmapDeviceAddressSpace
Description: Unmaps an attached device address space from an userspace address.
svcMapProcessMemory
Maps the src address from the supplied process handle into the current process.
This allows mapping code and rodata with RW- permission.
svcUnmapProcessMemory
Unmaps what was mapped by #svcMapProcessMemory.
svcQueryProcessMemory
Equivalent to #svcQueryMemory except takes a process handle.
svcMapProcessCodeMemory
Takes a process handle, and maps normal heap in that process as executable code in that process. Used when loading NROs.
svcUnmapProcessCodeMemory
Unmaps what was mapped by #svcMapProcessCodeMemory.
svcCreateProcess
Takes a #CreateProcessInfo as input.
svcGetProcessInfo
Returns an enum with value 0-7.
Debugging
[2.0.0+] Exactly 6 debug SVCs require that IsDebugMode is non-zero. Error 0x4201 is returned otherwise.
- svcBreakDebugProcess
- svcContinueDebugEvent
- svcWriteDebugProcessMemory
- svcSetDebugThreadContext
- svcTerminateDebugProcess
- svcSetHardwareBreakPoint
svcDebugActiveProcess stops execution of the target process, the normal method for resuming it requires svcContinueDebugEvent(see above). Closing the debug handle also results in execution being resumed.
Structures
DeviceName
Value | Name |
---|---|
0 | DeviceName_AFI |
1 | DeviceName_AVPC |
2 | DeviceName_DC |
3 | DeviceName_DCB |
4 | DeviceName_HC |
5 | DeviceName_HDA |
6 | DeviceName_ISP2 |
7 | DeviceName_MSENCNVENC |
8 | DeviceName_NV |
9 | DeviceName_NV2 |
10 | DeviceName_PPCS |
11 | DeviceName_SATA |
12 | DeviceName_VI |
13 | DeviceName_VIC |
14 | DeviceName_XUSB_HOST |
15 | DeviceName_XUSB_DEV |
16 | DeviceName_TSEC |
17 | DeviceName_PPCS1 |
18 | DeviceName_DC1 |
19 | DeviceName_SDMMC1A |
20 | DeviceName_SDMMC2A |
21 | DeviceName_SDMMC3A |
22 | DeviceName_SDMMC4A |
23 | DeviceName_ISP2B |
24 | DeviceName_GPU |
25 | DeviceName_GPUB |
26 | DeviceName_PPCS2 |
27 | DeviceName_NVDEC |
28 | DeviceName_APE |
29 | DeviceName_SE |
30 | DeviceName_NVJPG |
31 | DeviceName_HC1 |
32 | DeviceName_SE1 |
33 | DeviceName_AXIAP |
34 | DeviceName_ETR |
35 | DeviceName_TSECB |
36 | DeviceName_TSEC1 |
37 | DeviceName_TSECB1 |
38 | DeviceName_NVDEC1 |
LimitableResource
Value | Name |
---|---|
0 | LimitableResource_Memory |
1 | LimitableResource_Threads |
2 | LimitableResource_Events |
3 | LimitableResource_TransferMemories |
4 | LimitableResource_Sessions |
CreateProcessInfo
Offset | Length | Bits | Description |
---|---|---|---|
0 | 12 | ProcessName (doesn't have to be null-terminated) | |
0xC | 4 | ||
0x10 | 8 | TitleId | |
0x18 | 8 | CodeAddr | |
0x20 | 4 | CodeNumPages | |
0x24 | 4 | MmuFlags | |
Bit0 | Is64bit | ||
Bit3-1 | #AddressSpaceType | ||
Bit4 | |||
Bit5 | EnableAslr | ||
Bit6 | IsSystem | ||
0x28 | 4 | ResourceLimitHandle | |
0x2C | 4 |
AddressSpaceType
Type | Name | Width | Description |
---|---|---|---|
0 | Normal_32Bit | 32 | |
1 | Normal_36Bit | 36 | |
2 | WithoutMap_32Bit | 32 | Appears to be missing map region [?] |
3 | [2.0.0+] Normal_39Bit | 39 |
MemoryInfo
Offset | Length | Description |
---|---|---|
0 | 8 | BaseAddress |
8 | 8 | Size |
0x10 | 4 | MemoryType: lower 8 bits of #MemoryState |
0x14 | 4 | #MemoryAttribute |
0x18 | 4 | Permission (bit0: R, bit1: W, bit2: X) |
0x1C | 4 | DeviceRefCount |
0x20 | 4 | IpcRefCount |
0x24 | 4 | Padding: always zero |
MemoryAttribute
Bits | Description |
---|---|
0 | IsBorrowed |
1 | IsIpcMapped: when IpcRefCount > 0. |
2 | IsDeviceMapped: when DeviceRefCount > 0. |
3 | IsUncached |
MemoryState
Bits | Description |
---|---|
7-0 | Type |
8 | PermissionChangeAllowed |
9 | IsUserWritable [?] |
10 | IpcSendAllowed_Type0 |
11 | IpcSendAllowed_Type3 |
12 | IpcSendAllowed_Type1 |
14 | ProcessPermissionChangeAllowed |
15 | MapAllowed |
16 | UnmapProcessCodeMemoryAllowed |
17 | TransferMemoryAllowed |
19 | MapDeviceAllowed (#svcMapDeviceAddressSpace and #svcMapDeviceAddressSpaceByForce) |
20 | MapDeviceAlignedAllowed |
21 | IpcBufferAllowed |
22 | IsPoolAllocated/IsReferenceCounted |
23 | MapProcessAllowed |
24 | AttributeChangeAllowed |
Value | Type | Meaning |
---|---|---|
0x00000000 |
Unmapped | |
0x00002001 |
IO | Mapped by kernel capability parsing in #svcCreateProcess. |
0x00042002 |
Normal | Mapped by kernel capability parsing in #svcCreateProcess. |
0x00DC7E03 |
Code static | Mapped during #svcCreateProcess. |
0x01FEBD04 |
Code | Transition from 0xDC7E03 performed by #svcSetProcessMemoryPermission. |
0x017EBD05 |
Heap | Mapped using #svcSetHeapSize. |
0x00402006 |
Shared memory block | Mapped using #svcMapSharedMemory. |
0x00482907 |
[1.0.0] Weird mapped memory | Mapped using #svcMapMemory. |
0x00DD7E08 |
Module code static | Mapped using #svcMapProcessCodeMemory. |
0x01FFBD09 |
Module code mutable | Transition from 0xDD7E08 performed by #svcSetProcessMemoryPermission. |
0x005C3C0A |
IPC buffers | IPC buffers with descriptor flags=0. |
0x005C3C0B |
Mapped memory | Mapped using #svcMapMemory. |
0x0040200C |
Thread local storage | Mapped during #svcCreateThread. |
0x015C3C0D |
Isolated transfer memory | Mapped using #svcMapTransferMemory when the owning process has perm=0. |
0x005C380E |
Transfer memory | Mapped using #svcMapTransferMemory when the owning process has perm!=0. |
0x0040380F |
Process memory | Mapped using #svcMapProcessMemory. |
0x00000010 |
Reserved | |
0x005C3811 |
IPC buffers | IPC buffers with descriptor flags=1. |
0x004C2812 |
IPC buffers | IPC buffers with descriptor flags=3. |
0x00002013 |
Kernel per-thread stack | Mapped in kernel during #svcCreateThread. |
Exception handling
There is userland code for handling exceptions, however this doesn't seem to be executed on retail mode.
When a usermode exception occurs, it jumps to the main code binary entrypoint (main_binary_address + 0 == _start).
During normal boot _start is invoked with X0=0 and X1=main_thread_handle (triggering normal crt0 setup). During an usermode exception _start is invoked with X0=exception_info0_ptr and X1=exception_info1_ptr instead.
The _start method determines whether to boot normally or handle an exception if X0 is set to 0 or not.