Difference between revisions of "SVC"

From Nintendo Switch Brew
Jump to navigation Jump to search
(→‎Object types: KThread)
 
(120 intermediate revisions by 12 users not shown)
Line 3: Line 3:
 
= System calls =
 
= System calls =
 
{| class=wikitable
 
{| class=wikitable
! Id || Name || In || Out
+
! ID || Return Type || Name || Arguments
 
|-
 
|-
| 0x1 || [[#svcSetHeapSize]] || W1=size || W0=result, X1=outaddr
+
| 0x01 || Result || [[#SetHeapSize|SetHeapSize]] || uintptr_t *out_address, size_t size
 
|-
 
|-
| 0x2 || [[#svcSetMemoryPermission]] || X0=addr, X1=size, W2=prot || W0=result
+
| 0x02 || Result || [[#SetMemoryPermission|SetMemoryPermission]] || uintptr_t address, size_t size, MemoryPermission perm
 
|-
 
|-
| 0x3 || [[#svcSetMemoryAttribute]] || X0=addr, X1=size, W2=state0, W3=state1 || W0=result
+
| 0x03 || Result || [[#SetMemoryAttribute|SetMemoryAttribute]] || uintptr_t address, size_t size, uint32_t mask, uint32_t attr
 
|-
 
|-
| 0x4 || [[#svcMapMemory]] || X0=dstaddr, X1=srcaddr, X2=size || W0=result
+
| 0x04 || Result || [[#MapMemory|MapMemory]] || uintptr_t dst_address, uintptr_t src_address, size_t size
 
|-
 
|-
| 0x5 || [[#svcUnmapMemory]] || X0=dstaddr, X1=srcaddr, X2=size || W0=result
+
| 0x05 || Result || [[#UnmapMemory|UnmapMemory]] || uintptr_t dst_address, uintptr_t src_address, size_t size
 
|-
 
|-
| 0x6 || [[#svcQueryMemory]] || X0=MemoryInfo*, X2=addr || W0=result, W1=PageInfo                                                       
+
| 0x06 || Result || [[#QueryMemory|QueryMemory]] || arch::MemoryInfo *out_memory_info, PageInfo *out_page_info, uintptr_t address
 
|-
 
|-
| 0x7 || [[#svcExitProcess]] || None ||
+
| 0x07 || void || [[#ExitProcess|ExitProcess]] ||  
 
|-
 
|-
| 0x8 || [[#svcCreateThread]] || X1=entry, X2=thread_context, X3=stacktop, W4=prio, W5=processor_id  || W0=result, W1=handle
+
| 0x08 || Result || [[#CreateThread|CreateThread]] || Handle *out_handle, ThreadFunc func, uintptr_t arg, uintptr_t stack_bottom, int32_t priority, int32_t core_id
 
|-
 
|-
| 0x9 || [[#svcStartThread]] || W0=thread_handle || W0=result
+
| 0x09 || Result || [[#StartThread|StartThread]] || Handle thread_handle
 
|-
 
|-
| 0xA || [[#svcExitThread]] || None ||                                                       
+
| 0x0A || void || [[#ExitThread|ExitThread]] ||  
 
|-
 
|-
| 0xB || [[#svcSleepThread]] || X0=nano || W0=result
+
| 0x0B || void || [[#SleepThread|SleepThread]] || int64_t ns
 
|-
 
|-
| 0xC || [[#svcGetThreadPriority]] || W1=thread_handle || W0=result, W1=prio
+
| 0x0C || Result || [[#GetThreadPriority|GetThreadPriority]] || int32_t *out_priority, Handle thread_handle
 
|-
 
|-
| 0xD || [[#svcSetThreadPriority]] || W0=thread_handle, W1=prio || W0=result
+
| 0x0D || Result || [[#SetThreadPriority|SetThreadPriority]] || Handle thread_handle, int32_t priority
 
|-
 
|-
| 0xE || [[#svcGetThreadCoreMask]] || W2=thread_handle || W0=result, W1=out, X2=out
+
| 0x0E || Result || [[#GetThreadCoreMask|GetThreadCoreMask]] || int32_t *out_core_id, uint64_t *out_affinity_mask, Handle thread_handle
 
|-
 
|-
| 0xF || [[#svcSetThreadCoreMask]] || W0=thread_handle, W1=in, X2=in2 || W0=result
+
| 0x0F || Result || [[#SetThreadCoreMask|SetThreadCoreMask]] || Handle thread_handle, int32_t core_id, uint64_t affinity_mask
 
|-
 
|-
| 0x10 || [[#svcGetCurrentProcessorNumber]] || None || W0/X0=cpuid
+
| 0x10 || int32_t || [[#GetCurrentProcessorNumber|GetCurrentProcessorNumber]] ||  
 
|-
 
|-
| 0x11 || svcSignalEvent || W0=wevent_handle || W0=result
+
| 0x11 || Result || [[#SignalEvent|SignalEvent]] || Handle event_handle
 
|-
 
|-
| 0x12 || svcClearEvent || W0=wevent_or_revent_handle || W0=result
+
| 0x12 || Result || [[#ClearEvent|ClearEvent]] || Handle event_handle
 
|-
 
|-
| 0x13 || [[#svcMapSharedMemory]] || W0=shmem_handle, X1=addr, X2=size, W3=perm || W0=result
+
| 0x13 || Result || [[#MapSharedMemory|MapSharedMemory]] || Handle shmem_handle, uintptr_t address, size_t size, MemoryPermission map_perm
 
|-
 
|-
| 0x14 || svcUnmapSharedMemory || W0=shmem_handle, X1=addr, X2=size || W0=result                                               
+
| 0x14 || Result || [[#UnmapSharedMemory|UnmapSharedMemory]] || Handle shmem_handle, uintptr_t address, size_t size
 
|-
 
|-
| 0x15 || [[#svcCreateTransferMemory]] || X1=addr, X2=size, W3=perm || W0=result, W1=tmem_handle
+
| 0x15 || Result || [[#CreateTransferMemory|CreateTransferMemory]] || Handle *out_handle, uintptr_t address, size_t size, MemoryPermission map_perm
 
|-
 
|-
| 0x16 || svcCloseHandle || W0=handle || W0=result
+
| 0x16 || Result || [[#CloseHandle|CloseHandle]] || Handle handle
 
|-
 
|-
| 0x17 || svcResetSignal || W0=revent_or_process_handle || W0=result
+
| 0x17 || Result || [[#ResetSignal|ResetSignal]] || Handle handle
 
|-
 
|-
| 0x18 || [[#svcWaitSynchronization]] || X1=handles_ptr, W2=num_handles. X3=timeout || W0=result, W1=handle_idx
+
| 0x18 || Result || [[#WaitSynchronization|WaitSynchronization]] || int32_t *out_index, const Handle *handles, int32_t numHandles, int64_t timeout_ns
 
|-
 
|-
| 0x19 || [[#svcCancelSynchronization]] || W0=thread_handle || W0=result
+
| 0x19 || Result || [[#CancelSynchronization|CancelSynchronization]] || Handle handle
 
|-
 
|-
| 0x1A || svcArbitrateLock || W0=cur_thread_handle, X1=ptr, W2=req_thread_handle ||                                   
+
| 0x1A || Result || [[#ArbitrateLock|ArbitrateLock]] || Handle thread_handle, uintptr_t address, uint32_t tag
 
|-
 
|-
| 0x1B || svcArbitrateUnlock || X0=ptr ||
+
| 0x1B || Result || [[#ArbitrateUnlock|ArbitrateUnlock]] || uintptr_t address
 
|-
 
|-
| 0x1C || svcWaitProcessWideKeyAtomic || X0=ptr0, X1=ptr, W2=thread_handle, X3=timeout || W0=result
+
| 0x1C || Result || [[#WaitProcessWideKeyAtomic|WaitProcessWideKeyAtomic]] || uintptr_t address, uintptr_t cv_key, uint32_t tag, int64_t timeout_ns
 
|-
 
|-
| 0x1D || svcSignalProcessWideKey || X0=ptr, W1=value || W0=result
+
| 0x1D || void || [[#SignalProcessWideKey|SignalProcessWideKey]] || uintptr_t cv_key, int32_t count
 
|-
 
|-
| 0x1E || [[#svcGetSystemTick]] || None || X0={value of cntpct_el0}
+
| 0x1E || int64_t || [[#GetSystemTick|GetSystemTick]] ||  
 
|-
 
|-
| 0x1F || svcConnectToNamedPort || X1=port_name_str || W0=result, W1=handle
+
| 0x1F || Result || [[#ConnectToNamedPort|ConnectToNamedPort]] || Handle *out_handle, const char *name
 
|-
 
|-
| 0x20 || svcSendSyncRequestLight || W0=light_session_handle, X1=? || W0=result
+
| 0x20 || Result || [[#SendSyncRequestLight|SendSyncRequestLight]] || Handle session_handle
 
|-
 
|-
| 0x21 || svcSendSyncRequest || X0=normal_session_handle || W0=result
+
| 0x21 || Result || [[#SendSyncRequest|SendSyncRequest]] || Handle session_handle
 
|-
 
|-
| 0x22 || [[#svcSendSyncRequestWithUserBuffer]] || X0=cmdbufptr, X1=size, X2=handle || W0=result
+
| 0x22 || Result || [[#SendSyncRequestWithUserBuffer|SendSyncRequestWithUserBuffer]] || uintptr_t message_buffer, size_t message_buffer_size, Handle session_handle
 
|-
 
|-
| 0x23 || svcSendAsyncRequestWithUserBuffer || X1=cmdbufptr, X2=size, X3=handle || W0=result, W1=revent_handle
+
| 0x23 || Result || [[#SendAsyncRequestWithUserBuffer|SendAsyncRequestWithUserBuffer]] || Handle *out_event_handle, uintptr_t message_buffer, size_t message_buffer_size, Handle session_handle
 
|-
 
|-
| 0x24 || svcGetProcessId || W1=thread_or_process_or_debug_handle || W0=result, X1=pid
+
| 0x24 || Result || [[#GetProcessId|GetProcessId]] || uint64_t *out_process_id, Handle process_handle
 
|-
 
|-
| 0x25 || svcGetThreadId || W1=thread_handle || W0=result, X1=out
+
| 0x25 || Result || [[#GetThreadId|GetThreadId]] || uint64_t *out_thread_id, Handle thread_handle
 
|-
 
|-
| 0x26 || [[#svcBreak]] || X0=break_reason,X1,X2=info || W0=result = 0
+
| 0x26 || void || [[#Break|Break]] || BreakReason break_reason, uintptr_t arg, size_t size
 
|-
 
|-
| 0x27 || svcOutputDebugString || X0=str, X1=size || W0=result
+
| 0x27 || Result || [[#OutputDebugString|OutputDebugString]] || const char *debug_str, size_t len
 
|-
 
|-
| 0x28 || svcReturnFromException || X0=result ||  
+
| 0x28 || void || [[#ReturnFromException|ReturnFromException]] || Result result
 
|-
 
|-
| 0x29 || [[#svcGetInfo]] || X1=info_id, X2=handle, X3=info_sub_id || W0=result, X1=out
+
| 0x29 || Result || [[#GetInfo|GetInfo]] || uint64_t *out, InfoType info_type, Handle handle, uint64_t info_subtype
 
|-
 
|-
| 0x2A || svcFlushEntireDataCache || None || None
+
| 0x2A || void || [[#FlushEntireDataCache|FlushEntireDataCache]] ||  
 
|-
 
|-
| 0x2B || svcFlushDataCache || X0=addr, X1=size || W0=result
+
| 0x2B || Result || [[#FlushDataCache|FlushDataCache]] || uintptr_t address, size_t size
 
|-
 
|-
| 0x2C || [3.0.0+] [[#svcMapPhysicalMemory]] || X0=addr, X1=size || W0=result
+
| [3.0.0+] 0x2C  || Result || [[#MapPhysicalMemory|MapPhysicalMemory]] || uintptr_t address, size_t size
 
|-
 
|-
| 0x2D || [3.0.0+] svcUnmapPhysicalMemory || X0=addr, X1=size || W0=result
+
| [3.0.0+] 0x2D  || Result || [[#UnmapPhysicalMemory|UnmapPhysicalMemory]] || uintptr_t address, size_t size
 
|-
 
|-
| 0x2E || [5.0.0+] svcGetFutureThreadInfo || X3=timeout || W0=result, bunch of crap
+
| [5.0.0-5.1.0] 0x2E  || Result || GetFutureThreadInfo || arch::LastThreadContext *out_context, uintptr_t *out_tls_address, uint32_t *out_flags, int64_t ns
 
|-
 
|-
| 0x2F || svcGetLastThreadInfo || None || W0=result, W1,W2,W3,W4=unk, W5=truncated_u64, W6=bool
+
| [6.0.0+] 0x2E  || Result || [[#GetDebugFutureThreadInfo|GetDebugFutureThreadInfo]] || arch::LastThreadContext *out_context, uint64_t *thread_id, Handle debug_handle, int64_t ns
 
|-
 
|-
| 0x30 || svcGetResourceLimitLimitValue || W1=reslimit_handle, W2=[[#LimitableResource]] || W0=result, X1=value
+
| 0x2F || Result || [[#GetLastThreadInfo|GetLastThreadInfo]] || arch::LastThreadContext *out_context, uintptr_t *out_tls_address, uint32_t *out_flags
 
|-
 
|-
| 0x31 || svcGetResourceLimitCurrentValue || W1=reslimit_handle, W2=[[#LimitableResource]] || W0=result, X1=value
+
| 0x30 || Result || [[#GetResourceLimitLimitValue|GetResourceLimitLimitValue]] || int64_t *out_limit_value, Handle resource_limit_handle, LimitableResource which
 
|-
 
|-
| 0x32 || svcSetThreadActivity || W0=thread_handle, W1=bool || W0=result
+
| 0x31 || Result || [[#GetResourceLimitCurrentValue|GetResourceLimitCurrentValue]] || int64_t *out_current_value, Handle resource_limit_handle, LimitableResource which
 
|-
 
|-
| 0x33 || svcGetThreadContext3 || X0=[[#ThreadContext]]*, W1=thread_handle || W0=result
+
| 0x32 || Result || [[#SetThreadActivity|SetThreadActivity]] || Handle thread_handle, ThreadActivity thread_activity
 
|-
 
|-
| 0x34 || [4.0.0+] svcWaitForAddress || X0=ptr, W1=[[#ArbitrationType]], X2=value X3=timeout ||
+
| 0x33  || Result || [[#GetThreadContext3|GetThreadContext3]] || ThreadContext *out_context, Handle thread_handle
 
|-
 
|-
| 0x35 || [4.0.0+] svcSignalToAddress || X0=ptr, W1=[[#SignalType]], X2=value W3=num_to_signal ||
+
| [4.0.0+] 0x34 || Result || [[#WaitForAddress|WaitForAddress]] || uintptr_t address, ArbitrationType arb_type, int32_t value, int64_t timeout_ns
 +
|-
 +
| [4.0.0+] 0x35 || Result || [[#SignalToAddress|SignalToAddress]] || uintptr_t address, SignalType signal_type, int32_t value, int32_t count
 +
|-
 +
| [8.0.0+] 0x36 || void || [[#SynchronizePreemptionState|SynchronizePreemptionState]] ||
 +
|-
 +
| [11.0.0+] 0x37 || Result || [[#GetResourceLimitPeakValue|GetResourceLimitPeakValue]] || int64_t *out_peak_value, Handle resource_limit_handle, LimitableResource which
 +
|- style="border-top: double"
 +
| [13.0.0+] 0x39 || Result || CreateIoPool || Handle *out_handle, IoPoolType which_pool
 +
|-
 +
| [13.0.0+] 0x3A || Result || CreateIoRegion || Handle *out_handle, Handle io_pool, PhysicalAddress physical_address, size_t size, MemoryMapping mapping, MemoryPermission perm
 
|- style="border-top: double"
 
|- style="border-top: double"
| 0x3C || [[#svcDumpInfo]] || ||
+
| [1.0.0-3.0.2] 0x3C || void || [[#DumpInfo|DumpInfo]] || DumpInfoType dump_info_type, uint64_t arg
 +
|-
 +
| [4.0.0+] 0x3C || void || [[#KernelDebug|KernelDebug]] || KernelDebugType kern_debug_type, uint64_t arg0, uint64_t arg1, uint64_t arg2
 
|-
 
|-
| 0x3D || [4.0.0+] svcDumpInfoNew || ||
+
| [4.0.0+] 0x3D || void || [[#ChangeKernelTraceState|ChangeKernelTraceState]] || KernelTraceState kern_trace_state
 
|- style="border-top: double"
 
|- style="border-top: double"
| 0x40 || svcCreateSession || W2=is_light, X3=? || W0=result, W1=server_handle, W2=client_handle
+
| 0x40 || Result || [[#CreateSession|CreateSession]] || Handle *out_server_session_handle, Handle *out_client_session_handle, bool is_light, uintptr_t name
 +
|-
 +
| 0x41 || Result || [[#AcceptSession|AcceptSession]] || Handle *out_handle, Handle port
 
|-
 
|-
| 0x41 || [[#svcAcceptSession]] || W1=port_handle || W0=result, W1=session_handle
+
| 0x42 || Result || [[#ReplyAndReceiveLight|ReplyAndReceiveLight]] || Handle handle
 
|-
 
|-
| 0x42 || svcReplyAndReceiveLight || W0=light_session_handle || W0=result, W1,W2,W3,W4,W5,W6,W7=out
+
| 0x43 || Result || [[#ReplyAndReceive|ReplyAndReceive]] || int32_t *out_index, const Handle *handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns
 
|-
 
|-
| 0x43 || [[#svcReplyAndReceive]] || X1=ptr_handles, W2=num_handles, X3=replytarget_handle(0=none), X4=timeout || W0=result, W1=handle_idx
+
| 0x44 || Result || [[#ReplyAndReceiveWithUserBuffer|ReplyAndReceiveWithUserBuffer]] || int32_t *out_index, uintptr_t message_buffer, size_t message_buffer_size, const Handle *handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns
 
|-
 
|-
| 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 || Result || [[#CreateEvent|CreateEvent]] || Handle *out_write_handle, Handle *out_read_handle
 
|-
 
|-
| 0x45 || svcCreateEvent || None || W0=result, W1=wevent_handle, W2=revent_handle
+
| [13.0.0+] 0x46 || Result || MapIoRegion || Handle io_region, uintptr_t address, size_t size, MemoryPermission perm
|- style="border-top: double"
+
|-
| 0x48 || [5.0.0+] [[#svcMapPhysicalMemoryUnsafe]] || X0=addr, X1=size || W0=result
+
| [13.0.0+] 0x47 || Result || UnmapIoRegion || Handle io_region, uintptr_t address, size_t size
 +
|-
 +
| [5.0.0+] 0x48 || Result || [[#MapPhysicalMemoryUnsafe|MapPhysicalMemoryUnsafe]] || uintptr_t address, size_t size
 +
|-
 +
| [5.0.0+] 0x49 || Result || [[#UnmapPhysicalMemoryUnsafe|UnmapPhysicalMemoryUnsafe]] || uintptr_t address, size_t size
 
|-
 
|-
| 0x49 || [5.0.0+] svcUnmapPhysicalMemoryUnsafe || X0=addr, X1=size || W0=result
+
| [5.0.0+] 0x4A || Result || [[#SetUnsafeLimit|SetUnsafeLimit]] || size_t limit
 
|-
 
|-
| 0x4A || [5.0.0+] svcSetUnsafeLimit || X0=size || W0=result
+
| [4.0.0+] 0x4B || Result || [[#CreateCodeMemory|CreateCodeMemory]] || Handle *out_handle, uintptr_t address, size_t size
 
|-
 
|-
| 0x4B || [4.0.0+] [[#svcCreateCodeMemory]] || X1=addr, X2=size || W0=result, W1=code_memory_handle
+
| [4.0.0+] 0x4C || Result || [[#ControlCodeMemory|ControlCodeMemory]] || Handle code_memory_handle, CodeMemoryOperation operation, uint64_t address, uint64_t size, MemoryPermission perm
 
|-
 
|-
| 0x4C || [4.0.0+] [[#svcControlCodeMemory]] || W0=code_memory_handle, W1=[[#CodeMemoryOperation]], X2=dstaddr, X3=size, W4=perm || W0=result
+
| 0x4D || void || [[#SleepSystem|SleepSystem]] ||  
 
|-
 
|-
| 0x4D || svcSleepSystem || None || None
+
| 0x4E || Result || [[#ReadWriteRegister|ReadWriteRegister]] || uint32_t *out_value, PhysicalAddress address, uint32_t mask, uint32_t value
 
|-
 
|-
| 0x4E || [[#svcReadWriteRegister]] || X1=reg_addr, W2=rw_mask, W3=in_val || W0=result, W1=out_val
+
| 0x4F || Result || [[#SetProcessActivity|SetProcessActivity]] || Handle process_handle, ProcessActivity process_activity
 
|-
 
|-
| 0x4F || svcSetProcessActivity || W0=process_handle, W1=bool || W0=result
+
| 0x50 || Result || [[#CreateSharedMemory|CreateSharedMemory]] || Handle *out_handle, size_t size, MemoryPermission owner_perm, MemoryPermission remote_perm
 
|-
 
|-
| 0x50 || [[#svcCreateSharedMemory]] || W1=size, W2=myperm, W3=otherperm || W0=result, W1=shmem_handle
+
| 0x51 || Result || [[#MapTransferMemory|MapTransferMemory]] || Handle trmem_handle, uintptr_t address, size_t size, MemoryPermission owner_perm
 
|-
 
|-
| 0x51 || [[#svcMapTransferMemory]] || X0=tmem_handle, X1=addr, X2=size, W3=perm || W0=result
+
| 0x52 || Result || [[#UnmapTransferMemory|UnmapTransferMemory]] || Handle trmem_handle, uintptr_t address, size_t size
 
|-
 
|-
| 0x52 || [[#svcUnmapTransferMemory]] || W0=tmemhandle, X1=addr, X2=size || W0=result
+
| 0x53 || Result || [[#CreateInterruptEvent|CreateInterruptEvent]] || Handle *out_read_handle, int32_t interrupt_id, InterruptType interrupt_type
 
|-
 
|-
| 0x53 || svcCreateInterruptEvent || X1=irq_num, W2=flag || W0=result, W1=handle
+
| 0x54 || Result || [[#QueryPhysicalAddress|QueryPhysicalAddress]] || arch::PhysicalMemoryInfo *out_info, uintptr_t address
 
|-
 
|-
| 0x54 || [[#svcQueryPhysicalAddress]] || X1=addr || W0=result, X1=physaddr, X2=kerneladdr, X3=size
+
| [1.0.0-9.2.0] 0x55 || Result || [[#QueryIoMapping|QueryIoMapping]] || uintptr_t *out_address, PhysicalAddress physical_address, size_t size
 
|-
 
|-
| 0x55 || [[#svcQueryIoMapping]] || X1=physaddr, X2=size || W0=result, X1=virtaddr
+
| [10.0.0+] 0x55 || Result || QueryMemoryMapping || uintptr_t *out_address, size_t *out_size, PhysicalAddress physical_address, size_t size
 
|-
 
|-
| 0x56 || [[#svcCreateDeviceAddressSpace]] || X1=dev_as_start_addr, X2=dev_as_end_addr || W0=result, W1=dev_as_handle
+
| 0x56 || Result || [[#CreateDeviceAddressSpace|CreateDeviceAddressSpace]] || Handle *out_handle, uint64_t das_address, uint64_t das_size
 
|-
 
|-
| 0x57 || [[#svcAttachDeviceAddressSpace]] || W0=device, X1=dev_as_handle || W0=result
+
| 0x57 || Result || [[#AttachDeviceAddressSpace|AttachDeviceAddressSpace]] || DeviceName device_name, Handle das_handle
 
|-
 
|-
| 0x58 || [[#svcDetachDeviceAddressSpace]] || W0=device, X1=dev_as_handle || W0=result
+
| 0x58 || Result || [[#DetachDeviceAddressSpace|DetachDeviceAddressSpace]] || DeviceName device_name, Handle das_handle
 
|-
 
|-
| 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
+
| 0x59 || Result || [[#MapDeviceAddressSpaceByForce|MapDeviceAddressSpaceByForce]] || Handle das_handle, Handle process_handle, uint64_t process_address, size_t size, uint64_t device_address, uint32_t option
 
|-
 
|-
| 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
+
| 0x5A || Result || [[#MapDeviceAddressSpaceAligned|MapDeviceAddressSpaceAligned]] || Handle das_handle, Handle process_handle, uint64_t process_address, size_t size, uint64_t device_address, uint32_t option
 
|-
 
|-
| 0x5B || svcMapDeviceAddressSpace || ||  
+
| [1.0.0-12.1.0] 0x5B || Result || [[#MapDeviceAddressSpace|MapDeviceAddressSpace]] || size_t *out_mapped_size, Handle das_handle, Handle process_handle, uint64_t process_address, size_t size, uint64_t device_address, MemoryPermission device_perm
 
|-
 
|-
| 0x5C || [[#svcUnmapDeviceAddressSpace]] || W0=dev_as_handle, W1=proc_handle, X2=dev_map_addr, X3=dev_as_size, X4=dev_as_addr || W0=result
+
| 0x5C || Result || [[#UnmapDeviceAddressSpace|UnmapDeviceAddressSpace]] || Handle das_handle, Handle process_handle, uint64_t process_address, size_t size, uint64_t device_address
 
|-
 
|-
| 0x5D || svcInvalidateProcessDataCache || W0=process_handle, X1=addr, X2=size || W0=size
+
| 0x5D || Result || [[#InvalidateProcessDataCache|InvalidateProcessDataCache]] || Handle process_handle, uint64_t address, uint64_t size
 
|-
 
|-
| 0x5E || svcStoreProcessDataCache || W0=process_handle, X1=addr, X2=size || W0=size
+
| 0x5E || Result || [[#StoreProcessDataCache|StoreProcessDataCache]] || Handle process_handle, uint64_t address, uint64_t size
 
|-
 
|-
| 0x5F || svcFlushProcessDataCache || W0=process_handle, X1=addr, X2=size || W0=size
+
| 0x5F || Result || [[#FlushProcessDataCache|FlushProcessDataCache]] || Handle process_handle, uint64_t address, uint64_t size
 
|-
 
|-
| 0x60 || svcDebugActiveProcess || X1=pid || W0=result, W1=debug_handle
+
| 0x60 || Result || [[#DebugActiveProcess|DebugActiveProcess]] || Handle *out_handle, uint64_t process_id
 
|-
 
|-
| 0x61 || svcBreakDebugProcess || W0=debug_handle || W0=result
+
| 0x61 || Result || [[#BreakDebugProcess|BreakDebugProcess]] || Handle debug_handle
 
|-
 
|-
| 0x62 || svcTerminateDebugProcess || W0=debug_handle || W0=result
+
| 0x62 || Result || [[#TerminateDebugProcess|TerminateDebugProcess]] || Handle debug_handle
 
|-
 
|-
| 0x63 || svcGetDebugEvent || X0=[[#DebugEventInfo]]*, W1=debug_handle || W0=result
+
| 0x63 || Result || [[#GetDebugEvent|GetDebugEvent]] || arch::DebugEventInfo *out_info, Handle debug_handle
 
|-
 
|-
| 0x64 || svcContinueDebugEvent || [1.0.0-2.3.0] W0=debug_handle, W1=[[#ContinueDebugFlagsOld]], X2=thread_id
+
| 0x64 || Result || [[#ContinueDebugEvent|ContinueDebugEvent]] || Handle debug_handle, uint32_t flags, const uint64_t *thread_ids, int32_t num_thread_ids
[3.0.0+] W0=debug_handle, W1=[[#ContinueDebugFlags]], X2=thread_id_list(u64 *), W3=num_tids (max 64, 0 means "all threads")
 
|| W0=result
 
 
|-
 
|-
| 0x65 || svcGetProcessList || X1=pids_out_ptr, W2=max_out || W0=result, W1=num_out
+
| 0x65 || Result || [[#GetProcessList|GetProcessList]] || int32_t *out_num_processes, uint64_t *out_process_ids, int32_t max_out_count
 
|-
 
|-
| 0x66 || svcGetThreadList || X1=tids_out_ptr, W2=max_out, W3=debug_handle_or_zero || W0=result, X1=num_out
+
| 0x66 || Result || [[#GetThreadList|GetThreadList]] || int32_t *out_num_threads, uint64_t *out_thread_ids, int32_t max_out_count, Handle debug_handle
 
|-
 
|-
| 0x67 || svcGetDebugThreadContext || X0=ThreadContext*, X1=debug_handle, X2=thread_id, W3=[[#ThreadContextFlags]] || W0=result
+
| 0x67 || Result || [[#GetDebugThreadContext|GetDebugThreadContext]] || ThreadContext *out_context, Handle debug_handle, uint64_t thread_id, uint32_t context_flags
 
|-
 
|-
| 0x68 || svcSetDebugThreadContext || W0=debug_handle, W1=[[#ThreadContextFlags]], X2=ThreadContext*, X3=thread_id || W0=result
+
| 0x68 || Result || [[#SetDebugThreadContext|SetDebugThreadContext]] || Handle debug_handle, uint64_t thread_id, const ThreadContext *context, uint32_t context_flags
 
|-
 
|-
| 0x69 || svcQueryDebugProcessMemory || X0=[[#MemoryInfo]]*, X2=debug_handle, X3=addr || W0=result, W1=PageInfo
+
| 0x69 || Result || [[#QueryDebugProcessMemory|QueryDebugProcessMemory]] || arch::MemoryInfo *out_memory_info, PageInfo *out_page_info, Handle process_handle, uintptr_t address
 
|-
 
|-
| 0x6A || svcReadDebugProcessMemory || X0=buffer*, X1=debug_handle, X2=src_addr, X3=size || W0=result
+
| 0x6A || Result || [[#ReadDebugProcessMemory|ReadDebugProcessMemory]] || uintptr_t buffer, Handle debug_handle, uintptr_t address, size_t size
 
|-
 
|-
| 0x6B || svcWriteDebugProcessMemory || X0=debug_handle, X1=buffer*, X2=dst_addr, X3=size || W0=result
+
| 0x6B || Result || [[#WriteDebugProcessMemory|WriteDebugProcessMemory]] || Handle debug_handle, uintptr_t buffer, uintptr_t address, size_t size
 
|-
 
|-
| 0x6C || [[#svcSetHardwareBreakPoint]] || W0=HardwareBreakpointId, X1=watchpoint_flags/breakpoint_flags, X2=watchpoint_value/debug_handle ||
+
| 0x6C || Result || [[#SetHardwareBreakPoint|SetHardwareBreakPoint]] || HardwareBreakPointRegisterName name, uint64_t flags, uint64_t value
 
|-
 
|-
| 0x6D || svcGetDebugThreadParam || X2=debug_handle, X3=thread_id, W4=[[#DebugThreadParam]] || W0=result, X1=out0, W2=out1
+
| 0x6D || Result || [[#GetDebugThreadParam|GetDebugThreadParam]] || uint64_t *out_64, uint32_t *out_32, Handle debug_handle, uint64_t thread_id, DebugThreadParam param
 
|- style="border-top: double"
 
|- style="border-top: double"
| 0x6F || [5.0.0+] [[#svcGetSystemInfo]] || X1=info_id, X2=handle, X3=info_sub_id || W0=result, X1=out
+
| [5.0.0+] 0x6F || Result || [[#GetSystemInfo|GetSystemInfo]] || uint64_t *out, SystemInfoType info_type, Handle handle, uint64_t info_subtype
 
|-
 
|-
| 0x70 || svcCreatePort || W2=max_sessions, W3=unk_bool, X4=name_ptr || W0=result, W1=clientport_handle, W2=serverport_handle
+
| 0x70 || Result || [[#CreatePort|CreatePort]] || Handle *out_server_handle, Handle *out_client_handle, int32_t max_sessions, bool is_light, uintptr_t name
 
|-
 
|-
| 0x71 || svcManageNamedPort || X1=name_ptr, W2=max_sessions || W0=result, W1=serverport_handle
+
| 0x71 || Result || [[#ManageNamedPort|ManageNamedPort]] || Handle *out_server_handle, const char *name, int32_t max_sessions
 
|-
 
|-
| 0x72 || svcConnectToPort || W1=clientport_handle || W0=result, W1=session_handle
+
| 0x72 || Result || [[#ConnectToPort|ConnectToPort]] || Handle *out_handle, Handle port
 
|-
 
|-
| 0x73 || [[#svcSetProcessMemoryPermission]] || W0=process_handle, X1=addr, X2=size, W3=perm || W0=result
+
| 0x73 || Result || [[#SetProcessMemoryPermission|SetProcessMemoryPermission]] || Handle process_handle, uint64_t address, uint64_t size, MemoryPermission perm
 
|-
 
|-
| 0x74 || [[#svcMapProcessMemory]] || X0=dstaddr, W1=process_handle, X2=srcaddr, X3=size || W0=result
+
| 0x74 || Result || [[#MapProcessMemory|MapProcessMemory]] || uintptr_t dst_address, Handle process_handle, uint64_t src_address, size_t size
 
|-
 
|-
| 0x75 || [[#svcUnmapProcessMemory]] || X0=dstaddr, W1=process_handle, X2=srcaddr, X3=size || W0=result
+
| 0x75 || Result || [[#UnmapProcessMemory|UnmapProcessMemory]] || uintptr_t dst_address, Handle process_handle, uint64_t src_address, size_t size
 
|-
 
|-
| 0x76 || [[#svcQueryProcessMemory]] || X0=meminfo_ptr, W2=process_handle, X3=addr || W0=result, W1=pageinfo
+
| 0x76 || Result || [[#QueryProcessMemory|QueryProcessMemory]] || arch::MemoryInfo *out_memory_info, PageInfo *out_page_info, Handle process_handle, uint64_t address
 
|-
 
|-
| 0x77 || [[#svcMapProcessCodeMemory]] || W0=process_handle, X1=dstaddr, X2=srcaddr, X3=size || W0=result
+
| 0x77 || Result || [[#MapProcessCodeMemory|MapProcessCodeMemory]] || Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size
 
|-
 
|-
| 0x78 || [[#svcUnmapProcessCodeMemory]] || W0=process_handle, X1=dstaddr, X2=srcaddr, X3=size || W0=result
+
| 0x78 || Result || [[#UnmapProcessCodeMemory|UnmapProcessCodeMemory]] || Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size
 
|-
 
|-
| 0x79 || [[#svcCreateProcess]] || X1=procinfo_ptr, X2=caps_ptr, W3=cap_num ||  W0=result, W1=process_handle
+
| 0x79 || Result || [[#CreateProcess|CreateProcess]] || Handle *out_handle, const arch::CreateProcessParameter *parameters, const uint32_t *caps, int32_t num_caps
 
|-
 
|-
| 0x7A || svcStartProcess || W0=process_handle, W1=main_thread_prio, W2=default_cpuid, W3=main_thread_stacksz || W0=result
+
| 0x7A || Result || [[#StartProcess|StartProcess]] || Handle process_handle, int32_t priority, int32_t core_id, uint64_t main_thread_stack_size
 
|-
 
|-
| 0x7B || svcTerminateProcess || W0=process_handle || W0=result
+
| 0x7B || Result || [[#TerminateProcess|TerminateProcess]] || Handle process_handle
 
|-
 
|-
| 0x7C || [[#svcGetProcessInfo]] || W0=process_handle, W1=[[#ProcessInfoType]] || W0=result, X1=[[#ProcessState]]
+
| 0x7C || Result || [[#GetProcessInfo|GetProcessInfo]] || int64_t *out_info, Handle process_handle, ProcessInfoType info_type
 
|-
 
|-
| 0x7D || svcCreateResourceLimit || None || W0=result, W1=reslimit_handle
+
| 0x7D || Result || [[#CreateResourceLimit|CreateResourceLimit]] || Handle *out_handle
 
|-
 
|-
| 0x7E || svcSetResourceLimitLimitValue || W0=reslimit_handle, W1=[[#LimitableResource]], X2=value || W0=result
+
| 0x7E || Result || [[#SetResourceLimitLimitValue|SetResourceLimitLimitValue]] || Handle resource_limit_handle, LimitableResource which, int64_t limit_value
 +
|-
 +
| 0x7F || void || [[#CallSecureMonitor|CallSecureMonitor]] || SecureMonitorArguments *args
 +
|- style="border-top: double"
 +
| [15.0.0+] 0x90  || Result || MapInsecurePhysicalMemory || uintptr_t address, size_t size
 +
|-
 +
| [15.0.0+] 0x91  || Result || UnmapInsecurePhysicalMemory || uintptr_t address, size_t size
 
|-
 
|-
| 0x7F || svcCallSecureMonitor || X0=smc_sub_id, X1,X2,X3,X4,X5,X6,X7=smc_args || X0,X1,X2,X3,X4,X5,X6,X7=result
 
 
|}
 
|}
  
== svcSetHeapSize ==
+
== SetHeapSize ==
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 246: Line 267:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) W1 || u64 || Size
+
| (In) X1 || uint64_t || Size
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (Out) W0 || [[#Result]] || Result
 
|-
 
|-
| (Out) X1 || u64 || OutAddr
+
| (Out) X1 || void* || HeapAddress
 
|}
 
|}
 
</div>
 
</div>
  
'''Description:''' Set the process heap to a given Size. It can both extend and shrink the heap.
+
Sets the process heap to a given Size. It can both extend and shrink the heap.
  
 
Size must be a multiple of 0x200000 (2MB).
 
Size must be a multiple of 0x200000 (2MB).
  
On success, the heap base-address (which is fixed by kernel, aslr'd) is written to OutAddr.
+
On success, the heap base-address (which is fixed by kernel, aslr'd, and always in the Heap memory region) is written to HeapAddress.
  
Uses current process pool partition.
+
Uses current process pool partition. The memory allocated counts towards the caller's process Memory ResourceLimit.
  
 
[2.0.0+] Size must be less than or equal to 4GB.
 
[2.0.0+] Size must be less than or equal to 4GB.
  
== svcSetMemoryPermission ==
+
=== Result codes ===
 +
'''0x0:''' Success.
 +
 
 +
'''0xCA01:''' Invalid size passed. It's either bigger than 4GB, or misaligned.
 +
 
 +
'''0xD001:''' Size is bigger than the Heap Region size.
 +
 
 +
'''0xCE01:''' KMemoryBlockAllocator slab allocator exhausted.
 +
 
 +
'''0xD401:''' The memory region is in an invalid state. Likely because a mapping was made in the heap region.
  
 +
'''0x10801:''' Memory resource limit reached.
 +
 +
== SetMemoryPermission ==
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 271: Line 304:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) X0 || void* || Addr
+
| (In) X0 || void* || Address
 
|-
 
|-
| (In) X1 || u64 || Size
+
| (In) X1 || uint64_t || Size
 
|-
 
|-
| (In) W2 || [[#Permission]] || Prot
+
| (In) W2 || [[#MemoryPermission]] || MemoryPermission
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (Out) W0 || [[#Result]] || Result
 
|}
 
|}
 
</div>
 
</div>
  
'''Description:''' Change permission of page-aligned memory region.
+
Changes permission of page-aligned memory region.
  
 
Bit2 of permission (exec) is not allowed. Setting write-only is not allowed either (bit1).
 
Bit2 of permission (exec) is not allowed. Setting write-only is not allowed either (bit1).
Line 287: Line 320:
 
This can be used to move back and forth between ---, r-- and rw-.
 
This can be used to move back and forth between ---, r-- and rw-.
  
== svcSetMemoryAttribute ==
+
=== Result codes ===
 +
'''0x0:''' Success. The memory region was reprotected.
 +
 
 +
'''0xCC01:''' Unaligned address specified.
  
<div style="display: inline-block;">
+
'''0xCA01:''' Unaligned or zero size specified.
{| class="wikitable" border="1"
+
 
 +
'''0xD401:''' The provided memory region does not fall within the userland address space.
 +
 
 +
'''0xD801:''' Invalid permission specified. Valid permissions are ---, r-- and rw-.
 +
 
 +
'''0xD401:''' The provided memory region was in an invalid state. The region must have the [[#MemoryState|FlagCanReprotect]] state, and must not have the [[#MemoryAttribute|Locked]] or [[#MemoryAttribute|Uncached]] attributes.
 +
 
 +
'''0xCE01:''' Kernel resource exhausted.
 +
 
 +
== SetMemoryAttribute ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 
|-
 
|-
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) X0 || void* || Addr
+
| (In) X0 || void* || Address
 
|-
 
|-
| (In) X1 || u64 || Size
+
| (In) X1 || uint64_t || Size
 
|-
 
|-
| (In) W2 || u32 || State0
+
| (In) W2 || uint32_t || Mask
 
|-
 
|-
| (In) W3 || u32 || State1
+
| (In) W3 || uint32_t || Value
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (Out) W0 || [[#Result]] || Result
 
|}
 
|}
 
</div>
 
</div>
  
'''Description:''' Change attribute of page-aligned memory region.  
+
Changes attribute of page-aligned memory region. The only allowed combination of Value and Mask is 0x8, which means only bit3 in [[#MemoryAttribute]] can be set or cleared.
  
 
This is used to turn on/off caching for a given memory area. Useful when talking to devices such as the GPU.
 
This is used to turn on/off caching for a given memory area. Useful when talking to devices such as the GPU.
Line 312: Line 359:
 
What happens "under the hood" is the "Memory Attribute Indirection Register" index is changed from 2 to 3 in the MMU descriptor.
 
What happens "under the hood" is the "Memory Attribute Indirection Register" index is changed from 2 to 3 in the MMU descriptor.
  
{| class=wikitable
+
== MapMemory ==
! State0 || State1 || Action
 
|-
 
| 0 || 0 || Clear bit3 in [[#MemoryAttribute]].
 
|-
 
| 8 || 0 || Clear bit3 in [[#MemoryAttribute]].
 
|-
 
| 8 || 8 || Set bit3 in [[#MemoryAttribute]].
 
|}
 
 
 
== svcMapMemory ==
 
 
 
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 329: Line 365:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) X0 || void* || DstAddr
+
| (In) X0 || void* || DstAddress
 
|-
 
|-
| (In) X1 || void* || SrcAddr
+
| (In) X1 || void* || SrcAddress
 
|-
 
|-
| (In) X2 || u64 || Size
+
| (In) X2 || uint64_t || Size
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (Out) W0 || [[#Result]] || Result
 
|}
 
|}
 
</div>
 
</div>
  
'''Description:''' Maps a memory range into a different range.
+
Maps a memory range into a different range.
  
 
Mainly used for adding guard pages around stack.
 
Mainly used for adding guard pages around stack.
Line 349: Line 385:
 
[2.0.0+] This can only be used to map into the Stack region.
 
[2.0.0+] This can only be used to map into the Stack region.
  
Code can get the range of the Alias region from [[#svcGetInfo]] id0=2,3, and on 2.0.0+ the range of the Stack region via [[#svcGetInfo]] id0=14, 15 (on 1.0.0, the Stack region had hardcoded limits).
+
Code can get the range of the Alias region from [[#GetInfo]] id0=2,3, and on 2.0.0+ the range of the Stack region via [[#GetInfo]] id0=14, 15 (on 1.0.0, the Stack region had hardcoded limits).
  
 
When mapped into the Alias region, the mapped memory will have state 0x482907.
 
When mapped into the Alias region, the mapped memory will have state 0x482907.
Line 355: Line 391:
 
When mapped into the Stack region, the mapped memory will have state 0x5C3C0B.
 
When mapped into the Stack region, the mapped memory will have state 0x5C3C0B.
  
== svcUnmapMemory ==
+
== UnmapMemory ==
 
 
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 362: Line 397:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) X0 || void* || DstAddr
+
| (In) X0 || void* || DstAddress
 
|-
 
|-
| (In) X1 || void* || SrcAddr
+
| (In) X1 || void* || SrcAddress
 
|-
 
|-
| (In) X2 || u64 || Size
+
| (In) X2 || uint64_t || Size
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (Out) W0 || [[#Result]] || Result
 
|}
 
|}
 
</div>
 
</div>
  
'''Description:''' Unmaps a region that was previously mapped with [[#svcMapMemory]].
+
Unmaps a region that was previously mapped with [[#MapMemory]].
  
 
It's possible to unmap ranges partially, you don't need to unmap the entire range "in one go".
 
It's possible to unmap ranges partially, you don't need to unmap the entire range "in one go".
Line 378: Line 413:
 
The srcaddr/dstaddr must match what was given when the pages were originally mapped.
 
The srcaddr/dstaddr must match what was given when the pages were originally mapped.
  
== svcQueryMemory ==
+
== QueryMemory ==
 
 
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 385: Line 419:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) X0 || [[#MemoryInfo]]* || MemInfo
+
| (In) X0 || [[#MemoryInfo]]* || MemoryInfo
 
|-
 
|-
| (In) X2 || void* || Addr
+
| (In) X2 || void* || Address
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (Out) W0 || [[#Result]] || Result
 
|-
 
|-
| (Out) W1 || PageInfo || PageInfo
+
| (Out) W1 || [[#PageInfo]] || PageInfo
 
|}
 
|}
 
</div>
 
</div>
  
'''Description:''' Query information about an address. Will always fetch the lowest page-aligned mapping that contains the provided address.
+
Queries information about an address. Will always fetch the lowest page-aligned mapping that contains the provided address.
  
 
Outputs a [[#MemoryInfo]] struct.
 
Outputs a [[#MemoryInfo]] struct.
  
== svcExitProcess ==
+
== ExitProcess ==
 
 
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 412: Line 445:
 
</div>
 
</div>
  
'''Description:''' Exits the current process.
+
Exits the current process.
 
 
== svcCreateThread ==
 
  
 +
== CreateThread ==
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! Argument || Type || Name
+
! Argument64 || Argument32 || Type || Name
 
|-
 
|-
| (In) X1 || void(*)(void*) || Entry
+
| (In) X1 || R1 || void(*)(void*) || Entry
 
|-
 
|-
| (In) X2 || void* || ThreadContext
+
| (In) X2 || R2 || void* || ThreadContext
 
|-
 
|-
| (In) X3 || void* || StackTop
+
| (In) X3 || R3 || void* || StackTop
 
|-
 
|-
| (In) W4 || u32 || Priority
+
| (In) W4 || R0 || int32_t || Priority
 
|-
 
|-
| (In) W5 || u32 || ProcessorId
+
| (In) W5 || R4 || int32_t || ProcessorId
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (Out) W0 || R0 || [[#Result]] || Result
 
|-
 
|-
| (Out) W1 || Handle<Thread> || Handle
+
| (Out) W1 || R1 || Handle<Thread> || ThreadHandle
 
|}
 
|}
 
</div>
 
</div>
  
'''Description:''' Create a thread in the current process.
+
Creates 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 ==
+
ProcessorId must be 0,1,2,3 or -2, where -2 uses the default CpuId for process.
  
 +
== StartThread ==
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 448: Line 479:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) W0 || Handle<Thread> || Handle
+
| (In) W0 || Handle<Thread> || ThreadHandle
 
|-
 
|-
 
| (Out) None ||  ||
 
| (Out) None ||  ||
Line 454: Line 485:
 
</div>
 
</div>
  
'''Description:''' Starts the thread for the provided handle.
+
Starts the thread for the provided handle.
 
 
== svcExitThread ==
 
  
 +
== ExitThread ==
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 469: Line 499:
 
</div>
 
</div>
  
'''Description:''' Exits the current thread.
+
Exits the current thread.
 
 
== svcSleepThread ==
 
  
 +
== SleepThread ==
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! Argument || Type || Name
+
! Argument64 || Argument32 || Type || Name
|-
 
| (In) X0 || u64 || Nano
 
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (In) X0 || R0, R1 || uint64_t || Nanoseconds
 
|}
 
|}
 
</div>
 
</div>
  
'''Description:''' Sleep for a specified amount of time, or yield thread.
+
Sleeps for a specified amount of time, or yields the thread.
  
Setting nano=0 means "yield thread".
+
Setting nanoseconds to 0, -1, or -2 indicates a yielding type.
 
 
== svcGetThreadPriority ==
 
  
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! Argument || Type || Name
+
! Value || Type
 
|-
 
|-
| (In) W1|| Handle<Thread> || Handle
+
| 0 || Yielding without core migration
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| -1 || Yielding with core migration
 
|-
 
|-
| (Out) W1 || u64 || Priority
+
| -2 || Yielding to any other thread
 
|}
 
|}
 
</div>
 
</div>
  
'''Description:''' Get priority of provided thread handle.
+
== GetThreadPriority ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) W1|| Handle<Thread> || ThreadHandle
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|-
 +
| (Out) W1 || int32_t || Priority
 +
|}
 +
</div>
  
== svcSetThreadPriority ==
+
Gets the priority of provided thread handle.
  
 +
== SetThreadPriority ==
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 512: Line 550:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) W0|| Handle<Thread> || Handle
+
| (In) W0|| Handle<Thread> || ThreadHandle
 
|-
 
|-
| (In) W1|| u32 || Priority
+
| (In) W1|| int32_t || Priority
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (Out) W0 || [[#Result]] || Result
 
|}
 
|}
 
</div>
 
</div>
  
'''Description:''' Set priority of provided thread handle.
+
Sets the priority of provided thread handle.
  
 
Priority is a number 0-0x3F. Lower value means higher priority.
 
Priority is a number 0-0x3F. Lower value means higher priority.
  
== svcGetThreadCoreMask ==
+
== GetThreadCoreMask ==
 
 
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! Argument || Type || Name
+
! Argument64 || Argument32 || Type || Name
 
|-
 
|-
| (In) W2 || Handle<Thread> || Handle
+
| (In) W2 || R2 || Handle<Thread> || ThreadHandle
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (Out) W0 || R0 || [[#Result]] || Result
 
|-
 
|-
| (Out) W1 || u32 || Out0
+
| (Out) W1 || R1 || int32_t || CoreMask0
 
|-
 
|-
| (Out) X2 || u64 || Out1
+
| (Out) X2 || R2, R3 || uint64_t || CoreMask1
 
|}
 
|}
 
</div>
 
</div>
  
'''Description:''' Get affinity mask of provided thread handle.
+
Gets the affinity mask of provided thread handle.
 
 
== svcSetThreadCoreMask ==
 
  
 +
== SetThreadCoreMask ==
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! Argument || Type || Name
+
! Argument64 || Argument32 || Type || Name
 
|-
 
|-
| (In) W0 || Handle<Thread> || Handle
+
| (In) W0 || R0 || Handle<Thread> || ThreadHandle
 
|-
 
|-
| (In) W1 || u32 || In0
+
| (In) W1 || R1 || int32_t || CoreMask0
 
|-
 
|-
| (In) X2 || u64 || In1
+
| (In) X2 || R2, R3 || uint64_t || CoreMask1
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (Out) W0 || R0 || [[#Result]] || Result
 
|}
 
|}
 
</div>
 
</div>
  
'''Description:''' Set affinity mask of provided thread handle.
+
Sets the affinity mask of provided thread handle.
 
 
== svcGetCurrentProcessorNumber ==
 
  
 +
== GetCurrentProcessorNumber ==
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 571: Line 606:
 
| (In) None || ||  
 
| (In) None || ||  
 
|-
 
|-
| (Out) W0/X0 || u64 || CpuId
+
| (Out) W0 || uint32_t || CpuId
 
|}
 
|}
 
</div>
 
</div>
  
'''Description:''' Get which cpu is executing the current thread.
+
Gets which cpu is executing the current thread.
 
 
Cpu-id is an integer in the range 0-3.
 
  
== svcMapSharedMemory ==
+
CpuId is an integer in the range 0-3.
  
 +
== SignalEvent ==
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 586: Line 620:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) W0 || Handle<SharedMemory> || MemHandle
+
| (In) W0 || Handle<WritableEvent> || EventHandle
|-
 
| (In) X1 || void* || Addr
 
|-
 
| (In) X2 || u64 || Size
 
|-
 
| (In) W3 || [[#Permission]] || Permissions
 
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (Out) X0 || [[#Result]] || Result
 
|}
 
|}
 
</div>
 
</div>
  
Maps the block supplied by the handle. The required permissions are different for the process that created the handle and all other processes.
+
Puts the given event in the signaled state.
 +
 
 +
Will wake up any thread currently waiting on this event. Can potentially trigger a reschedule.
 +
 
 +
Any calls to [[#WaitSynchronization]] on this handle will return immediately, until the event's signaled state is reset.
  
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.
+
=== Result codes ===
 +
'''0x0:''' Success. Event is now in signaled state.
  
== svcCreateTransferMemory ==
+
'''0xE401:''' Invalid handle. The handle either does not exist, or is not a WritableEvent.
  
 +
== ClearEvent ==
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 609: Line 643:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) X1 || void* || Addr
+
| (In) W0 || Handle<WritableEvent> or Handle<ReadableEvent> || EventHandle
|-
 
| (In) X2 || u64 || Size
 
|-
 
| (In) W3 || [[#Permission]] || Permissions
 
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (Out) X0 || [[#Result]] || Result
|-
 
| (Out) W1 || Handle<TransferMemory> || Handle
 
 
|}
 
|}
 
</div>
 
</div>
  
This one reprotects the src block with perms you give it. It also sets bit0 into [[#MemoryAttribute]].
+
Takes the given event out of the signaled state, if it is signaled.
  
Executable bit perm not allowed.
+
=== Result codes ===
 +
'''0x0:''' Success, the event is now in the not-signaled state.
  
Closing all handles automatically causes the bit0 in [[#MemoryAttribute]] to clear, and the permission to reset.
+
'''0xE401:''' Invalid handle. The handle either does not exist, or is not a ReadableEvent nor a WritableEvent.
 
 
== svcWaitSynchronization ==
 
  
 +
== MapSharedMemory ==
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 634: Line 662:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) X1 || Handle* || HandlesPtr
+
| (In) W0 || Handle<SharedMemory> || SharedMemoryHandle
 
|-
 
|-
| (In) W2 || u64 || HandlesNum
+
| (In) X1 || void* || Address
 
|-
 
|-
| (In) X3 || u64 || Timeout
+
| (In) X2 || uint64_t || Size
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (In) W3 || [[#MemoryPermission]] || MemoryPermission
 
|-
 
|-
| (Out) W1 || u64 || HandleIndex
+
| (Out) W0 || [[#Result]] || Result
 
|}
 
|}
 
</div>
 
</div>
  
Works with num_handles <= 0x40.
+
Maps the block supplied by the handle. The required permissions are different for the process that created the handle and all other processes.
  
When zero handles are passed, this will wait forever until either timeout or cancellation occurs.
+
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.
  
Does not accept 0xFFFF8001 or 0xFFFF8000 as handles.
+
== UnmapSharedMemory ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) W0 || Handle<SharedMemory> || SharedMemoryHandle
 +
|-
 +
| (In) X1 || void* || Address
 +
|-
 +
| (In) X2 || uint64_t || Size
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
  
=== Object types ===
+
== CreateTransferMemory ==
 
+
<div style="display: inline-block;">
'''Debug:''' signals when there is a new [[#DebugEventInfo|DebugEvent]] (retrievable via [[#svcGetDebugEvent]]).
+
{| class="wikitable" border="1"
 
+
|-
'''Port:''' signals when there is an incoming connection waiting to be [[#svcAcceptSession|accepted]].
+
! Argument || Type || Name
 
+
|-
'''Process:''' signals when the process undergoes a state change (retrievable via [[#svcGetProcessInfo]]).
+
| (In) X1 || void* || Address
 
+
|-
'''ReadableEvent:''' signals when the event has been signaled via svcSignalEvent.
+
| (In) X2 || uint64_t || Size
 
+
|-
'''Session (server-side):''' signals when there is an incoming message waiting to be [[#svcReplyAndReceive|received]] or the pipe is closed.
+
| (In) W3 || [[#MemoryPermission]] || MemoryPermission
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|-
 +
| (Out) W1 || Handle<TransferMemory> || TransferMemoryHandle
 +
|}
 +
</div>
  
'''Thread:''' signals when the thread has exited.
+
This one reprotects the src block with perms you give it. It also sets bit0 into [[#MemoryAttribute]].
  
=== Result codes ===
+
Executable bit perm not allowed.
  
'''0x0:''' Success. One of the objects was signaled before the timeout expired, or one of the objects is a Session with a closed remote. Handle index is updated to indicate which object signaled.
+
Closing all handles automatically causes the bit0 in [[#MemoryAttribute]] to clear, and the permission to reset.
 
 
'''0x7601:''' Thread termination requested. Handle index is not updated.
 
 
 
'''0xe401:''' Invalid handle. Returned when one of the handles passed is invalid. Handle index is not updated.
 
 
 
'''0xe601:''' Invalid address. Returned when the handles pointer is not a readable address. Handle index is not updated.
 
 
 
'''0xea01:''' Timeout. Returned when no objects have been signaled within the timeout. Handle index is not updated.
 
 
 
'''0xec01:''' Interrupted. Returned when another thread uses [[#svcCancelSynchronization]] to cancel this thread. Handle index is not updated.
 
 
 
'''0xee01:''' Too many handles. Returned when the number of handles passed is > 0x40.
 
 
 
== svcCancelSynchronization ==
 
  
 +
== CloseHandle ==
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 689: Line 724:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) W0 || Handle<Thread> || Handle
+
| (In) W0 || Handle || Handle
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (Out) W0 || [[#Result]] || Result
 
|}
 
|}
 
</div>
 
</div>
  
If the referenced thread is currently in a synchronization call ([[#svcWaitSynchronization]], [[#svcReplyAndReceive]] or [[#svcReplyAndReceiveLight]]), that call will be interrupted and return 0xec01.
+
== ResetSignal ==
If that thread is not currently executing such a synchronization call, the next call to a synchronization call will return 0xec01.
+
<div style="display: inline-block;">
 
+
{| class="wikitable" border="1"
This doesn't take force-pause (activity/debug pause) into account.
+
|-
 
+
! Argument || Type || Name
=== Result codes ===
 
 
 
'''0x0:''' Success. The thread was either interrupted or has had its flag set.
 
 
 
'''0xe401:''' Invalid handle. The handle given was either invalid or not a thread handle.
 
 
 
== svcGetSystemTick ==
 
 
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
 
|-
 
|-
! Argument || Type || Name
+
| (In) W0 || Handle<ReadableEvent> or Handle<Process> || Handle
 
|-
 
|-
| (Out) X0 || u64 || Ticks
+
| (Out) W0 || [[#Result]] || Result
 
|}
 
|}
 
</div>
 
</div>
  
Returns the value of cntpct_el0.
+
Resets the signal on the given handle, ensuring future calls to [[#WaitSynchronization]] on this handle will sleep until the handle is signaled again. If the handle is a ReadableEvent, this returns ResultInvalidState if the event is not signaled.
 +
 
 +
If the handle is a Process, it will clear the signaled state (which is set when the process changes [[#ProcessState]]. Once the process enters the Exited state, calling ResetSignal on the process will no longer have an effect (the process is permanently signaled), and the syscall will return 0xFA01.
  
The frequency is 19200000 Hz (constant from official sw).
+
=== Result codes ===
 +
'''0x0:''' Success. The signal was reset.
  
Official sw reads cntpct_el0 directly from usermode without using this SVC. [[ExeFS|sdk-nso]] has this SVC, but it's not known to be called anywhere.
+
'''0xE401:''' The handle is invalid or of the wrong type.
  
== svcSendSyncRequestWithUserBuffer ==
+
'''0xFA01:''' The handle was not signaled, or the process is in exited state, causing it to be permanently signaled.
  
 +
== WaitSynchronization ==
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! Argument || Type || Name
+
! Argument64 || Argument32 || Type || Name
 +
|-
 +
| (In) X1 || R1 || Handle* || HandlesPtr
 
|-
 
|-
| (In) X0 || void* || CmdPtr
+
| (In) W2 || R2 || int32_t || HandlesNum
 
|-
 
|-
| (In) X1 || u64 || Size
+
| (In) X3 || R0, R3 || int64_t || Timeout
 
|-
 
|-
| (In) W2 || Handle<Session> || Handle
+
| (Out) W0 || R0 || [[#Result]] || Result
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (Out) W1 || R1 || uint64_t || HandleIndex
 
|}
 
|}
 
</div>
 
</div>
  
Size and CmdPtr must be 0x1000-aligned.
+
Works with HandlesNum <= 0x40.
 +
 
 +
When zero handles are passed, this will wait forever until either timeout or cancellation occurs.
  
=== Result codes ===
+
Does not accept 0xFFFF8001 or 0xFFFF8000 as handles.
  
'''0x0:''' Success.
+
=== Object types ===
 +
'''KDebug:''' signals when there is a new [[#DebugEventInfo|DebugEvent]] (retrievable via [[#GetDebugEvent]]).
  
'''0xcc01:''' CmdPtr is not 0x1000-aligned.
+
'''KClientPort:''' signals when the number of sessions is less than the maximum allowed.
  
'''0xca01:''' Size is not 0x1000-aligned.
+
'''KProcess:''' signals when the process undergoes a state change (retrievable via [[#GetProcessInfo]]).
  
'''0xce01:''' KSessionRequest allocation failed (unlikely) or pointer buffer size exceeded.
+
'''KReadableEvent:''' signals when the event's corresponding KWritableEvent has been signaled via [[#SignalEvent]].
  
'''0xe401:''' Handles does not exist, or handle is not an instance of KClientSession.
+
'''KServerPort:''' signals when there is an incoming connection waiting to be [[#AcceptSession|accepted]].
  
== svcBreak ==
+
'''KServerSession:''' signals when there is an incoming message waiting to be [[#ReplyAndReceive|received]] or the pipe is closed.
  
<div style="display: inline-block;">
+
'''KThread:''' signals when the thread has exited.
 +
 
 +
=== Result codes ===
 +
'''0x0:''' Success. One of the objects was signaled before the timeout expired, or one of the objects is a Session with a closed remote. Handle index is updated to indicate which object signaled.
 +
 
 +
'''0x7601:''' Thread termination requested. Handle index is not updated.
 +
 
 +
'''0xe401:''' Invalid handle. Returned when one of the handles passed is invalid. Handle index is not updated.
 +
 
 +
'''0xe601:''' Invalid address. Returned when the handles pointer is not a readable address. Handle index is not updated.
 +
 
 +
'''0xea01:''' Timeout. Returned when no objects have been signaled within the timeout. Handle index is not updated.
 +
 
 +
'''0xec01:''' Interrupted. Returned when another thread uses [[#CancelSynchronization]] to cancel this thread. Handle index is not updated.
 +
 
 +
'''0xee01:''' Too many handles. Returned when the number of handles passed is > 0x40.
 +
 
 +
== CancelSynchronization ==
 +
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) X0 || u64 || Break Reason
+
| (In) W0 || Handle<Thread> || ThreadHandle
 
|-
 
|-
| (In) X1 || u64 ||
+
| (Out) W0 || [[#Result]] || Result
|-
 
| (In) X2 || u64 || Info
 
|-
 
| (Out) W0 || Result || 0 (Success)
 
 
|}
 
|}
 
</div>
 
</div>
  
If the process is attached, report the Break event. Then, if svcContinueDebugEvent didn't apply IgnoreException on the thread: if TPIDR_EL0 is 0, adjust ELR_EL1 to retry to svc instruction (and set TPIDR_EL0 to 1).
+
If the referenced thread is currently in a synchronization call ([[#WaitSynchronization]], [[#ReplyAndReceive]] or [[#ReplyAndReceiveLight]]), that call will be interrupted and return 0xec01.
 +
If that thread is not currently executing such a synchronization call, the next call to a synchronization call will return 0xec01.
  
Otherwise, if bit31 in reason isn't set, perform crash reporting (see Exception Handling section below), if it doesn't terminate the process adjust ELR_EL1 as well.
+
This doesn't take force-pause (activity/debug pause) into account.
  
Otherwise just return 0.
+
=== Result codes ===
 +
'''0x0:''' Success. The thread was either interrupted or has had its flag set.
  
== svcGetInfo ==
+
'''0xe401:''' Invalid handle. The handle given was either invalid or not a thread handle.
  
 +
== ArbitrateLock ==
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 784: Line 835:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) X1 || u64 || InfoId
+
| (In) W0 || Handle<Thread> || ThreadHandle
 
|-
 
|-
| (In) W2 || Handle || Handle
+
| (In) X1 || void* || Address
 
|-
 
|-
| (In) X3 || u64 || InfoSubId
+
| (In) W2 || uint32_t || Tag
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (Out) W0 || [[#Result]] || Result
|-
 
| (Out) X1 || u64 || Out
 
 
|}
 
|}
</div>
+
</div>                                
  
{| class=wikitable
+
== ArbitrateUnlock ==
! Handle type || Id0 || Id1 || Description
+
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 
|-
 
|-
| Process || 0 || 0 || AllowedCpuIdBitmask
+
! Argument || Type || Name
 
|-
 
|-
| Process || 1 || 0 || AllowedThreadPrioBitmask
+
| (In) X0 || void* || Address
 
|-
 
|-
| Process || 2 || 0 || AliasRegionBaseAddr
+
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
== WaitProcessWideKeyAtomic ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 
|-
 
|-
| Process || 3 || 0 || AliasRegionSize
+
! Argument64 || Argument32 || Type || Name
 
|-
 
|-
| Process || 4 || 0 || HeapRegionBaseAddr
+
| (In) X0 || R0 || void* || KeyAddress
 
|-
 
|-
| Process || 5 || 0 || HeapRegionSize
+
| (In) X1 || R1 || void* || TagAddress
 
|-
 
|-
| Process || 6 || 0 || TotalMemoryAvailable. Total memory available(free+used).
+
| (In) W2 || R2 || uint32_t || Tag
 
|-
 
|-
| Process || 7 || 0 || TotalMemoryUsage. Total used size of codebin memory + main-thread stack + allocated heap.
+
| (In) X3 || R3, R4 || int64_t || Timeout
 
|-
 
|-
| Zero    || 8 || 0 || IsCurrentProcessBeingDebugged
+
| (Out) W0 || R0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
== SignalProcessWideKey ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 
|-
 
|-
| Zero    || 9 || 0 || Returns ResourceLimit handle for current process. Used by [[Process_Manager_services|PM]].
+
! Argument || Type || Name
 
|-
 
|-
| Zero    || 10 || -1, {current coreid} || IdleTickCount
+
| (In) X0 || void* || Address
 
|-
 
|-
| Zero    || 11 || 0-3 || RandomEntropy from current process. TRNG. Used to seed usermode PRNGs.
+
| (In) W1 || int32_t || Value
 
|-
 
|-
| Process || 12 || 0 || [2.0.0+] AddressSpaceBaseAddr
+
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
== GetSystemTick ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 
|-
 
|-
| Process || 13 || 0 || [2.0.0+] AddressSpaceSize
+
! Argument64 || Argument32 || Type || Name
 
|-
 
|-
| Process || 14 || 0 || [2.0.0+] StackRegionBaseAddr
+
| (Out) X0 || R0, R1 || uint64_t || Ticks
|-
+
|}
| Process || 15 || 0 || [2.0.0+] StackRegionSize
+
</div>
 +
 
 +
Returns the value of cntpct_el0.
 +
 
 +
The frequency is 19200000 Hz (constant from official sw).
 +
 
 +
Official sw reads cntpct_el0 directly from usermode without using this SVC. [[ExeFS|sdk-nso]] has this SVC, but it's not known to be called anywhere.
 +
 
 +
== ConnectToNamedPort ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 
|-
 
|-
| Process || 16 || 0 || [3.0.0+] PersonalMmHeapSize
+
! Argument || Type || Name
 
|-
 
|-
| Process || 17 || 0 || [3.0.0+] PersonalMmHeapUsage
+
| (In) X1 || char* || PortName
 
|-
 
|-
| Process || 18 || 0 || [3.0.0+] TitleId
+
| (Out) W0 || [[#Result]] || Result
|-
 
| Zero    || 19 || 0 || [4.0.0-4.1.0] PrivilegedProcessId_LowerBound
 
 
|-
 
|-
| Zero    || 19 || 1 || [4.0.0-4.1.0] PrivilegedProcessId_UpperBound
+
| (Out) W1 || Handle<Session> || SessionHandle
|-
 
| Process || 20 || 0 || [5.0.0+] UserExceptionContextAddr
 
|-
 
| Thread  || 0xF0000002 || 0 || Performance counter related.
 
 
|}
 
|}
 +
</div>
  
== svcMapPhysicalMemory ==
+
== SendSyncRequestLight ==
This is like svcSetHeapSize except you can allocate heap at any address you'd like.
 
 
 
Uses current process pool partition.
 
 
 
== svcDumpInfo ==
 
 
 
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 858: Line 925:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) None || ||  
+
| (In) W0 || Handle<Session> || SessionHandle
 
|-
 
|-
| (Out) None || ||
+
| (Out) W0 || [[#Result]] || Result
 
|}
 
|}
 
</div>
 
</div>
  
Does nothing, just returns with registers set to all-zero.
+
== SendSyncRequest ==
 
 
== svcAcceptSession ==
 
 
 
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 873: Line 937:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) W1 || Handle<Port> || Port
+
| (In) W0 || Handle<Session> || SessionHandle
 
|-
 
|-
 
| (Out) W0 || [[#Result]] || Result
 
| (Out) W0 || [[#Result]] || Result
|-
 
| (Out) W1 || Handle<ServerSession> || Session
 
 
|}
 
|}
 
</div>
 
</div>
  
=== Result codes ===
+
== SendSyncRequestWithUserBuffer ==
 
 
'''0xf201:''' No session waiting to be accepted
 
 
 
== svcReplyAndReceive ==
 
 
 
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 892: Line 949:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) W1 || *Handle<Port or ServerSession> || Handles
+
| (In) X0 || void* || Address
 
|-
 
|-
| (In) W2 || u32 || NumHandles
+
| (In) X1 || uint64_t || Size
 
|-
 
|-
| (In) W3 || Handle<ServerSession> || ReplyTarget
+
| (In) W2 || Handle<Session> || SessionHandle
|-
 
| (In) X4 || u64 (nanoseconds) || Timeout
 
 
|-
 
|-
 
| (Out) W0 || [[#Result]] || Result
 
| (Out) W0 || [[#Result]] || Result
|-
 
| (Out) W1 || u32 || HandleIndex
 
 
|}
 
|}
 
</div>
 
</div>
  
If ReplyTarget is not zero, a reply from the TLS will be sent to that session.
+
Size and Address must be 0x1000-aligned.
Then it will wait until either of the passed sessions has an incoming message, is closed, a passed port has an incoming connection, or the timeout expires.
 
If there is an incoming message, it is copied to the TLS.
 
 
 
If ReplyTarget is zero, the TLS should contain a blank message. If this message has a C descriptor, the buffer it points to will be used as the pointer buffer. See [[IPC_Marshalling#IPC_buffers]]. Note that a pointer buffer cannot be specified if ReplyTarget is not zero.
 
 
 
After being validated, passed handles will be enumerated in order; even if a session has been closed, if one that appears earlier in the list has an incoming message, it will take priority and a result code of 0x0 will be returned.
 
  
 
=== Result codes ===
 
=== Result codes ===
 +
'''0x0:''' Success.
  
'''0x0:''' Success. Either a session has an incoming message or a port has an incoming connection. HandleIndex is set appropriately.
+
'''0xcc01:''' Address is not 0x1000-aligned.
  
'''0xea01:''' Timeout. No handles were signalled before the timeout expired. HandleIndex is not updated.
+
'''0xca01:''' Size is not 0x1000-aligned.
  
'''0xf601:''' Port remote dead. One of the sessions has been closed. HandleIndex is set appropriately.
+
'''0xce01:''' KSessionRequest allocation failed (unlikely) or pointer buffer size exceeded.
  
== svcMapPhysicalMemoryUnsafe ==
+
'''0xe401:''' Handles does not exist, or handle is not an instance of KClientSession.
Same as [[#svcMapPhysicalMemory]] except it always uses pool partition 0.
 
 
 
== svcCreateCodeMemory ==
 
Takes an address range with backing memory to create the code memory object.
 
 
 
The memory is initially memset to 0xFF after being locked.
 
 
 
== svcControlCodeMemory ==
 
Maps the backing memory for a Code memory object into the current process.
 
 
 
For [[#CodeMemoryOperation|CodeMemoryOperation_MapOwner]], memory permission must be RW-.
 
 
 
For [[#CodeMemoryOperation|CodeMemoryOperation_MapSlave]], memory permission must be R-- or R-X.
 
 
 
Operations [[#CodeMemoryOperation|CodeMemoryOperation_UnmapOwner/CodeMemoryOperation_UnmapSlave]] unmap memory that was previously mapped this way.
 
 
 
This allows one "secure JIT" process to map the code memory as RW-, and the other "slave" process to map it R-X.
 
 
 
[5.0.0+] Error 0xE401 is now returned when the process owner of the Code memory object is the same as the current process.
 
 
 
== svcReadWriteRegister ==
 
  
 +
== SendAsyncRequestWithUserBuffer ==
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 950: Line 978:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) X1 || u64 || RegAddr
+
| (In) X1 || void* || Address
 
|-
 
|-
| (In) W2 || u64 || RwMask
+
| (In) X2 || uint64_t || Size
 
|-
 
|-
| (In) W3 || u64 || InValue
+
| (In) W3 || Handle<Session> || SessionHandle
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (Out) W0 || [[#Result]] || Result
 
|-
 
|-
| (Out) W1|| u64 || OutValue
+
| (Out) W1 || Handle<ReadableEvent> || EventHandle
 
|}
 
|}
 
</div>
 
</div>
  
Read/write IO registers with a hardcoded whitelist. Input address is physical-address and must be aligned to 4.
+
Size and Address must be 0x1000-aligned.
  
rw_mask is 0 for reading and 0xffffffff for writing. You can also write individual bits by using a mask value.
+
== GetProcessId ==
 
+
<div style="display: inline-block;">
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).
 
 
 
[4.0.0+] Access to the Memory Controller (0x70019000) also uses smcReadWriteRegister.
 
 
 
Here is the whitelist imposed by that SMC, relative to the start of the PMC registers:
 
 
 
0x000, 0x00c, 0x010, 0x014, 0x01c, 0x020, 0x02c, 0x030, 0x034, 0x038, 0x03c, 0x040, 0x044, 0x048, 0x0dc, 0x0e0, 0x0e4, 0x160, 0x164, 0x168, 0x170, 0x1a8, 0x1b8, 0x1bc, 0x1c0, 0x1c4, 0x1c8, 0x2b4, 0x2d4, 0x440, 0x4d8
 
 
 
Here is the whitelist imposed by smcReadWriteRegister (checked in addition to the whitelist in svcReadWriteRegister), relative to the start of the MC registers:
 
 
 
0x000, 0x004, 0x008, 0x00C, 0x010, 0x01C, 0x020, 0x030, 0x034, 0x050, 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, 0x238, 0x240, 0x244, 0x250, 0x254, 0x258, 0x264, 0x268, 0x26C, 0x270, 0x274, 0x280, 0x284, 0x288, 0x28C, 0x294, 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, 0x4C4, 0x4C8, 0x4CC, 0x50C, 0x554, 0x558, 0x55C, 0x584, 0x588, 0x58C, 0x670, 0x674, 0x690, 0x694, 0x698, 0x69C, 0x6A0, 0x6A4, 0x6C0, 0x6C4, 0x6F0, 0x6F4, 0x960, 0x970, 0x974, 0x9B8, 0xA20, 0xA24, 0xA88, 0xA94, 0xA98, 0xA9C, 0xAA0, 0xAA4, 0xAA8, 0xAAC, 0xAB0, 0xAB4, 0xAB8, 0xABC, 0xAC0, 0xAC4, 0xAC8, 0xACC, 0xAD0, 0xAD4, 0xAD8, 0xADC, 0xAE0, 0xB88, 0xB8C, 0xBC4, 0xBC8, 0xBCC, 0xBD0, 0xBD4, 0xBD8, 0xBDC, 0xBE0, 0xBE4, 0xBE8, 0xBEC, 0xC00, 0xC5C, 0xCAC
 
 
 
== svcCreateSharedMemory ==
 
 
 
<div style="display: inline-block;">
 
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! Argument || Type || Name
+
! Argument64 || Argument32 || Type || Name
|-
 
| (In) W1 || u64 || Size
 
 
|-
 
|-
| (In) W2 || [[#Permission]] || LocalPerm
+
| (In) W1 || R1 || Handle<Process> || ProcessHandle
 
|-
 
|-
| (In) W3 || [[#Permission]] || RemotePerm
+
| (Out) W0 || R0 || [[#Result]] || Result
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (Out) X1 || R1, R2 || uint64_t || ProcessId
|-
 
| (Out) W1 || Handle<SharedMemory> || MemHandle
 
 
|}
 
|}
 
</div>
 
</div>
  
Other perm can be used to enforce permission 1, 3, or 0x10000000 if don't care.
+
== GetThreadId ==
 
+
<div style="display: inline-block;">
Allocates memory from the current process' pool partition.
+
{| class="wikitable" border="1"
 
+
|-
== svcMapTransferMemory ==
+
! Argument64 || Argument32 || Type || Name
 +
|-
 +
| (In) W1 || R1 || Handle<Thread> || ThreadHandle
 +
|-
 +
| (Out) W0 || R0 || [[#Result]] || Result
 +
|-
 +
| (Out) X1 || R1, R2 || uint64_t || ThreadId
 +
|}
 +
</div>
  
 +
== Break ==
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 1,019: Line 1,026:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) X0 || Handle<TransferMemory> || MemHandle
+
| (In) X0 || [[#BreakReason]] || BreakReason
 
|-
 
|-
| (In) X1 || void* || Addr
+
| (In) X1 || uint64_t ||
 
|-
 
|-
| (In) X2 || u64 || Size
+
| (In) X2 || uint64_t || Info
 
|-
 
|-
| (In) W3 || [[#Permission]] || Permissions
+
| (Out) W0 || [[#Result]] || Result
|-
 
| (Out) W0 || [[#Result]] || Ret
 
 
|}
 
|}
 
</div>
 
</div>
  
The newly mapped pages will have [[#MemoryState]] type 0xE.
+
If the process is attached, report the Break event. Then, if [[#ContinueDebugEvent]] didn't apply IgnoreException on the thread: if TPIDR_EL0 is 0, adjust ELR_EL1 to retry to svc instruction (and set TPIDR_EL0 to 1).
  
You must pass same size and permissions as given in svcCreateMemoryMirror, otherwise error.
+
Otherwise, if bit31 in reason isn't set, perform crash reporting (see Exception Handling section below), if it doesn't terminate the process adjust ELR_EL1 as well.
  
== svcUnmapTransferMemory ==
+
Otherwise just return 0.
  
 +
== OutputDebugString ==
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 1,042: Line 1,048:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) X0 || Handle<TransferMemory> || MemHandle
+
| (In) X0 || char* || String
 
|-
 
|-
| (In) X1 || void* || Addr
+
| (In) X1 || uint64_t || Size
 
|-
 
|-
| (In) X2 || u64 || Size
+
| (Out) W0 || [[#Result]] || Result
|-
 
| (Out) W0 || [[#Result]] || Ret
 
 
|}
 
|}
 
</div>
 
</div>
  
Size must match size given in map syscall, otherwise there's an invalid-size error.
+
== ReturnFromException ==
 
 
== svcQueryPhysicalAddress ==
 
 
 
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 1,061: Line 1,062:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) X1 || u64 || Addr
+
| (In) W0 || [[#Result]] || Result
|-
 
| (Out) W0 || [[#Result]]|| Ret
 
|-
 
| (Out) X1 || u64 || PhysAddr
 
|-
 
| (Out) X2 || u64 || KernelAddr
 
|-
 
| (Out) X3 || u64 || Size
 
 
|}
 
|}
 
</div>
 
</div>
  
== svcQueryIoMapping ==
+
== GetInfo ==
 
 
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! Argument || Type || Name
+
! Argument64 || Argument32 || Type || Name
 +
|-
 +
| (In) W1 || R1 || [[#InfoType]] || InfoType
 
|-
 
|-
| (In) X1 || u64 || PhysAddr
+
| (In) W2 || R2 || Handle || Handle
 
|-
 
|-
| (In) X2 || u64 || Size
+
| (In) X3 || R0, R3 || uint64_t || InfoSubType
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (Out) W0 || R0 || [[#Result]] || Result
 
|-
 
|-
| (Out) X1 || void* || VirtAddr
+
| (Out) X1 || R1, R2 || uint64_t || Info
 
|}
 
|}
 
</div>
 
</div>
  
'''Description:''' Returns a virtual address mapped to a given IO range.
+
== FlushEntireDataCache ==
 
 
== svcCreateDeviceAddressSpace ==
 
 
 
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 1,099: Line 1,090:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) X1 || u64 || StartAddr
+
| (In) None || ||
 
|-
 
|-
| (In) X2 || u64 || EndAddr
+
| (Out) None || ||
|-
 
| (Out) W0 || [[#Result]] || Ret
 
|-
 
| (Out) W1 || Handle<DeviceAddressSpace> || AddressSpaceHandle
 
 
|}
 
|}
 
</div>
 
</div>
  
'''Description:''' Creates a virtual address space for binding device address spaces and returns a handle.
+
== FlushDataCache ==
 
 
dev_as_start_addr is normally set to 0 and dev_as_end_addr is normally set to 0xFFFFFFFF.
 
 
 
== svcAttachDeviceAddressSpace ==
 
 
 
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 1,120: Line 1,102:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) W0 || [[#DeviceName]] || DeviceId
+
| (In) X0 || void* || Address
 
|-
 
|-
| (In) X1 || Handle<DeviceAddressSpace> || DeviceAsHandle
+
| (In) X1 || uint64_t || Size
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (Out) W0 || [[#Result]] || Result
 
|}
 
|}
 
</div>
 
</div>
  
'''Description:''' Attaches a device address space to a [[#DeviceName|device]].
+
== MapPhysicalMemory ==
 
 
== svcDetachDeviceAddressSpace ==
 
 
 
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 1,137: Line 1,116:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) W0 || [[#DeviceName]] || DeviceId
+
| (In) X0 || void* || Address
 
|-
 
|-
| (In) X1 || Handle<DeviceAddressSpace> || DeviceAsHandle
+
| (In) X1 || uint64_t || Size
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (Out) W0 || [[#Result]] || Result
 
|}
 
|}
 
</div>
 
</div>
  
'''Description:''' Detaches a device address space from a [[#DeviceName|device]].
+
Acts like [[#SetHeapSize]] except you can allocate heap at any address you'd like.
 +
 
 +
Uses current process pool partition.
 +
 
 +
=== Result codes ===
 +
'''0x0:''' Success.
 +
 
 +
'''0xCA01:''' Invalid size passed. It's either zero or not 4k-aligned
 +
 
 +
'''0xCC01:''' Invalid address. (not 4k-aligned)
 +
 
 +
'''0xDC01:''' Invalid memory range. It's either causes overflow, or does not fall into "reserved" address range (aka Alias). See AliasRegionAddress at [[#InfoType]]
  
== svcMapDeviceAddressSpaceByForce ==
+
'''0xFA01:''' Invalid state. (not enough SystemResource (see [[NPDM#SystemResourceSize]]))
  
 +
== UnmapPhysicalMemory ==
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 1,154: Line 1,145:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) W0 || Handle<DeviceAddressSpace> || DeviceAsHandle
+
| (In) X0 || void* || Address
 
|-
 
|-
| (In) W1 || Handle<Process> || ProcessHandle
+
| (In) X1 || uint64_t || Size
 
|-
 
|-
| (In) X2 || void* || SrcAddr
+
| (Out) W0 || [[#Result]] || Result
|-
 
| (In) X3 || u64 || DeviceAsSize
 
|-
 
| (In) X4 || u64 || DeviceAsAddr
 
|-
 
| (In) W5 || [[#Permission]] || Permissions
 
|-
 
| (Out) W0 || [[#Result]] || Ret
 
 
|}
 
|}
 
</div>
 
</div>
  
'''Description:''' Maps an attached device address space to an userspace address.
+
== GetDebugFutureThreadInfo ==
 
 
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 [[SVC#MemoryState|MapDeviceAllowed]] bit set. Bit [[SVC#MemoryAttribute|IsDeviceMapped]] will be set after mapping.
 
 
 
== svcMapDeviceAddressSpaceAligned ==
 
 
 
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! Argument || Type || Name
+
! Argument64 || Argument32 || Type || Name
 +
|-
 +
| (In) X3 || R0, R1 || uint64_t || Timeout
 
|-
 
|-
| (In) W0 || Handle<DeviceAddressSpace> || DeviceAsHandle
+
| (Out) W0 || R0 || [[#Result]] || Result
 
|-
 
|-
| (In) W1 || Handle<Process> || ProcessHandle
+
| (Out) X1 || uint64_t || LastThreadContextParam0
 
|-
 
|-
| (In) X2 || void* || SrcAddr
+
| (Out) X2 || uint64_t || LastThreadContextParam1
 
|-
 
|-
| (In) X3 || u64 || DeviceAsSize
+
| (Out) X3 || uint64_t || LastThreadContextParam2
 
|-
 
|-
| (In) X4 || u64 || DeviceAsAddr
+
| (Out) X4 || uint64_t || LastThreadContextParam3
 
|-
 
|-
| (In) W5 || [[#Permission]] || Permissions
+
| (Out) X5 || uint64_t ||
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (Out) W6 || uint32_t ||
 
|}
 
|}
 
</div>
 
</div>
  
'''Description:''' Maps an attached device address space to an userspace address.
+
== GetLastThreadInfo ==
 
 
Same as [[#svcMapDeviceAddressSpaceByForce]], but the userspace destination address must have the [[SVC#MemoryState|MapDeviceAlignedAllowed]] bit set instead.
 
 
 
== svcUnmapDeviceAddressSpace ==
 
 
 
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 1,210: Line 1,183:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) W0 || Handle<DeviceAddressSpace> || DeviceAsHandle
+
| (In) None || ||  
 
|-
 
|-
| (In) W1 || Handle<Process> || ProcessHandle
+
| (Out) W0 || [[#Result]] || Result
 +
|-
 +
| (Out) X1 || uint64_t || LastThreadContextParam0
 +
|-
 +
| (Out) X2 || uint64_t || LastThreadContextParam1
 
|-
 
|-
| (In) X2 || void* || SrcAddr
+
| (Out) X3 || uint64_t || LastThreadContextParam2
 
|-
 
|-
| (In) X3 || u64 || DeviceAsSize
+
| (Out) X4 || uint64_t || LastThreadContextParam3
 
|-
 
|-
| (In) X4 || u64 || DeviceAsAddr
+
| (Out) X5 || uint64_t ||
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (Out) W6 || uint32_t ||
 
|}
 
|}
 
</div>
 
</div>
  
'''Description:''' Unmaps an attached device address space from an userspace address.
+
== GetResourceLimitLimitValue ==
 
 
== svcGetSystemInfo ==
 
 
 
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! Argument || Type || Name
+
! Argument64 || Argument32 || Type || Name
|-
 
| (In) X1 || u64 || InfoId
 
 
|-
 
|-
| (In) W2 || Handle || Handle
+
| (In) W1 || R1 || Handle<ResourceLimit> || ResourceLimitHandle
 
|-
 
|-
| (In) X3 || u64 || InfoSubId
+
| (In) W2 || R2 || [[#LimitableResource]] || LimitableResource
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (Out) W0 || R0 || [[#Result]] || Result
 
|-
 
|-
| (Out) X1 || u64 || Out
+
| (Out) X1 || R1, R2 || int64_t || LimitValue
 
|}
 
|}
 
</div>
 
</div>
  
{| class=wikitable
+
== GetResourceLimitCurrentValue ==
! Handle type || Id0 || Id1 || Description
+
<div style="display: inline-block;">
|-
+
{| class="wikitable" border="1"
| Zero    || 0 || 0 || TotalMemorySize_Application
 
|-
 
| Zero    || 0 || 1 || TotalMemorySize_Applet
 
|-
 
| Zero    || 0 || 2 || TotalMemorySize_System
 
|-
 
| Zero    || 0 || 3 || TotalMemorySize_SystemUnsafe
 
|-
 
| Zero    || 1 || 0 || CurrentMemorySize_Application
 
|-
 
| Zero    || 1 || 1 || CurrentMemorySize_Applet
 
 
|-
 
|-
| Zero    || 1 || 2 || CurrentMemorySize_System
+
! Argument64 || Argument32 || Type || Name
 
|-
 
|-
| Zero    || 1 || 3 || CurrentMemorySize_SystemUnsafe
+
| (In) W1 || R1 || Handle<ResourceLimit> || ResourceLimitHandle
 
|-
 
|-
| Zero    || 2 || 0 || PrivilegedProcessId_LowerBound
+
| (In) W2 || R2 || [[#LimitableResource]] || LimitableResource
 
|-
 
|-
| Zero    || 2 || 1 || PrivilegedProcessId_UpperBound
+
| (Out) W0 || R0 || [[#Result]] || Result
 
|-
 
|-
 +
| (Out) X1 || R1, R2 || int64_t || CurrentValue
 
|}
 
|}
 +
</div>
  
== svcSetProcessMemoryPermission ==
+
== SetThreadActivity ==
 
 
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 1,277: Line 1,239:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) W0 || Handle<Process> || ProcessHandle
+
| (In) W0 || Handle<Thread> || ThreadHandle
 
|-
 
|-
| (In) X1 || u64 || Addr
+
| (In) W1 || [[#ThreadActivity]] || ThreadActivity
 
|-
 
|-
| (In) X2 || u64 || Size
+
| (Out) W0 || [[#Result]] || Result
|-
 
| (In) W3 || void* || Perm
 
|-
 
| (Out) W0 || [[#Result]] || Ret
 
 
|}
 
|}
 
</div>
 
</div>
  
This sets the memory permissions for the specified memory with the supplied process handle.
+
== GetThreadContext3 ==
 
 
This throws an error(0xD801) when the input perm is >0x5, hence -WX and RWX are not allowed.
 
 
 
== svcMapProcessMemory ==
 
 
 
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 1,300: Line 1,253:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) X0 || u64 || DstAddr
+
| (In) X0 || [[#ThreadContext]]* || ThreadContext
 
|-
 
|-
| (In) W1 || Handle<Process> || ProcessHandle
+
| (In) W1 || Handle<Thread> || ThreadHandle
 
|-
 
|-
| (In) X2 || void* || SrcAddr
+
| (Out) W0 || [[#Result]] || Result
|-
 
| (In) X3 || u64 || Size
 
|-
 
| (Out) W0 || [[#Result]] || Ret
 
 
|}
 
|}
 
</div>
 
</div>
  
Maps the src address from the supplied process handle into the current process.
+
== WaitForAddress ==
 
 
This allows mapping code and rodata with RW- permission.
 
 
 
== svcUnmapProcessMemory ==
 
 
 
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! Argument || Type || Name
+
! Argument64 || Argument32 || Type || Name
 
|-
 
|-
| (In) X0 || void* || DstAddr
+
| (In) X0 || R0 || void* || Address
 
|-
 
|-
| (In) W1 || Handle<Process> || ProcessHandle
+
| (In) W1 || R1 || [[#ArbitrationType]] || ArbitrationType
 
|-
 
|-
| (In) X2 || u64 || SrcAddr
+
| (In) W2 || R2 || uint32_t || Value
 
|-
 
|-
| (In) X3 || u64 || Size
+
| (In) X3 || R3, R4 || uint64_t || Timeout
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (Out) W0 || R0 || [[#Result]] || Result
 
|}
 
|}
 
</div>
 
</div>
  
Unmaps what was mapped by [[#svcMapProcessMemory]].
+
== SignalToAddress ==
 
 
== svcQueryProcessMemory ==
 
 
 
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! Argument || Type || Name
+
! Argument64 || Argument32 || Type || Name
 
|-
 
|-
| (In) X0 || [[#MemoryInfo]]* || MemInfoPtr
+
| (In) X0 || R0 || void* || Address
 
|-
 
|-
| (In) W2 || Handle<Process> || ProcessHandle
+
| (In) W1 || R1 || [[#SignalType]] || SignalType
 
|-
 
|-
| (In) X3 || u64 || Addr
+
| (In) W2 || R2 || uint32_t || Value
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (In) W3 || R3 || uint32_t || NumToSignal
 
|-
 
|-
| (Out) W1 || PageInfo || PageInfo
+
| (Out) W0 || R0  || [[#Result]] || Result
 
|}
 
|}
 
</div>
 
</div>
  
Equivalent to [[#svcQueryMemory]] except takes a process handle.
+
== SynchronizePreemptionState ==
 
 
== svcMapProcessCodeMemory ==
 
 
 
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 1,365: Line 1,303:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) W0 || Handle<Process> || ProcessHandle
+
| (In) None || ||  
|-
 
| (In) X1 || u64 || DstAddr
 
|-
 
| (In) X2 || u64 || SrcAddr
 
|-
 
| (In) X3 || u64 || Size
 
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (Out) None || ||  
 
|}
 
|}
 
</div>
 
</div>
  
Takes a process handle, and maps normal heap in that process as executable code in that process. Used when loading NROs. This does not support using the current-process handle alias.
+
== GetResourceLimitPeakValue ==
 
 
== svcUnmapProcessCodeMemory ==
 
 
 
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! Argument || Type || Name
+
! Argument64 || Argument32 || Type || Name
|-
 
| (In) W0 || Handle<Process> || ProcessHandle
 
 
|-
 
|-
| (In) X1 || u64 || DstAddr
+
| (In) W1 || R1 || Handle<ResourceLimit> || ResourceLimitHandle
 
|-
 
|-
| (In) X2 || u64 || SrcAddr
+
| (In) W2 || R2 || [[#LimitableResource]] || LimitableResource
 
|-
 
|-
| (In) X3 || u64 || Size
+
| (Out) W0 || R0 || [[#Result]] || Result
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (Out) X1 || R1, R2 || int64_t || PeakValue
 
|}
 
|}
 
</div>
 
</div>
  
Unmaps what was mapped by [[#svcMapProcessCodeMemory]].
+
== DumpInfo ==
 
 
== svcCreateProcess ==
 
 
 
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 1,407: Line 1,331:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) X1 || [[#CreateProcessInfo]]* || InfoPtr
+
| (In) X0 || [[#DumpInfoType]] || DumpInfoType
 
|-
 
|-
| (In) X2 || u64 || CapabilitiesPtr
+
| (In) X1 || uint64_t || DumpInfoSubType
 
|-
 
|-
| (In) X3 || u64 || CapabilitiesNum
+
| (Out) W0 || [[#Result]] || Result
|-
 
| (Out) W0 || [[#Result]] || Ret
 
|-
 
| (Out) W1 || Handle<Process> || ProcessHandle
 
 
|}
 
|}
 
</div>
 
</div>
  
Takes a [[#CreateProcessInfo]] as input.
+
Stubbed in retail kernel.
  
== svcGetProcessInfo ==
+
[4.0.0+] This function was removed and replaced by [[#KernelDebug]].
  
 +
== KernelDebug ==
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 1,428: Line 1,349:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) W0 || Handle<Process> || ProcessHandle
+
| (In) W0 || [[#KernelDebugType]] || KernelDebugType
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
+
| (In) X1 || uint64_t ||  
 
|-
 
|-
| (Out) W1 || [[#ProcessState]] || State
+
| (In) X2 || uint64_t ||
 +
|-
 +
| (In) X3 || uint64_t ||
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 
|}
 
|}
 
</div>
 
</div>
  
Returns an enum with value 0-7.
+
Stubbed in retail kernel.
 
 
== Debugging ==
 
[2.0.0+] Exactly 6 debug SVCs require that [[SPL_services#GetConfig|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.
 
 
 
== svcSetHardwareBreakPoint ==
 
  
 +
== ChangeKernelTraceState ==
 
<div style="display: inline-block;">
 
<div style="display: inline-block;">
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 1,456: Line 1,369:
 
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) W0 || u32 || hardware_breakpoint_id
+
| (In) W0 || [[#KernelTraceState]] || KernelTraceState
 
|-
 
|-
| (In) W1 || u64 || flags
+
| (Out) W0 || [[#Result]] || Result
|-
 
| (In) W2 || u64 || value
 
|-
 
| (Out) W0 || [[#Result]] || Ret
 
 
|}
 
|}
 
</div>
 
</div>
  
Sets one of the AArch64 hardware breakpoints. The nintendo switch has 6 hardware breakpoints, and 4 hardware watchpoints. The syscall has two behaviors depending on the value of hardware_breakpoint_id:
+
Stubbed in retail kernel.
  
If hardware_breakpoint_id < 0x10, then it sets one of the AArch64 hardware breakpoints. Flags will go to DBGBCRn_EL1, and value to DBGBVRn_EL1. The only flags the user is allowed to set are those in the bitmask 0x7F01E1. Furthermore, the kernel will or it with 0x4004, in order to set various security flags to guarantee the watchpoints only triggers for code in EL0. If the user asks for a Breakpoint Type of ContextIDR match, the kernel shall use the given debug_handle to set DBGBVRn_EL1 to the ContextID of the debugged process.
+
== CreateSession ==
 
+
<div style="display: inline-block;">
 
+
{| class="wikitable" border="1"
If hardware_breakpoint_id is between 0x10 and 0x20 (exclusive), then it sets one of the AArch64 hardware watchpoints. Flags will go to DBGWCRn_EL1, and the value to DBGWVRn_EL1. The only flags the user is allowed to set are those in the bitmask 0xFF0F1FF9. Furthermore, the kernel will or it with 0x104004. This will set various security flags, and set the watchpoint type to be a Linked Watchpoint. This means that you need to link it to a Linked ContextIDR breakpoint. Check the ARM documentation for more information.
+
|-
 
+
! Argument || Type || Name
Note that hardware_breakpoint_id 0 to 4 match only to Virtual Address, while hardware_breakpoint_id 5 and 6 match against either Virtual Address, ContextID, or VMID. As such, if you are configuring a breakpoint to link for a watchpoint, make sure you use hardware_breakpoint_id 5 or 6.
+
|-
 
+
| (In) W2 || bool || IsLight
 
 
For more documentation for hardware breakpoints, check out the AArch64 documentation for the [http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0488h/way1382455558968.html DBGBCRn_EL1 register] and the [http://infocenter.arm.com/help/topic/com.arm.doc.ddi0488h/way1382455560629.html DBGWCRn_EL1 register]
 
 
 
= Enum/Structures =
 
== ThreadContextRequestFlags ==
 
Bitfield of one of more of these:
 
 
 
{| class=wikitable
 
! Bit || Bitmask || Name
 
 
|-
 
|-
| 0 || 1 || NormalContext
+
| (In) X3 || uint64_t || Name
 
|-
 
|-
| 1 || 2 ||
+
| (Out) W0 || [[#Result]] || Result
 
|-
 
|-
| 2 || 4 ||
+
| (Out) W1 || Handle<ServerSession> || ServerSessionHandle
 
|-
 
|-
| 3 || 8 ||
+
| (Out) W2 || Handle<ClientSession> || ClientSessionHandle
 
|}
 
|}
 +
</div>
  
== DeviceName ==
+
== AcceptSession ==
{| class=wikitable
+
<div style="display: inline-block;">
! Value || Name
+
{| class="wikitable" border="1"
 
|-
 
|-
| 0 || DeviceName_AFI
+
! Argument || Type || Name
 
|-
 
|-
| 1 || DeviceName_AVPC
+
| (In) W1 || Handle<Port> || PortHandle
 
|-
 
|-
| 2 || DeviceName_DC
+
| (Out) W0 || [[#Result]] || Result
 
|-
 
|-
| 3 || DeviceName_DCB
+
| (Out) W1 || Handle<ServerSession> || ServerSessionHandle
 +
|}
 +
</div>
 +
 
 +
=== Result codes ===
 +
'''0xf201:''' No session waiting to be accepted
 +
 
 +
== ReplyAndReceiveLight ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 
|-
 
|-
| 4 || DeviceName_HC
+
! Argument || Type || Name
 
|-
 
|-
| 5 || DeviceName_HDA
+
| (In) W0 || Handle<Port> or Handle<ServerSession> || Handle
 
|-
 
|-
| 6 || DeviceName_ISP2
+
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
== ReplyAndReceive ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 
|-
 
|-
| 7 || DeviceName_MSENCNVENC
+
! Argument64 || Argument32 || Type || Name
 
|-
 
|-
| 8 || DeviceName_NV
+
| (In) X1 || R1 || Handle<Port>* or Handle<ServerSession>* || Handles
 
|-
 
|-
| 9 || DeviceName_NV2
+
| (In) W2 || R2 || uint32_t || NumHandles
 
|-
 
|-
| 10 || DeviceName_PPCS
+
| (In) W3 || R3 || Handle<ServerSession> || ReplyTargetSessionHandle
 
|-
 
|-
| 11 || DeviceName_SATA
+
| (In) X4 || R0, R4 || uint64_t || Timeout
 
|-
 
|-
| 12 || DeviceName_VI
+
| (Out) W0 || R0 || [[#Result]] || Result
 
|-
 
|-
| 13 || DeviceName_VIC
+
| (Out) W1 || R1 || uint32_t || HandleIndex
|-
+
|}
| 14 || DeviceName_XUSB_HOST
+
</div>
|-
+
 
| 15 || DeviceName_XUSB_DEV
+
If ReplyTargetSessionHandle is not zero, a reply from the TLS will be sent to that session.
|-
+
Then it will wait until either of the passed sessions has an incoming message, is closed, a passed port has an incoming connection, or the timeout expires.
| 16 || DeviceName_TSEC
+
If there is an incoming message, it is copied to the TLS.
|-
+
 
| 17 || DeviceName_PPCS1
+
If ReplyTargetSessionHandle is zero, the TLS should contain a blank message. If this message has a C descriptor, the buffer it points to will be used as the pointer buffer. See [[IPC_Marshalling#IPC_buffers]]. Note that a pointer buffer cannot be specified if ReplyTargetSessionHandle is not zero.
 +
 
 +
After being validated, passed handles will be enumerated in order; even if a session has been closed, if one that appears earlier in the list has an incoming message, it will take priority and a result code of 0x0 will be returned.
 +
 
 +
=== Result codes ===
 +
'''0x0:''' Success. Either a session has an incoming message or a port has an incoming connection. HandleIndex is set appropriately.
 +
 
 +
'''0xea01:''' Timeout. No handles were signalled before the timeout expired. HandleIndex is not updated.
 +
 
 +
'''0xf601:''' Port remote dead. One of the sessions has been closed. HandleIndex is set appropriately.
 +
 
 +
== ReplyAndReceiveWithUserBuffer ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 
|-
 
|-
| 18 || DeviceName_DC1
+
! Argument64 || Argument32 || Type || Name
 
|-
 
|-
| 19 || DeviceName_SDMMC1A
+
| (In) X1 || R1 || void* || Address
 
|-
 
|-
| 20 || DeviceName_SDMMC2A
+
| (In) X2 || R2 || uint64_t || Size
 
|-
 
|-
| 21 || DeviceName_SDMMC3A
+
| (In) X3 || R3 || Handle<Port>* or Handle<ServerSession>* || Handles
 
|-
 
|-
| 22 || DeviceName_SDMMC4A
+
| (In) W4 || R0 || uint32_t || NumHandles
 
|-
 
|-
| 23 || DeviceName_ISP2B
+
| (In) W5 || R4 || Handle<ServerSession> || ReplyTargetSessionHandle
 
|-
 
|-
| 24 || DeviceName_GPU
+
| (In) X6 || R5, R6 || uint64_t || Timeout
 
|-
 
|-
| 25 || DeviceName_GPUB
+
| (Out) W0 || R0 || [[#Result]] || Result
 
|-
 
|-
| 26 || DeviceName_PPCS2
+
| (Out) W1 || R1 || uint32_t || HandleIndex
 +
|}
 +
</div>
 +
 
 +
== CreateEvent ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 
|-
 
|-
| 27 || DeviceName_NVDEC
+
! Argument || Type || Name
 
|-
 
|-
| 28 || DeviceName_APE
+
| (In) None || ||
 
|-
 
|-
| 29 || DeviceName_SE
+
| (Out) W0 || [[#Result]] || Result
 
|-
 
|-
| 30 || DeviceName_NVJPG
+
| (Out) W1 || Handle<WritableEvent> || WritableEventHandle
 
|-
 
|-
| 31 || DeviceName_HC1
+
| (Out) W2 || Handle<ReadableEvent> || ReadableEventHandle
 +
|}
 +
</div>
 +
 
 +
== MapPhysicalMemoryUnsafe ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 
|-
 
|-
| 32 || DeviceName_SE1
+
! Argument || Type || Name
 
|-
 
|-
| 33 || DeviceName_AXIAP
+
| (In) X0 || void* || Address
 
|-
 
|-
| 34 || DeviceName_ETR
+
| (In) X1 || uint64_t || Size
 
|-
 
|-
| 35 || DeviceName_TSECB
+
| (Out) W0 || [[#Result]] || Result
|-
+
|}
| 36 || DeviceName_TSEC1
+
</div>
 +
 
 +
Same as [[#MapPhysicalMemory]] except it always uses pool partition 0.
 +
 
 +
== UnmapPhysicalMemoryUnsafe ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 
|-
 
|-
| 37 || DeviceName_TSECB1
+
| (In) X0 || void* || Address
 
|-
 
|-
| 38 || DeviceName_NVDEC1
+
| (In) X1 || uint64_t || Size
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 
|}
 
|}
 +
</div>
  
== CodeMemoryOperation ==
+
== SetUnsafeLimit ==
{| class=wikitable
+
<div style="display: inline-block;">
! Value || Name
+
{| class="wikitable" border="1"
 
|-
 
|-
| 0 || CodeMemoryOperation_MapOwner
+
! Argument || Type || Name
 
|-
 
|-
| 1 || CodeMemoryOperation_MapSlave
+
| (In) X0 || uint64_t || Limit
 
|-
 
|-
| 2 || CodeMemoryOperation_UnmapOwner
+
| (Out) W0 || [[#Result]] || Result
|-
 
| 3 || CodeMemoryOperation_UnmapSlave
 
 
|}
 
|}
 +
</div>
  
 
+
== CreateCodeMemory ==
== LimitableResource ==
+
<div style="display: inline-block;">
{| class=wikitable
+
{| class="wikitable" border="1"
! Value || Name
 
 
|-
 
|-
| 0 || LimitableResource_Memory
+
! Argument || Type || Name
 
|-
 
|-
| 1 || LimitableResource_Threads
+
| (In) X1 || void* || Address
 
|-
 
|-
| 2 || LimitableResource_Events
+
| (In) X2 || uint64_t || Size
 
|-
 
|-
| 3 || LimitableResource_TransferMemories
+
| (Out) W0 || [[#Result]] || Result
 
|-
 
|-
| 4 || LimitableResource_Sessions
+
| (Out) W1 || Handle<CodeMemory> || CodeMemoryHandle
 
|}
 
|}
 +
</div>
  
== ProcessInfoType ==
+
Takes an address range with backing memory to create the code memory object.
  
{| class=wikitable
+
The memory is initially memset to 0xFF after being locked.
! Value || Name
 
|-
 
| 0 || [[#ProcessState|ProcessInfoType_ProcessState]]
 
|-
 
|}
 
  
== ProcessState ==
+
== ControlCodeMemory ==
{| class=wikitable
+
<div style="display: inline-block;">
! Value || Name || Notes
+
{| class="wikitable" border="1"
 
|-
 
|-
| 0 || ProcessState_Created ||
+
! Argument64 || Argument32 || Type || Name
 
|-
 
|-
| 1 || ProcessState_CreatedAttached ||
+
| (In) W0 || R0 || Handle<CodeMemory> || CodeMemoryHandle
 
|-
 
|-
| 2 || ProcessState_Started ||
+
| (In) W1 || R1 || [[#CodeMemoryOperation]] || CodeMemoryOperation
 
|-
 
|-
| 3 || ProcessState_Crashed || Processes will not enter this state unless they were created with [[#CreateProcessInfo|EnableDebug]].
+
| (In) X2 || R2, R3 || void* || Address
 
|-
 
|-
| 4 || ProcessState_StartedAttached ||
+
| (In) X3 || R4, R5 || uint64_t || Size
 
|-
 
|-
| 5 || ProcessState_Exiting ||
+
| (In) W4 || R6 || [[#MemoryPermission]] || MemoryPermission
 
|-
 
|-
| 6 || ProcessState_Exited ||
+
| (Out) W0 || R0 || [[#Result]] || Result
|-
 
| 7 || ProcessState_DebugSuspended ||
 
 
|}
 
|}
 +
</div>
  
== DebugThreadParam ==
+
Maps the backing memory for a CodeMemory object into the current process.
{| class=wikitable
 
! Value || Name
 
|-
 
| 0 || DebugThreadParam_DynamicPriority
 
|-
 
| 1 || DebugThreadParam_SchedulingStatus
 
|-
 
| 2 || DebugThreadParam_PreferredCpuCore
 
|-
 
| 3 || DebugThreadParam_CurrentCpuCore
 
|-
 
| 4 || DebugThreadParam_AffinityMask
 
|}
 
  
Dynamic priority: output in out2
+
For [[#CodeMemoryOperation|MapOwner]], memory permission must be RW-.
  
Scheduling status: out1 contains bit0: is debug-suspended, bit1: is user-suspended (svcSetThreadActivity 1 or svcSetProcessActivity 1).
+
For [[#CodeMemoryOperation|MapSlave]], memory permission must be R-- or R-X.
Out2 contains {suspended, idle, running, terminating} => {5, 0, 1, 4}
 
  
DebugThreadParam_PreferredCpuCore: output in out2
+
Operations [[#CodeMemoryOperation|UnmapOwner/UnmapSlave]] unmap memory that was previously mapped this way.
  
DebugThreadParam_CurrentCpuCore: output in out2
+
This allows one "secure JIT" process to map the code memory as RW-, and the other "slave" process to map it R-X.
  
DebugThreadParam_AffinityMask: output in out1
+
[5.0.0+] Error 0xE401 is now returned when the process owner of the Code memory object is the same as the current process.
  
== CreateProcessInfo ==
+
== SleepSystem ==
{| class=wikitable
+
<div style="display: inline-block;">
! Offset || Length || Bits || Description
+
{| class="wikitable" border="1"
 
|-
 
|-
| 0 || 12 || || ProcessName (doesn't have to be null-terminated)
+
! Argument || Type || Name
 
|-
 
|-
| 0 || 4 || || ProcessCategory (0: regular title, 1: kernel built-in)
+
| (In) None || ||  
 
|-
 
|-
| 0x10 || 8 || || TitleId
+
| (Out) None || ||  
|-
+
|}
| 0x18 || 8 || || CodeAddr
+
</div>
|-
+
 
| 0x20 || 4 || || CodeNumPages
+
== ReadWriteRegister ==
|-
+
<div style="display: inline-block;">
| 0x24 || 4 || || MmuFlags
+
{| class="wikitable" border="1"
|-
 
| || || Bit0 || IsAarch64
 
|-
 
| || || Bit3-1 || [[#AddressSpaceType]]
 
|-
 
| || || Bit4 || [2.0.0+] EnableDebug
 
 
|-
 
|-
| || || Bit5 || EnableAslr
+
! Argument64 || Argument32 || Type || Name
 
|-
 
|-
| || || Bit6 || UseSystemMemBlocks
+
| (In) X1 || R2, R3 || uint64_t || RegisterAddress
 
|-
 
|-
| || || Bit7 || [4.0.0] ?
+
| (In) W2 || R0 || uint32_t || RwMask
 
|-
 
|-
| || || Bit10-7 || [5.0.0+] PoolPartition (0=Application, 1=Applet, 2=Sysmodule, 3=Nvservices)
+
| (In) W3 || R1 || uint32_t || InValue
 
|-
 
|-
| 0x28 || 4 || || ResourceLimitHandle
+
| (Out) W0 || R0 || [[#Result]] || Result
 
|-
 
|-
| 0x2C || 4 || || [3.0.0+] PersonalMmHeapNumPages
+
| (Out) W1 || R1 || uint32_t || OutValue
 
|}
 
|}
 +
</div>
  
On [1.0.0] there's only one pool.
+
Read/write IO registers with a hardcoded whitelist. Input address is physical-address and must be aligned to 4.
  
On [2.0.0-4.0.0] PoolPartition is 1 for built-ins and 0 for rest.
+
rw_mask is 0 for reading and 0xffffffff for writing. You can also write individual bits by using a mask value.
  
On [5.0.0] PoolPartition is specified in CreateProcessArgs. There are now 4 pool partitions.
+
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.
  
=== AddressSpaceType ===
+
The whitelist is:
{| class=wikitable
+
 
! Type || Name || Width || Description
+
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#ReadWriteRegister|ReadWriteRegister]].
 +
 
 +
[4.0.0+] Access to the Memory Controller (0x70019000) also uses smcReadWriteRegister.
 +
 
 +
Here is the whitelist imposed by that SMC, relative to the start of the PMC registers:
 +
 
 +
0x000, 0x00c, 0x010, 0x014, 0x01c, 0x020, 0x02c, 0x030, 0x034, 0x038, 0x03c, 0x040, 0x044, 0x048, 0x0dc, 0x0e0, 0x0e4, 0x160, 0x164, 0x168, 0x170, 0x1a8, 0x1b8, 0x1bc, 0x1c0, 0x1c4, 0x1c8, 0x2b4, 0x2d4, 0x440, 0x4d8
 +
 
 +
Here is the whitelist imposed by the SMC [[SMC#ReadWriteRegister|ReadWriteRegister]] (checked in addition to the whitelist in the ReadWriteRegister SVC), relative to the start of the MC registers:
 +
 
 +
0x000, 0x004, 0x008, 0x00C, 0x010, 0x01C, 0x020, 0x030, 0x034, 0x050, 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, 0x238, 0x240, 0x244, 0x250, 0x254, 0x258, 0x264, 0x268, 0x26C, 0x270, 0x274, 0x280, 0x284, 0x288, 0x28C, 0x294, 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, 0x4C4, 0x4C8, 0x4CC, 0x50C, 0x554, 0x558, 0x55C, 0x584, 0x588, 0x58C, 0x670, 0x674, 0x690, 0x694, 0x698, 0x69C, 0x6A0, 0x6A4, 0x6C0, 0x6C4, 0x6F0, 0x6F4, 0x960, 0x970, 0x974, 0x9B8, 0xA20, 0xA24, 0xA88, 0xA94, 0xA98, 0xA9C, 0xAA0, 0xAA4, 0xAA8, 0xAAC, 0xAB0, 0xAB4, 0xAB8, 0xABC, 0xAC0, 0xAC4, 0xAC8, 0xACC, 0xAD0, 0xAD4, 0xAD8, 0xADC, 0xAE0, 0xB88, 0xB8C, 0xBC4, 0xBC8, 0xBCC, 0xBD0, 0xBD4, 0xBD8, 0xBDC, 0xBE0, 0xBE4, 0xBE8, 0xBEC, 0xC00, 0xC5C, 0xCAC
 +
 
 +
== SetProcessActivity ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 
|-
 
|-
| 0 || Normal_32Bit || 32 ||
+
! Argument || Type || Name
 
|-
 
|-
| 1 || Normal_36Bit || 36 ||
+
| (In) W0 || Handle<Process> || ProcessHandle
 
|-
 
|-
| 2 || WithoutMap_32Bit || 32 || Appears to be missing map region [?]
+
| (In) W1 || [[#ProcessActivity]] || ProcessActivity
 
|-
 
|-
| 3 || [2.0.0+] Normal_39Bit || 39 ||
+
| (Out) W0 || [[#Result]] || Result
 
|}
 
|}
 +
</div>
  
== MemoryInfo ==
+
== CreateSharedMemory ==
{| class=wikitable
+
<div style="display: inline-block;">
! Offset || Length || Description
+
{| class="wikitable" border="1"
 
|-
 
|-
| 0 || 8 || BaseAddress
+
! Argument || Type || Name
 
|-
 
|-
| 8 || 8 || Size
+
| (In) W1 || uint64_t || Size
 
|-
 
|-
| 0x10 || 4 || MemoryType: lower 8 bits of [[#MemoryState]]
+
| (In) W2 || [[#MemoryPermission]] || LocalMemoryPermission
 
|-
 
|-
| 0x14 || 4 || [[#MemoryAttribute]]
+
| (In) W3 || [[#MemoryPermission]] || RemoteMemoryPermission
 
|-
 
|-
| 0x18 || 4 || Permission (bit0: R, bit1: W, bit2: X)
+
| (Out) W0 || [[#Result]] || Result
|-
 
| 0x1C || 4 || IpcRefCount
 
|-
 
| 0x20 || 4 || DeviceRefCount
 
 
|-
 
|-
| 0x24 || 4 || Padding: always zero
+
| (Out) W1 || Handle<SharedMemory> || SharedMemoryHandle
 
|}
 
|}
 +
</div>
  
== MemoryAttribute ==
+
Other perm can be used to enforce permission 1, 3, or 0x10000000 if don't care.
{| class=wikitable
+
 
! Bits || Description
+
Allocates memory from the current process' pool partition.
|-
 
| 0 || IsBorrowed
 
|-
 
| 1 || IsIpcMapped: when IpcRefCount > 0.
 
|-
 
| 2 || IsDeviceMapped: when DeviceRefCount > 0.
 
|-
 
| 3 || IsUncached
 
|}
 
  
== MemoryState ==
+
== MapTransferMemory ==
{| class=wikitable
+
<div style="display: inline-block;">
! Bits || Description
+
{| class="wikitable" border="1"
 
|-
 
|-
| 7-0 || Type
+
! Argument || Type || Name
 
|-
 
|-
| 8 || [[#svcSetMemoryPermission|PermissionChangeAllowed]]
+
| (In) X0 || Handle<TransferMemory> || TransferMemoryHandle
 
|-
 
|-
| 9 || ForceReadWritableByDebugSyscalls
+
| (In) X1 || void* || Address
 
|-
 
|-
| 10 || IpcSendAllowed_Type0
+
| (In) X2 || uint64_t || Size
 
|-
 
|-
| 11 || IpcSendAllowed_Type3
+
| (In) W3 || [[#MemoryPermission]] || MemoryPermission
 
|-
 
|-
| 12 || IpcSendAllowed_Type1
+
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
You must pass same size and permissions as given in [[#CreateTransferMemory]], otherwise error.
 +
 
 +
== UnmapTransferMemory ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 
|-
 
|-
| 14 || [[#svcSetProcessMemoryPermission|ProcessPermissionChangeAllowed]]
+
! Argument || Type || Name
 
|-
 
|-
| 15 || [[#svcMapMemory|MapAllowed]]
+
| (In) X0 || Handle<TransferMemory> || TransferMemoryHandle
 
|-
 
|-
| 16 || [[#svcUnmapProcessCodeMemory|UnmapProcessCodeMemoryAllowed]]
+
| (In) X1 || void* || Address
 
|-
 
|-
| 17 || [[#svcCreateTransferMemory|TransferMemoryAllowed]]
+
| (In) X2 || uint64_t || Size
 
|-
 
|-
| 18 || [[#svcQueryPhysicalAddress|QueryPhysicalAddressAllowed]]
+
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
Size must match size given in map syscall, otherwise there's an invalid-size error.
 +
 
 +
== CreateInterruptEvent ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 
|-
 
|-
| 19 || MapDeviceAllowed ([[#svcMapDeviceAddressSpace]] and [[#svcMapDeviceAddressSpaceByForce]])
+
! Argument || Type || Name
 
|-
 
|-
| 20 || [[#svcMapDeviceAddressSpaceAligned|MapDeviceAlignedAllowed]]
+
| (In) X1 || [[#Interrupt]] || Interrupt
 
|-
 
|-
| 21 || [[#svcSendSyncRequestWithUserBuffer|IpcBufferAllowed]]
+
| (In) W2 || [[#InterruptType]] || InterruptType
 
|-
 
|-
| 22 || IsPoolAllocated/IsReferenceCounted
+
| (Out) W0 || [[#Result]] || Result
|-
 
| 23 || [[#svcMapProcessMemory|MapProcessAllowed]]
 
 
|-
 
|-
| 24 || [[#svcSetMemoryAttribute|AttributeChangeAllowed]]
+
| (Out) W1 || Handle<ReadableEvent> || ReadableEventHandle
|-
 
| 25 || [4.0.0+] CodeMemoryAllowed
 
 
|}
 
|}
 +
</div>
 +
 +
Creates an event handle for the given IRQ number. Waiting on this handle will wait until the IRQ is triggered. The InterruptType argument configures the triggering. If it is 0, the IRQ is active HIGH level sensitive, if it is 1 it is rising-edge sensitive.
 +
 +
=== Result codes ===
 +
'''0x0:''' Success.
 +
 +
'''0xF001:''' Flags was > 1
 +
 +
'''0xF201:''' IRQ above 0x3FF or outside the [[NPDM#Kernel_Access_Control|IRQ access mask]] was given.
 +
 +
'''0xCE01:''' A SlabHeap was exhausted (too many interrupts created).
 +
 +
'''0xF401:''' IRQ already has an event registered.
 +
 +
'''0xD201:''' The handle table is full. Try closing some handles.
  
{| class=wikitable
+
== QueryPhysicalAddress ==
! Value || Type || Meaning
+
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 
|-
 
|-
| 0x00000000 || MemoryType_Unmapped ||
+
| (In) X1 || void* || VirtualAddress
 
|-
 
|-
| 0x00002001 || MemoryType_Io || Mapped by kernel capability parsing in [[#svcCreateProcess]].
+
| (Out) W0 || [[#Result]]|| Result
 
|-
 
|-
| 0x00042002 || MemoryType_Normal || Mapped by kernel capability parsing in [[#svcCreateProcess]].
+
| (Out) X1 || uint64_t || PhysicalMemoryInfoAddress
 
|-
 
|-
| 0x00DC7E03 || MemoryType_CodeStatic || Mapped during [[#svcCreateProcess]].
+
| (Out) X2 || uint64_t || PhysicalMemoryInfoBaseAddress
 
|-
 
|-
| [1.0.0+]
+
| (Out) X3 || uint64_t || PhysicalMemoryInfoSize
 
+
|}
0x01FEBD04
+
</div>
 +
 
 +
Queries the physical address of a virtual address. Will always fetch the lowest page-aligned mapping that contains the provided physical address.
  
[4.0.0+]
+
The returned PhysicalMemoryInfoBaseAddress is the virtual address of that page-aligned mapping, while PhysicalMemoryInfoAddress is the physical address of that page. PhysicalMemoryInfoSize is the amount of continuous physical memory in that mapping.
  
0x03FEBD04
+
== QueryIoMapping ==
|| MemoryType_CodeMutable || Transition from 0xDC7E03 performed by [[#svcSetProcessMemoryPermission]].
+
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument64 || Argument32 || Type || Name
 +
|-
 +
| (In) X1 || R2, R3 || uint64_t || IoAddress
 +
|-
 +
| (In) X2 || R0 || uint64_t || Size
 +
|-
 +
| (Out) W0 || R0 || [[#Result]] || Result
 
|-
 
|-
| [1.0.0+]
+
| (Out) X1 || R1 || void* || VirtualAddress
0x017EBD05
+
|}
 +
</div>
  
[4.0.0+]
+
Returns a virtual address mapped to a given IO range.
  
0x037EBD05
+
== CreateDeviceAddressSpace ==
|| MemoryType_Heap || Mapped using [[#svcSetHeapSize]].
+
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument64 || Argument32 || Type || Name
 
|-
 
|-
| 0x00402006 || MemoryType_SharedMemory || Mapped using [[#svcMapSharedMemory]].
+
| (In) X1 || R2, R3 || uint64_t || DeviceAddressSpaceStartAddress
 
|-
 
|-
| 0x00482907 || [1.0.0] MemoryType_Alias || Mapped using [[#svcMapMemory]].
+
| (In) X2 || R0, R1 || uint64_t || DeviceAddressSpaceEndAddress
 
|-
 
|-
| 0x00DD7E08 || MemoryType_ModuleCodeStatic || Mapped using [[#svcMapProcessCodeMemory]].
+
| (Out) W0 || R0 || [[#Result]] || Result
 
|-
 
|-
| [1.0.0+]
+
| (Out) W1 || R1 || Handle<DeviceAddressSpace> || DeviceAddressSpaceHandle
 +
|}
 +
</div>
  
0x01FFBD09
+
Creates a virtual address space for binding device address spaces and returns a handle.
  
[4.0.0+]
+
StartAddr is normally set to 0 and EndAddr is normally set to 0xFFFFFFFF.
  
0x03FFBD09
+
== AttachDeviceAddressSpace ==
|| MemoryType_ModuleCodeMutable || Transition from 0xDD7E08 performed by [[#svcSetProcessMemoryPermission]].
+
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 
|-
 
|-
| 0x005C3C0A || [[IPC_Marshalling|MemoryType_IpcBuffer0]] || IPC buffers with descriptor flags=0.
+
! Argument || Type || Name
 
|-
 
|-
| 0x005C3C0B || MemoryType_Stack || Mapped using [[#svcMapMemory]].
+
| (In) W0 || [[#DeviceName]] || DeviceName
 
|-
 
|-
| 0x0040200C || [[Thread Local Storage|MemoryType_ThreadLocal]] || Mapped during [[#svcCreateThread]].
+
| (In) X1 || Handle<DeviceAddressSpace> || DeviceAddressSpaceHandle
 
|-
 
|-
| 0x015C3C0D || MemoryType_TransferMemoryIsolated || Mapped using [[#svcMapTransferMemory]] when the owning process has perm=0.
+
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
Attaches a device address space to a [[#DeviceName|device]].
 +
 
 +
== DetachDeviceAddressSpace ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 
|-
 
|-
| 0x005C380E || MemoryType_TransferMemory || Mapped using [[#svcMapTransferMemory]] when the owning process has perm!=0.
+
! Argument || Type || Name
 
|-
 
|-
| 0x0040380F || MemoryType_ProcessMemory || Mapped using [[#svcMapProcessMemory]].
+
| (In) W0 || [[#DeviceName]] || DeviceName
 
|-
 
|-
| 0x00000010 || MemoryType_Reserved ||
+
| (In) X1 || Handle<DeviceAddressSpace> || DeviceAddressSpaceHandle
 
|-
 
|-
| 0x005C3811 || [[IPC_Marshalling|MemoryType_IpcBuffer1]] || IPC buffers with descriptor flags=1.
+
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
Detaches a device address space from a [[#DeviceName|device]].
 +
 
 +
== MapDeviceAddressSpaceByForce ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 
|-
 
|-
| 0x004C2812 || [[IPC_Marshalling|MemoryType_IpcBuffer3]] || IPC buffers with descriptor flags=3.
+
! Argument64 || Argument32 || Type || Name
 
|-
 
|-
| 0x00002013 || MemoryType_KernelStack || Mapped in kernel during [[#svcCreateThread]].
+
| (In) W0 || R0 || Handle<DeviceAddressSpace> || DeviceAddressSpaceHandle
 
|-
 
|-
| 0x00402214 || [4.0.0+] MemoryType_CodeReadOnly || Mapped in kernel during [[#svcControlCodeMemory]].
+
| (In) W1 || R1 || Handle<Process> || ProcessHandle
 
|-
 
|-
| 0x00402015 || [4.0.0+] MemoryType_CodeWritable || Mapped in kernel during [[#svcControlCodeMemory]].
+
| (In) X2 || R2, R3 || void* || Address
|}
 
 
 
== ArbitrationType ==
 
 
 
{| class=wikitable
 
! Value || Type
 
 
|-
 
|-
| 0x0 || WaitIfLessThan
+
| (In) X3 || R4 || uint64_t || DeviceAddressSpaceSize
 
|-
 
|-
| 0x1 || DecrementAndWaitIfLessThan
+
| (In) X4 || R5, R6 || uint64_t || DeviceAddressSpaceAddress
 
|-
 
|-
| 0x2 || WaitIfEqual
+
| (In) W5 || R7 || uint32_t || Option
 
|-
 
|-
 +
| (Out) W0 || R0 || [[#Result]] || Result
 
|}
 
|}
 +
</div>
 +
 +
Maps an attached device address space to an userspace address.
  
== SignalType ==
+
Address is the userspace destination address, while DeviceAddressSpaceAddress is the source address between DeviceAddressSpaceStartAddress and DeviceAddressSpaceEndAddress (passed to [[#CreateDeviceAddressSpace]]).
 +
 
 +
The userspace destination address must have the [[SVC#MemoryState|FlagCanDeviceMap]] bit set. Bit [[SVC#MemoryAttribute|DeviceShared]] will be set after mapping.
  
{| class=wikitable
+
The Option encodes a [[#MemoryPermission]] in the low 16 bits, and an indicator of IO mapping in the high bits.
! Value || Type
+
 
 +
== MapDeviceAddressSpaceAligned ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument64 || Argument32 || Type || Name
 
|-
 
|-
| 0x0 || Signal
+
| (In) W0 || R0 || Handle<DeviceAddressSpace> || DeviceAddressSpaceHandle
 
|-
 
|-
| 0x1 || SignalAndIncrementIfEqual
+
| (In) W1 || R1 || Handle<Process> || ProcessHandle
 
|-
 
|-
| 0x2 || SignalAndModifyBasedOnWaitingThreadCountIfEqual
+
| (In) X2 || R2, R3 || void* || Address
 
|-
 
|-
|}
+
| (In) X3 || R4 || uint64_t || DeviceAddressSpaceSize
 
 
== ContinueDebugFlagsOld ==
 
[1.0.0-2.3.0]
 
 
 
{| class=wikitable
 
! Bit || Bitmask || Description
 
 
|-
 
|-
| 0 || 1 || IgnoreException (note: ResumeAllThreads or debug-suspended-thread-id needed)
+
| (In) X4 || R5, R6 || uint64_t || DeviceAddressSpaceAddress
 
|-
 
|-
| 1 || 2 || SwallowException
+
| (In) W5 || R7 || uint32_t  || Option
 
|-
 
|-
| 2 || 4 || ResumeAllThreads
+
| (Out) W0 || R0 || [[#Result]] || Result
 
|}
 
|}
 +
</div>
 +
 +
Maps an attached device address space to an userspace address.
 +
 +
Same as [[#MapDeviceAddressSpaceByForce]], but the userspace destination address must have the [[SVC#MemoryState|FlagCanAlignedDeviceMap]] bit set instead.
  
== ContinueDebugFlags ==
+
The Option encodes a [[#MemoryPermission]] in the low 16 bits, and an indicator of IO mapping in the high bits.
[3.0.0+]
 
  
{| class=wikitable
+
== MapDeviceAddressSpace ==
! Bit || Bitmask || Description
+
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument64 || Argument32 || Type || Name
 
|-
 
|-
| 0 || 1 || IgnoreException (note: doesn't need to be set in the same call than Resume)
+
| (In) W1 || R1 || Handle<DeviceAddressSpace> || DeviceAddressSpaceHandle
 
|-
 
|-
| 1 || 2 || DontCatchExceptions
+
| (In) W2 || R2 || Handle<Process> || ProcessHandle
 
|-
 
|-
| 2 || 4 || Resume
+
| (In) X3 || R0, R3 || void* || Address
 
|-
 
|-
| 3 || 8 || IgnoreOtherThreadsExceptions
+
| (In) X4 || R4 || uint64_t || DeviceAddressSpaceSize
|}
 
 
 
IgnoreExceptionsOfOthers is like IgnoreException but acts on all threads that aren't in the input list. The affected threads are resumed.
 
 
 
Only one of of Resume and IgnoreOtherThreadsExceptions can be set at a time.
 
 
 
If the input number of threads is 0, this means "all threads".
 
 
 
== DebugEventInfo ==
 
 
 
The below table is for the Aarch64 version of the system call. For A32, all u64 fields but title/process/thread id are actually u32, making the structure 0x28-byte-big (0x40 for a64).
 
 
 
Size: 0x40
 
 
 
{| class=wikitable
 
! Offset || Length || Description
 
 
|-
 
|-
| 0 || u32 || EventType
+
| (In) X5 || R5, R6 || uint64_t || DeviceAddressSpaceAddress
 
|-
 
|-
| 4 || u32 || Flags (bit0: NeedsContinue)
+
| (In) W6 || R7 || [[#MemoryPermission]] || MemoryPermission
 
|-
 
|-
| 8 || u64 || ThreadId
+
| (Out) W0 || R0 || [[#Result]] || Result
 
|-
 
|-
| 0x10 || || PerTypeSpecifics
+
| (Out) X1 || R1 || uint64_t || Size
 
|}
 
|}
 +
</div>
  
AttachProcess specific:
+
== UnmapDeviceAddressSpace ==
{| class=wikitable
+
<div style="display: inline-block;">
! Offset || Length || Description
+
{| class="wikitable" border="1"
 
|-
 
|-
| 0x10 || u64 || TitleId
+
! Argument64 || Argument32 || Type || Name
 
|-
 
|-
| 0x18 || u64 || ProcessId
+
| (In) W0 || R0 || Handle<DeviceAddressSpace> || DeviceAddressSpaceHandle
 
|-
 
|-
| 0x20 || char[12] || ProcessName
+
| (In) W1 || R1 || Handle<Process> || ProcessHandle
 
|-
 
|-
| 0x2C || u32 || MmuFlags
+
| (In) X2 || R2, R3 || void* || Address
 +
|-
 +
| (In) X3 || R4 || uint64_t || DeviceAddressSpaceSize
 +
|-
 +
| (In) X4 || R5, R6 || uint64_t || DeviceAddressSpaceAddress
 
|-
 
|-
| 0x30 || u64 || [5.0.0+] UserExceptionContextAddr
+
| (Out) W0 || R0 || [[#Result]] || Result
 
|}
 
|}
 +
</div>
 +
 +
Unmaps an attached device address space from an userspace address.
  
AttachThread specific:
+
== InvalidateProcessDataCache ==
{| class=wikitable
+
<div style="display: inline-block;">
! Offset || Length || Description
+
{| class="wikitable" border="1"
 +
|-
 +
! Argument64 || Argument32 || Type || Name
 +
|-
 +
| (In) W0 || R0 || Handle<Process> || ProcessHandle
 
|-
 
|-
| 0x10 || u64 || ThreadId
+
| (In) X1 || R2, R3 || void* || Address
 
|-
 
|-
| 0x18 || u64 || TlsPtr
+
| (In) X2 || R1, R4 || uint64_t || Size
 
|-
 
|-
| 0x20 || u64 || Entrypoint
+
| (Out) W0 || R0 || [[#Result]] || Result
 
|}
 
|}
 +
</div>
  
Exit specific:
+
== StoreProcessDataCache ==
{| class=wikitable
+
<div style="display: inline-block;">
! Offset || Length || Description
+
{| class="wikitable" border="1"
 
|-
 
|-
| 0x10 || u32|| Type (0=PausedThread, 1=RunningThread, 2=ExitedProcess, 3=TerminatedProcess)
+
! Argument64 || Argument32 || Type || Name
|}
 
 
 
Exception specific:
 
{| class=wikitable
 
! Offset || Length || Description
 
 
|-
 
|-
| 0x10 || u32 || ExceptionType
+
| (In) W0 || R0 || Handle<Process> || ProcessHandle
 
|-
 
|-
| 0x18 || u64 || FaultRegister
+
| (In) X1 || R2, R3 || void* || Address
 
|-
 
|-
| 0x20 || || PerExceptionSpecifics
+
| (In) X2 || R1, R4 || uint64_t || Size
 +
|-
 +
| (Out) W0 || R0 || [[#Result]] || Result
 
|}
 
|}
 +
</div>
  
=== DebugEventType ===
+
== FlushProcessDataCache ==
{| class=wikitable
+
<div style="display: inline-block;">
! Value || Name
+
{| class="wikitable" border="1"
 
|-
 
|-
| 0 || DebugEvent_AttachProcess
+
! Argument64 || Argument32 || Type || Name
 
|-
 
|-
| 1 || DebugEvent_AttachThread
+
| (In) W0 || R0 || Handle<Process> || ProcessHandle
 
|-
 
|-
| 2 || DebugEvent_ExitProcess
+
| (In) X1 || R2, R3 || void* || Address
 
|-
 
|-
| 3 || DebugEvent_ExitThread
+
| (In) X2 || R1, R4 || uint64_t || Size
 
|-
 
|-
| 4 || DebugEvent_Exception
+
| (Out) W0 || R0 || [[#Result]] || Result
 
|}
 
|}
 +
</div>
  
=== DebugExceptionType ===
+
== DebugActiveProcess ==
{| class=wikitable
+
<div style="display: inline-block;">
! Value || Name
+
{| class="wikitable" border="1"
 
|-
 
|-
| 0 || Exception_Trap (*)
+
! Argument64 || Argument32 || Type || Name
 
|-
 
|-
| 1 || Exception_InstructionAbort
+
| (In) X1 || R2, R3 || uint64_t || ProcessId
 
|-
 
|-
| 2 || Exception_DataAbortMisc (**)
+
| (Out) W0 || R0 || [[#Result]] || Result
 
|-
 
|-
| 3 || Exception_PcSpAlignmentFault
+
| (Out) W1 || R1 || Handle<Debug> || DebugHandle
 +
|}
 +
</div>
 +
 
 +
== BreakDebugProcess ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 
|-
 
|-
| 4 || Exception_DebuggerAttached
+
! Argument || Type || Name
 
|-
 
|-
| 5 || Exception_BreakPoint
+
| (In) W0 || Handle<Debug> || DebugHandle
 
|-
 
|-
| 6 || Exception_UserBreak
+
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
== TerminateDebugProcess ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 
|-
 
|-
| 7 || Exception_DebuggerBreak
+
! Argument || Type || Name
 
|-
 
|-
| 8 || Exception_BadSvcId
+
| (In) W0 || Handle<Debug> || DebugHandle
 
|-
 
|-
| 9 || Exception_SError [not in 1.0.0]
+
| (Out) W0 || [[#Result]] || Result
 
|}
 
|}
 +
</div>
  
* Undefined instructions, software breakpoints, some other traps.
+
== GetDebugEvent ==
** Data aborts, FP traps, and everything else that doesn't belong to any of the above.
+
<div style="display: inline-block;">
 
+
{| class="wikitable" border="1"
Trap specifics:
+
|-
{| class=wikitable
+
! Argument || Type || Name
! Offset || Length || Description
+
|-
 +
| (In) X0 || [[#DebugEventInfo]]* || DebugEventInfo
 +
|-
 +
| (In) W1 || Handle<Debug> || DebugHandle
 
|-
 
|-
| 0x20 || u32 || Opcode
+
| (Out) W0 || [[#Result]] || Result
 
|}
 
|}
 +
</div>
  
BreakPoint specifics:
+
== ContinueDebugEvent ==
{| class=wikitable
+
<div style="display: inline-block;">
! Offset || Length || Description
+
{| class="wikitable" border="1"
 +
|-
 +
! Argument64 || Argument32 || Type || Name
 +
|-
 +
| (In) W0 || R0 || Handle<Debug> || DebugHandle
 
|-
 
|-
| 0x20 || u32 || IsWatchpoint
+
| (In) W1 || R1 || uint32_t || [[#ContinueDebugFlags]] ([1.0.0-2.3.0] [[#ContinueDebugFlagsOld]])
|}
 
 
 
UserBreak specifics:
 
{| class=wikitable
 
! Offset || Length || Description
 
 
|-
 
|-
| 0x20 || u32 || Info0
+
| (In) X2 || R2 ([1.0.0-2.3.0] R2, R3) || uint64_t* ([1.0.0-2.3.0] uint64_t)|| ThreadIdList ([1.0.0-2.3.0] ThreadId)
 
|-
 
|-
| 0x28 || u64 || Info1
+
| (In) X3 || R3 || uint64_t || [3.0.0+] NumThreadIds
 
|-
 
|-
| 0x30 || u64 || Info2
+
| (Out) W0 || R0 || [[#Result]] || Result
 
|}
 
|}
 +
</div>
  
BadSvcId specifics:
+
Maximum NumThreadIds is 64. 0 means "all threads".
{| class=wikitable
+
 
! Offset || Length || Description
+
=== Result codes ===
 +
'''0x0:''' Success. The process has been resumed.
 +
 
 +
'''0xe401:''' Invalid debug handle.
 +
 
 +
'''0xf401:''' Process has debug events queued or is already running.
 +
 
 +
== GetProcessList ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument64 || Argument32 || Type || Name
 +
|-
 +
| (In) X1 || R1 || uint64_t* || ProcessIdBuffer
 +
|-
 +
| (In) W2 || R2 || uint32_t || ProcessIdBufferSize
 +
|-
 +
| (Out) X0 || R0 || [[#Result]] || Result
 
|-
 
|-
| 0x20 || u32 || SvcId
+
| (Out) W1 || R1 || uint32_t || NumProcesses
 
|}
 
|}
 +
</div>
 +
 +
Fills the provided array with the pids of currently living processes. A process "lives" so long as it is currently running or a handle to it still exists.
 +
 +
It returns the total number of processes currently alive. If this number is bigger than the size of ProcessIdBuffer, the user won't have all the pids.
 +
 +
=== Result codes ===
 +
'''0x0:''' Success.
  
= Exception handling =
+
'''0xd401:''' The provided buffer is outside the process address space.
First of all, a function that might be called by synchronous exception handler and that is called by the SError handler fetches the exception info, adjusts PC, panics on exceptions taken from EL1, then dispatches the exception.
 
  
The dispatcher has two mutually exclusive exception reporting methods:
+
'''0xe601:''' copyToUser failed. The provided buffer is not user-accessible.
* by storing information at the start of the process's TLS memregion (TPIDRRO_EL0) and jumping back to the crt0
 
* by using KDebug
 
  
KDebug dispatching is used when at least one of the following conditions are met:
+
'''0xee01:''' The provided buffer size is too big. Max value is 0xFFFFFFF.
* SMC ConfigItem KernelMemConfig bit 1 is NOT set (it isn't on retail), unless: this is a software or hardware breakpoint, or a watchpoint, or [4.0.0+?] the process is attached and this is a Google PNaCl trap instruction (see LLVM source)
 
* PC doesn't point to a valid address in mapped-readable CodeStatic memory (i.e. this is the case for NRO and JIT memory) or this one of the following exceptions (it particular, that doesn't include FP exceptions occuring in CodeStatic memory):
 
** Uncategorized
 
** IllegalState
 
** SupervisorCallA32
 
** SupervisorCallA64
 
** PCAlignment
 
** SPAlignment
 
** SError
 
** BreakpointLowerEl
 
** SoftwareStepLowerEl (note: no way set single-step flag; not parsed)
 
** WatchpointLowerEl
 
** SoftwareBreakpointA32 (note: not parsed)
 
** SoftwareBreakpointA64 (note: not parsed)
 
   
 
In all other cases the userland-handled exception path is taken.
 
  
KDebug path:
+
== GetThreadList ==
 
+
<div style="display: inline-block;">
If the process is attached, the exception is reported to the KDebug. If the thread was continued using flag IgnoreExceptions, it returns from the exception as if nothing happened.
+
{| class="wikitable" border="1"
 
+
|-
If the latter is not the case, or if the process isn't attached, process to [2.0.0+] crash reporting (or in [1.0.0] just terminate the process):
+
! Argument64 || Argument32 || Type || Name
if EnableDebug is set, and depending on the process state (more than one crash per process isn't permitted) it may signal itself with ProcessState_Crashed so that PM asks NS to start creport so that creports attaches to it and reports the crashes. Otherwise, just terminate.
+
|-
 
+
| (In) X1 || R1 || uint64_t* || ThreadIdBuffer
Userland reporting path and svcReturnFromException:
+
|-
 
+
| (In) W2 || R2 || uint32_t || ThreadIdBufferSize
TLS region start (A64):
+
|-
 
+
| (In) W3 || R3 || Handle<Debug> || DebugHandle
{| class=wikitable
 
! Offset || Length || Description
 
 
|-
 
|-
| 0x0 || 0x148 || Exception stack
+
| (Out) X0 || R0 || [[#Result]] || Result
 
|-
 
|-
| 0x148 || 0x78 || Frame: x0..x30, sp, elr_el1=unadjusted PC, pstate & 0xFF0FFE20,
+
| (Out) W1 || R1 || uint32_t || NumThreads
afsr0, afsr1, esr, pc (stored using the regs' own size)
 
 
|}
 
|}
 +
</div>
  
TLS region start (A32):
+
== GetDebugThreadContext ==
 
+
<div style="display: inline-block;">
{| class=wikitable
+
{| class="wikitable" border="1"
! Offset || Length || Description
+
|-
 +
! Argument64 || Argument32 || Type || Name
 +
|-
 +
| (In) X0 || R0 || [[#ThreadContext]]* || ThreadContext
 +
|-
 +
| (In) X1 || R1 || Handle<Debug> || DebugHandle
 +
|-
 +
| (In) X2 || R2, R3 || uint64_t || ThreadId
 
|-
 
|-
| 0x0 || 0x178 || Exception stack
+
| (In) W3 || R4 || uint32_t || [[#ThreadContextFlags]]
 
|-
 
|-
| 0x148 || 0x30 || Frame: r0..r14, elr_el1=unadjusted PC, tpidr_el0 = 1, cpsr & 0xFF0FFE20,
+
| (Out) W0 || R0 || [[#Result]] || Result
afsr0, afsr1, esr, pc (stored using the regs' own size)
 
 
|}
 
|}
 +
</div>
  
 
+
== SetDebugThreadContext ==
In that case, after storing the regs in the TLS, the exception handler returns to the application's crt0 (entrypoint), with X0=<error description code> (see below) and X1=SP=frame=<stack top> (see above)
+
<div style="display: inline-block;">
 
+
{| class="wikitable" border="1"
 
 
{| class=wikitable
 
! Desc. code || Meaning
 
 
|-
 
|-
| 0x100 || Instruction abort
+
! Argument64 || Argument32 || Type || Name
 
|-
 
|-
| 0x102 || Misaligned PC
+
| (In) W0 || R0 || Handle<Debug> || DebugHandle
 
|-
 
|-
| 0x103 || Misaligned SP
+
| (In) X1 || R2, R3 || uint64_t || ThreadId
 
|-
 
|-
| 0x106 || SError [not in 1.0.0?]
+
| (In) X2 || R1 || [[#ThreadContext]]* || ThreadContext
 
|-
 
|-
| 0x301 || Bad SVC
+
| (In) W3 || R4 || uint32_t || [[#ThreadContextFlags]]
|-
 
| 0x104 || Uncategorized, CP15RTTrap, CP15RRTTrap, CP14RTTrap, CP14RRTTrap, IllegalState, SystemRegisterTrap
 
|-
 
| 0x101 || None of the above, EC <= 0x34 and not a breakpoint
 
 
|-
 
|-
 +
| (Out) W0 || R0 || [[#Result]] || Result
 
|}
 
|}
 +
</div>
  
(During normal app boot the process is invoked with X0=0 and X1=main_thread_handle. The crt0 of retail apps determines whether to boot normally or handle an exception if X0 is set to 0 or not)
+
== QueryDebugProcessMemory ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) X0 || [[#MemoryInfo]]* || MemoryInfo
 +
|-
 +
| (In) W2 || Handle<Debug> || DebugHandle
 +
|-
 +
| (In) X3 || void* || Address
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|-
 +
| (Out) W1 || [[#PageInfo]] || PageInfo
 +
|}
 +
</div>
  
The application is supposed to promptly update the contents of elr_el1 to a user handler (and any other regs it sees fit) and call svcReturnFromException (error code) to call that handler. The latter is then expected to promptly abort the program.
+
== ReadDebugProcessMemory ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) X0 || void* || MemoryBufferAddress
 +
|-
 +
| (In) W1 || Handle<Debug> || DebugHandle
 +
|-
 +
| (In) X2 || void* || SrcAddress
 +
|-
 +
| (In) X3 || uint64_t || Size
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
  
svcReturnFromException updates the contents of the kernel stack frame with what the user provided in the TLS structure, sets TPIDR_EL0 to 1, then:
+
== WriteDebugProcessMemory ==
* if the provided error code is 0, gracefully pivots and returns from exception
+
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) W0 || Handle<Debug> || DebugHandle
 +
|-
 +
| (In) X1 || void* || MemoryBufferAddress
 +
|-
 +
| (In) X2 || void* || DstAddress
 +
|-
 +
| (In) X3 || uint64_t || Size
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
== SetHardwareBreakPoint ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument64 || Argument32 || Type || Name
 +
|-
 +
| (In) W0 || R0 || [[#HardwareBreakPointRegisterName]] || Name
 +
|-
 +
| (In) X1 || R2, R3 || uint64_t || Flags
 +
|-
 +
| (In) X2 || R1, R4 || uint64_t || Value
 +
|-
 +
| (Out) W0 || R0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
Sets one of the AArch64 hardware breakpoints. The nintendo switch has 6 hardware breakpoints, and 4 hardware watchpoints. The syscall has two behaviors depending on the value of HardwareBreakPointRegisterName:
 +
 
 +
If HardwareBreakPointRegisterName < 0x10, then it sets one of the AArch64 hardware breakpoints. Flags will go to DBGBCRn_EL1, and value to DBGBVRn_EL1. The only flags the user is allowed to set are those in the bitmask 0x7F01E1. Furthermore, the kernel will or it with 0x4004, in order to set various security flags to guarantee the watchpoints only triggers for code in EL0. If the user asks for a Breakpoint Type of ContextIDR match, the kernel shall use the given DebugHandle to set DBGBVRn_EL1 to the ContextID of the debugged process.
 +
 
 +
If HardwareBreakPointRegisterName is between 0x10 and 0x20 (exclusive), then it sets one of the AArch64 hardware watchpoints. Flags will go to DBGWCRn_EL1, and the value to DBGWVRn_EL1. The only flags the user is allowed to set are those in the bitmask 0xFF0F1FF9. Furthermore, the kernel will or it with 0x104004. This will set various security flags, and set the watchpoint type to be a Linked Watchpoint. This means that you need to link it to a Linked ContextIDR breakpoint. Check the ARM documentation for more information.
 +
 
 +
Note that HardwareBreakPointRegisterName 0 to 4 match only to Virtual Address, while HardwareBreakPointRegisterName 5 and 6 match against either Virtual Address, ContextID, or VMID. As such, if you are configuring a breakpoint to link for a watchpoint, make sure you use hardware_breakpoint_id 5 or 6.
 +
 
 +
For more documentation for hardware breakpoints, check out the AArch64 documentation for the [http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0488h/way1382455558968.html DBGBCRn_EL1 register] and the [http://infocenter.arm.com/help/topic/com.arm.doc.ddi0488h/way1382455560629.html DBGWCRn_EL1 register]
 +
 
 +
== GetDebugThreadParam ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument64 || Argument32 || Type || Name
 +
|-
 +
| (In) X2 || R2 || Handle<Debug> || DebugHandle
 +
|-
 +
| (In) X3 || R0, R1 || uint64_t || ThreadId
 +
|-
 +
| (In) W4 || R3 || [[#DebugThreadParam]] || DebugThreadParam
 +
|-
 +
| (Out) W0 || R0 || [[#Result]] || Result
 +
|-
 +
| (Out) X1 || R1, R2 || uint64_t || Out0
 +
|-
 +
| (Out) W2 || R3 || uint32_t || Out1
 +
|}
 +
</div>
 +
 
 +
== GetSystemInfo ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) X1 || [[#SystemInfoType]] || SystemInfoType
 +
|-
 +
| (In) W2 || Handle || Handle
 +
|-
 +
| (In) X3 || uint64_t || SystemInfoSubType
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|-
 +
| (Out) X1 || uint64_t || SystemInfo
 +
|}
 +
</div>
 +
 
 +
== CreatePort ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument64 || Argument32 || Type || Name
 +
|-
 +
| (In) W2 || R2 || int32_t || MaxSessions
 +
|-
 +
| (In) W3 || R3 || bool || IsLight
 +
|-
 +
| (In) X4 || R0 || uint64_t || Name
 +
|-
 +
| (Out) W0 || R0 || [[#Result]] || Result
 +
|-
 +
| (Out) W1 || R1 || Handle<Port> || ServerPortHandle
 +
|-
 +
| (Out) W2 || R2 || Handle<Port> || ClientPortHandle
 +
|}
 +
</div>
 +
 
 +
== ManageNamedPort ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) X1 || char* || Name
 +
|-
 +
| (In) W2 || int32_t || MaxSessions
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|-
 +
| (Out) W1 || Handle<Port> || ServerPortHandle
 +
|}
 +
</div>
 +
 
 +
== ConnectToPort ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) W1 || Handle<Port> || ClientPortHandle
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|-
 +
| (Out) W1 || Handle<Session> || SessionHandle
 +
|}
 +
</div>
 +
 
 +
== SetProcessMemoryPermission ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument64 || Argument32 || Type || Name
 +
|-
 +
| (In) W0 || R0 || Handle<Process> || ProcessHandle
 +
|-
 +
| (In) X1 || R2, R3 || void* || Addr
 +
|-
 +
| (In) X2 || R1, R4 || uint64_t || Size
 +
|-
 +
| (In) W3 || R5 || [[#MemoryPermission]] || MemoryPermission
 +
|-
 +
| (Out) W0 || R0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
This sets the memory permissions for the specified memory with the supplied process handle.
 +
 
 +
This throws an error(0xD801) when the input perm is >0x5, hence -WX and RWX are not allowed.
 +
 
 +
== MapProcessMemory ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument64 || Argument32 || Type || Name
 +
|-
 +
| (In) X0 || R0 || void* || DstAddress
 +
|-
 +
| (In) W1 || R1 || Handle<Process> || ProcessHandle
 +
|-
 +
| (In) X2 || R2, R3 || void* || SrcAddress
 +
|-
 +
| (In) X3 || R4 || uint64_t || Size
 +
|-
 +
| (Out) W0 || R0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
Maps the src address from the supplied process handle into the current process.
 +
 
 +
This allows mapping code and rodata with RW- permission.
 +
 
 +
== UnmapProcessMemory ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument64 || Argument32 || Type || Name
 +
|-
 +
| (In) X0 || R0 || void* || DstAddress
 +
|-
 +
| (In) W1 || R1 || Handle<Process> || ProcessHandle
 +
|-
 +
| (In) X2 || R2, R3 || void* || SrcAddress
 +
|-
 +
| (In) X3 || R4 || uint64_t || Size
 +
|-
 +
| (Out) W0 || R0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
Unmaps what was mapped by [[#MapProcessMemory]].
 +
 
 +
== QueryProcessMemory ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument64 || Argument32 || Type || Name
 +
|-
 +
| (In) X0 || R0 || [[#MemoryInfo]]* || MemoryInfo
 +
|-
 +
| (In) W2 || R2 || Handle<Process> || ProcessHandle
 +
|-
 +
| (In) X3 || R1, R3 || void* || Address
 +
|-
 +
| (Out) W0 || R0 || [[#Result]] || Result
 +
|-
 +
| (Out) W1 || R1 || [[#PageInfo]] || PageInfo
 +
|}
 +
</div>
 +
 
 +
Equivalent to [[#QueryMemory]] except takes a process handle.
 +
 
 +
== MapProcessCodeMemory ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument64 || Argument32 || Type || Name
 +
|-
 +
| (In) W0 || R0 || Handle<Process> || ProcessHandle
 +
|-
 +
| (In) X1 || R2, R3 || void* || DstAddress
 +
|-
 +
| (In) X2 || R1, R4 || void* || SrcAddress
 +
|-
 +
| (In) X3 || R5, R6 || uint64_t || Size
 +
|-
 +
| (Out) W0 || R0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
Takes a process handle, and maps normal heap in that process as executable code in that process. Used when loading NROs. This does not support using the current-process handle alias.
 +
 
 +
== UnmapProcessCodeMemory ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument64 || Argument32 || Type || Name
 +
|-
 +
| (In) W0 || R0 || Handle<Process> || ProcessHandle
 +
|-
 +
| (In) X1 || R2, R3 || void* || DstAddress
 +
|-
 +
| (In) X2 || R1, R4 || void* || SrcAddress
 +
|-
 +
| (In) X3 || R5, R6 || uint64_t || Size
 +
|-
 +
| (Out) W0 || R0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
Unmaps what was mapped by [[#MapProcessCodeMemory]].
 +
 
 +
== CreateProcess ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) X1 || [[#CreateProcessParameter]]* || CreateProcessParameter
 +
|-
 +
| (In) X2 || uint32_t* || Capabilities
 +
|-
 +
| (In) X3 || int32_t || CapabilitiesNum
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|-
 +
| (Out) W1 || Handle<Process> || ProcessHandle
 +
|}
 +
</div>
 +
 
 +
Takes a [[#CreateProcessParameter]] as input.
 +
Capabilities points to an array of [[NPDM#Kernel_Access_Control|kernel capabilities]].
 +
CapabilitiesNum is a number of capabilities in the Capabilities array (number of element, not number of bytes).
 +
 
 +
=== Result codes ===
 +
'''0x0:''' Success.
 +
 
 +
'''0xCA01:''' Attempted to map more code pages than available in address space.
 +
 
 +
'''0xCC01:''' Provided CodeAddr is invalid (make sure it's in range?)
 +
 
 +
'''0xE401:''' The resource handle passed is invalid.
 +
 
 +
'''0xE601:''' Attempt to copy procinfo from user-supplied pointer failed. Attempt to copy capabilities_num from user-supplied pointer failed.
 +
 
 +
'''0xE801:''' Attempted to create a 32-bit process with a 36-bit address space.
 +
 
 +
'''0xF001:''' Unused bits are set in mmuflags. Unknown address space type used.
 +
 
 +
== StartProcess ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument64 || Argument32 || Type || Name
 +
|-
 +
| (In) W0 || R0 || Handle<Process> || ProcessHandle
 +
|-
 +
| (In) W1 || R1 || int32_t || MainThreadPriority
 +
|-
 +
| (In) W2 || R2 || int32_t || DefaultCpuId
 +
|-
 +
| (In) X3 || R3, R4 || uint64_t || MainThreadStackSize
 +
|-
 +
| (Out) W0 || R0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
== TerminateProcess ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) W0 || Handle<Process> || ProcessHandle
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
== GetProcessInfo ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument64 || Argument32 || Type || Name
 +
|-
 +
| (In) W0 || R1 || Handle<Process> || ProcessHandle
 +
|-
 +
| (In) W1 || R2 || [[#ProcessInfoType]] || ProcessInfoType
 +
|-
 +
| (Out) W0 || R0 || [[#Result]] || Result
 +
|-
 +
| (Out) X1 || R1, R2 || uint64_t || [[#ProcessState]]
 +
|}
 +
</div>
 +
 
 +
Returns an enum with value 0-7.
 +
 
 +
== CreateResourceLimit ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) None || ||
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|-
 +
| (Out) W1 || Handle<ResourceLimit> || ResourceLimitHandle
 +
|}
 +
</div>
 +
 
 +
== SetResourceLimitLimitValue ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument64 || Argument32 || Type || Name
 +
|-
 +
| (In) W0 || R0 || Handle<ResourceLimit> || ResourceLimitHandle
 +
|-
 +
| (In) W1 || R1 || [[#LimitableResource]] || LimitableResource
 +
|-
 +
| (In) X2 || R2, R3 || int64_t || LimitValue
 +
|-
 +
| (Out) W0 || R0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
== CallSecureMonitor ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument64 || Argument32 || Type || Name
 +
|-
 +
| (In) X0 || R0 || uint64_t || [[SMC#Secure_Monitor_calls|FunctionId]]
 +
|-
 +
| (In) X1-X7 || R1-R7 || uint64_t || SMC arguments
 +
|-
 +
| (Out) X0 || R0 || [[SMC#Result|Result]] || SMC result
 +
|-
 +
| (Out) X1-X7 || R1-R7 || uint64_t || SMC output
 +
|}
 +
</div>
 +
 
 +
Takes in a SMC function ID in X0, and arguments for that SMC function in X1-X7.
 +
 
 +
Passing an invalid SMC function ID or calling from a core other than core 3 will result in a secure monitor panic.
 +
 
 +
The kernel parses bits 9-15 in the passed SMC function ID (per the ARM SMC calling convention), and when set uses as an indicator to translate a pointer in the associated register (X1-X7) to a physical address. The kernel will translate any address mapped as R-W, other addresses (R--, R-X, or invalid pointers) will be translated as 0/NULL.
 +
 
 +
Output is returned raw from the Secure Monitor; X0 will be the untranslated SMC result and X1-X7 will contain other SMC output (or be unchanged, depending on the SMC).
 +
 
 +
== Debugging ==
 +
[2.0.0+] Exactly 6 debug SVCs require that [[SPL_services#GetConfig|IsDebugMode]] is non-zero. Error 0x4201 is returned otherwise.
 +
* BreakDebugProcess
 +
* ContinueDebugEvent
 +
* WriteDebugProcessMemory
 +
* SetDebugThreadContext
 +
* TerminateDebugProcess
 +
* SetHardwareBreakPoint
 +
 
 +
DebugActiveProcess stops execution of the target process, the normal method for resuming it requires ContinueDebugEvent(see above). Closing the debug handle also results in execution being resumed.
 +
 
 +
= Enum/Structures =
 +
== InfoType ==
 +
{| class=wikitable
 +
! Handle type || InfoType || InfoSubType || Description
 +
|-
 +
| Process || 0 || 0 || CoreMask
 +
|-
 +
| Process || 1 || 0 || PriorityMask
 +
|-
 +
| Process || 2 || 0 || AliasRegionAddress
 +
|-
 +
| Process || 3 || 0 || AliasRegionSize
 +
|-
 +
| Process || 4 || 0 || HeapRegionAddress
 +
|-
 +
| Process || 5 || 0 || HeapRegionSize
 +
|-
 +
| Process || 6 || 0 || TotalMemorySize. Total memory available(free+used).
 +
|-
 +
| Process || 7 || 0 || UsedMemorySize. Total used size of codebin memory + main-thread stack + allocated heap.
 +
|-
 +
| Zero    || 8 || 0 || DebuggerAttached
 +
|-
 +
| Zero    || 9 || 0 || ResourceLimit
 +
|-
 +
| Zero    || 10 || -1, {current coreid} || IdleTickCount
 +
|-
 +
| Zero    || 11 || 0-3 || RandomEntropy. Used to seed usermode PRNGs.
 +
|-
 +
| Process || 12 || 0 || [2.0.0+] AslrRegionAddress
 +
|-
 +
| Process || 13 || 0 || [2.0.0+] AslrRegionSize
 +
|-
 +
| Process || 14 || 0 || [2.0.0+] StackRegionAddress
 +
|-
 +
| Process || 15 || 0 || [2.0.0+] StackRegionSize
 +
|-
 +
| Process || 16 || 0 || [3.0.0+] SystemResourceSizeTotal
 +
|-
 +
| Process || 17 || 0 || [3.0.0+] SystemResourceSizeUsed
 +
|-
 +
| Process || 18 || 0 || [3.0.0+] ProgramId
 +
|-
 +
| Zero    || 19 || 0 || [4.0.0-4.1.0] InitialProcessIdRange_LowerBound
 +
|-
 +
| Zero    || 19 || 1 || [4.0.0-4.1.0] InitialProcessIdRange_UpperBound
 +
|-
 +
| Process || 20 || 0 || [5.0.0+] UserExceptionContextAddress
 +
|-
 +
| Process || 21 || 0 || [6.0.0+] TotalNonSystemMemorySize
 +
|-
 +
| Process || 22 || 0 || [6.0.0+] UsedNonSystemMemorySize
 +
|-
 +
| Process || 23 || 0 || [9.0.0+] IsApplication
 +
|-
 +
| Process || 24 || 0 || [11.0.0+] FreeThreadCount
 +
|-
 +
| Thread  || 25 ([1.0.0-12.1.0] 0xF0000002) || 0-3, -1 || ThreadTickCount. When 0-3 are passed, gets specific core CPU ticks spent on thread. When -1 is passed, gets total CPU ticks spent on thread.
 +
|-
 +
| Process || 26 || 0 || [14.0.0+] IsSvcPermitted
 +
|-
 +
| Process || 27 || 0 || [16.0.0+] IoRegionHint
 +
|-
 +
| Process || 28 || 0 || [18.0.0+] AliasRegionExtraSize
 +
|}
 +
 
 +
== SystemInfoType ==
 +
{| class=wikitable
 +
! Handle type || SystemInfoType || SystemInfoSubType || Description
 +
|-
 +
| Zero    || 0 || 0 || TotalPhysicalMemorySize_Application
 +
|-
 +
| Zero    || 0 || 1 || TotalPhysicalMemorySize_Applet
 +
|-
 +
| Zero    || 0 || 2 || TotalPhysicalMemorySize_System
 +
|-
 +
| Zero    || 0 || 3 || TotalPhysicalMemorySize_SystemUnsafe
 +
|-
 +
| Zero    || 1 || 0 || UsedPhysicalMemorySize_Application
 +
|-
 +
| Zero    || 1 || 1 || UsedPhysicalMemorySize_Applet
 +
|-
 +
| Zero    || 1 || 2 || UsedPhysicalMemorySize_System
 +
|-
 +
| Zero    || 1 || 3 || UsedPhysicalMemorySize_SystemUnsafe
 +
|-
 +
| Zero    || 2 || 0 || InitialProcessIdRange_LowerBound
 +
|-
 +
| Zero    || 2 || 1 || InitialProcessIdRange_UpperBound
 +
|}
 +
 
 +
== ThreadContextFlags ==
 +
Bitfield of one of more of these:
 +
 
 +
{| class=wikitable
 +
! Bit || Bitmask || Name || Description
 +
|-
 +
| 0 || 1 || General-purpose registers || If in 64-bit mode, GPRs 0–28 will be read/written. If in 32-bit mode, GPRs 0–12 will be read/written.
 +
|-
 +
| 1 || 2 || Control registers || Reads/writes the FP, LR, PC, SP, PSTATE, and TPIDR registers.
 +
|-
 +
| 2 || 4 || Floating-point registers || Reads/writes the floating-point vector registers.
 +
|-
 +
| 3 || 8 || Floating-point control registers || Reads/writes the FPCR and FPSR registers.
 +
|}
 +
 
 +
== DeviceName ==
 +
{| class=wikitable
 +
! Value || Name
 +
|-
 +
| 0 || AFI
 +
|-
 +
| 1 || AVPC
 +
|-
 +
| 2 || DC
 +
|-
 +
| 3 || DCB
 +
|-
 +
| 4 || HC
 +
|-
 +
| 5 || HDA
 +
|-
 +
| 6 || ISP2
 +
|-
 +
| 7 || MSENCNVENC
 +
|-
 +
| 8 || NV
 +
|-
 +
| 9 || NV2
 +
|-
 +
| 10 || PPCS
 +
|-
 +
| 11 || SATA
 +
|-
 +
| 12 || VI
 +
|-
 +
| 13 || VIC
 +
|-
 +
| 14 || XUSB_HOST
 +
|-
 +
| 15 || XUSB_DEV
 +
|-
 +
| 16 || TSEC
 +
|-
 +
| 17 || PPCS1
 +
|-
 +
| 18 || DC1
 +
|-
 +
| 19 || SDMMC1A
 +
|-
 +
| 20 || SDMMC2A
 +
|-
 +
| 21 || SDMMC3A
 +
|-
 +
| 22 || SDMMC4A
 +
|-
 +
| 23 || ISP2B
 +
|-
 +
| 24 || GPU
 +
|-
 +
| 25 || GPUB
 +
|-
 +
| 26 || PPCS2
 +
|-
 +
| 27 || NVDEC
 +
|-
 +
| 28 || APE
 +
|-
 +
| 29 || SE
 +
|-
 +
| 30 || NVJPG
 +
|-
 +
| 31 || HC1
 +
|-
 +
| 32 || SE1
 +
|-
 +
| 33 || AXIAP
 +
|-
 +
| 34 || ETR
 +
|-
 +
| 35 || TSECB
 +
|-
 +
| 36 || TSEC1
 +
|-
 +
| 37 || TSECB1
 +
|-
 +
| 38 || NVDEC1
 +
|}
 +
 
 +
== CodeMemoryOperation ==
 +
{| class=wikitable
 +
! Value || Name
 +
|-
 +
| 0 || MapOwner
 +
|-
 +
| 1 || MapSlave
 +
|-
 +
| 2 || UnmapOwner
 +
|-
 +
| 3 || UnmapSlave
 +
|}
 +
 
 +
== LimitableResource ==
 +
{| class=wikitable
 +
! Value || Name || Description
 +
|-
 +
| 0 || PhysicalMemoryMax || Bytes of memory a process may allocate.
 +
|-
 +
| 1 || ThreadCountMax || Amount of threads a process can create.
 +
|-
 +
| 2 || EventCountMax || Amount of events a process can create through [[#CreateEvent]] or [[#SendAsyncRequestWithUserBuffer]].
 +
|-
 +
| 3 || TransferMemoryCountMax || Amount of TransferMemory a process can create through [[#CreateTransferMemory]].
 +
|-
 +
| 4 || SessionCountMax || Amount of session a process can create through [[#CreateSession]], [[#ConnectToPort]] or [[#ConnectToNamedPort]].
 +
|}
 +
 
 +
= ThreadActivity =
 +
{| class=wikitable
 +
! Value || Name
 +
|-
 +
| 0 || None
 +
|-
 +
| 1 || Runnable
 +
|}
 +
 
 +
== ProcessActivity ==
 +
{| class=wikitable
 +
! Value || Name
 +
|-
 +
| 0 || None
 +
|-
 +
| 1 || Runnable
 +
|}
 +
 
 +
== ProcessInfoType ==
 +
{| class=wikitable
 +
! Value || Name
 +
|-
 +
| 0 || [[#ProcessState|ProcessState]]
 +
|}
 +
 
 +
== ProcessState ==
 +
{| class=wikitable
 +
! Value || Name || Notes
 +
|-
 +
| 0 || Created ||
 +
|-
 +
| 1 || CreatedAttached ||
 +
|-
 +
| 2 || Started ||
 +
|-
 +
| 3 || Crashed || Processes will not enter this state unless they were created with [[#CreateProcessParameter|EnableDebug]].
 +
|-
 +
| 4 || StartedAttached ||
 +
|-
 +
| 5 || Exiting ||
 +
|-
 +
| 6 || Exited ||
 +
|-
 +
| 7 || DebugSuspended ||
 +
|}
 +
 
 +
== DebugThreadParam ==
 +
{| class=wikitable
 +
! Value || Name
 +
|-
 +
| 0 || DynamicPriority
 +
|-
 +
| 1 || SchedulingStatus
 +
|-
 +
| 2 || PreferredCpuCore
 +
|-
 +
| 3 || CurrentCpuCore
 +
|-
 +
| 4 || AffinityMask
 +
|}
 +
 
 +
Dynamic priority: output in out2
 +
 
 +
Scheduling status: out1 contains bit0: is debug-suspended, bit1: is user-suspended ([[#SetThreadActivity]] 1 or [[#SetProcessActivity]] 1).
 +
Out2 contains {suspended, idle, running, terminating} => {5, 0, 1, 4}
 +
 
 +
PreferredCpuCore: output in out2
 +
 
 +
CurrentCpuCore: output in out2
 +
 
 +
AffinityMask: output in out1
 +
 
 +
== CreateProcessParameter ==
 +
{| class=wikitable
 +
! Offset || Length || Bits || Description
 +
|-
 +
| 0 || 12 || || ProcessName (doesn't have to be null-terminated)
 +
|-
 +
| 0x0C || 4 || || ProcessCategory (0: regular title, 1: kernel built-in)
 +
|-
 +
| 0x10 || 8 || || TitleId
 +
|-
 +
| 0x18 || 8 || || CodeAddr
 +
|-
 +
| 0x20 || 4 || || CodeNumPages
 +
|-
 +
| 0x24 || 4 || || Flags
 +
|-
 +
| || || Bit0 || Is64BitInstruction
 +
|-
 +
| || || Bit3-1 || [[#AddressSpaceType]]
 +
|-
 +
| || || Bit4 || [2.0.0+] EnableDebug
 +
|-
 +
| || || Bit5 || EnableAslr
 +
|-
 +
| || || Bit6 || IsApplication
 +
|-
 +
| || || Bit7 || [4.0.0] UseSecureMemory
 +
|-
 +
| || || Bit10-7 || [5.0.0+] MemoryRegion (0 = Application, 1 = Applet, 2 = SecureSystem, 3 = NonSecureSystem)
 +
|-
 +
| || || Bit11 || [7.0.0+] OptimizeMemoryAllocation (only allowed in combination with IsApplication)
 +
|-
 +
| 0x28 || 4 || || ResourceLimitHandle (can be zero)
 +
|-
 +
| 0x2C || 4 || || [3.0.0+] SystemResourceNumPages
 +
|}
 +
 
 +
On [1.0.0] there's only one MemoryRegion.
 +
 
 +
On [2.0.0-4.0.0] MemoryRegion is 1 for built-ins and 0 for rest.
 +
 
 +
On [5.0.0] MemoryRegion is specified in CreateProcessArgs. There are now 4 pool partitions.
 +
 
 +
On [5.0.0] (maybe lower?) a zero ResourceLimitHandle defaults to sysmodule limits and 0x12300000 bytes of memory.
 +
 
 +
The PersonalMmHeap are allocated as follows:
 +
* For the application, normal insecure pool is used. Carveout 5 is used to provide protection.
 +
* For the applet, a pre-allocated secure pool segment of size 0x400000 is used.
 +
* For sysmodules, secure pool is allocated.
 +
 
 +
=== AddressSpaceType ===
 +
{| class=wikitable
 +
! Type || Name || Width || Description
 +
|-
 +
| 0 || AddressSpace32Bit || 32 ||
 +
|-
 +
| 1 || AddressSpace64BitOld || 36 ||
 +
|-
 +
| 2 || AddressSpace32BitNoReserved || 32 || Appears to be missing map region [?]
 +
|-
 +
| 3 || [2.0.0+] AddressSpace64Bit || 39 ||
 +
|}
 +
 
 +
== MemoryInfo ==
 +
{| class=wikitable
 +
! Offset || Length || Description
 +
|-
 +
| 0 || 8 || BaseAddress
 +
|-
 +
| 8 || 8 || Size
 +
|-
 +
| 0x10 || 4 || [[#MemoryType]]
 +
|-
 +
| 0x14 || 4 || [[#MemoryAttribute]]
 +
|-
 +
| 0x18 || 4 || [[#MemoryPermission]]
 +
|-
 +
| 0x1C || 4 || IpcRefCount
 +
|-
 +
| 0x20 || 4 || DeviceRefCount
 +
|-
 +
| 0x24 || 4 || Padding: always zero
 +
|}
 +
 
 +
== MemoryPermission ==
 +
{| class=wikitable
 +
! Bits || Name || Description
 +
|-
 +
| 0 || Read || Can be set by [[#SetMemoryPermission]].
 +
|-
 +
| 1 || Write || Can be set by [[#SetMemoryPermission]].
 +
|-
 +
| 2 || Execute || Can be set by [[#SetProcessMemoryPermission]] and [[#ControlCodeMemory]].
 +
|-
 +
| 28 || DontCare ||
 +
|}
 +
 
 +
== MemoryAttribute ==
 +
{| class=wikitable
 +
! Bits || Name || Description
 +
|-
 +
| 0 || Locked || Used by MapMemory, as an async IPC user buffer.
 +
|-
 +
| 1 || IpcLocked || True when IpcRefCount > 0.
 +
|-
 +
| 2 || DeviceShared || True when DeviceRefCount > 0.
 +
|-
 +
| 3 || Uncached ||
 +
|}
 +
 
 +
== MemoryState ==
 +
{| class=wikitable
 +
! Bits || Description || Meaning
 +
|-
 +
| 7-0 || [[#MemoryType]] ||
 +
|-
 +
| 8 || [[#SetMemoryPermission|FlagCanReprotect]] ||
 +
|-
 +
| 9 || FlagCanDebug || Allows using [[#WriteDebugProcessMemory]] on segments mapped read-only.
 +
|-
 +
| 10 || FlagCanUseIpc || Allows sending this region as an IPC A/B/W buffer with flags=0.
 +
|-
 +
| 11 || FlagCanUseNonDeviceIpc || Allows sending this region as an IPC A/B/W buffer with flags=1.
 +
|-
 +
| 12 || FlagCanUseNonSecureIpc || Allows sending this region as an IPC A/B/W buffer with flags=3.
 +
|-
 +
| 13 || FlagMapped ||
 +
|-
 +
| 14 || [[#SetProcessMemoryPermission|FlagCode]] ||
 +
|-
 +
| 15 || [[#MapMemory|FlagCanAlias]] ||
 +
|-
 +
| 16 || [[#MapProcessCodeMemory|FlagCanCodeAlias]] ||
 +
|-
 +
| 17 || [[#CreateTransferMemory|FlagCanTransfer]] ||
 +
|-
 +
| 18 || [[#QueryPhysicalAddress|FlagCanQueryPhysical]] ||
 +
|-
 +
| 19 || [[#MapDeviceAddressSpace|FlagCanDeviceMap]] ||
 +
|-
 +
| 20 || [[#MapDeviceAddressSpaceAligned|FlagCanAlignedDeviceMap]] ||
 +
|-
 +
| 21 || [[#SendSyncRequestWithUserBuffer|FlagCanIpcUserBuffer]] ||
 +
|-
 +
| 22 || FlagReferenceCounted || The physical memory blocks backing this region are refcounted.
 +
|-
 +
| 23 || [[#MapProcessMemory|FlagCanMapProcess]] ||
 +
|-
 +
| 24 || [[#SetMemoryAttribute|FlagCanChangeAttribute]] ||
 +
|-
 +
| 25 || [4.0.0+] [[#CreateCodeMemory|FlagCanCodeMemory]] ||
 +
|-
 +
| 26 || [15.0.0+] FlagLinearMapped ||
 +
|}
 +
 
 +
=== MemoryType ===
 +
{| class=wikitable
 +
! Value || Type || Meaning
 +
|-
 +
| 0x00000000 || Free ||
 +
|-
 +
| 0x00002001 || Io || Mapped by kernel capability parsing in [[#CreateProcess]].
 +
|-
 +
| 0x00042002 || Static || Mapped by kernel capability parsing in [[#CreateProcess]].
 +
|-
 +
| 0x00DC7E03 || Code || Mapped during [[#CreateProcess]].
 +
|-
 +
| [1.0.0+]
 +
 
 +
0x01FEBD04
 +
 
 +
[4.0.0+]
 +
 
 +
0x03FEBD04
 +
|| CodeData || Transition from 0xDC7E03 performed by [[#SetProcessMemoryPermission]].
 +
|-
 +
| [1.0.0+]
 +
0x017EBD05
 +
 
 +
[4.0.0+]
 +
 
 +
0x037EBD05
 +
|| Normal || Mapped using [[#SetHeapSize]].
 +
|-
 +
| 0x00402006 || Shared || Mapped using [[#MapSharedMemory]].
 +
|-
 +
| 0x00482907 || [1.0.0] Alias || Mapped using [[#MapMemory]].
 +
|-
 +
| 0x00DD7E08 || AliasCode || Mapped using [[#MapProcessCodeMemory]].
 +
|-
 +
| [1.0.0+]
 +
 
 +
0x01FFBD09
 +
 
 +
[4.0.0+]
 +
 
 +
0x03FFBD09
 +
|| AliasCodeData || Transition from 0xDD7E08 performed by [[#SetProcessMemoryPermission]].
 +
|-
 +
| 0x005C3C0A || [[IPC_Marshalling|Ipc]] || IPC buffers with descriptor flags=0.
 +
|-
 +
| 0x005C3C0B || Stack || Mapped using [[#MapMemory]].
 +
|-
 +
| 0x0040200C || [[Thread Local Storage|ThreadLocal]] || Mapped during [[#CreateThread]].
 +
|-
 +
| 0x015C3C0D || Transfered || Mapped using [[#MapTransferMemory]] when the owning process has perm=0.
 +
|-
 +
| 0x005C380E || SharedTransfered || Mapped using [[#MapTransferMemory]] when the owning process has perm!=0.
 +
|-
 +
| 0x0040380F || SharedCode || Mapped using [[#MapProcessMemory]].
 +
|-
 +
| 0x00000010 || Inaccessible ||
 +
|-
 +
| 0x005C3811 || [[IPC_Marshalling|NonSecureIpc]] || IPC buffers with descriptor flags=1.
 +
|-
 +
| 0x004C2812 || [[IPC_Marshalling|NonDeviceIpc]] || IPC buffers with descriptor flags=3.
 +
|-
 +
| 0x00002013 || Kernel || Mapped in kernel during [[#CreateThread]].
 +
|-
 +
| 0x00402214 || [4.0.0+] GeneratedCode || Mapped in kernel during [[#ControlCodeMemory]].
 +
|-
 +
| 0x00402015 || [4.0.0+] CodeOut || Mapped in kernel during [[#ControlCodeMemory]].
 +
|-
 +
| 0x00002016 || [13.0.0+] Coverage ||
 +
|-
 +
| 0x05583817 || [15.0.0+] Insecure ||
 +
|}
 +
 
 +
== ArbitrationType ==
 +
{| class=wikitable
 +
! Value || Type
 +
|-
 +
| 0x0 || WaitIfLessThan
 +
|-
 +
| 0x1 || DecrementAndWaitIfLessThan
 +
|-
 +
| 0x2 || WaitIfEqual
 +
|}
 +
 
 +
== SignalType ==
 +
{| class=wikitable
 +
! Value || Type
 +
|-
 +
| 0x0 || Signal
 +
|-
 +
| 0x1 || SignalAndIncrementIfEqual
 +
|-
 +
| 0x2 || SignalAndModifyBasedOnWaitingThreadCountIfEqual
 +
|}
 +
 
 +
== ContinueDebugFlagsOld ==
 +
[1.0.0-2.3.0]
 +
{| class=wikitable
 +
! Bit || Bitmask || Description
 +
|-
 +
| 0 || 1 || IgnoreException (note: ResumeAllThreads or debug-suspended-thread-id needed)
 +
|-
 +
| 1 || 2 || SwallowException
 +
|-
 +
| 2 || 4 || ResumeAllThreads
 +
|}
 +
 
 +
== ContinueDebugFlags ==
 +
[3.0.0+]
 +
{| class=wikitable
 +
! Bit || Bitmask || Description
 +
|-
 +
| 0 || 1 || IgnoreException (note: doesn't need to be set in the same call than Resume)
 +
|-
 +
| 1 || 2 || DontCatchExceptions
 +
|-
 +
| 2 || 4 || Resume
 +
|-
 +
| 3 || 8 || IgnoreOtherThreadsExceptions
 +
|}
 +
 
 +
IgnoreExceptionsOfOthers is like IgnoreException but acts on all threads that aren't in the input list. The affected threads are resumed.
 +
 
 +
Only one of of Resume and IgnoreOtherThreadsExceptions can be set at a time.
 +
 
 +
If the input number of threads is 0, this means "all threads".
 +
 
 +
== DebugEventInfo ==
 +
The below table is for the Aarch64 version of the system call. For A32, all u64 fields but title/process/thread id are actually u32, making the structure 0x28-byte-big (0x40 for a64).
 +
 
 +
Size: 0x40
 +
 
 +
{| class=wikitable
 +
! Offset || Length || Description
 +
|-
 +
| 0 || u32 || EventType
 +
|-
 +
| 4 || u32 || Flags (bit0: NeedsContinue)
 +
|-
 +
| 8 || u64 || ThreadId
 +
|-
 +
| 0x10 || || PerTypeSpecifics
 +
|}
 +
 
 +
AttachProcess specific:
 +
{| class=wikitable
 +
! Offset || Length || Description
 +
|-
 +
| 0x10 || u64 || TitleId
 +
|-
 +
| 0x18 || u64 || ProcessId
 +
|-
 +
| 0x20 || char[12] || ProcessName
 +
|-
 +
| 0x2C || u32 || MmuFlags
 +
|-
 +
| 0x30 || u64 || [5.0.0+] UserExceptionContextAddr
 +
|}
 +
 
 +
AttachThread specific:
 +
{| class=wikitable
 +
! Offset || Length || Description
 +
|-
 +
| 0x10 || u64 || ThreadId
 +
|-
 +
| 0x18 || u64 || TlsPtr
 +
|-
 +
| 0x20 || u64 || Entrypoint
 +
|}
 +
 
 +
Exit specific:
 +
{| class=wikitable
 +
! Offset || Length || Description
 +
|-
 +
| 0x10 || u32|| Type (0=PausedThread, 1=RunningThread, 2=ExitedProcess, 3=TerminatedProcess)
 +
|}
 +
 
 +
Exception specific:
 +
{| class=wikitable
 +
! Offset || Length || Description
 +
|-
 +
| 0x10 || u32 || ExceptionType
 +
|-
 +
| 0x18 || u64 || FaultRegister
 +
|-
 +
| 0x20 || || PerExceptionSpecifics
 +
|}
 +
 
 +
=== DebugEventType ===
 +
{| class=wikitable
 +
! Value || Name
 +
|-
 +
| 0 || AttachProcess
 +
|-
 +
| 1 || AttachThread
 +
|-
 +
| 2 || ExitProcess
 +
|-
 +
| 3 || ExitThread
 +
|-
 +
| 4 || Exception
 +
|}
 +
 
 +
=== DebugExceptionType ===
 +
{| class=wikitable
 +
! Value || Name
 +
|-
 +
| 0 || Trap (*)
 +
|-
 +
| 1 || InstructionAbort
 +
|-
 +
| 2 || DataAbortMisc (**)
 +
|-
 +
| 3 || PcSpAlignmentFault
 +
|-
 +
| 4 || DebuggerAttached
 +
|-
 +
| 5 || BreakPoint
 +
|-
 +
| 6 || UserBreak
 +
|-
 +
| 7 || DebuggerBreak
 +
|-
 +
| 8 || BadSvcId
 +
|-
 +
| 9 || [2.0.0+] SError
 +
|}
 +
 
 +
<nowiki>*</nowiki> Undefined instructions, software breakpoints, some other traps.
 +
 
 +
<nowiki>**</nowiki> Data aborts, FP traps, and everything else that doesn't belong to any of the above.
 +
 
 +
Trap specifics:
 +
{| class=wikitable
 +
! Offset || Length || Description
 +
|-
 +
| 0x20 || u32 || Opcode
 +
|}
 +
 
 +
BreakPoint specifics:
 +
{| class=wikitable
 +
! Offset || Length || Description
 +
|-
 +
| 0x20 || u32 || IsWatchpoint
 +
|}
 +
 
 +
UserBreak specifics:
 +
{| class=wikitable
 +
! Offset || Length || Description
 +
|-
 +
| 0x20 || u32 || Info0
 +
|-
 +
| 0x28 || u64 || Info1
 +
|-
 +
| 0x30 || u64 || Info2
 +
|}
 +
 
 +
BadSvcId specifics:
 +
{| class=wikitable
 +
! Offset || Length || Description
 +
|-
 +
| 0x20 || u32 || SvcId
 +
|}
 +
 
 +
= Exception handling =
 +
First of all, a function that might be called by synchronous exception handler and that is called by the SError handler fetches the exception info, adjusts PC, panics on exceptions taken from EL1, then dispatches the exception.
 +
 
 +
The dispatcher has two mutually exclusive exception reporting methods:
 +
* by storing information at the start of the process's TLS memregion (TPIDRRO_EL0) and jumping back to the crt0
 +
* by using KDebug
 +
 
 +
KDebug dispatching is used when at least one of the following conditions are met:
 +
* SMC ConfigItem KernelMemConfig bit 1 is NOT set (it isn't on retail), unless: this is a software or hardware breakpoint, or a watchpoint, or [4.0.0+?] the process is attached and this is a Google PNaCl trap instruction (see LLVM source)
 +
* FAR doesn't point to a valid address in mapped-readable CodeStatic memory (i.e. this is the case for NRO and JIT memory) or this is one of the following exceptions (it particular, that doesn't include FP exceptions occurring in CodeStatic memory):
 +
** Uncategorized
 +
** IllegalState
 +
** SupervisorCallA32
 +
** SupervisorCallA64
 +
** PCAlignment
 +
** SPAlignment
 +
** SError
 +
** BreakpointLowerEl
 +
** SoftwareStepLowerEl (note: no way set single-step flag; not parsed)
 +
** WatchpointLowerEl
 +
** SoftwareBreakpointA32 (note: not parsed)
 +
** SoftwareBreakpointA64 (note: not parsed)
 +
   
 +
In all other cases the userland-handled exception path is taken.
 +
 
 +
KDebug path:
 +
 
 +
If the process is attached, the exception is reported to the KDebug. If the thread was continued using flag IgnoreExceptions, it returns from the exception as if nothing happened.
 +
 
 +
If the latter is not the case, or if the process isn't attached, proceed to [2.0.0+] crash reporting (or in [1.0.0] just terminate the process):
 +
if EnableDebug is set, and depending on the process state (more than one crash per process isn't permitted) it may signal itself with ProcessState_Crashed so that PM asks NS to start creport so that creport attaches to it and reports the crashes. Otherwise, just terminate.
 +
 
 +
Userland reporting path and [[#ReturnFromException]]:
 +
 
 +
TLS region start (A64):
 +
{| class=wikitable
 +
! Offset || Length || Description
 +
|-
 +
| 0x0 || 0x148 || Exception stack
 +
|-
 +
| 0x148 || 0x78 || ExceptionFrameA64
 +
|}
 +
 
 +
ExceptionFrameA64:
 +
{| class=wikitable
 +
! Offset || Length || Description
 +
|-
 +
| 0x0 || 0x48 (8*9) || GPRs 0..8.
 +
|-
 +
| 0x48 || 0x8 || lr
 +
|-
 +
| 0x50 || 0x8 || sp
 +
|-
 +
| 0x58 || 0x8 || pc (elr_el1)
 +
|-
 +
| 0x60 || 0x4 || pstate & 0xFF0FFE20
 +
|-
 +
| 0x64 || 0x4 || afsr0
 +
|-
 +
| 0x68 || 0x4 || afsr1
 +
|-
 +
| 0x6C || 0x4 || esr
 +
|-
 +
| 0x70 || 0x8 || far
 +
|}
 +
 
 +
TLS region start (A32):
 +
{| class=wikitable
 +
! Offset || Length || Description
 +
|-
 +
| 0x0 || 0x178 || Exception stack
 +
|-
 +
| 0x148 || 0x44 || ExceptionFrameA32
 +
|}
 +
 
 +
ExceptionFrameA32:
 +
{| class=wikitable
 +
! Offset || Length || Description
 +
|-
 +
| 0x0 || 0x20 (8*4) || GPRs 0..7.
 +
|-
 +
| 0x20 || 0x4 || sp
 +
|-
 +
| 0x24 || 0x4 || lr
 +
|-
 +
| 0x28 || 0x4 || pc (elr_el1)
 +
|-
 +
| 0x2C || 0x4 || tpidr_el0 = 1
 +
|-
 +
| 0x30 || 0x4 || cpsr & 0xFF0FFE20
 +
|-
 +
| 0x34 || 0x4 || afsr0
 +
|-
 +
| 0x38 || 0x4 || afsr1
 +
|-
 +
| 0x3C || 0x4 || esr
 +
|-
 +
| 0x40 || 0x4 || far
 +
|}
 +
 
 +
In that case, after storing the regs in the TLS, the exception handler returns to the application's crt0 (entrypoint), with X0=<error description code> (see below) and X1=SP=frame=<stack top> (see above)
 +
 
 +
{| class=wikitable
 +
! Desc. code || Meaning
 +
|-
 +
| 0x100 || Instruction abort
 +
|-
 +
| 0x102 || Misaligned PC
 +
|-
 +
| 0x103 || Misaligned SP
 +
|-
 +
| 0x106 || [2.0.0+] SError
 +
|-
 +
| 0x301 || Bad SVC
 +
|-
 +
| 0x104 || Uncategorized, CP15RTTrap, CP15RRTTrap, CP14RTTrap, CP14RRTTrap, IllegalState, SystemRegisterTrap
 +
|-
 +
| 0x101 || None of the above, EC <= 0x34 and not a breakpoint
 +
|-
 +
|}
 +
 
 +
(During normal app boot the process is invoked with X0=0 and X1=main_thread_handle. The crt0 of retail apps determines whether to boot normally or handle an exception if X0 is set to 0 or not)
 +
 
 +
The application is supposed to promptly update the contents of elr_el1 to a user handler (and any other regs it sees fit) and call [[#ReturnFromException]] (error code) to call that handler. The latter is then expected to promptly abort the program.
 +
 
 +
[[#ReturnFromException]] updates the contents of the kernel stack frame with what the user provided in the TLS structure, sets TPIDR_EL0 to 1, then:
 +
* if the provided error code is 0, gracefully pivots and returns from exception
 
* if it is not, replays the exception and pass it to the KDebug (see above). One can pass 0x10001 to prevent process termination. If the process is attached, this also prevents crash-collection/termination (different from the exception handler behavior)
 
* if it is not, replays the exception and pass it to the KDebug (see above). One can pass 0x10001 to prevent process termination. If the process is attached, this also prevents crash-collection/termination (different from the exception handler behavior)
  
Note that if a thread that wasn't faulting calls svcReturnFromException, it signals an "invalid syscall" exception
+
If an exception occurs from the above user handler, the entire exception handling process will repeat with the new exception.
 +
 
 +
Note that if a thread that wasn't faulting calls [[#ReturnFromException]], it signals an "invalid syscall" exception
 +
 
 +
Note that [[SMC|IsDebugMode]] is not used during exception-handling, except for enabling printing a message to UART-A. This UART code causes a system-hang on retail (likely due to a loop that doesn't exit). This printing doesn't seem to run when the process is attached for debugging?

Latest revision as of 19:21, 11 June 2024


System calls

ID Return Type Name Arguments
0x01 Result SetHeapSize uintptr_t *out_address, size_t size
0x02 Result SetMemoryPermission uintptr_t address, size_t size, MemoryPermission perm
0x03 Result SetMemoryAttribute uintptr_t address, size_t size, uint32_t mask, uint32_t attr
0x04 Result MapMemory uintptr_t dst_address, uintptr_t src_address, size_t size
0x05 Result UnmapMemory uintptr_t dst_address, uintptr_t src_address, size_t size
0x06 Result QueryMemory arch::MemoryInfo *out_memory_info, PageInfo *out_page_info, uintptr_t address
0x07 void ExitProcess
0x08 Result CreateThread Handle *out_handle, ThreadFunc func, uintptr_t arg, uintptr_t stack_bottom, int32_t priority, int32_t core_id
0x09 Result StartThread Handle thread_handle
0x0A void ExitThread
0x0B void SleepThread int64_t ns
0x0C Result GetThreadPriority int32_t *out_priority, Handle thread_handle
0x0D Result SetThreadPriority Handle thread_handle, int32_t priority
0x0E Result GetThreadCoreMask int32_t *out_core_id, uint64_t *out_affinity_mask, Handle thread_handle
0x0F Result SetThreadCoreMask Handle thread_handle, int32_t core_id, uint64_t affinity_mask
0x10 int32_t GetCurrentProcessorNumber
0x11 Result SignalEvent Handle event_handle
0x12 Result ClearEvent Handle event_handle
0x13 Result MapSharedMemory Handle shmem_handle, uintptr_t address, size_t size, MemoryPermission map_perm
0x14 Result UnmapSharedMemory Handle shmem_handle, uintptr_t address, size_t size
0x15 Result CreateTransferMemory Handle *out_handle, uintptr_t address, size_t size, MemoryPermission map_perm
0x16 Result CloseHandle Handle handle
0x17 Result ResetSignal Handle handle
0x18 Result WaitSynchronization int32_t *out_index, const Handle *handles, int32_t numHandles, int64_t timeout_ns
0x19 Result CancelSynchronization Handle handle
0x1A Result ArbitrateLock Handle thread_handle, uintptr_t address, uint32_t tag
0x1B Result ArbitrateUnlock uintptr_t address
0x1C Result WaitProcessWideKeyAtomic uintptr_t address, uintptr_t cv_key, uint32_t tag, int64_t timeout_ns
0x1D void SignalProcessWideKey uintptr_t cv_key, int32_t count
0x1E int64_t GetSystemTick
0x1F Result ConnectToNamedPort Handle *out_handle, const char *name
0x20 Result SendSyncRequestLight Handle session_handle
0x21 Result SendSyncRequest Handle session_handle
0x22 Result SendSyncRequestWithUserBuffer uintptr_t message_buffer, size_t message_buffer_size, Handle session_handle
0x23 Result SendAsyncRequestWithUserBuffer Handle *out_event_handle, uintptr_t message_buffer, size_t message_buffer_size, Handle session_handle
0x24 Result GetProcessId uint64_t *out_process_id, Handle process_handle
0x25 Result GetThreadId uint64_t *out_thread_id, Handle thread_handle
0x26 void Break BreakReason break_reason, uintptr_t arg, size_t size
0x27 Result OutputDebugString const char *debug_str, size_t len
0x28 void ReturnFromException Result result
0x29 Result GetInfo uint64_t *out, InfoType info_type, Handle handle, uint64_t info_subtype
0x2A void FlushEntireDataCache
0x2B Result FlushDataCache uintptr_t address, size_t size
[3.0.0+] 0x2C Result MapPhysicalMemory uintptr_t address, size_t size
[3.0.0+] 0x2D Result UnmapPhysicalMemory uintptr_t address, size_t size
[5.0.0-5.1.0] 0x2E Result GetFutureThreadInfo arch::LastThreadContext *out_context, uintptr_t *out_tls_address, uint32_t *out_flags, int64_t ns
[6.0.0+] 0x2E Result GetDebugFutureThreadInfo arch::LastThreadContext *out_context, uint64_t *thread_id, Handle debug_handle, int64_t ns
0x2F Result GetLastThreadInfo arch::LastThreadContext *out_context, uintptr_t *out_tls_address, uint32_t *out_flags
0x30 Result GetResourceLimitLimitValue int64_t *out_limit_value, Handle resource_limit_handle, LimitableResource which
0x31 Result GetResourceLimitCurrentValue int64_t *out_current_value, Handle resource_limit_handle, LimitableResource which
0x32 Result SetThreadActivity Handle thread_handle, ThreadActivity thread_activity
0x33 Result GetThreadContext3 ThreadContext *out_context, Handle thread_handle
[4.0.0+] 0x34 Result WaitForAddress uintptr_t address, ArbitrationType arb_type, int32_t value, int64_t timeout_ns
[4.0.0+] 0x35 Result SignalToAddress uintptr_t address, SignalType signal_type, int32_t value, int32_t count
[8.0.0+] 0x36 void SynchronizePreemptionState
[11.0.0+] 0x37 Result GetResourceLimitPeakValue int64_t *out_peak_value, Handle resource_limit_handle, LimitableResource which
[13.0.0+] 0x39 Result CreateIoPool Handle *out_handle, IoPoolType which_pool
[13.0.0+] 0x3A Result CreateIoRegion Handle *out_handle, Handle io_pool, PhysicalAddress physical_address, size_t size, MemoryMapping mapping, MemoryPermission perm
[1.0.0-3.0.2] 0x3C void DumpInfo DumpInfoType dump_info_type, uint64_t arg
[4.0.0+] 0x3C void KernelDebug KernelDebugType kern_debug_type, uint64_t arg0, uint64_t arg1, uint64_t arg2
[4.0.0+] 0x3D void ChangeKernelTraceState KernelTraceState kern_trace_state
0x40 Result CreateSession Handle *out_server_session_handle, Handle *out_client_session_handle, bool is_light, uintptr_t name
0x41 Result AcceptSession Handle *out_handle, Handle port
0x42 Result ReplyAndReceiveLight Handle handle
0x43 Result ReplyAndReceive int32_t *out_index, const Handle *handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns
0x44 Result ReplyAndReceiveWithUserBuffer int32_t *out_index, uintptr_t message_buffer, size_t message_buffer_size, const Handle *handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns
0x45 Result CreateEvent Handle *out_write_handle, Handle *out_read_handle
[13.0.0+] 0x46 Result MapIoRegion Handle io_region, uintptr_t address, size_t size, MemoryPermission perm
[13.0.0+] 0x47 Result UnmapIoRegion Handle io_region, uintptr_t address, size_t size
[5.0.0+] 0x48 Result MapPhysicalMemoryUnsafe uintptr_t address, size_t size
[5.0.0+] 0x49 Result UnmapPhysicalMemoryUnsafe uintptr_t address, size_t size
[5.0.0+] 0x4A Result SetUnsafeLimit size_t limit
[4.0.0+] 0x4B Result CreateCodeMemory Handle *out_handle, uintptr_t address, size_t size
[4.0.0+] 0x4C Result ControlCodeMemory Handle code_memory_handle, CodeMemoryOperation operation, uint64_t address, uint64_t size, MemoryPermission perm
0x4D void SleepSystem
0x4E Result ReadWriteRegister uint32_t *out_value, PhysicalAddress address, uint32_t mask, uint32_t value
0x4F Result SetProcessActivity Handle process_handle, ProcessActivity process_activity
0x50 Result CreateSharedMemory Handle *out_handle, size_t size, MemoryPermission owner_perm, MemoryPermission remote_perm
0x51 Result MapTransferMemory Handle trmem_handle, uintptr_t address, size_t size, MemoryPermission owner_perm
0x52 Result UnmapTransferMemory Handle trmem_handle, uintptr_t address, size_t size
0x53 Result CreateInterruptEvent Handle *out_read_handle, int32_t interrupt_id, InterruptType interrupt_type
0x54 Result QueryPhysicalAddress arch::PhysicalMemoryInfo *out_info, uintptr_t address
[1.0.0-9.2.0] 0x55 Result QueryIoMapping uintptr_t *out_address, PhysicalAddress physical_address, size_t size
[10.0.0+] 0x55 Result QueryMemoryMapping uintptr_t *out_address, size_t *out_size, PhysicalAddress physical_address, size_t size
0x56 Result CreateDeviceAddressSpace Handle *out_handle, uint64_t das_address, uint64_t das_size
0x57 Result AttachDeviceAddressSpace DeviceName device_name, Handle das_handle
0x58 Result DetachDeviceAddressSpace DeviceName device_name, Handle das_handle
0x59 Result MapDeviceAddressSpaceByForce Handle das_handle, Handle process_handle, uint64_t process_address, size_t size, uint64_t device_address, uint32_t option
0x5A Result MapDeviceAddressSpaceAligned Handle das_handle, Handle process_handle, uint64_t process_address, size_t size, uint64_t device_address, uint32_t option
[1.0.0-12.1.0] 0x5B Result MapDeviceAddressSpace size_t *out_mapped_size, Handle das_handle, Handle process_handle, uint64_t process_address, size_t size, uint64_t device_address, MemoryPermission device_perm
0x5C Result UnmapDeviceAddressSpace Handle das_handle, Handle process_handle, uint64_t process_address, size_t size, uint64_t device_address
0x5D Result InvalidateProcessDataCache Handle process_handle, uint64_t address, uint64_t size
0x5E Result StoreProcessDataCache Handle process_handle, uint64_t address, uint64_t size
0x5F Result FlushProcessDataCache Handle process_handle, uint64_t address, uint64_t size
0x60 Result DebugActiveProcess Handle *out_handle, uint64_t process_id
0x61 Result BreakDebugProcess Handle debug_handle
0x62 Result TerminateDebugProcess Handle debug_handle
0x63 Result GetDebugEvent arch::DebugEventInfo *out_info, Handle debug_handle
0x64 Result ContinueDebugEvent Handle debug_handle, uint32_t flags, const uint64_t *thread_ids, int32_t num_thread_ids
0x65 Result GetProcessList int32_t *out_num_processes, uint64_t *out_process_ids, int32_t max_out_count
0x66 Result GetThreadList int32_t *out_num_threads, uint64_t *out_thread_ids, int32_t max_out_count, Handle debug_handle
0x67 Result GetDebugThreadContext ThreadContext *out_context, Handle debug_handle, uint64_t thread_id, uint32_t context_flags
0x68 Result SetDebugThreadContext Handle debug_handle, uint64_t thread_id, const ThreadContext *context, uint32_t context_flags
0x69 Result QueryDebugProcessMemory arch::MemoryInfo *out_memory_info, PageInfo *out_page_info, Handle process_handle, uintptr_t address
0x6A Result ReadDebugProcessMemory uintptr_t buffer, Handle debug_handle, uintptr_t address, size_t size
0x6B Result WriteDebugProcessMemory Handle debug_handle, uintptr_t buffer, uintptr_t address, size_t size
0x6C Result SetHardwareBreakPoint HardwareBreakPointRegisterName name, uint64_t flags, uint64_t value
0x6D Result GetDebugThreadParam uint64_t *out_64, uint32_t *out_32, Handle debug_handle, uint64_t thread_id, DebugThreadParam param
[5.0.0+] 0x6F Result GetSystemInfo uint64_t *out, SystemInfoType info_type, Handle handle, uint64_t info_subtype
0x70 Result CreatePort Handle *out_server_handle, Handle *out_client_handle, int32_t max_sessions, bool is_light, uintptr_t name
0x71 Result ManageNamedPort Handle *out_server_handle, const char *name, int32_t max_sessions
0x72 Result ConnectToPort Handle *out_handle, Handle port
0x73 Result SetProcessMemoryPermission Handle process_handle, uint64_t address, uint64_t size, MemoryPermission perm
0x74 Result MapProcessMemory uintptr_t dst_address, Handle process_handle, uint64_t src_address, size_t size
0x75 Result UnmapProcessMemory uintptr_t dst_address, Handle process_handle, uint64_t src_address, size_t size
0x76 Result QueryProcessMemory arch::MemoryInfo *out_memory_info, PageInfo *out_page_info, Handle process_handle, uint64_t address
0x77 Result MapProcessCodeMemory Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size
0x78 Result UnmapProcessCodeMemory Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size
0x79 Result CreateProcess Handle *out_handle, const arch::CreateProcessParameter *parameters, const uint32_t *caps, int32_t num_caps
0x7A Result StartProcess Handle process_handle, int32_t priority, int32_t core_id, uint64_t main_thread_stack_size
0x7B Result TerminateProcess Handle process_handle
0x7C Result GetProcessInfo int64_t *out_info, Handle process_handle, ProcessInfoType info_type
0x7D Result CreateResourceLimit Handle *out_handle
0x7E Result SetResourceLimitLimitValue Handle resource_limit_handle, LimitableResource which, int64_t limit_value
0x7F void CallSecureMonitor SecureMonitorArguments *args
[15.0.0+] 0x90 Result MapInsecurePhysicalMemory uintptr_t address, size_t size
[15.0.0+] 0x91 Result UnmapInsecurePhysicalMemory uintptr_t address, size_t size

SetHeapSize

Argument Type Name
(In) X1 uint64_t Size
(Out) W0 #Result Result
(Out) X1 void* HeapAddress

Sets the process heap to a given Size. It can both extend and shrink the heap.

Size must be a multiple of 0x200000 (2MB).

On success, the heap base-address (which is fixed by kernel, aslr'd, and always in the Heap memory region) is written to HeapAddress.

Uses current process pool partition. The memory allocated counts towards the caller's process Memory ResourceLimit.

[2.0.0+] Size must be less than or equal to 4GB.

Result codes

0x0: Success.

0xCA01: Invalid size passed. It's either bigger than 4GB, or misaligned.

0xD001: Size is bigger than the Heap Region size.

0xCE01: KMemoryBlockAllocator slab allocator exhausted.

0xD401: The memory region is in an invalid state. Likely because a mapping was made in the heap region.

0x10801: Memory resource limit reached.

SetMemoryPermission

Argument Type Name
(In) X0 void* Address
(In) X1 uint64_t Size
(In) W2 #MemoryPermission MemoryPermission
(Out) W0 #Result Result

Changes 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-.

Result codes

0x0: Success. The memory region was reprotected.

0xCC01: Unaligned address specified.

0xCA01: Unaligned or zero size specified.

0xD401: The provided memory region does not fall within the userland address space.

0xD801: Invalid permission specified. Valid permissions are ---, r-- and rw-.

0xD401: The provided memory region was in an invalid state. The region must have the FlagCanReprotect state, and must not have the Locked or Uncached attributes.

0xCE01: Kernel resource exhausted.

SetMemoryAttribute

Argument Type Name
(In) X0 void* Address
(In) X1 uint64_t Size
(In) W2 uint32_t Mask
(In) W3 uint32_t Value
(Out) W0 #Result Result

Changes attribute of page-aligned memory region. The only allowed combination of Value and Mask is 0x8, which means only bit3 in #MemoryAttribute can be set or cleared.

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.

MapMemory

Argument Type Name
(In) X0 void* DstAddress
(In) X1 void* SrcAddress
(In) X2 uint64_t Size
(Out) W0 #Result Result

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.

[1.0.0] This could be used to map into either the Alias Region or the Stack region.

[2.0.0+] This can only be used to map into the Stack region.

Code can get the range of the Alias region from #GetInfo id0=2,3, and on 2.0.0+ the range of the Stack region via #GetInfo id0=14, 15 (on 1.0.0, the Stack region had hardcoded limits).

When mapped into the Alias region, the mapped memory will have state 0x482907.

When mapped into the Stack region, the mapped memory will have state 0x5C3C0B.

UnmapMemory

Argument Type Name
(In) X0 void* DstAddress
(In) X1 void* SrcAddress
(In) X2 uint64_t Size
(Out) W0 #Result Result

Unmaps a region that was previously mapped with #MapMemory.

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.

QueryMemory

Argument Type Name
(In) X0 #MemoryInfo* MemoryInfo
(In) X2 void* Address
(Out) W0 #Result Result
(Out) W1 #PageInfo PageInfo

Queries information about an address. Will always fetch the lowest page-aligned mapping that contains the provided address.

Outputs a #MemoryInfo struct.

ExitProcess

Argument Type Name
(In) None
(Out) None

Exits the current process.

CreateThread

Argument64 Argument32 Type Name
(In) X1 R1 void(*)(void*) Entry
(In) X2 R2 void* ThreadContext
(In) X3 R3 void* StackTop
(In) W4 R0 int32_t Priority
(In) W5 R4 int32_t ProcessorId
(Out) W0 R0 #Result Result
(Out) W1 R1 Handle<Thread> ThreadHandle

Creates a thread in the current process.

ProcessorId must be 0,1,2,3 or -2, where -2 uses the default CpuId for process.

StartThread

Argument Type Name
(In) W0 Handle<Thread> ThreadHandle
(Out) None

Starts the thread for the provided handle.

ExitThread

Argument Type Name
(In) None
(Out) None

Exits the current thread.

SleepThread

Argument64 Argument32 Type Name
(In) X0 R0, R1 uint64_t Nanoseconds

Sleeps for a specified amount of time, or yields the thread.

Setting nanoseconds to 0, -1, or -2 indicates a yielding type.

Value Type
0 Yielding without core migration
-1 Yielding with core migration
-2 Yielding to any other thread

GetThreadPriority

Argument Type Name
(In) W1 Handle<Thread> ThreadHandle
(Out) W0 #Result Result
(Out) W1 int32_t Priority

Gets the priority of provided thread handle.

SetThreadPriority

Argument Type Name
(In) W0 Handle<Thread> ThreadHandle
(In) W1 int32_t Priority
(Out) W0 #Result Result

Sets the priority of provided thread handle.

Priority is a number 0-0x3F. Lower value means higher priority.

GetThreadCoreMask

Argument64 Argument32 Type Name
(In) W2 R2 Handle<Thread> ThreadHandle
(Out) W0 R0 #Result Result
(Out) W1 R1 int32_t CoreMask0
(Out) X2 R2, R3 uint64_t CoreMask1

Gets the affinity mask of provided thread handle.

SetThreadCoreMask

Argument64 Argument32 Type Name
(In) W0 R0 Handle<Thread> ThreadHandle
(In) W1 R1 int32_t CoreMask0
(In) X2 R2, R3 uint64_t CoreMask1
(Out) W0 R0 #Result Result

Sets the affinity mask of provided thread handle.

GetCurrentProcessorNumber

Argument Type Name
(In) None
(Out) W0 uint32_t CpuId

Gets which cpu is executing the current thread.

CpuId is an integer in the range 0-3.

SignalEvent

Argument Type Name
(In) W0 Handle<WritableEvent> EventHandle
(Out) X0 #Result Result

Puts the given event in the signaled state.

Will wake up any thread currently waiting on this event. Can potentially trigger a reschedule.

Any calls to #WaitSynchronization on this handle will return immediately, until the event's signaled state is reset.

Result codes

0x0: Success. Event is now in signaled state.

0xE401: Invalid handle. The handle either does not exist, or is not a WritableEvent.

ClearEvent

Argument Type Name
(In) W0 Handle<WritableEvent> or Handle<ReadableEvent> EventHandle
(Out) X0 #Result Result

Takes the given event out of the signaled state, if it is signaled.

Result codes

0x0: Success, the event is now in the not-signaled state.

0xE401: Invalid handle. The handle either does not exist, or is not a ReadableEvent nor a WritableEvent.

MapSharedMemory

Argument Type Name
(In) W0 Handle<SharedMemory> SharedMemoryHandle
(In) X1 void* Address
(In) X2 uint64_t Size
(In) W3 #MemoryPermission MemoryPermission
(Out) W0 #Result Result

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.

UnmapSharedMemory

Argument Type Name
(In) W0 Handle<SharedMemory> SharedMemoryHandle
(In) X1 void* Address
(In) X2 uint64_t Size
(Out) W0 #Result Result

CreateTransferMemory

Argument Type Name
(In) X1 void* Address
(In) X2 uint64_t Size
(In) W3 #MemoryPermission MemoryPermission
(Out) W0 #Result Result
(Out) W1 Handle<TransferMemory> TransferMemoryHandle

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.

CloseHandle

Argument Type Name
(In) W0 Handle Handle
(Out) W0 #Result Result

ResetSignal

Argument Type Name
(In) W0 Handle<ReadableEvent> or Handle<Process> Handle
(Out) W0 #Result Result

Resets the signal on the given handle, ensuring future calls to #WaitSynchronization on this handle will sleep until the handle is signaled again. If the handle is a ReadableEvent, this returns ResultInvalidState if the event is not signaled.

If the handle is a Process, it will clear the signaled state (which is set when the process changes #ProcessState. Once the process enters the Exited state, calling ResetSignal on the process will no longer have an effect (the process is permanently signaled), and the syscall will return 0xFA01.

Result codes

0x0: Success. The signal was reset.

0xE401: The handle is invalid or of the wrong type.

0xFA01: The handle was not signaled, or the process is in exited state, causing it to be permanently signaled.

WaitSynchronization

Argument64 Argument32 Type Name
(In) X1 R1 Handle* HandlesPtr
(In) W2 R2 int32_t HandlesNum
(In) X3 R0, R3 int64_t Timeout
(Out) W0 R0 #Result Result
(Out) W1 R1 uint64_t HandleIndex

Works with HandlesNum <= 0x40.

When zero handles are passed, this will wait forever until either timeout or cancellation occurs.

Does not accept 0xFFFF8001 or 0xFFFF8000 as handles.

Object types

KDebug: signals when there is a new DebugEvent (retrievable via #GetDebugEvent).

KClientPort: signals when the number of sessions is less than the maximum allowed.

KProcess: signals when the process undergoes a state change (retrievable via #GetProcessInfo).

KReadableEvent: signals when the event's corresponding KWritableEvent has been signaled via #SignalEvent.

KServerPort: signals when there is an incoming connection waiting to be accepted.

KServerSession: signals when there is an incoming message waiting to be received or the pipe is closed.

KThread: signals when the thread has exited.

Result codes

0x0: Success. One of the objects was signaled before the timeout expired, or one of the objects is a Session with a closed remote. Handle index is updated to indicate which object signaled.

0x7601: Thread termination requested. Handle index is not updated.

0xe401: Invalid handle. Returned when one of the handles passed is invalid. Handle index is not updated.

0xe601: Invalid address. Returned when the handles pointer is not a readable address. Handle index is not updated.

0xea01: Timeout. Returned when no objects have been signaled within the timeout. Handle index is not updated.

0xec01: Interrupted. Returned when another thread uses #CancelSynchronization to cancel this thread. Handle index is not updated.

0xee01: Too many handles. Returned when the number of handles passed is > 0x40.

CancelSynchronization

Argument Type Name
(In) W0 Handle<Thread> ThreadHandle
(Out) W0 #Result Result

If the referenced thread is currently in a synchronization call (#WaitSynchronization, #ReplyAndReceive or #ReplyAndReceiveLight), that call will be interrupted and return 0xec01. If that thread is not currently executing such a synchronization call, the next call to a synchronization call will return 0xec01.

This doesn't take force-pause (activity/debug pause) into account.

Result codes

0x0: Success. The thread was either interrupted or has had its flag set.

0xe401: Invalid handle. The handle given was either invalid or not a thread handle.

ArbitrateLock

Argument Type Name
(In) W0 Handle<Thread> ThreadHandle
(In) X1 void* Address
(In) W2 uint32_t Tag
(Out) W0 #Result Result

ArbitrateUnlock

Argument Type Name
(In) X0 void* Address
(Out) W0 #Result Result

WaitProcessWideKeyAtomic

Argument64 Argument32 Type Name
(In) X0 R0 void* KeyAddress
(In) X1 R1 void* TagAddress
(In) W2 R2 uint32_t Tag
(In) X3 R3, R4 int64_t Timeout
(Out) W0 R0 #Result Result

SignalProcessWideKey

Argument Type Name
(In) X0 void* Address
(In) W1 int32_t Value
(Out) W0 #Result Result

GetSystemTick

Argument64 Argument32 Type Name
(Out) X0 R0, R1 uint64_t Ticks

Returns the value of cntpct_el0.

The frequency is 19200000 Hz (constant from official sw).

Official sw reads cntpct_el0 directly from usermode without using this SVC. sdk-nso has this SVC, but it's not known to be called anywhere.

ConnectToNamedPort

Argument Type Name
(In) X1 char* PortName
(Out) W0 #Result Result
(Out) W1 Handle<Session> SessionHandle

SendSyncRequestLight

Argument Type Name
(In) W0 Handle<Session> SessionHandle
(Out) W0 #Result Result

SendSyncRequest

Argument Type Name
(In) W0 Handle<Session> SessionHandle
(Out) W0 #Result Result

SendSyncRequestWithUserBuffer

Argument Type Name
(In) X0 void* Address
(In) X1 uint64_t Size
(In) W2 Handle<Session> SessionHandle
(Out) W0 #Result Result

Size and Address must be 0x1000-aligned.

Result codes

0x0: Success.

0xcc01: Address is not 0x1000-aligned.

0xca01: Size is not 0x1000-aligned.

0xce01: KSessionRequest allocation failed (unlikely) or pointer buffer size exceeded.

0xe401: Handles does not exist, or handle is not an instance of KClientSession.

SendAsyncRequestWithUserBuffer

Argument Type Name
(In) X1 void* Address
(In) X2 uint64_t Size
(In) W3 Handle<Session> SessionHandle
(Out) W0 #Result Result
(Out) W1 Handle<ReadableEvent> EventHandle

Size and Address must be 0x1000-aligned.

GetProcessId

Argument64 Argument32 Type Name
(In) W1 R1 Handle<Process> ProcessHandle
(Out) W0 R0 #Result Result
(Out) X1 R1, R2 uint64_t ProcessId

GetThreadId

Argument64 Argument32 Type Name
(In) W1 R1 Handle<Thread> ThreadHandle
(Out) W0 R0 #Result Result
(Out) X1 R1, R2 uint64_t ThreadId

Break

Argument Type Name
(In) X0 #BreakReason BreakReason
(In) X1 uint64_t
(In) X2 uint64_t Info
(Out) W0 #Result Result

If the process is attached, report the Break event. Then, if #ContinueDebugEvent didn't apply IgnoreException on the thread: if TPIDR_EL0 is 0, adjust ELR_EL1 to retry to svc instruction (and set TPIDR_EL0 to 1).

Otherwise, if bit31 in reason isn't set, perform crash reporting (see Exception Handling section below), if it doesn't terminate the process adjust ELR_EL1 as well.

Otherwise just return 0.

OutputDebugString

Argument Type Name
(In) X0 char* String
(In) X1 uint64_t Size
(Out) W0 #Result Result

ReturnFromException

Argument Type Name
(In) W0 #Result Result

GetInfo

Argument64 Argument32 Type Name
(In) W1 R1 #InfoType InfoType
(In) W2 R2 Handle Handle
(In) X3 R0, R3 uint64_t InfoSubType
(Out) W0 R0 #Result Result
(Out) X1 R1, R2 uint64_t Info

FlushEntireDataCache

Argument Type Name
(In) None
(Out) None

FlushDataCache

Argument Type Name
(In) X0 void* Address
(In) X1 uint64_t Size
(Out) W0 #Result Result

MapPhysicalMemory

Argument Type Name
(In) X0 void* Address
(In) X1 uint64_t Size
(Out) W0 #Result Result

Acts like #SetHeapSize except you can allocate heap at any address you'd like.

Uses current process pool partition.

Result codes

0x0: Success.

0xCA01: Invalid size passed. It's either zero or not 4k-aligned

0xCC01: Invalid address. (not 4k-aligned)

0xDC01: Invalid memory range. It's either causes overflow, or does not fall into "reserved" address range (aka Alias). See AliasRegionAddress at #InfoType

0xFA01: Invalid state. (not enough SystemResource (see NPDM#SystemResourceSize))

UnmapPhysicalMemory

Argument Type Name
(In) X0 void* Address
(In) X1 uint64_t Size
(Out) W0 #Result Result

GetDebugFutureThreadInfo

Argument64 Argument32 Type Name
(In) X3 R0, R1 uint64_t Timeout
(Out) W0 R0 #Result Result
(Out) X1 uint64_t LastThreadContextParam0
(Out) X2 uint64_t LastThreadContextParam1
(Out) X3 uint64_t LastThreadContextParam2
(Out) X4 uint64_t LastThreadContextParam3
(Out) X5 uint64_t
(Out) W6 uint32_t

GetLastThreadInfo

Argument Type Name
(In) None
(Out) W0 #Result Result
(Out) X1 uint64_t LastThreadContextParam0
(Out) X2 uint64_t LastThreadContextParam1
(Out) X3 uint64_t LastThreadContextParam2
(Out) X4 uint64_t LastThreadContextParam3
(Out) X5 uint64_t
(Out) W6 uint32_t

GetResourceLimitLimitValue

Argument64 Argument32 Type Name
(In) W1 R1 Handle<ResourceLimit> ResourceLimitHandle
(In) W2 R2 #LimitableResource LimitableResource
(Out) W0 R0 #Result Result
(Out) X1 R1, R2 int64_t LimitValue

GetResourceLimitCurrentValue

Argument64 Argument32 Type Name
(In) W1 R1 Handle<ResourceLimit> ResourceLimitHandle
(In) W2 R2 #LimitableResource LimitableResource
(Out) W0 R0 #Result Result
(Out) X1 R1, R2 int64_t CurrentValue

SetThreadActivity

Argument Type Name
(In) W0 Handle<Thread> ThreadHandle
(In) W1 #ThreadActivity ThreadActivity
(Out) W0 #Result Result

GetThreadContext3

Argument Type Name
(In) X0 #ThreadContext* ThreadContext
(In) W1 Handle<Thread> ThreadHandle
(Out) W0 #Result Result

WaitForAddress

Argument64 Argument32 Type Name
(In) X0 R0 void* Address
(In) W1 R1 #ArbitrationType ArbitrationType
(In) W2 R2 uint32_t Value
(In) X3 R3, R4 uint64_t Timeout
(Out) W0 R0 #Result Result

SignalToAddress

Argument64 Argument32 Type Name
(In) X0 R0 void* Address
(In) W1 R1 #SignalType SignalType
(In) W2 R2 uint32_t Value
(In) W3 R3 uint32_t NumToSignal
(Out) W0 R0 #Result Result

SynchronizePreemptionState

Argument Type Name
(In) None
(Out) None

GetResourceLimitPeakValue

Argument64 Argument32 Type Name
(In) W1 R1 Handle<ResourceLimit> ResourceLimitHandle
(In) W2 R2 #LimitableResource LimitableResource
(Out) W0 R0 #Result Result
(Out) X1 R1, R2 int64_t PeakValue

DumpInfo

Argument Type Name
(In) X0 #DumpInfoType DumpInfoType
(In) X1 uint64_t DumpInfoSubType
(Out) W0 #Result Result

Stubbed in retail kernel.

[4.0.0+] This function was removed and replaced by #KernelDebug.

KernelDebug

Argument Type Name
(In) W0 #KernelDebugType KernelDebugType
(In) X1 uint64_t
(In) X2 uint64_t
(In) X3 uint64_t
(Out) W0 #Result Result

Stubbed in retail kernel.

ChangeKernelTraceState

Argument Type Name
(In) W0 #KernelTraceState KernelTraceState
(Out) W0 #Result Result

Stubbed in retail kernel.

CreateSession

Argument Type Name
(In) W2 bool IsLight
(In) X3 uint64_t Name
(Out) W0 #Result Result
(Out) W1 Handle<ServerSession> ServerSessionHandle
(Out) W2 Handle<ClientSession> ClientSessionHandle

AcceptSession

Argument Type Name
(In) W1 Handle<Port> PortHandle
(Out) W0 #Result Result
(Out) W1 Handle<ServerSession> ServerSessionHandle

Result codes

0xf201: No session waiting to be accepted

ReplyAndReceiveLight

Argument Type Name
(In) W0 Handle<Port> or Handle<ServerSession> Handle
(Out) W0 #Result Result

ReplyAndReceive

Argument64 Argument32 Type Name
(In) X1 R1 Handle<Port>* or Handle<ServerSession>* Handles
(In) W2 R2 uint32_t NumHandles
(In) W3 R3 Handle<ServerSession> ReplyTargetSessionHandle
(In) X4 R0, R4 uint64_t Timeout
(Out) W0 R0 #Result Result
(Out) W1 R1 uint32_t HandleIndex

If ReplyTargetSessionHandle is not zero, a reply from the TLS will be sent to that session. Then it will wait until either of the passed sessions has an incoming message, is closed, a passed port has an incoming connection, or the timeout expires. If there is an incoming message, it is copied to the TLS.

If ReplyTargetSessionHandle is zero, the TLS should contain a blank message. If this message has a C descriptor, the buffer it points to will be used as the pointer buffer. See IPC_Marshalling#IPC_buffers. Note that a pointer buffer cannot be specified if ReplyTargetSessionHandle is not zero.

After being validated, passed handles will be enumerated in order; even if a session has been closed, if one that appears earlier in the list has an incoming message, it will take priority and a result code of 0x0 will be returned.

Result codes

0x0: Success. Either a session has an incoming message or a port has an incoming connection. HandleIndex is set appropriately.

0xea01: Timeout. No handles were signalled before the timeout expired. HandleIndex is not updated.

0xf601: Port remote dead. One of the sessions has been closed. HandleIndex is set appropriately.

ReplyAndReceiveWithUserBuffer

Argument64 Argument32 Type Name
(In) X1 R1 void* Address
(In) X2 R2 uint64_t Size
(In) X3 R3 Handle<Port>* or Handle<ServerSession>* Handles
(In) W4 R0 uint32_t NumHandles
(In) W5 R4 Handle<ServerSession> ReplyTargetSessionHandle
(In) X6 R5, R6 uint64_t Timeout
(Out) W0 R0 #Result Result
(Out) W1 R1 uint32_t HandleIndex

CreateEvent

Argument Type Name
(In) None
(Out) W0 #Result Result
(Out) W1 Handle<WritableEvent> WritableEventHandle
(Out) W2 Handle<ReadableEvent> ReadableEventHandle

MapPhysicalMemoryUnsafe

Argument Type Name
(In) X0 void* Address
(In) X1 uint64_t Size
(Out) W0 #Result Result

Same as #MapPhysicalMemory except it always uses pool partition 0.

UnmapPhysicalMemoryUnsafe

Argument Type Name
(In) X0 void* Address
(In) X1 uint64_t Size
(Out) W0 #Result Result

SetUnsafeLimit

Argument Type Name
(In) X0 uint64_t Limit
(Out) W0 #Result Result

CreateCodeMemory

Argument Type Name
(In) X1 void* Address
(In) X2 uint64_t Size
(Out) W0 #Result Result
(Out) W1 Handle<CodeMemory> CodeMemoryHandle

Takes an address range with backing memory to create the code memory object.

The memory is initially memset to 0xFF after being locked.

ControlCodeMemory

Argument64 Argument32 Type Name
(In) W0 R0 Handle<CodeMemory> CodeMemoryHandle
(In) W1 R1 #CodeMemoryOperation CodeMemoryOperation
(In) X2 R2, R3 void* Address
(In) X3 R4, R5 uint64_t Size
(In) W4 R6 #MemoryPermission MemoryPermission
(Out) W0 R0 #Result Result

Maps the backing memory for a CodeMemory object into the current process.

For MapOwner, memory permission must be RW-.

For MapSlave, memory permission must be R-- or R-X.

Operations UnmapOwner/UnmapSlave unmap memory that was previously mapped this way.

This allows one "secure JIT" process to map the code memory as RW-, and the other "slave" process to map it R-X.

[5.0.0+] Error 0xE401 is now returned when the process owner of the Code memory object is the same as the current process.

SleepSystem

Argument Type Name
(In) None
(Out) None

ReadWriteRegister

Argument64 Argument32 Type Name
(In) X1 R2, R3 uint64_t RegisterAddress
(In) W2 R0 uint32_t RwMask
(In) W3 R1 uint32_t InValue
(Out) W0 R0 #Result Result
(Out) W1 R1 uint32_t OutValue

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 ReadWriteRegister.

[4.0.0+] Access to the Memory Controller (0x70019000) also uses smcReadWriteRegister.

Here is the whitelist imposed by that SMC, relative to the start of the PMC registers:

0x000, 0x00c, 0x010, 0x014, 0x01c, 0x020, 0x02c, 0x030, 0x034, 0x038, 0x03c, 0x040, 0x044, 0x048, 0x0dc, 0x0e0, 0x0e4, 0x160, 0x164, 0x168, 0x170, 0x1a8, 0x1b8, 0x1bc, 0x1c0, 0x1c4, 0x1c8, 0x2b4, 0x2d4, 0x440, 0x4d8

Here is the whitelist imposed by the SMC ReadWriteRegister (checked in addition to the whitelist in the ReadWriteRegister SVC), relative to the start of the MC registers:

0x000, 0x004, 0x008, 0x00C, 0x010, 0x01C, 0x020, 0x030, 0x034, 0x050, 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, 0x238, 0x240, 0x244, 0x250, 0x254, 0x258, 0x264, 0x268, 0x26C, 0x270, 0x274, 0x280, 0x284, 0x288, 0x28C, 0x294, 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, 0x4C4, 0x4C8, 0x4CC, 0x50C, 0x554, 0x558, 0x55C, 0x584, 0x588, 0x58C, 0x670, 0x674, 0x690, 0x694, 0x698, 0x69C, 0x6A0, 0x6A4, 0x6C0, 0x6C4, 0x6F0, 0x6F4, 0x960, 0x970, 0x974, 0x9B8, 0xA20, 0xA24, 0xA88, 0xA94, 0xA98, 0xA9C, 0xAA0, 0xAA4, 0xAA8, 0xAAC, 0xAB0, 0xAB4, 0xAB8, 0xABC, 0xAC0, 0xAC4, 0xAC8, 0xACC, 0xAD0, 0xAD4, 0xAD8, 0xADC, 0xAE0, 0xB88, 0xB8C, 0xBC4, 0xBC8, 0xBCC, 0xBD0, 0xBD4, 0xBD8, 0xBDC, 0xBE0, 0xBE4, 0xBE8, 0xBEC, 0xC00, 0xC5C, 0xCAC

SetProcessActivity

Argument Type Name
(In) W0 Handle<Process> ProcessHandle
(In) W1 #ProcessActivity ProcessActivity
(Out) W0 #Result Result

CreateSharedMemory

Argument Type Name
(In) W1 uint64_t Size
(In) W2 #MemoryPermission LocalMemoryPermission
(In) W3 #MemoryPermission RemoteMemoryPermission
(Out) W0 #Result Result
(Out) W1 Handle<SharedMemory> SharedMemoryHandle

Other perm can be used to enforce permission 1, 3, or 0x10000000 if don't care.

Allocates memory from the current process' pool partition.

MapTransferMemory

Argument Type Name
(In) X0 Handle<TransferMemory> TransferMemoryHandle
(In) X1 void* Address
(In) X2 uint64_t Size
(In) W3 #MemoryPermission MemoryPermission
(Out) W0 #Result Result

You must pass same size and permissions as given in #CreateTransferMemory, otherwise error.

UnmapTransferMemory

Argument Type Name
(In) X0 Handle<TransferMemory> TransferMemoryHandle
(In) X1 void* Address
(In) X2 uint64_t Size
(Out) W0 #Result Result

Size must match size given in map syscall, otherwise there's an invalid-size error.

CreateInterruptEvent

Argument Type Name
(In) X1 #Interrupt Interrupt
(In) W2 #InterruptType InterruptType
(Out) W0 #Result Result
(Out) W1 Handle<ReadableEvent> ReadableEventHandle

Creates an event handle for the given IRQ number. Waiting on this handle will wait until the IRQ is triggered. The InterruptType argument configures the triggering. If it is 0, the IRQ is active HIGH level sensitive, if it is 1 it is rising-edge sensitive.

Result codes

0x0: Success.

0xF001: Flags was > 1

0xF201: IRQ above 0x3FF or outside the IRQ access mask was given.

0xCE01: A SlabHeap was exhausted (too many interrupts created).

0xF401: IRQ already has an event registered.

0xD201: The handle table is full. Try closing some handles.

QueryPhysicalAddress

Argument Type Name
(In) X1 void* VirtualAddress
(Out) W0 #Result Result
(Out) X1 uint64_t PhysicalMemoryInfoAddress
(Out) X2 uint64_t PhysicalMemoryInfoBaseAddress
(Out) X3 uint64_t PhysicalMemoryInfoSize

Queries the physical address of a virtual address. Will always fetch the lowest page-aligned mapping that contains the provided physical address.

The returned PhysicalMemoryInfoBaseAddress is the virtual address of that page-aligned mapping, while PhysicalMemoryInfoAddress is the physical address of that page. PhysicalMemoryInfoSize is the amount of continuous physical memory in that mapping.

QueryIoMapping

Argument64 Argument32 Type Name
(In) X1 R2, R3 uint64_t IoAddress
(In) X2 R0 uint64_t Size
(Out) W0 R0 #Result Result
(Out) X1 R1 void* VirtualAddress

Returns a virtual address mapped to a given IO range.

CreateDeviceAddressSpace

Argument64 Argument32 Type Name
(In) X1 R2, R3 uint64_t DeviceAddressSpaceStartAddress
(In) X2 R0, R1 uint64_t DeviceAddressSpaceEndAddress
(Out) W0 R0 #Result Result
(Out) W1 R1 Handle<DeviceAddressSpace> DeviceAddressSpaceHandle

Creates a virtual address space for binding device address spaces and returns a handle.

StartAddr is normally set to 0 and EndAddr is normally set to 0xFFFFFFFF.

AttachDeviceAddressSpace

Argument Type Name
(In) W0 #DeviceName DeviceName
(In) X1 Handle<DeviceAddressSpace> DeviceAddressSpaceHandle
(Out) W0 #Result Result

Attaches a device address space to a device.

DetachDeviceAddressSpace

Argument Type Name
(In) W0 #DeviceName DeviceName
(In) X1 Handle<DeviceAddressSpace> DeviceAddressSpaceHandle
(Out) W0 #Result Result

Detaches a device address space from a device.

MapDeviceAddressSpaceByForce

Argument64 Argument32 Type Name
(In) W0 R0 Handle<DeviceAddressSpace> DeviceAddressSpaceHandle
(In) W1 R1 Handle<Process> ProcessHandle
(In) X2 R2, R3 void* Address
(In) X3 R4 uint64_t DeviceAddressSpaceSize
(In) X4 R5, R6 uint64_t DeviceAddressSpaceAddress
(In) W5 R7 uint32_t Option
(Out) W0 R0 #Result Result

Maps an attached device address space to an userspace address.

Address is the userspace destination address, while DeviceAddressSpaceAddress is the source address between DeviceAddressSpaceStartAddress and DeviceAddressSpaceEndAddress (passed to #CreateDeviceAddressSpace).

The userspace destination address must have the FlagCanDeviceMap bit set. Bit DeviceShared will be set after mapping.

The Option encodes a #MemoryPermission in the low 16 bits, and an indicator of IO mapping in the high bits.

MapDeviceAddressSpaceAligned

Argument64 Argument32 Type Name
(In) W0 R0 Handle<DeviceAddressSpace> DeviceAddressSpaceHandle
(In) W1 R1 Handle<Process> ProcessHandle
(In) X2 R2, R3 void* Address
(In) X3 R4 uint64_t DeviceAddressSpaceSize
(In) X4 R5, R6 uint64_t DeviceAddressSpaceAddress
(In) W5 R7 uint32_t Option
(Out) W0 R0 #Result Result

Maps an attached device address space to an userspace address.

Same as #MapDeviceAddressSpaceByForce, but the userspace destination address must have the FlagCanAlignedDeviceMap bit set instead.

The Option encodes a #MemoryPermission in the low 16 bits, and an indicator of IO mapping in the high bits.

MapDeviceAddressSpace

Argument64 Argument32 Type Name
(In) W1 R1 Handle<DeviceAddressSpace> DeviceAddressSpaceHandle
(In) W2 R2 Handle<Process> ProcessHandle
(In) X3 R0, R3 void* Address
(In) X4 R4 uint64_t DeviceAddressSpaceSize
(In) X5 R5, R6 uint64_t DeviceAddressSpaceAddress
(In) W6 R7 #MemoryPermission MemoryPermission
(Out) W0 R0 #Result Result
(Out) X1 R1 uint64_t Size

UnmapDeviceAddressSpace

Argument64 Argument32 Type Name
(In) W0 R0 Handle<DeviceAddressSpace> DeviceAddressSpaceHandle
(In) W1 R1 Handle<Process> ProcessHandle
(In) X2 R2, R3 void* Address
(In) X3 R4 uint64_t DeviceAddressSpaceSize
(In) X4 R5, R6 uint64_t DeviceAddressSpaceAddress
(Out) W0 R0 #Result Result

Unmaps an attached device address space from an userspace address.

InvalidateProcessDataCache

Argument64 Argument32 Type Name
(In) W0 R0 Handle<Process> ProcessHandle
(In) X1 R2, R3 void* Address
(In) X2 R1, R4 uint64_t Size
(Out) W0 R0 #Result Result

StoreProcessDataCache

Argument64 Argument32 Type Name
(In) W0 R0 Handle<Process> ProcessHandle
(In) X1 R2, R3 void* Address
(In) X2 R1, R4 uint64_t Size
(Out) W0 R0 #Result Result

FlushProcessDataCache

Argument64 Argument32 Type Name
(In) W0 R0 Handle<Process> ProcessHandle
(In) X1 R2, R3 void* Address
(In) X2 R1, R4 uint64_t Size
(Out) W0 R0 #Result Result

DebugActiveProcess

Argument64 Argument32 Type Name
(In) X1 R2, R3 uint64_t ProcessId
(Out) W0 R0 #Result Result
(Out) W1 R1 Handle<Debug> DebugHandle

BreakDebugProcess

Argument Type Name
(In) W0 Handle<Debug> DebugHandle
(Out) W0 #Result Result

TerminateDebugProcess

Argument Type Name
(In) W0 Handle<Debug> DebugHandle
(Out) W0 #Result Result

GetDebugEvent

Argument Type Name
(In) X0 #DebugEventInfo* DebugEventInfo
(In) W1 Handle<Debug> DebugHandle
(Out) W0 #Result Result

ContinueDebugEvent

Argument64 Argument32 Type Name
(In) W0 R0 Handle<Debug> DebugHandle
(In) W1 R1 uint32_t #ContinueDebugFlags ([1.0.0-2.3.0] #ContinueDebugFlagsOld)
(In) X2 R2 ([1.0.0-2.3.0] R2, R3) uint64_t* ([1.0.0-2.3.0] uint64_t) ThreadIdList ([1.0.0-2.3.0] ThreadId)
(In) X3 R3 uint64_t [3.0.0+] NumThreadIds
(Out) W0 R0 #Result Result

Maximum NumThreadIds is 64. 0 means "all threads".

Result codes

0x0: Success. The process has been resumed.

0xe401: Invalid debug handle.

0xf401: Process has debug events queued or is already running.

GetProcessList

Argument64 Argument32 Type Name
(In) X1 R1 uint64_t* ProcessIdBuffer
(In) W2 R2 uint32_t ProcessIdBufferSize
(Out) X0 R0 #Result Result
(Out) W1 R1 uint32_t NumProcesses

Fills the provided array with the pids of currently living processes. A process "lives" so long as it is currently running or a handle to it still exists.

It returns the total number of processes currently alive. If this number is bigger than the size of ProcessIdBuffer, the user won't have all the pids.

Result codes

0x0: Success.

0xd401: The provided buffer is outside the process address space.

0xe601: copyToUser failed. The provided buffer is not user-accessible.

0xee01: The provided buffer size is too big. Max value is 0xFFFFFFF.

GetThreadList

Argument64 Argument32 Type Name
(In) X1 R1 uint64_t* ThreadIdBuffer
(In) W2 R2 uint32_t ThreadIdBufferSize
(In) W3 R3 Handle<Debug> DebugHandle
(Out) X0 R0 #Result Result
(Out) W1 R1 uint32_t NumThreads

GetDebugThreadContext

Argument64 Argument32 Type Name
(In) X0 R0 #ThreadContext* ThreadContext
(In) X1 R1 Handle<Debug> DebugHandle
(In) X2 R2, R3 uint64_t ThreadId
(In) W3 R4 uint32_t #ThreadContextFlags
(Out) W0 R0 #Result Result

SetDebugThreadContext

Argument64 Argument32 Type Name
(In) W0 R0 Handle<Debug> DebugHandle
(In) X1 R2, R3 uint64_t ThreadId
(In) X2 R1 #ThreadContext* ThreadContext
(In) W3 R4 uint32_t #ThreadContextFlags
(Out) W0 R0 #Result Result

QueryDebugProcessMemory

Argument Type Name
(In) X0 #MemoryInfo* MemoryInfo
(In) W2 Handle<Debug> DebugHandle
(In) X3 void* Address
(Out) W0 #Result Result
(Out) W1 #PageInfo PageInfo

ReadDebugProcessMemory

Argument Type Name
(In) X0 void* MemoryBufferAddress
(In) W1 Handle<Debug> DebugHandle
(In) X2 void* SrcAddress
(In) X3 uint64_t Size
(Out) W0 #Result Result

WriteDebugProcessMemory

Argument Type Name
(In) W0 Handle<Debug> DebugHandle
(In) X1 void* MemoryBufferAddress
(In) X2 void* DstAddress
(In) X3 uint64_t Size
(Out) W0 #Result Result

SetHardwareBreakPoint

Argument64 Argument32 Type Name
(In) W0 R0 #HardwareBreakPointRegisterName Name
(In) X1 R2, R3 uint64_t Flags
(In) X2 R1, R4 uint64_t Value
(Out) W0 R0 #Result Result

Sets one of the AArch64 hardware breakpoints. The nintendo switch has 6 hardware breakpoints, and 4 hardware watchpoints. The syscall has two behaviors depending on the value of HardwareBreakPointRegisterName:

If HardwareBreakPointRegisterName < 0x10, then it sets one of the AArch64 hardware breakpoints. Flags will go to DBGBCRn_EL1, and value to DBGBVRn_EL1. The only flags the user is allowed to set are those in the bitmask 0x7F01E1. Furthermore, the kernel will or it with 0x4004, in order to set various security flags to guarantee the watchpoints only triggers for code in EL0. If the user asks for a Breakpoint Type of ContextIDR match, the kernel shall use the given DebugHandle to set DBGBVRn_EL1 to the ContextID of the debugged process.

If HardwareBreakPointRegisterName is between 0x10 and 0x20 (exclusive), then it sets one of the AArch64 hardware watchpoints. Flags will go to DBGWCRn_EL1, and the value to DBGWVRn_EL1. The only flags the user is allowed to set are those in the bitmask 0xFF0F1FF9. Furthermore, the kernel will or it with 0x104004. This will set various security flags, and set the watchpoint type to be a Linked Watchpoint. This means that you need to link it to a Linked ContextIDR breakpoint. Check the ARM documentation for more information.

Note that HardwareBreakPointRegisterName 0 to 4 match only to Virtual Address, while HardwareBreakPointRegisterName 5 and 6 match against either Virtual Address, ContextID, or VMID. As such, if you are configuring a breakpoint to link for a watchpoint, make sure you use hardware_breakpoint_id 5 or 6.

For more documentation for hardware breakpoints, check out the AArch64 documentation for the DBGBCRn_EL1 register and the DBGWCRn_EL1 register

GetDebugThreadParam

Argument64 Argument32 Type Name
(In) X2 R2 Handle<Debug> DebugHandle
(In) X3 R0, R1 uint64_t ThreadId
(In) W4 R3 #DebugThreadParam DebugThreadParam
(Out) W0 R0 #Result Result
(Out) X1 R1, R2 uint64_t Out0
(Out) W2 R3 uint32_t Out1

GetSystemInfo

Argument Type Name
(In) X1 #SystemInfoType SystemInfoType
(In) W2 Handle Handle
(In) X3 uint64_t SystemInfoSubType
(Out) W0 #Result Result
(Out) X1 uint64_t SystemInfo

CreatePort

Argument64 Argument32 Type Name
(In) W2 R2 int32_t MaxSessions
(In) W3 R3 bool IsLight
(In) X4 R0 uint64_t Name
(Out) W0 R0 #Result Result
(Out) W1 R1 Handle<Port> ServerPortHandle
(Out) W2 R2 Handle<Port> ClientPortHandle

ManageNamedPort

Argument Type Name
(In) X1 char* Name
(In) W2 int32_t MaxSessions
(Out) W0 #Result Result
(Out) W1 Handle<Port> ServerPortHandle

ConnectToPort

Argument Type Name
(In) W1 Handle<Port> ClientPortHandle
(Out) W0 #Result Result
(Out) W1 Handle<Session> SessionHandle

SetProcessMemoryPermission

Argument64 Argument32 Type Name
(In) W0 R0 Handle<Process> ProcessHandle
(In) X1 R2, R3 void* Addr
(In) X2 R1, R4 uint64_t Size
(In) W3 R5 #MemoryPermission MemoryPermission
(Out) W0 R0 #Result Result

This sets the memory permissions for the specified memory with the supplied process handle.

This throws an error(0xD801) when the input perm is >0x5, hence -WX and RWX are not allowed.

MapProcessMemory

Argument64 Argument32 Type Name
(In) X0 R0 void* DstAddress
(In) W1 R1 Handle<Process> ProcessHandle
(In) X2 R2, R3 void* SrcAddress
(In) X3 R4 uint64_t Size
(Out) W0 R0 #Result Result

Maps the src address from the supplied process handle into the current process.

This allows mapping code and rodata with RW- permission.

UnmapProcessMemory

Argument64 Argument32 Type Name
(In) X0 R0 void* DstAddress
(In) W1 R1 Handle<Process> ProcessHandle
(In) X2 R2, R3 void* SrcAddress
(In) X3 R4 uint64_t Size
(Out) W0 R0 #Result Result

Unmaps what was mapped by #MapProcessMemory.

QueryProcessMemory

Argument64 Argument32 Type Name
(In) X0 R0 #MemoryInfo* MemoryInfo
(In) W2 R2 Handle<Process> ProcessHandle
(In) X3 R1, R3 void* Address
(Out) W0 R0 #Result Result
(Out) W1 R1 #PageInfo PageInfo

Equivalent to #QueryMemory except takes a process handle.

MapProcessCodeMemory

Argument64 Argument32 Type Name
(In) W0 R0 Handle<Process> ProcessHandle
(In) X1 R2, R3 void* DstAddress
(In) X2 R1, R4 void* SrcAddress
(In) X3 R5, R6 uint64_t Size
(Out) W0 R0 #Result Result

Takes a process handle, and maps normal heap in that process as executable code in that process. Used when loading NROs. This does not support using the current-process handle alias.

UnmapProcessCodeMemory

Argument64 Argument32 Type Name
(In) W0 R0 Handle<Process> ProcessHandle
(In) X1 R2, R3 void* DstAddress
(In) X2 R1, R4 void* SrcAddress
(In) X3 R5, R6 uint64_t Size
(Out) W0 R0 #Result Result

Unmaps what was mapped by #MapProcessCodeMemory.

CreateProcess

Argument Type Name
(In) X1 #CreateProcessParameter* CreateProcessParameter
(In) X2 uint32_t* Capabilities
(In) X3 int32_t CapabilitiesNum
(Out) W0 #Result Result
(Out) W1 Handle<Process> ProcessHandle

Takes a #CreateProcessParameter as input. Capabilities points to an array of kernel capabilities. CapabilitiesNum is a number of capabilities in the Capabilities array (number of element, not number of bytes).

Result codes

0x0: Success.

0xCA01: Attempted to map more code pages than available in address space.

0xCC01: Provided CodeAddr is invalid (make sure it's in range?)

0xE401: The resource handle passed is invalid.

0xE601: Attempt to copy procinfo from user-supplied pointer failed. Attempt to copy capabilities_num from user-supplied pointer failed.

0xE801: Attempted to create a 32-bit process with a 36-bit address space.

0xF001: Unused bits are set in mmuflags. Unknown address space type used.

StartProcess

Argument64 Argument32 Type Name
(In) W0 R0 Handle<Process> ProcessHandle
(In) W1 R1 int32_t MainThreadPriority
(In) W2 R2 int32_t DefaultCpuId
(In) X3 R3, R4 uint64_t MainThreadStackSize
(Out) W0 R0 #Result Result

TerminateProcess

Argument Type Name
(In) W0 Handle<Process> ProcessHandle
(Out) W0 #Result Result

GetProcessInfo

Argument64 Argument32 Type Name
(In) W0 R1 Handle<Process> ProcessHandle
(In) W1 R2 #ProcessInfoType ProcessInfoType
(Out) W0 R0 #Result Result
(Out) X1 R1, R2 uint64_t #ProcessState

Returns an enum with value 0-7.

CreateResourceLimit

Argument Type Name
(In) None
(Out) W0 #Result Result
(Out) W1 Handle<ResourceLimit> ResourceLimitHandle

SetResourceLimitLimitValue

Argument64 Argument32 Type Name
(In) W0 R0 Handle<ResourceLimit> ResourceLimitHandle
(In) W1 R1 #LimitableResource LimitableResource
(In) X2 R2, R3 int64_t LimitValue
(Out) W0 R0 #Result Result

CallSecureMonitor

Argument64 Argument32 Type Name
(In) X0 R0 uint64_t FunctionId
(In) X1-X7 R1-R7 uint64_t SMC arguments
(Out) X0 R0 Result SMC result
(Out) X1-X7 R1-R7 uint64_t SMC output

Takes in a SMC function ID in X0, and arguments for that SMC function in X1-X7.

Passing an invalid SMC function ID or calling from a core other than core 3 will result in a secure monitor panic.

The kernel parses bits 9-15 in the passed SMC function ID (per the ARM SMC calling convention), and when set uses as an indicator to translate a pointer in the associated register (X1-X7) to a physical address. The kernel will translate any address mapped as R-W, other addresses (R--, R-X, or invalid pointers) will be translated as 0/NULL.

Output is returned raw from the Secure Monitor; X0 will be the untranslated SMC result and X1-X7 will contain other SMC output (or be unchanged, depending on the SMC).

Debugging

[2.0.0+] Exactly 6 debug SVCs require that IsDebugMode is non-zero. Error 0x4201 is returned otherwise.

  • BreakDebugProcess
  • ContinueDebugEvent
  • WriteDebugProcessMemory
  • SetDebugThreadContext
  • TerminateDebugProcess
  • SetHardwareBreakPoint

DebugActiveProcess stops execution of the target process, the normal method for resuming it requires ContinueDebugEvent(see above). Closing the debug handle also results in execution being resumed.

Enum/Structures

InfoType

Handle type InfoType InfoSubType Description
Process 0 0 CoreMask
Process 1 0 PriorityMask
Process 2 0 AliasRegionAddress
Process 3 0 AliasRegionSize
Process 4 0 HeapRegionAddress
Process 5 0 HeapRegionSize
Process 6 0 TotalMemorySize. Total memory available(free+used).
Process 7 0 UsedMemorySize. Total used size of codebin memory + main-thread stack + allocated heap.
Zero 8 0 DebuggerAttached
Zero 9 0 ResourceLimit
Zero 10 -1, {current coreid} IdleTickCount
Zero 11 0-3 RandomEntropy. Used to seed usermode PRNGs.
Process 12 0 [2.0.0+] AslrRegionAddress
Process 13 0 [2.0.0+] AslrRegionSize
Process 14 0 [2.0.0+] StackRegionAddress
Process 15 0 [2.0.0+] StackRegionSize
Process 16 0 [3.0.0+] SystemResourceSizeTotal
Process 17 0 [3.0.0+] SystemResourceSizeUsed
Process 18 0 [3.0.0+] ProgramId
Zero 19 0 [4.0.0-4.1.0] InitialProcessIdRange_LowerBound
Zero 19 1 [4.0.0-4.1.0] InitialProcessIdRange_UpperBound
Process 20 0 [5.0.0+] UserExceptionContextAddress
Process 21 0 [6.0.0+] TotalNonSystemMemorySize
Process 22 0 [6.0.0+] UsedNonSystemMemorySize
Process 23 0 [9.0.0+] IsApplication
Process 24 0 [11.0.0+] FreeThreadCount
Thread 25 ([1.0.0-12.1.0] 0xF0000002) 0-3, -1 ThreadTickCount. When 0-3 are passed, gets specific core CPU ticks spent on thread. When -1 is passed, gets total CPU ticks spent on thread.
Process 26 0 [14.0.0+] IsSvcPermitted
Process 27 0 [16.0.0+] IoRegionHint
Process 28 0 [18.0.0+] AliasRegionExtraSize

SystemInfoType

Handle type SystemInfoType SystemInfoSubType Description
Zero 0 0 TotalPhysicalMemorySize_Application
Zero 0 1 TotalPhysicalMemorySize_Applet
Zero 0 2 TotalPhysicalMemorySize_System
Zero 0 3 TotalPhysicalMemorySize_SystemUnsafe
Zero 1 0 UsedPhysicalMemorySize_Application
Zero 1 1 UsedPhysicalMemorySize_Applet
Zero 1 2 UsedPhysicalMemorySize_System
Zero 1 3 UsedPhysicalMemorySize_SystemUnsafe
Zero 2 0 InitialProcessIdRange_LowerBound
Zero 2 1 InitialProcessIdRange_UpperBound

ThreadContextFlags

Bitfield of one of more of these:

Bit Bitmask Name Description
0 1 General-purpose registers If in 64-bit mode, GPRs 0–28 will be read/written. If in 32-bit mode, GPRs 0–12 will be read/written.
1 2 Control registers Reads/writes the FP, LR, PC, SP, PSTATE, and TPIDR registers.
2 4 Floating-point registers Reads/writes the floating-point vector registers.
3 8 Floating-point control registers Reads/writes the FPCR and FPSR registers.

DeviceName

Value Name
0 AFI
1 AVPC
2 DC
3 DCB
4 HC
5 HDA
6 ISP2
7 MSENCNVENC
8 NV
9 NV2
10 PPCS
11 SATA
12 VI
13 VIC
14 XUSB_HOST
15 XUSB_DEV
16 TSEC
17 PPCS1
18 DC1
19 SDMMC1A
20 SDMMC2A
21 SDMMC3A
22 SDMMC4A
23 ISP2B
24 GPU
25 GPUB
26 PPCS2
27 NVDEC
28 APE
29 SE
30 NVJPG
31 HC1
32 SE1
33 AXIAP
34 ETR
35 TSECB
36 TSEC1
37 TSECB1
38 NVDEC1

CodeMemoryOperation

Value Name
0 MapOwner
1 MapSlave
2 UnmapOwner
3 UnmapSlave

LimitableResource

Value Name Description
0 PhysicalMemoryMax Bytes of memory a process may allocate.
1 ThreadCountMax Amount of threads a process can create.
2 EventCountMax Amount of events a process can create through #CreateEvent or #SendAsyncRequestWithUserBuffer.
3 TransferMemoryCountMax Amount of TransferMemory a process can create through #CreateTransferMemory.
4 SessionCountMax Amount of session a process can create through #CreateSession, #ConnectToPort or #ConnectToNamedPort.

ThreadActivity

Value Name
0 None
1 Runnable

ProcessActivity

Value Name
0 None
1 Runnable

ProcessInfoType

Value Name
0 ProcessState

ProcessState

Value Name Notes
0 Created
1 CreatedAttached
2 Started
3 Crashed Processes will not enter this state unless they were created with EnableDebug.
4 StartedAttached
5 Exiting
6 Exited
7 DebugSuspended

DebugThreadParam

Value Name
0 DynamicPriority
1 SchedulingStatus
2 PreferredCpuCore
3 CurrentCpuCore
4 AffinityMask

Dynamic priority: output in out2

Scheduling status: out1 contains bit0: is debug-suspended, bit1: is user-suspended (#SetThreadActivity 1 or #SetProcessActivity 1). Out2 contains {suspended, idle, running, terminating} => {5, 0, 1, 4}

PreferredCpuCore: output in out2

CurrentCpuCore: output in out2

AffinityMask: output in out1

CreateProcessParameter

Offset Length Bits Description
0 12 ProcessName (doesn't have to be null-terminated)
0x0C 4 ProcessCategory (0: regular title, 1: kernel built-in)
0x10 8 TitleId
0x18 8 CodeAddr
0x20 4 CodeNumPages
0x24 4 Flags
Bit0 Is64BitInstruction
Bit3-1 #AddressSpaceType
Bit4 [2.0.0+] EnableDebug
Bit5 EnableAslr
Bit6 IsApplication
Bit7 [4.0.0] UseSecureMemory
Bit10-7 [5.0.0+] MemoryRegion (0 = Application, 1 = Applet, 2 = SecureSystem, 3 = NonSecureSystem)
Bit11 [7.0.0+] OptimizeMemoryAllocation (only allowed in combination with IsApplication)
0x28 4 ResourceLimitHandle (can be zero)
0x2C 4 [3.0.0+] SystemResourceNumPages

On [1.0.0] there's only one MemoryRegion.

On [2.0.0-4.0.0] MemoryRegion is 1 for built-ins and 0 for rest.

On [5.0.0] MemoryRegion is specified in CreateProcessArgs. There are now 4 pool partitions.

On [5.0.0] (maybe lower?) a zero ResourceLimitHandle defaults to sysmodule limits and 0x12300000 bytes of memory.

The PersonalMmHeap are allocated as follows:

  • For the application, normal insecure pool is used. Carveout 5 is used to provide protection.
  • For the applet, a pre-allocated secure pool segment of size 0x400000 is used.
  • For sysmodules, secure pool is allocated.

AddressSpaceType

Type Name Width Description
0 AddressSpace32Bit 32
1 AddressSpace64BitOld 36
2 AddressSpace32BitNoReserved 32 Appears to be missing map region [?]
3 [2.0.0+] AddressSpace64Bit 39

MemoryInfo

Offset Length Description
0 8 BaseAddress
8 8 Size
0x10 4 #MemoryType
0x14 4 #MemoryAttribute
0x18 4 #MemoryPermission
0x1C 4 IpcRefCount
0x20 4 DeviceRefCount
0x24 4 Padding: always zero

MemoryPermission

Bits Name Description
0 Read Can be set by #SetMemoryPermission.
1 Write Can be set by #SetMemoryPermission.
2 Execute Can be set by #SetProcessMemoryPermission and #ControlCodeMemory.
28 DontCare

MemoryAttribute

Bits Name Description
0 Locked Used by MapMemory, as an async IPC user buffer.
1 IpcLocked True when IpcRefCount > 0.
2 DeviceShared True when DeviceRefCount > 0.
3 Uncached

MemoryState

Bits Description Meaning
7-0 #MemoryType
8 FlagCanReprotect
9 FlagCanDebug Allows using #WriteDebugProcessMemory on segments mapped read-only.
10 FlagCanUseIpc Allows sending this region as an IPC A/B/W buffer with flags=0.
11 FlagCanUseNonDeviceIpc Allows sending this region as an IPC A/B/W buffer with flags=1.
12 FlagCanUseNonSecureIpc Allows sending this region as an IPC A/B/W buffer with flags=3.
13 FlagMapped
14 FlagCode
15 FlagCanAlias
16 FlagCanCodeAlias
17 FlagCanTransfer
18 FlagCanQueryPhysical
19 FlagCanDeviceMap
20 FlagCanAlignedDeviceMap
21 FlagCanIpcUserBuffer
22 FlagReferenceCounted The physical memory blocks backing this region are refcounted.
23 FlagCanMapProcess
24 FlagCanChangeAttribute
25 [4.0.0+] FlagCanCodeMemory
26 [15.0.0+] FlagLinearMapped

MemoryType

Value Type Meaning
0x00000000 Free
0x00002001 Io Mapped by kernel capability parsing in #CreateProcess.
0x00042002 Static Mapped by kernel capability parsing in #CreateProcess.
0x00DC7E03 Code Mapped during #CreateProcess.
[1.0.0+]

0x01FEBD04

[4.0.0+]

0x03FEBD04

CodeData Transition from 0xDC7E03 performed by #SetProcessMemoryPermission.
[1.0.0+]

0x017EBD05

[4.0.0+]

0x037EBD05

Normal Mapped using #SetHeapSize.
0x00402006 Shared Mapped using #MapSharedMemory.
0x00482907 [1.0.0] Alias Mapped using #MapMemory.
0x00DD7E08 AliasCode Mapped using #MapProcessCodeMemory.
[1.0.0+]

0x01FFBD09

[4.0.0+]

0x03FFBD09

AliasCodeData Transition from 0xDD7E08 performed by #SetProcessMemoryPermission.
0x005C3C0A Ipc IPC buffers with descriptor flags=0.
0x005C3C0B Stack Mapped using #MapMemory.
0x0040200C ThreadLocal Mapped during #CreateThread.
0x015C3C0D Transfered Mapped using #MapTransferMemory when the owning process has perm=0.
0x005C380E SharedTransfered Mapped using #MapTransferMemory when the owning process has perm!=0.
0x0040380F SharedCode Mapped using #MapProcessMemory.
0x00000010 Inaccessible
0x005C3811 NonSecureIpc IPC buffers with descriptor flags=1.
0x004C2812 NonDeviceIpc IPC buffers with descriptor flags=3.
0x00002013 Kernel Mapped in kernel during #CreateThread.
0x00402214 [4.0.0+] GeneratedCode Mapped in kernel during #ControlCodeMemory.
0x00402015 [4.0.0+] CodeOut Mapped in kernel during #ControlCodeMemory.
0x00002016 [13.0.0+] Coverage
0x05583817 [15.0.0+] Insecure

ArbitrationType

Value Type
0x0 WaitIfLessThan
0x1 DecrementAndWaitIfLessThan
0x2 WaitIfEqual

SignalType

Value Type
0x0 Signal
0x1 SignalAndIncrementIfEqual
0x2 SignalAndModifyBasedOnWaitingThreadCountIfEqual

ContinueDebugFlagsOld

[1.0.0-2.3.0]

Bit Bitmask Description
0 1 IgnoreException (note: ResumeAllThreads or debug-suspended-thread-id needed)
1 2 SwallowException
2 4 ResumeAllThreads

ContinueDebugFlags

[3.0.0+]

Bit Bitmask Description
0 1 IgnoreException (note: doesn't need to be set in the same call than Resume)
1 2 DontCatchExceptions
2 4 Resume
3 8 IgnoreOtherThreadsExceptions

IgnoreExceptionsOfOthers is like IgnoreException but acts on all threads that aren't in the input list. The affected threads are resumed.

Only one of of Resume and IgnoreOtherThreadsExceptions can be set at a time.

If the input number of threads is 0, this means "all threads".

DebugEventInfo

The below table is for the Aarch64 version of the system call. For A32, all u64 fields but title/process/thread id are actually u32, making the structure 0x28-byte-big (0x40 for a64).

Size: 0x40

Offset Length Description
0 u32 EventType
4 u32 Flags (bit0: NeedsContinue)
8 u64 ThreadId
0x10 PerTypeSpecifics

AttachProcess specific:

Offset Length Description
0x10 u64 TitleId
0x18 u64 ProcessId
0x20 char[12] ProcessName
0x2C u32 MmuFlags
0x30 u64 [5.0.0+] UserExceptionContextAddr

AttachThread specific:

Offset Length Description
0x10 u64 ThreadId
0x18 u64 TlsPtr
0x20 u64 Entrypoint

Exit specific:

Offset Length Description
0x10 u32 Type (0=PausedThread, 1=RunningThread, 2=ExitedProcess, 3=TerminatedProcess)

Exception specific:

Offset Length Description
0x10 u32 ExceptionType
0x18 u64 FaultRegister
0x20 PerExceptionSpecifics

DebugEventType

Value Name
0 AttachProcess
1 AttachThread
2 ExitProcess
3 ExitThread
4 Exception

DebugExceptionType

Value Name
0 Trap (*)
1 InstructionAbort
2 DataAbortMisc (**)
3 PcSpAlignmentFault
4 DebuggerAttached
5 BreakPoint
6 UserBreak
7 DebuggerBreak
8 BadSvcId
9 [2.0.0+] SError

* Undefined instructions, software breakpoints, some other traps.

** Data aborts, FP traps, and everything else that doesn't belong to any of the above.

Trap specifics:

Offset Length Description
0x20 u32 Opcode

BreakPoint specifics:

Offset Length Description
0x20 u32 IsWatchpoint

UserBreak specifics:

Offset Length Description
0x20 u32 Info0
0x28 u64 Info1
0x30 u64 Info2

BadSvcId specifics:

Offset Length Description
0x20 u32 SvcId

Exception handling

First of all, a function that might be called by synchronous exception handler and that is called by the SError handler fetches the exception info, adjusts PC, panics on exceptions taken from EL1, then dispatches the exception.

The dispatcher has two mutually exclusive exception reporting methods:

  • by storing information at the start of the process's TLS memregion (TPIDRRO_EL0) and jumping back to the crt0
  • by using KDebug

KDebug dispatching is used when at least one of the following conditions are met:

  • SMC ConfigItem KernelMemConfig bit 1 is NOT set (it isn't on retail), unless: this is a software or hardware breakpoint, or a watchpoint, or [4.0.0+?] the process is attached and this is a Google PNaCl trap instruction (see LLVM source)
  • FAR doesn't point to a valid address in mapped-readable CodeStatic memory (i.e. this is the case for NRO and JIT memory) or this is one of the following exceptions (it particular, that doesn't include FP exceptions occurring in CodeStatic memory):
    • Uncategorized
    • IllegalState
    • SupervisorCallA32
    • SupervisorCallA64
    • PCAlignment
    • SPAlignment
    • SError
    • BreakpointLowerEl
    • SoftwareStepLowerEl (note: no way set single-step flag; not parsed)
    • WatchpointLowerEl
    • SoftwareBreakpointA32 (note: not parsed)
    • SoftwareBreakpointA64 (note: not parsed)

In all other cases the userland-handled exception path is taken.

KDebug path:

If the process is attached, the exception is reported to the KDebug. If the thread was continued using flag IgnoreExceptions, it returns from the exception as if nothing happened.

If the latter is not the case, or if the process isn't attached, proceed to [2.0.0+] crash reporting (or in [1.0.0] just terminate the process): if EnableDebug is set, and depending on the process state (more than one crash per process isn't permitted) it may signal itself with ProcessState_Crashed so that PM asks NS to start creport so that creport attaches to it and reports the crashes. Otherwise, just terminate.

Userland reporting path and #ReturnFromException:

TLS region start (A64):

Offset Length Description
0x0 0x148 Exception stack
0x148 0x78 ExceptionFrameA64

ExceptionFrameA64:

Offset Length Description
0x0 0x48 (8*9) GPRs 0..8.
0x48 0x8 lr
0x50 0x8 sp
0x58 0x8 pc (elr_el1)
0x60 0x4 pstate & 0xFF0FFE20
0x64 0x4 afsr0
0x68 0x4 afsr1
0x6C 0x4 esr
0x70 0x8 far

TLS region start (A32):

Offset Length Description
0x0 0x178 Exception stack
0x148 0x44 ExceptionFrameA32

ExceptionFrameA32:

Offset Length Description
0x0 0x20 (8*4) GPRs 0..7.
0x20 0x4 sp
0x24 0x4 lr
0x28 0x4 pc (elr_el1)
0x2C 0x4 tpidr_el0 = 1
0x30 0x4 cpsr & 0xFF0FFE20
0x34 0x4 afsr0
0x38 0x4 afsr1
0x3C 0x4 esr
0x40 0x4 far

In that case, after storing the regs in the TLS, the exception handler returns to the application's crt0 (entrypoint), with X0=<error description code> (see below) and X1=SP=frame=<stack top> (see above)

Desc. code Meaning
0x100 Instruction abort
0x102 Misaligned PC
0x103 Misaligned SP
0x106 [2.0.0+] SError
0x301 Bad SVC
0x104 Uncategorized, CP15RTTrap, CP15RRTTrap, CP14RTTrap, CP14RRTTrap, IllegalState, SystemRegisterTrap
0x101 None of the above, EC <= 0x34 and not a breakpoint

(During normal app boot the process is invoked with X0=0 and X1=main_thread_handle. The crt0 of retail apps determines whether to boot normally or handle an exception if X0 is set to 0 or not)

The application is supposed to promptly update the contents of elr_el1 to a user handler (and any other regs it sees fit) and call #ReturnFromException (error code) to call that handler. The latter is then expected to promptly abort the program.

#ReturnFromException updates the contents of the kernel stack frame with what the user provided in the TLS structure, sets TPIDR_EL0 to 1, then:

  • if the provided error code is 0, gracefully pivots and returns from exception
  • if it is not, replays the exception and pass it to the KDebug (see above). One can pass 0x10001 to prevent process termination. If the process is attached, this also prevents crash-collection/termination (different from the exception handler behavior)

If an exception occurs from the above user handler, the entire exception handling process will repeat with the new exception.

Note that if a thread that wasn't faulting calls #ReturnFromException, it signals an "invalid syscall" exception

Note that IsDebugMode is not used during exception-handling, except for enabling printing a message to UART-A. This UART code causes a system-hang on retail (likely due to a loop that doesn't exit). This printing doesn't seem to run when the process is attached for debugging?