Changes

Jump to navigation Jump to search
88,572 bytes added ,  18:13, 9 February 2020
Synchronize with AMS enums
Line 1: Line 1:  +
__NOTOC__
 +
 
= System calls =
 
= System calls =
 
{| class=wikitable
 
{| class=wikitable
! Id || Name || In || Out
+
! ID || Return Type || Name || Arguments
 +
|-
 +
| 0x01 || Result || [[#SetHeapSize|SetHeapSize]] || uintptr_t *out_address, size_t size
 +
|-
 +
| 0x02 || Result || [[#SetMemoryPermission|SetMemoryPermission]] || uintptr_t address, size_t size, MemoryPermission perm
 +
|-
 +
| 0x03 || Result || [[#SetMemoryAttribute|SetMemoryAttribute]] || uintptr_t address, size_t size, uint32_t mask, uint32_t attr
 +
|-
 +
| 0x04 || Result || [[#MapMemory|MapMemory]] || uintptr_t dst_address, uintptr_t src_address, size_t size
 +
|-
 +
| 0x05 || Result || [[#UnmapMemory|UnmapMemory]] || uintptr_t dst_address, uintptr_t src_address, size_t size
 +
|-
 +
| 0x06 || Result || [[#QueryMemory|QueryMemory]] || arch::MemoryInfo *out_memory_info, PageInfo *out_page_info, uintptr_t address
 +
|-
 +
| 0x07 || void || [[#ExitProcess|ExitProcess]] ||
 +
|-
 +
| 0x08 || Result || [[#CreateThread|CreateThread]] || Handle *out_handle, ThreadFunc func, uintptr_t arg, uintptr_t stack_bottom, int32_t priority, int32_t core_id
 +
|-
 +
| 0x09 || Result || [[#StartThread|StartThread]] || Handle thread_handle
 +
|-
 +
| 0x0A || void || [[#ExitThread|ExitThread]] ||
 +
|-
 +
| 0x0B || void || [[#SleepThread|SleepThread]] || int64_t ns
 +
|-
 +
| 0x0C || Result || [[#GetThreadPriority|GetThreadPriority]] || int32_t *out_priority, Handle thread_handle
 +
|-
 +
| 0x0D || Result || [[#SetThreadPriority|SetThreadPriority]] || Handle thread_handle, int32_t priority
 +
|-
 +
| 0x0E || Result || [[#GetThreadCoreMask|GetThreadCoreMask]] || int32_t *out_core_id, uint64_t *out_affinity_mask, Handle thread_handle
 +
|-
 +
| 0x0F || Result || [[#SetThreadCoreMask|SetThreadCoreMask]] || Handle thread_handle, int32_t core_id, uint64_t affinity_mask
 +
|-
 +
| 0x10 || int32_t || [[#GetCurrentProcessorNumber|GetCurrentProcessorNumber]] ||
 +
|-
 +
| 0x11 || Result || [[#SignalEvent|SignalEvent]] || Handle event_handle
 +
|-
 +
| 0x12 || Result || [[#ClearEvent|ClearEvent]] || Handle event_handle
 +
|-
 +
| 0x13 || Result || [[#MapSharedMemory|MapSharedMemory]] || Handle shmem_handle, uintptr_t address, size_t size, MemoryPermission map_perm
 +
|-
 +
| 0x14 || Result || [[#UnmapSharedMemory|UnmapSharedMemory]] || Handle shmem_handle, uintptr_t address, size_t size
 +
|-
 +
| 0x15 || Result || [[#CreateTransferMemory|CreateTransferMemory]] || Handle *out_handle, uintptr_t address, size_t size, MemoryPermission map_perm
 +
|-
 +
| 0x16 || Result || [[#CloseHandle|CloseHandle]] || Handle handle
 +
|-
 +
| 0x17 || Result || [[#ResetSignal|ResetSignal]] || Handle handle
 +
|-
 +
| 0x18 || Result || [[#WaitSynchronization|WaitSynchronization]] || int32_t *out_index, const Handle *handles, int32_t numHandles, int64_t timeout_ns
 +
|-
 +
| 0x19 || Result || [[#CancelSynchronization|CancelSynchronization]] || Handle handle
 +
|-
 +
| 0x1A || Result || [[#ArbitrateLock|ArbitrateLock]] || Handle thread_handle, uintptr_t address, uint32_t tag
 +
|-
 +
| 0x1B || Result || [[#ArbitrateUnlock|ArbitrateUnlock]] || uintptr_t address
 +
|-
 +
| 0x1C || Result || [[#WaitProcessWideKeyAtomic|WaitProcessWideKeyAtomic]] || uintptr_t address, uintptr_t cv_key, uint32_t tag, int64_t timeout_ns
 +
|-
 +
| 0x1D || void || [[#SignalProcessWideKey|SignalProcessWideKey]] || uintptr_t cv_key, int32_t count
 +
|-
 +
| 0x1E || int64_t || [[#GetSystemTick|GetSystemTick]] ||
 +
|-
 +
| 0x1F || Result || [[#ConnectToNamedPort|ConnectToNamedPort]] || Handle *out_handle, const char *name
 +
|-
 +
| 0x20 || Result || [[#SendSyncRequestLight|SendSyncRequestLight]] || Handle session_handle
 +
|-
 +
| 0x21 || Result || [[#SendSyncRequest|SendSyncRequest]] || Handle session_handle
 +
|-
 +
| 0x22 || Result || [[#SendSyncRequestWithUserBuffer|SendSyncRequestWithUserBuffer]] || uintptr_t message_buffer, size_t message_buffer_size, Handle session_handle
 +
|-
 +
| 0x23 || Result || [[#SendAsyncRequestWithUserBuffer|SendAsyncRequestWithUserBuffer]] || Handle *out_event_handle, uintptr_t message_buffer, size_t message_buffer_size, Handle session_handle
 +
|-
 +
| 0x24 || Result || [[#GetProcessId|GetProcessId]] || uint64_t *out_process_id, Handle process_handle
 +
|-
 +
| 0x25 || Result || [[#GetThreadId|GetThreadId]] || uint64_t *out_thread_id, Handle thread_handle
 +
|-
 +
| 0x26 || void || [[#Break|Break]] || BreakReason break_reason, uintptr_t arg, size_t size
 +
|-
 +
| 0x27 || Result || [[#OutputDebugString|OutputDebugString]] || const char *debug_str, size_t len
 +
|-
 +
| 0x28 || void || [[#ReturnFromException|ReturnFromException]] || Result result
 +
|-
 +
| 0x29 || Result || [[#GetInfo|GetInfo]] || uint64_t *out, InfoType info_type, Handle handle, uint64_t info_subtype
 +
|-
 +
| 0x2A || void || [[#FlushEntireDataCache|FlushEntireDataCache]] ||
 +
|-
 +
| 0x2B || Result || [[#FlushDataCache|FlushDataCache]] || uintptr_t address, size_t size
 +
|-
 +
| [3.0.0+] 0x2C  || Result || [[#MapPhysicalMemory|MapPhysicalMemory]] || uintptr_t address, size_t size
 +
|-
 +
| [3.0.0+] 0x2D  || Result || [[#UnmapPhysicalMemory|UnmapPhysicalMemory]] || uintptr_t address, size_t size
 +
|-
 +
| [5.0.0+] 0x2E  || Result || [[#GetDebugFutureThreadInfo|GetDebugFutureThreadInfo]] || arch::LastThreadContext *out_context, uint64_t *thread_id, Handle debug_handle, int64_t ns
 +
|-
 +
| 0x2F || Result || [[#GetLastThreadInfo|GetLastThreadInfo]] || arch::LastThreadContext *out_context, uintptr_t *out_tls_address, uint32_t *out_flags
 +
|-
 +
| 0x30 || Result || [[#GetResourceLimitLimitValue|GetResourceLimitLimitValue]] || int64_t *out_limit_value, Handle resource_limit_handle, LimitableResource which
 +
|-
 +
| 0x31 || Result || [[#GetResourceLimitCurrentValue|GetResourceLimitCurrentValue]] || int64_t *out_current_value, Handle resource_limit_handle, LimitableResource which
 +
|-
 +
| 0x32 || Result || [[#SetThreadActivity|SetThreadActivity]] || Handle thread_handle, ThreadActivity thread_activity
 +
|-
 +
| 0x33  || Result || [[#GetThreadContext3|GetThreadContext3]] || ThreadContext *out_context, Handle thread_handle
 +
|-
 +
| [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]] ||
 +
|- style="border-top: double"
 +
| [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
 +
|-
 +
| [4.0.0+] 0x3D || void || [[#ChangeKernelTraceState|ChangeKernelTraceState]] || KernelTraceState kern_trace_state
 +
|- style="border-top: double"
 +
| 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
 +
|-
 +
| 0x42 || Result || [[#ReplyAndReceiveLight|ReplyAndReceiveLight]] || Handle handle
 +
|-
 +
| 0x43 || Result || [[#ReplyAndReceive|ReplyAndReceive]] || int32_t *out_index, const Handle *handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns
 +
|-
 +
| 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
 +
|-
 +
| 0x45 || Result || [[#CreateEvent|CreateEvent]] || Handle *out_write_handle, Handle *out_read_handle
 +
|- style="border-top: double"
 +
| [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
 +
|-
 +
| [5.0.0+] 0x4A || Result || [[#SetUnsafeLimit|SetUnsafeLimit]] || size_t limit
 +
|-
 +
| [4.0.0+] 0x4B || Result || [[#CreateCodeMemory|CreateCodeMemory]] || Handle *out_handle, uintptr_t address, size_t size
 +
|-
 +
| [4.0.0+] 0x4C || Result || [[#ControlCodeMemory|ControlCodeMemory]] || Handle code_memory_handle, CodeMemoryOperation operation, uint64_t address, uint64_t size, MemoryPermission perm
 +
|-
 +
| 0x4D || void || [[#SleepSystem|SleepSystem]] ||
 +
|-
 +
| 0x4E || Result || [[#ReadWriteRegister|ReadWriteRegister]] || uint32_t *out_value, PhysicalAddress address, uint32_t mask, uint32_t value
 +
|-
 +
| 0x4F || Result || [[#SetProcessActivity|SetProcessActivity]] || Handle process_handle, ProcessActivity process_activity
 +
|-
 +
| 0x50 || Result || [[#CreateSharedMemory|CreateSharedMemory]] || Handle *out_handle, size_t size, MemoryPermission owner_perm, MemoryPermission remote_perm
 +
|-
 +
| 0x51 || Result || [[#MapTransferMemory|MapTransferMemory]] || Handle trmem_handle, uintptr_t address, size_t size, MemoryPermission owner_perm
 +
|-
 +
| 0x52 || Result || [[#UnmapTransferMemory|UnmapTransferMemory]] || Handle trmem_handle, uintptr_t address, size_t size
 +
|-
 +
| 0x53 || Result || [[#CreateInterruptEvent|CreateInterruptEvent]] || Handle *out_read_handle, int32_t interrupt_id, InterruptType interrupt_type
 +
|-
 +
| 0x54 || Result || [[#QueryPhysicalAddress|QueryPhysicalAddress]] || arch::PhysicalMemoryInfo *out_info, uintptr_t address
 +
|-
 +
| 0x55 || Result || [[#QueryIoMapping|QueryIoMapping]] || uintptr_t *out_address, PhysicalAddress physical_address, size_t size
 +
|-
 +
| 0x56 || Result || [[#CreateDeviceAddressSpace|CreateDeviceAddressSpace]] || Handle *out_handle, uint64_t das_address, uint64_t das_size
 +
|-
 +
| 0x57 || Result || [[#AttachDeviceAddressSpace|AttachDeviceAddressSpace]] || DeviceName device_name, Handle das_handle
 +
|-
 +
| 0x58 || Result || [[#DetachDeviceAddressSpace|DetachDeviceAddressSpace]] || DeviceName device_name, Handle das_handle
 +
|-
 +
| 0x59 || Result || [[#MapDeviceAddressSpaceByForce|MapDeviceAddressSpaceByForce]] || Handle das_handle, Handle process_handle, uint64_t process_address, size_t size, uint64_t device_address, MemoryPermission device_perm
 +
|-
 +
| 0x5A || Result || [[#MapDeviceAddressSpaceAligned|MapDeviceAddressSpaceAligned]] || Handle das_handle, Handle process_handle, uint64_t process_address, size_t size, uint64_t device_address, MemoryPermission device_perm
 +
|-
 +
| 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 || Result || [[#UnmapDeviceAddressSpace|UnmapDeviceAddressSpace]] || Handle das_handle, Handle process_handle, uint64_t process_address, size_t size, uint64_t device_address
 +
|-
 +
| 0x5D || Result || [[#InvalidateProcessDataCache|InvalidateProcessDataCache]] || Handle process_handle, uint64_t address, uint64_t size
 +
|-
 +
| 0x5E || Result || [[#StoreProcessDataCache|StoreProcessDataCache]] || Handle process_handle, uint64_t address, uint64_t size
 +
|-
 +
| 0x5F || Result || [[#FlushProcessDataCache|FlushProcessDataCache]] || Handle process_handle, uint64_t address, uint64_t size
 +
|-
 +
| 0x60 || Result || [[#DebugActiveProcess|DebugActiveProcess]] || Handle *out_handle, uint64_t process_id
 +
|-
 +
| 0x61 || Result || [[#BreakDebugProcess|BreakDebugProcess]] || Handle debug_handle
 +
|-
 +
| 0x62 || Result || [[#TerminateDebugProcess|TerminateDebugProcess]] || Handle debug_handle
 +
|-
 +
| 0x63 || Result || [[#GetDebugEvent|GetDebugEvent]] || arch::DebugEventInfo *out_info, Handle debug_handle
 +
|-
 +
| 0x64 || Result || [[#ContinueDebugEvent|ContinueDebugEvent]] || Handle debug_handle, uint32_t flags, const uint64_t *thread_ids, int32_t num_thread_ids
 +
|-
 +
| 0x65 || Result || [[#GetProcessList|GetProcessList]] || int32_t *out_num_processes, uint64_t *out_process_ids, int32_t max_out_count
 
|-
 
|-
| 0x1 || [[#svcSetHeapSize]] || W1=size || W0=result, X1=outaddr
+
| 0x66 || Result || [[#GetThreadList|GetThreadList]] || int32_t *out_num_threads, uint64_t *out_thread_ids, int32_t max_out_count, Handle debug_handle
 
|-
 
|-
| 0x2 || [[#svcProtectMemory]] || X0=addr, X1=size, W2=prot || W0=result
+
| 0x67 || Result || [[#GetDebugThreadContext|GetDebugThreadContext]] || ThreadContext *out_context, Handle debug_handle, uint64_t thread_id, uint32_t context_flags
 
|-
 
|-
| 0x3 || [[#svcSetMemoryState]] || X0=addr, X1=size, W2=state0, W3=state1 || W0=result
+
| 0x68 || Result || [[#SetDebugThreadContext|SetDebugThreadContext]] || Handle debug_handle, uint64_t thread_id, const ThreadContext *context, uint32_t context_flags
 
|-
 
|-
| 0x4 || [[#svcMirrorStack]] || X0=dstaddr, X1=srcaddr, X2=size || W0=result
+
| 0x69 || Result || [[#QueryDebugProcessMemory|QueryDebugProcessMemory]] || arch::MemoryInfo *out_memory_info, PageInfo *out_page_info, Handle process_handle, uintptr_t address
 
|-
 
|-
| 0x5 || svcUnmirrorStack || X0=dstaddr, X1=srcaddr, X2=size || W0=result
+
| 0x6A || Result || [[#ReadDebugProcessMemory|ReadDebugProcessMemory]] || uintptr_t buffer, Handle debug_handle, uintptr_t address, size_t size
 
|-
 
|-
| 0x6 || svcQueryMemory || X0=meminfo_ptr, X2=addr || W0=result, W1=pageinfo                                                       
+
| 0x6B || Result || [[#WriteDebugProcessMemory|WriteDebugProcessMemory]] || Handle debug_handle, uintptr_t buffer, uintptr_t address, size_t size
 
|-
 
|-
| 0x7 || svcExitProcess || None ||
+
| 0x6C || Result || [[#SetHardwareBreakPoint|SetHardwareBreakPoint]] || HardwareBreakPointRegisterName name, uint64_t flags, uint64_t value
 
|-
 
|-
| 0x8 || [[#svcCreateThread]] || X1=entry, X2=arg, X3=stacktop, W4=prio, W5=processor_id  || W0=result, W1=handle
+
| 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"
 +
| [5.0.0+] 0x6F || Result || [[#GetSystemInfo|GetSystemInfo]] || uint64_t *out, SystemInfoType info_type, Handle handle, uint64_t info_subtype
 
|-
 
|-
| 0x9 || svcStartThread || W0=thread_handle ||
+
| 0x70 || Result || [[#CreatePort|CreatePort]] || Handle *out_server_handle, Handle *out_client_handle, int32_t max_sessions, bool is_light, uintptr_t name
 
|-
 
|-
| 0xA || svcExitThread || None ||                                                        
+
| 0x71 || Result || [[#ManageNamedPort|ManageNamedPort]] || Handle *out_server_handle, const char *name, int32_t max_sessions
 
|-
 
|-
| 0xB || [[#svcSleepThread]] || X0=nano ||
+
| 0x72 || Result || [[#ConnectToPort|ConnectToPort]] || Handle *out_handle, Handle port
 
|-
 
|-
| 0xC || svcGetThreadPriority || W1=thread_handle || W0=result, W1=prio
+
| 0x73 || Result || [[#SetProcessMemoryPermission|SetProcessMemoryPermission]] || Handle process_handle, uint64_t address, uint64_t size, MemoryPermission perm
 
|-
 
|-
| 0xD || svcSetThreadPriority || W0=thread_handle, W1=prio || W0=result
+
| 0x74 || Result || [[#MapProcessMemory|MapProcessMemory]] || uintptr_t dst_address, Handle process_handle, uint64_t src_address, size_t size
 
|-
 
|-
| 0xE || svcGetThreadAffinityMask || W2=thread_handle || W0=result, W1=out, X2=out
+
| 0x75 || Result || [[#UnmapProcessMemory|UnmapProcessMemory]] || uintptr_t dst_address, Handle process_handle, uint64_t src_address, size_t size
 
|-
 
|-
| 0xF || svcSetThreadAffinityMask || W0=thread_handle, W1=in, X2=in2 || W0=result
+
| 0x76 || Result || [[#QueryProcessMemory|QueryProcessMemory]] || arch::MemoryInfo *out_memory_info, PageInfo *out_page_info, Handle process_handle, uint64_t address
 
|-
 
|-
| 0x10 || svcGetCurrentProcessorNumber || None || W0/X0=cpuid
+
| 0x77 || Result || [[#MapProcessCodeMemory|MapProcessCodeMemory]] || Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size
 
|-
 
|-
| 0x11 || svcGetMemoryBlockSomethingA? || W0=handle || ?
+
| 0x78 || Result || [[#UnmapProcessCodeMemory|UnmapProcessCodeMemory]] || Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size
 
|-
 
|-
| 0x12 || svcGetMemoryBlockSomethingB? || W0=handle || ?
+
| 0x79 || Result || [[#CreateProcess|CreateProcess]] || Handle *out_handle, const arch::CreateProcessParameter *parameters, const uint32_t *caps, int32_t num_caps
 
|-
 
|-
| 0x13 || svcMapMemoryBlock || W0=memblk_handle, X1=addr, X2=size, W3=perm || W0=result
+
| 0x7A || Result || [[#StartProcess|StartProcess]] || Handle process_handle, int32_t priority, int32_t core_id, uint64_t main_thread_stack_size
 
|-
 
|-
| 0x14 || svcUnmapMemoryBlock || W0=memblk_handle, X1=addr, X2=size || W0=result                                               
+
| 0x7B || Result || [[#TerminateProcess|TerminateProcess]] || Handle process_handle
 
|-
 
|-
| 0x15 || [[#svcCreateMemoryMirror]] || X1=addr, X2=size, W3=perm || W0=result, W1=handle
+
| 0x7C || Result || [[#GetProcessInfo|GetProcessInfo]] || int64_t *out_info, Handle process_handle, ProcessInfoType info_type
 
|-
 
|-
| 0x16 || svcCloseHandle || W0=handle || W0=result
+
| 0x7D || Result || [[#CreateResourceLimit|CreateResourceLimit]] || Handle *out_handle
 
|-
 
|-
| 0x17 || svcClearEvent || W0=handle || W0=result
+
| 0x7E || Result || [[#SetResourceLimitLimitValue|SetResourceLimitLimitValue]] || Handle resource_limit_handle, LimitableResource which, int64_t limit_value
 
|-
 
|-
| 0x18 || [[#svcWaitEvents]] || X1=handles_ptr, W2=num_handles. X3=timeout || W0=result, W1=handle_idx
+
| 0x7F || void || [[#CallSecureMonitor|CallSecureMonitor]] || SecureMonitorArguments *args
 
|-
 
|-
| 0x19 || svcSignalEvent || W0=handle || W0=result
+
|}
 +
 
 +
== SetHeapSize ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 
|-
 
|-
| 0x1A || svcLockMutex || W0=cur_thread_handle, X1=ptr, W2=req_thread_handle ||                                       
+
! Argument || Type || Name
 
|-
 
|-
| 0x1B || svcUnlockMutex || X0=ptr ||
+
| (In) W1 || uint32_t || Size
 
|-
 
|-
| 0x1C || svcCondWait || X0=ptr0, X1=ptr, W2=thread_handle, X3=timeout || W0=result
+
| (Out) W0 || [[#Result]] || Result
 
|-
 
|-
| 0x1D || svcCondBroadcast || X0=ptr, W1=value || W0=result
+
| (Out) X1 || void* || HeapAddress
 +
|}
 +
</div>
 +
 
 +
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 ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 
|-
 
|-
| .... || ? || ? || ?
+
! Argument || Type || Name
 
|-
 
|-
| 0x1F || svcConnectToPort || X1=port_name_str || W0=result, W1=handle
+
| (In) X0 || void* || Address
 
|-
 
|-
| .... || ? || ? || ?
+
| (In) X1 || uint64_t || Size
 
|-
 
|-
| 0x21 || svcSendSyncRequest || X0=handle || W0=result
+
| (In) W2 || [[#MemoryPermission]] || MemoryPermission
 
|-
 
|-
| 0x22 || svcSendSyncRequestByBuf || X0=cmdbufptr, X1=size, X2=handle || W0=result
+
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
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 [[#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
 
|-
 
|-
| 0x25 || svcGetThreadId || W0=thread_handle || W0=result, X1=out
+
| (In) X0 || void* || Address
 
|-
 
|-
| 0x26 || svcBreak || X0,X1,X2=info || ?
+
| (In) X1 || uint64_t || Size
 
|-
 
|-
| 0x27 || svcOutputDebugString || X0=str, X1=size ||
+
| (In) W2 || uint32_t || Mask
 
|-
 
|-
| 0x28 || svcReturnFromException || X0=result ||
+
| (In) W3 || uint32_t || Value
 
|-
 
|-
| 0x29 || [[#svcGetInfo]] || X1=info_id, X2=handle, X3=info_sub_id || W0=result, X1=out
+
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
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 ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 
|-
 
|-
| .... || ? || ? || ?
+
! Argument || Type || Name
 
|-
 
|-
| 0x40 || ??? || W2=?, X3=? || W0=result, W1=?, W2=?
+
| (In) X0 || void* || DstAddress
 
|-
 
|-
| 0x41 || svcAcceptSession || W1=port_handle || W0=result, W1=session_handle
+
| (In) X1 || void* || SrcAddress
 
|-
 
|-
| .... || ? || ? || ?
+
| (In) X2 || uint64_t || Size
 
|-
 
|-
| 0x43 || svcReplyAndReceive || X1=ptr_handles, W2=num_handles, X3=?, X4=timeout || W0=result, W1=handle_idx
+
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
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 ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 
|-
 
|-
| 0x44 || svcReplyAndReceiveByBuf || X1=buf, X2=sz, X3=ptr_handles, W4=num_handles, X5=?, X6=timeout || W0=result, W1=handle_idx
+
! Argument || Type || Name
 
|-
 
|-
| 0x45 || svcCreateSession || None || W0=result, W1=client_handle, W2=server_handle
+
| (In) X0 || void* || DstAddress
 
|-
 
|-
| .... || ? || ? || ?
+
| (In) X1 || void* || SrcAddress
 
|-
 
|-
| 0x50 || svcCreateMemoryBlock || W1=size?, W2=perm0, W3=perm1 || W0=result, W1=handle
+
| (In) X2 || uint64_t || Size
 
|-
 
|-
| 0x51 || [[#svcMapMemoryMirror]] || X0=mirror_handle, X1=addr, X2=size, W3=perm || W0=result
+
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
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 ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) X0 || [[#MemoryInfo]]* || MemoryInfo
 +
|-
 +
| (In) X2 || void* || Address
 
|-
 
|-
| 0x52 || [[#svcUnmapMemoryMirror]] || W0=mirror_handle, X1=addr, X2=size || W0=result
+
| (Out) W0 || [[#Result]] || Result
 +
|-
 +
| (Out) W1 || [[#PageInfo]] || PageInfo
 
|}
 
|}
 +
</div>
 +
 +
Queries information about an address. Will always fetch the lowest page-aligned mapping that contains the provided address.
   −
== svcSetHeapSize ==
+
Outputs a [[#MemoryInfo]] struct.
Size must be a multiple of 0x2000000. The heap base-address is written to out.
     −
== svcProtectMemory ==
+
== ExitProcess ==
Bit2 of permission (exec) is not allowed.
+
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) None || ||
 +
|-
 +
| (Out) None || ||
 +
|}
 +
</div>
   −
Setting write-only is not allowed either (bit1).
+
Exits the current process.
   −
== svcSetMemoryState ==
+
== CreateThread ==
{| class=wikitable
+
<div style="display: inline-block;">
! State0 || State1 || Action
+
{| class="wikitable" border="1"
 +
|-
 +
! 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
 +
|}
 +
</div>
 +
 
 +
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 ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) W0 || Handle<Thread> || ThreadHandle
 +
|-
 +
| (Out) None ||  ||
 +
|}
 +
</div>
 +
 
 +
Starts the thread for the provided handle.
 +
 
 +
== ExitThread ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) None || ||
 +
|-
 +
| (Out) None || ||
 +
|}
 +
</div>
 +
 
 +
Exits the current thread.
 +
 
 +
== SleepThread ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument64 || Argument32 || Type || Name
 +
|-
 +
| (In) X0 || R0, R1 || uint64_t || Nanoseconds
 +
|}
 +
</div>
 +
 
 +
Sleeps for a specified amount of time, or yields the thread.
 +
 
 +
Setting nanoseconds to 0, -1, or -2 indicates a yielding type.
 +
 
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Value || Type
 +
|-
 +
| 0 || Yielding without core migration
 +
|-
 +
| -1 || Yielding with core migration
 +
|-
 +
| -2 || Yielding to any other thread
 +
|}
 +
</div>
 +
 
 +
== 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>
 +
 
 +
Gets the priority of provided thread handle.
 +
 
 +
== SetThreadPriority ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) W0|| Handle<Thread> || ThreadHandle
 +
|-
 +
| (In) W1|| int32_t || Priority
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
Sets the priority of provided thread handle.
 +
 
 +
Priority is a number 0-0x3F. Lower value means higher priority.
 +
 
 +
== GetThreadCoreMask ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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
 +
|}
 +
</div>
 +
 
 +
Gets the affinity mask of provided thread handle.
 +
 
 +
== SetThreadCoreMask ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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
 +
|}
 +
</div>
 +
 
 +
Sets the affinity mask of provided thread handle.
 +
 
 +
== GetCurrentProcessorNumber ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) None || ||
 +
|-
 +
| (Out) W0 || uint32_t || CpuId
 +
|}
 +
</div>
 +
 
 +
Gets which cpu is executing the current thread.
 +
 
 +
CpuId is an integer in the range 0-3.
 +
 
 +
== SignalEvent ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) W0 || Handle<WritableEvent> || EventHandle
 +
|-
 +
| (Out) X0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
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 ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 
|-
 
|-
| 0 || 0 || Clear bit35 in [[#MemoryState]].
+
! Argument || Type || Name
 
|-
 
|-
| 8 || 0 || Clear bit35 in [[#MemoryState]].
+
| (In) W0 || Handle<WritableEvent> or Handle<ReadableEvent> || EventHandle
 
|-
 
|-
| 8 || 8 || Set bit35 in [[#MemoryState]].
+
| (Out) X0 || [[#Result]] || Result
 
|}
 
|}
 +
</div>
   −
This might used for switching between cached and non-cached mappings.
+
Takes the given event out of the signaled state.
   −
== svcMirrorStack ==
+
=== Result codes ===
Memory is only allowed to be mapped into a special region.
+
'''0x0:''' Success, the event is now in the not-signaled state.
   −
Code can get the range of this region from [[#svcGetInfo]].
+
'''0xE401:''' Invalid handle. The handle either does not exist, or is not a ReadableEvent nor a WritableEvent.
   −
The source region gets reprotected to ---, and sets bit32 is set in [[#MemoryState]].
+
'''0xFA01:''' The handle was not in a signaled state.
   −
== svcCreateThread ==
+
== MapSharedMemory ==
Processor_id must be 0,1,2,3 or -2.
+
<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
 +
|-
 +
| (In) W3 || [[#MemoryPermission]] || MemoryPermission
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
   −
== svcSleepThread ==
+
Maps the block supplied by the handle. The required permissions are different for the process that created the handle and all other processes.
Setting nano=0 means "yield thread".
     −
== svcCreateMemoryMirror ==
+
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.
This one reprotects the src block with perms you give it. It also sets bit32 into [[#MemoryState]].
+
 
 +
== 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>
 +
 
 +
== CreateTransferMemory ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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
 +
|}
 +
</div>
 +
 
 +
This one reprotects the src block with perms you give it. It also sets bit0 into [[#MemoryAttribute]].
    
Executable bit perm not allowed.
 
Executable bit perm not allowed.
   −
Closing all handles automatically causes the bit32 in [[#MemoryState]] to clear, and the permission to reset.
+
Closing all handles automatically causes the bit0 in [[#MemoryAttribute]] to clear, and the permission to reset.
 +
 
 +
== CloseHandle ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) W0 || Handle || Handle
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
== ResetSignal ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) W0 || Handle<ReadableEvent> or Handle<Process> || Handle
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
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 is equivalent to calling ClearEvent() on the handle.
   −
== svcWaitSynchronizationN ==
+
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.
Works with num_handles <= 0x40, error on num_handles == 0.
+
 
 +
=== 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 ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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
 +
|}
 +
</div>
 +
 
 +
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.
 
Does not accept 0xFFFF8001 or 0xFFFF8000 as handles.
   −
== svcBreak ==
+
=== Object types ===
When used on retail where inx0 bit31 is clear, the system will throw a [[Error_codes|fatal-error]]. Otherwise when bit31 is set, it will return 0.
+
'''KDebug:''' signals when there is a new [[#DebugEventInfo|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 [[#AcceptSession|accepted]].
 +
 
 +
'''KServerSession:''' signals when there is an incoming message waiting to be [[#ReplyAndReceive|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 ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) W0 || Handle<Thread> || ThreadHandle
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
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 ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) W0 || Handle<Thread> || ThreadHandle
 +
|-
 +
| (In) X1 || void* || Address
 +
|-
 +
| (In) W2 || uint32_t || Tag
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>                                 
 +
 
 +
== ArbitrateUnlock ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) X0 || void* || Address
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
== WaitProcessWideKeyAtomic ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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
 +
|}
 +
</div>
 +
 
 +
== SignalProcessWideKey ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) X0 || void* || Address
 +
|-
 +
| (In) W1 || int32_t || Value
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
== GetSystemTick ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument64 || Argument32 || Type || Name
 +
|-
 +
| (Out) X0 || R0, R1 || uint64_t || Ticks
 +
|}
 +
</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"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) X1 || char* || PortName
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|-
 +
| (Out) W1 || Handle<Session> || SessionHandle
 +
|}
 +
</div>
 +
 
 +
== SendSyncRequestLight ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) W0 || Handle<Session> || SessionHandle
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
== SendSyncRequest ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) W0 || Handle<Session> || SessionHandle
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
== SendSyncRequestWithUserBuffer ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) X0 || void* || Address
 +
|-
 +
| (In) X1 || uint64_t || Size
 +
|-
 +
| (In) W2 || Handle<Session> || SessionHandle
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
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 ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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
 +
|}
 +
</div>
 +
 
 +
Size and Address must be 0x1000-aligned.
 +
 
 +
== GetProcessId ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument64 || Argument32 || Type || Name
 +
|-
 +
| (In) W1 || R1 || Handle<Process> || ProcessHandle
 +
|-
 +
| (Out) W0 || R0 || [[#Result]] || Result
 +
|-
 +
| (Out) X1 || R1, R2 || uint64_t || ProcessId
 +
|}
 +
</div>
 +
 
 +
== GetThreadId ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) X0 || [[#BreakReason]] || BreakReason
 +
|-
 +
| (In) X1 || uint64_t ||
 +
|-
 +
| (In) X2 || uint64_t || Info
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
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 ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) X0 || char* || String
 +
|-
 +
| (In) X1 || uint64_t || Size
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
== ReturnFromException ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
== GetInfo ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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
 +
|}
 +
</div>
 +
 
 +
== FlushEntireDataCache ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) None || ||
 +
|-
 +
| (Out) None || ||
 +
|}
 +
</div>
 +
 
 +
== FlushDataCache ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) X0 || void* || Address
 +
|-
 +
| (In) X1 || uint64_t || Size
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
== MapPhysicalMemory ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) X0 || void* || Address
 +
|-
 +
| (In) X1 || uint64_t || Size
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
Acts like [[#SetHeapSize]] except you can allocate heap at any address you'd like.
 +
 
 +
Uses current process pool partition.
 +
 
 +
== UnmapPhysicalMemory ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) X0 || void* || Address
 +
|-
 +
| (In) X1 || uint64_t || Size
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
== GetDebugFutureThreadInfo ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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 ||
 +
|}
 +
</div>
 +
 
 +
== GetLastThreadInfo ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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 ||
 +
|}
 +
</div>
 +
 
 +
== GetResourceLimitLimitValue ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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
 +
|}
 +
</div>
 +
 
 +
== GetResourceLimitCurrentValue ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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
 +
|}
 +
</div>
 +
 
 +
== SetThreadActivity ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) W0 || Handle<Thread> || ThreadHandle
 +
|-
 +
| (In) W1 || [[#ThreadActivity]] || ThreadActivity
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
== GetThreadContext3 ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) X0 || [[#ThreadContext]]* || ThreadContext
 +
|-
 +
| (In) W1 || Handle<Thread> || ThreadHandle
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
== WaitForAddress ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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) None || || ||
 +
|}
 +
</div>
 +
 
 +
== SignalToAddress ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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) None || || ||
 +
|}
 +
</div>
 +
 
 +
== SynchronizePreemptionState ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) None || ||
 +
|-
 +
| (Out) None ||  ||
 +
|}
 +
</div>
 +
 
 +
== DumpInfo ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) X0 || [[#DumpInfoType]] || DumpInfoType
 +
|-
 +
| (In) X1 || uint64_t || DumpInfoSubType
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
Stubbed in retail kernel.
 +
 
 +
[4.0.0+] This function was removed and replaced by [[#KernelDebug]].
 +
 
 +
== KernelDebug ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) W0 || [[#KernelDebugType]] || KernelDebugType
 +
|-
 +
| (In) X1 || uint64_t ||
 +
|-
 +
| (In) X2 || uint64_t ||
 +
|-
 +
| (In) X3 || uint64_t ||
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
Stubbed in retail kernel.
 +
 
 +
== ChangeKernelTraceState ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) W0 || [[#KernelTraceState]] || KernelTraceState
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
Stubbed in retail kernel.
 +
 
 +
== CreateSession ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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
 +
|}
 +
</div>
 +
 
 +
== AcceptSession ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) W1 || Handle<Port> || PortHandle
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|-
 +
| (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"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) W0 || Handle<Port> or Handle<ServerSession> || Handle
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
== ReplyAndReceive ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument64 || Argument32 || Type || Name
 +
|-
 +
| (In) W1 || 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
 +
|}
 +
</div>
 +
 
 +
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 ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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
 +
|}
 +
</div>
 +
 
 +
== CreateEvent ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) None || ||
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|-
 +
| (Out) W1 || Handle<WritableEvent> || WritableEventHandle
 +
|-
 +
| (Out) W2 || Handle<ReadableEvent> || ReadableEventHandle
 +
|}
 +
</div>
 +
 
 +
== MapPhysicalMemoryUnsafe ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) X0 || void* || Address
 +
|-
 +
| (In) X1 || uint64_t || Size
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
Same as [[#MapPhysicalMemory]] except it always uses pool partition 0.
 +
 
 +
== UnmapPhysicalMemoryUnsafe ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) X0 || void* || Address
 +
|-
 +
| (In) X1 || uint64_t || Size
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
== SetUnsafeLimit ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) X0 || uint64_t || Limit
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
== CreateCodeMemory ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) X1 || void* || Address
 +
|-
 +
| (In) X2 || uint64_t || Size
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|-
 +
| (Out) W1 || Handle<CodeMemory> || CodeMemoryHandle
 +
|}
 +
</div>
 +
 
 +
Takes an address range with backing memory to create the code memory object.
 +
 
 +
The memory is initially memset to 0xFF after being locked.
 +
 
 +
== ControlCodeMemory ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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
 +
|}
 +
</div>
 +
 
 +
Maps the backing memory for a CodeMemory object into the current process.
 +
 
 +
For [[#CodeMemoryOperation|MapOwner]], memory permission must be RW-.
 +
 
 +
For [[#CodeMemoryOperation|MapSlave]], memory permission must be R-- or R-X.
 +
 
 +
Operations [[#CodeMemoryOperation|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 ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) None || ||
 +
|-
 +
| (Out) None || ||
 +
|}
 +
</div>
 +
 
 +
== ReadWriteRegister ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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
 +
|}
 +
</div>
 +
 
 +
Read/write IO registers with a hardcoded whitelist. Input address is physical-address and must be aligned to 4.
 +
 
 +
rw_mask is 0 for reading and 0xffffffff for writing. You can also write individual bits by using a mask value.
 +
 
 +
You can only write to registers inside physical pages 0x70019000 (MC), 0x7001C000 (MC0), 0x7001D000 (MC1), and they all share the same whitelist.
 +
 
 +
The whitelist is same for writing as for reading.
 +
 
 +
The whitelist is:
 +
 
 +
0x054, 0x090, 0x094, 0x098, 0x09c, 0x0a0, 0x0a4, 0x0a8, 0x0ac, 0x0b0, 0x0b4, 0x0b8, 0x0bc, 0x0c0, 0x0c4, 0x0c8, 0x0d0, 0x0d4, 0x0d8, 0x0dc, 0x0e0, 0x100, 0x108, 0x10c, 0x118, 0x11c, 0x124, 0x128, 0x12c, 0x130, 0x134, 0x138, 0x13c, 0x158, 0x15c, 0x164, 0x168, 0x16c, 0x170, 0x174, 0x178, 0x17c, 0x200, 0x204, 0x2e4, 0x2e8, 0x2ec, 0x2f4, 0x2f8, 0x310, 0x314, 0x320, 0x328, 0x344, 0x348, 0x370, 0x374, 0x37c, 0x380, 0x390, 0x394, 0x398, 0x3ac, 0x3b8, 0x3bc, 0x3c0, 0x3c4, 0x3d8, 0x3e8, 0x41c, 0x420, 0x424, 0x428, 0x42c, 0x430, 0x44c, 0x47c, 0x480, 0x484, 0x50c, 0x554, 0x558, 0x55c, 0x670, 0x674, 0x690, 0x694, 0x698, 0x69c, 0x6a0, 0x6a4, 0x6c0, 0x6c4, 0x6f0, 0x6f4, 0x960, 0x970, 0x974, 0xa20, 0xa24, 0xb88, 0xb8c, 0xbc4, 0xbc8, 0xbcc, 0xbd0, 0xbd4, 0xbd8, 0xbdc, 0xbe0, 0xbe4, 0xbe8, 0xbec, 0xc00, 0xc5c, 0xcac
 +
 
 +
[2.0.0+] Whitelist was extended with 0x4c4, 0x4c8, 0x4cc, 0x584, 0x588, 0x58c.
 +
 
 +
[2.0.0+] The IO registers in range 0x7000E400 (PMC) size 0xC00 skip the whitelist, and do a TrustZone call using [[SMC#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"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) W0 || Handle<Process> || ProcessHandle
 +
|-
 +
| (In) W1 || [[#ProcessActivity]] || ProcessActivity
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
== CreateSharedMemory ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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
 +
|}
 +
</div>
 +
 
 +
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 ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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
 +
|}
 +
</div>
 +
 
 +
You must pass same size and permissions as given in [[#CreateTransferMemory]], otherwise error.
 +
 
 +
== UnmapTransferMemory ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) X0 || Handle<TransferMemory> || TransferMemoryHandle
 +
|-
 +
| (In) X1 || void* || Address
 +
|-
 +
| (In) X2 || uint64_t || Size
 +
|-
 +
| (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"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) X1 || [[#Interrupt]] || Interrupt
 +
|-
 +
| (In) W2 || [[#InterruptType]] || InterruptType
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|-
 +
| (Out) W1 || Handle<ReadableEvent> || ReadableEventHandle
 +
|}
 +
</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.
 +
 
 +
== QueryPhysicalAddress ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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
 +
|}
 +
</div>
 +
 
 +
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 ==
 +
<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
 +
|-
 +
| (Out) X1 || R1 || void* || VirtualAddress
 +
|}
 +
</div>
 +
 
 +
Returns a virtual address mapped to a given IO range.
 +
 
 +
== CreateDeviceAddressSpace ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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
 +
|}
 +
</div>
 +
 
 +
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 ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) W0 || [[#DeviceName]] || DeviceName
 +
|-
 +
| (In) X1 || Handle<DeviceAddressSpace> || DeviceAddressSpaceHandle
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
Attaches a device address space to a [[#DeviceName|device]].
 +
 
 +
== DetachDeviceAddressSpace ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) W0 || [[#DeviceName]] || DeviceName
 +
|-
 +
| (In) X1 || Handle<DeviceAddressSpace> || DeviceAddressSpaceHandle
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
Detaches a device address space from a [[#DeviceName|device]].
 +
 
 +
== MapDeviceAddressSpaceByForce ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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 || [[#MemoryPermission]] || MemoryPermission
 +
|-
 +
| (Out) W0 || R0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
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 [[SVC#MemoryState|FlagCanDeviceMap]] bit set. Bit [[SVC#MemoryAttribute|DeviceShared]] will be set after mapping.
 +
 
 +
== MapDeviceAddressSpaceAligned ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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 || [[#MemoryPermission]] || MemoryPermission
 +
|-
 +
| (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.
 +
 
 +
== MapDeviceAddressSpace ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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
 +
|}
 +
</div>
 +
 
 +
== UnmapDeviceAddressSpace ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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
 +
|}
 +
</div>
 +
 
 +
Unmaps an attached device address space from an userspace address.
 +
 
 +
== InvalidateProcessDataCache ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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
 +
|}
 +
</div>
 +
 
 +
== StoreProcessDataCache ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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
 +
|}
 +
</div>
 +
 
 +
== FlushProcessDataCache ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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
 +
|}
 +
</div>
 +
 
 +
== DebugActiveProcess ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument64 || Argument32 || Type || Name
 +
|-
 +
| (In) X1 || R2, R3 || uint64_t || ProcessId
 +
|-
 +
| (Out) W0 || R0 || [[#Result]] || Result
 +
|-
 +
| (Out) W1 || R1 || Handle<Debug> || DebugHandle
 +
|}
 +
</div>
 +
 
 +
== BreakDebugProcess ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) W0 || Handle<Debug> || DebugHandle
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
== TerminateDebugProcess ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) W0 || Handle<Debug> || DebugHandle
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
== GetDebugEvent ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) X0 || [[#DebugEventInfo]]* || DebugEventInfo
 +
|-
 +
| (In) W1 || Handle<Debug> || DebugHandle
 +
|-
 +
| (Out) W0 || [[#Result]] || Result
 +
|}
 +
</div>
 +
 
 +
== ContinueDebugEvent ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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
 +
|}
 +
</div>
 +
 
 +
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 ==
 +
<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
 +
|-
 +
| (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.
 +
 
 +
'''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 ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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
 +
|}
 +
</div>
 +
 
 +
== GetDebugThreadContext ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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
 +
|}
 +
</div>
 +
 
 +
== SetDebugThreadContext ==
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! 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
 +
|}
 +
</div>
 +
 
 +
== 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>
 +
 
 +
== 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>
 +
 
 +
== WriteDebugProcessMemory ==
 +
<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
 +
|-
 +
| Thread  || 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.
 +
|}
 +
 
 +
== 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}
   −
== svcGetInfo ==
+
PreferredCpuCore: output in out2
 +
 
 +
CurrentCpuCore: output in out2
 +
 
 +
AffinityMask: output in out1
 +
 
 +
== CreateProcessParameter ==
 
{| class=wikitable
 
{| class=wikitable
! Handle type || Id0 || Id1 || Description
+
! Offset || Length || Bits || Description
 
|-
 
|-
| Process || 0 || 0 || Core available mask. Always 0xF meaning all 4 cores available.
+
| 0 || 12 || || ProcessName (doesn't have to be null-terminated)
 
|-
 
|-
| Process || 1 || 0 || Always 0xfffffffff0000000.
+
| 0x0C || 4 || || ProcessCategory (0: regular title, 1: kernel built-in)
 
|-
 
|-
| Process || 2 || 0 || Randomized unknown base-address.
+
| 0x10 || 8 || || TitleId
 
|-
 
|-
| Process || 3 || 0 || Always 0x1000000000.
+
| 0x18 || 8 || || CodeAddr
 
|-
 
|-
| Process || 4 || 0 || Randomized heap base-address.
+
| 0x20 || 4 || || CodeNumPages
 
|-
 
|-
| Process || 5 || 0 || Always 0x180000000.
+
| 0x24 || 4 || || Flags
 
|-
 
|-
| Process || 6 || 0 || Total memory usage?
+
| || || Bit0 || Is64BitInstruction
 
|-
 
|-
| Process || 7 || 0 || Process heap size.
+
| || || Bit3-1 || [[#AddressSpaceType]]
 
|-
 
|-
| Zero    || 8 || 0 || Always 0. Used during exception handling.
+
| || || Bit4 || [2.0.0+] EnableDebug
 
|-
 
|-
| Zero    || 9 || 0 || This creates and returns an unknown handle.
+
| || || Bit5 || EnableAslr
 
|-
 
|-
| Zero    || 10 || -1, {current coreid} || Unknown. Output data changes each time this SVC is used. Global and core-specific tick-count?
+
| || || Bit6 || IsApplication
 
|-
 
|-
| Zero    || 11 || 0-3 || Returns random from TRNG. Used to seed usermode PRNGs. Unknown what exactly causes this output to change, however it does change when exiting+launching a process.
+
| || || Bit7 || [4.0.0] UseSecureMemory
 
|-
 
|-
| Process || 12 || 0 || Always 0x8000000.
+
| || || Bit10-7 || [5.0.0+] MemoryRegion (0 = Application, 1 = Applet, 2 = SecureSystem, 3 = NonSecureSystem)
 
|-
 
|-
| Process || 13 || 0 || Always 0x7ff8000000.
+
| || || Bit11 || [7.0.0+] OptimizeMemoryAllocation (only allowed in combination with IsApplication)
 
|-
 
|-
| Process || 14 || 0 || Start of stack mirror region.
+
| 0x28 || 4 || || ResourceLimitHandle (can be zero)
 
|-
 
|-
| Process || 15 || 0 || Size of stack mirror region.
+
| 0x2C || 4 || || [3.0.0+] SystemResourceNumPages
 
|}
 
|}
   −
== svcMapMemoryMirror ==
+
On [1.0.0] there's only one MemoryRegion.
The newly mapped pages will have [[#MemoryState]] type 0xE.
+
 
 +
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.
   −
You must pass same size and permissions as given in svcCreateMemoryMirror, otherwise error.
+
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.
   −
== svcUnmapMemoryMirror ==
+
=== AddressSpaceType ===
Size must match size given in map syscall, otherwise there's an invalid-size error.
+
{| 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 ==
 
== MemoryState ==
 
{| class=wikitable
 
{| class=wikitable
! Lower 8 bits || Type                || Meaning
+
! 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]] ||
 
|-
 
|-
| 0x3          || Code static          || .text and .rodata
+
| 16 || [[#MapProcessCodeMemory|FlagCanCodeAlias]] ||
 
|-
 
|-
| 0x4          || Code                || .data
+
| 17 || [[#CreateTransferMemory|FlagCanTransfer]] ||
 
|-
 
|-
| 0x5          || Heap                ||
+
| 18 || [[#QueryPhysicalAddress|FlagCanQueryPhysical]] ||
 
|-
 
|-
| 0x6          || Shared memory block  ||
+
| 19 || [[#MapDeviceAddressSpace|FlagCanDeviceMap]] ||
 
|-
 
|-
| 0x8          || Module code static  || .text and .rodata
+
| 20 || [[#MapDeviceAddressSpaceAligned|FlagCanAlignedDeviceMap]] ||
 
|-
 
|-
| 0x9          || Module code          || .data
+
| 21 || [[#SendSyncRequestWithUserBuffer|FlagCanIpcUserBuffer]] ||
 
|-
 
|-
| 0xB          || Stack mirror        ||
+
| 22 || FlagReferenceCounted || The physical memory blocks backing this region are refcounted.
 
|-
 
|-
| 0xC          || Thread local storage ||
+
| 23 || [[#MapProcessMemory|FlagCanMapProcess]] ||
 
|-
 
|-
| 0xE          || Memory mirror        ||
+
| 24 || [[#SetMemoryAttribute|FlagCanChangeAttribute]] ||
 
|-
 
|-
| 0x10        || Reserved            ||
+
| 25 || [4.0.0+] [[#CreateCodeMemory|FlagCanCodeMemory]] ||
 
|}
 
|}
   −
Bit32: is_mirrored
+
=== MemoryType ===
Bit34: is_nv_locked
+
{| class=wikitable
Bit35: is_uncached?
+
! 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]].
 +
|}
 +
 
 +
== 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 an exception occurs from the above user handler, the entire exception handling process will repeat with the new exception.
   −
=Exception Handling=
+
Note that if a thread that wasn't faulting calls [[#ReturnFromException]], it signals an "invalid syscall" exception
There appears to be userland code for handling exceptions, however this doesn't seem to be executed on retail.
     −
On usermode exception, it jumps to main code binary entrypoint (main_binary_address+0) with X0=exception_info_ptr and X1=exception_info2_ptr.
+
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?
On boot, X0 is set to 0 triggering normal crt0 setup.
 

Navigation menu