Difference between revisions of "SVC"

From 3dbrew
Jump to navigation Jump to search
m (Correct svc name from switchbrew)
 
(197 intermediate revisions by 17 users not shown)
Line 1: Line 1:
 
= System calls =
 
= System calls =
 +
'''Note: The argument-lists here apply to the official syscall wrapper-functions that are found in userland processes. The actual ordering passed to the kernel via the SVC instruction is documented in [[Kernel_ABI|Kernel ABI]].'''
 +
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
 
!  Id
 
!  Id
NATIVE_FIRM ARM11 kernel notes
+
NF ARM11
Enabled for the TWL_FIRM ARM11 kernel
+
NF ARM9
 +
!  TF ARM11
 
!  Description
 
!  Description
 +
! scope="col" width="200" |  Notes
 
|-
 
|-
 
| 0x01  
 
| 0x01  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| Result ControlMemory(u32* outaddr, u32 addr0, u32 addr1, u32 size, u32 operation, u32 permissions) (outaddr is usually the same as the input addr0)
+
| style="background: red" | No
 +
| Result [[Memory Management|ControlMemory]](u32* outaddr, u32 addr0, u32 addr1, u32 size, [[Memory Management#enum_MemoryOperation|MemoryOperation]] operation, [[Memory Management#enum_MemoryPermission|MemoryPermission]] permissions)
 +
| Outaddr is usually the same as the input addr0.
 
|-
 
|-
 
| 0x02  
 
| 0x02  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| Result QueryMemory(MemoryInfo* info, PageInfo* out, u32 Addr)
+
| style="background: red" | No
 +
| Result [[Memory Management|QueryMemory]]([[Memory Management#struct MemoryInfo|MemoryInfo]]* info, [[Memory Management#struct PageInfo|PageInfo]]* out, u32 Addr)
 +
|
 
|-
 
|-
 
| 0x03  
 
| 0x03  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
 +
| style="background: red" | No
 
| void ExitProcess(void)
 
| void ExitProcess(void)
 +
|
 
|-
 
|-
 
| 0x04  
 
| 0x04  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| Result GetProcessAffinityMask(u8* affinitymask, Handle process, s32 processorcount)
+
| style="background: red" | No
 +
| Result GetProcessAffinityMask(u8* affinitymask, Handle process, s32 processorcount)
 +
|
 
|-
 
|-
 
| 0x05  
 
| 0x05  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
 +
| style="background: red" | No
 
| Result SetProcessAffinityMask(Handle process, u8* affinitymask, s32 processorcount)
 
| Result SetProcessAffinityMask(Handle process, u8* affinitymask, s32 processorcount)
 +
|
 
|-
 
|-
 
| 0x06  
 
| 0x06  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
 +
| style="background: red" | No
 
| Result GetProcessIdealProcessor(s32 *idealprocessor, Handle process)
 
| Result GetProcessIdealProcessor(s32 *idealprocessor, Handle process)
 +
|
 
|-
 
|-
 
| 0x07  
 
| 0x07  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
 +
| style="background: red" | No
 
| Result SetProcessIdealProcessor(Handle process, s32 idealprocessor)
 
| Result SetProcessIdealProcessor(Handle process, s32 idealprocessor)
 +
|
 
|-
 
|-
 
| 0x08  
 
| 0x08  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
| Result [[#CreateThread|CreateThread]](Handle* thread, func entrypoint, u32 arg, u32 stacktop, s32 threadpriority, s32 processorid)
+
| style="background: green" | Yes
 +
| Result [[Multi-threading#CreateThread|CreateThread]](Handle* thread, func entrypoint, u32 arg, u32 stacktop, s32 threadpriority, s32 processorid)
 +
|
 
|-
 
|-
 
| 0x09  
 
| 0x09  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
| void ExitThread(void)
+
| style="background: green" | Yes
 +
| void [[Multi-threading#ExitThread|ExitThread]](void)
 +
|
 
|-
 
|-
 
| 0x0A  
 
| 0x0A  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
| void SleepThread(s64 nanoseconds)
+
| style="background: green" | Yes
 +
| void [[Multi-threading#SleepThread|SleepThread]](s64 nanoseconds)
 +
|
 
|-
 
|-
 
| 0x0B  
 
| 0x0B  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
| Result GetThreadPriority(s32* priority, Handle thread)
+
| style="background: green" | Yes
 +
| Result [[Multi-threading#GetThreadPriority|GetThreadPriority]](s32* priority, Handle thread)
 +
|
 
|-
 
|-
 
| 0x0C  
 
| 0x0C  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
| Result SetThreadPriority(Handle thread, s32 priority)
+
| style="background: green" | Yes
 +
| Result [[Multi-threading#SetThreadPriority|SetThreadPriority]](Handle thread, s32 priority)
 +
|
 
|-
 
|-
 
| 0x0D  
 
| 0x0D  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| Result GetThreadAffinityMask(u8* affinitymask, Handle thread, s32 processorcount)
+
| style="background: red" | No
 +
| Result [[Multi-threading#GetThreadAffinityMask|GetThreadAffinityMask]](u8* affinitymask, Handle thread, s32 processorcount)
 +
|
 
|-
 
|-
 
| 0x0E  
 
| 0x0E  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| Result SetThreadAffinityMask(Handle thread, u8* affinitymask, s32 processorcount)
+
| style="background: red" | No
 +
| Result [[Multi-threading#SetThreadAffinityMask|SetThreadAffinityMask]](Handle thread, u8* affinitymask, s32 processorcount)
 +
| Replaced with a stub in ARM11 NATIVE_FIRM kernel beginning with [[8.0.0-18]].
 
|-
 
|-
 
| 0x0F  
 
| 0x0F  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| Result GetThreadIdealProcessor(s32* processorid, Handle thread)
+
| style="background: red" | No
 +
| Result [[Multi-threading#GetThreadIdealProcessor|GetThreadIdealProcessor]](s32* processorid, Handle thread)
 +
|
 
|-
 
|-
 
| 0x10  
 
| 0x10  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| Result SetThreadIdealProcessor(Handle thread, s32 processorid)
+
| style="background: red" | No
 +
| Result [[Multi-threading#SetThreadIdealProcessor|SetThreadIdealProcessor]](Handle thread, s32 processorid)
 +
| Replaced with a stub in ARM11 NATIVE_FIRM kernel beginning with [[8.0.0-18]].
 
|-
 
|-
 
| 0x11  
 
| 0x11  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
 +
| style="background: red" | No
 
| s32 GetCurrentProcessorNumber(void)
 
| s32 GetCurrentProcessorNumber(void)
 +
|
 
|-
 
|-
 
| 0x12  
 
| 0x12  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| Result Run(Handle process, StartupInfo* info) (This starts the main() thread. Buf+0 is main-thread priority, Buf+4 is main-thread stack-size.)
+
| style="background: red" | No
 +
| Result [[Multi-threading#Run|Run]](Handle process, StartupInfo* info)
 +
| This starts the main() thread. Buf+0 is main-thread priority, Buf+4 is main-thread stack-size.
 
|-
 
|-
 
| 0x13  
 
| 0x13  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
| Result CreateMutex(Handle* mutex, bool initialLocked)
+
| style="background: green" | Yes
 +
| Result [[Multi-threading#CreateMutex|CreateMutex]](Handle* mutex, bool initialLocked)
 +
|
 
|-
 
|-
 
| 0x14  
 
| 0x14  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
| Result ReleaseMutex(Handle mutex)
+
| style="background: green" | Yes
 +
| Result [[Multi-threading#ReleaseMutex|ReleaseMutex]](Handle mutex)
 +
|
 
|-
 
|-
 
| 0x15  
 
| 0x15  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
| Result CreateSemaphore(Handle* semaphore, s32 initialCount, s32 maxCount)
+
| style="background: green" | Yes
 +
| Result [[Multi-threading#CreateSemaphore|CreateSemaphore]](Handle* semaphore, s32 initialCount, s32 maxCount)
 +
|
 
|-
 
|-
 
| 0x16  
 
| 0x16  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
| Result ReleaseSemaphore(s32* count, Handle semaphore, s32 releaseCount)
+
| style="background: green" | Yes
 +
| Result [[Multi-threading#ReleaseSemaphore|ReleaseSemaphore]](s32* count, Handle semaphore, s32 releaseCount)
 +
|
 
|-
 
|-
 
| 0x17  
 
| 0x17  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
| Result CreateEvent(Handle* event, ResetType resettype)
+
| style="background: green" | Yes
 +
| Result [[Multi-threading#CreateEvent|CreateEvent]](Handle* event, ResetType resettype)
 +
|
 
|-
 
|-
 
| 0x18  
 
| 0x18  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
| Result SignalEvent(Handle event)
+
| style="background: green" | Yes
 +
| Result [[Multi-threading#SignalEvent|SignalEvent]](Handle event)
 +
|
 
|-
 
|-
 
| 0x19  
 
| 0x19  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
| Result ClearEvent(Handle event)
+
| style="background: green" | Yes
 +
| Result [[Multi-threading#ClearEvent|ClearEvent]](Handle event)
 +
|
 
|-
 
|-
 
| 0x1A  
 
| 0x1A  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
 +
| style="background: green" | Yes
 
| Result CreateTimer(Handle* timer, ResetType resettype)
 
| Result CreateTimer(Handle* timer, ResetType resettype)
 +
|
 
|-
 
|-
 
| 0x1B  
 
| 0x1B  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
| Result SetTimer(Handle timer, s64 initial, s64 interval)
+
| style="background: green" | Yes
 +
| Result SetTimer(Handle timer, s64 initial_nanoseconds, s64 interval)
 +
|
 
|-
 
|-
 
| 0x1C  
 
| 0x1C  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
 +
| style="background: green" | Yes
 
| Result CancelTimer(Handle timer)
 
| Result CancelTimer(Handle timer)
 +
|
 
|-
 
|-
 
| 0x1D  
 
| 0x1D  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
 +
| style="background: green" | Yes
 
| Result ClearTimer(Handle timer)
 
| Result ClearTimer(Handle timer)
 +
|
 
|-
 
|-
 
| 0x1E  
 
| 0x1E  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| Result CreateMemoryBlock(Handle* memblock, u32 addr, u32 size, u32 mypermission, u32 otherpermission)
+
| style="background: red" | No
 +
| Result [[Memory Management|CreateMemoryBlock]](Handle* memblock, u32 addr, u32 size, [[Memory Management#enum_MemoryPermission|MemoryPermission]] mypermission, [[Memory Management#enum_MemoryPermission|MemoryPermission]] otherpermission)
 +
|
 
|-
 
|-
 
| 0x1F  
 
| 0x1F  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherpermission)
+
| style="background: red" | No
 +
| Result [[Memory Management|MapMemoryBlock]](Handle memblock, u32 addr, [[Memory Management#enum_MemoryPermission|MemoryPermission]] mypermissions, [[Memory Management#enum_MemoryPermission|MemoryPermission]] otherpermission)
 +
|
 
|-
 
|-
 
| 0x20  
 
| 0x20  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| Result UnmapMemoryBlock(Handle memblock, u32 addr)
+
| style="background: red" | No
 +
| Result [[Memory Management|UnmapMemoryBlock]](Handle memblock, u32 addr)
 +
|
 
|-
 
|-
 
| 0x21  
 
| 0x21  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
| Result CreateAddressArbiter(Handle* arbiter)
+
| style="background: green" | Yes
 +
| Result [[Multi-threading#Address_Arbiters|CreateAddressArbiter]](Handle* arbiter)
 +
|
 
|-
 
|-
 
| 0x22  
 
| 0x22  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
| Result ArbitrateAddress(Handle arbiter, u32 addr, ArbitrationType type, s32 value, s64 nanoseconds)
+
| style="background: green" | Yes
 +
| Result [[Multi-threading#Address_Arbiters|ArbitrateAddress]](Handle arbiter, u32 addr, ArbitrationType type, s32 value, s64 nanoseconds)
 +
|
 
|-
 
|-
 
| 0x23  
 
| 0x23  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
 +
| style="background: green" | Yes
 
| Result CloseHandle(Handle handle)
 
| Result CloseHandle(Handle handle)
 +
|
 
|-
 
|-
 
| 0x24  
 
| 0x24  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
| Result WaitSynchronization1(Handle handle, s64 nanoseconds)
+
| style="background: green" | Yes
 +
| Result WaitSynchronization1(Handle handle, s64 timeout_nanoseconds)
 +
|
 
|-
 
|-
 
| 0x25  
 
| 0x25  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
| Result WaitSynchronizationN(s32* out, Handle* handles, s32 handlecount, bool waitAll, s64 nanoseconds)
+
| style="background: green" | Yes
 +
| Result WaitSynchronizationN(s32* out, Handle* handles, s32 handlecount, bool waitAll, s64 timeout_nanoseconds)
 +
|
 
|-
 
|-
 
| 0x26  
 
| 0x26  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
 +
| style="background: red" | No
 
| Result SignalAndWait(s32* out, Handle signal, Handle* handles, s32 handleCount, bool waitAll, s64 nanoseconds)
 
| Result SignalAndWait(s32* out, Handle signal, Handle* handles, s32 handleCount, bool waitAll, s64 nanoseconds)
 +
| Stubbed
 
|-
 
|-
 
| 0x27  
 
| 0x27  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
 +
| style="background: green" | Yes
 
| Result DuplicateHandle(Handle* out, Handle original)
 
| Result DuplicateHandle(Handle* out, Handle original)
 +
|
 
|-
 
|-
 
| 0x28  
 
| 0x28  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
 +
| style="background: green" | Yes
 
| s64 GetSystemTick(void) (This returns the total CPU ticks elapsed since the CPU was powered-on)
 
| s64 GetSystemTick(void) (This returns the total CPU ticks elapsed since the CPU was powered-on)
 +
|
 
|-
 
|-
 
| 0x29  
 
| 0x29  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
 +
| style="background: red" | No
 
| Result GetHandleInfo(s64* out, Handle handle, HandleInfoType type)
 
| Result GetHandleInfo(s64* out, Handle handle, HandleInfoType type)
 +
|
 
|-
 
|-
 
| 0x2A  
 
| 0x2A  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
 +
| style="background: green" | Yes
 
| Result GetSystemInfo(s64* out, SystemInfoType type, s32 param)
 
| Result GetSystemInfo(s64* out, SystemInfoType type, s32 param)
 +
|
 
|-
 
|-
 
| 0x2B  
 
| 0x2B  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
 +
| style="background: green" | Yes
 
| Result GetProcessInfo(s64* out, Handle process, ProcessInfoType type)
 
| Result GetProcessInfo(s64* out, Handle process, ProcessInfoType type)
 +
|
 
|-
 
|-
 
| 0x2C  
 
| 0x2C  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
| Result GetThreadInfo(s64* out, Handle thread, ThreadInfoType type)
+
| style="background: green" | Yes
 +
| Result [[Multi-threading#GetThreadInfo|GetThreadInfo]](s64* out, Handle thread, ThreadInfoType type)
 +
|
 
|-
 
|-
 
| 0x2D  
 
| 0x2D  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| Result ConnectToPort(Handle* out, const char* portName)
+
| style="background: red" | No
 +
| Result [[IPC|ConnectToPort]](Handle* out, const char* portName)
 +
|
 
|-
 
|-
 
| 0x2E  
 
| 0x2E  
 +
| style="background: green" | Yes
 +
| style="background: red" | No
 +
| style="background: red" | No
 +
| Result SendSyncRequest1(Handle session)
 
| Stubbed
 
| Stubbed
| No
+
|
| Result SendSyncRequest1(Handle session)
 
 
|-
 
|-
 
| 0x2F  
 
| 0x2F  
 +
| style="background: green" | Yes
 +
| style="background: red" | No
 +
| style="background: red" | No
 +
| Result SendSyncRequest2(Handle session)
 
| Stubbed
 
| Stubbed
| No
+
|
| Result SendSyncRequest2(Handle session)
 
 
|-
 
|-
 
| 0x30  
 
| 0x30  
 +
| style="background: green" | Yes
 +
| style="background: red" | No
 +
| style="background: red" | No
 +
| Result SendSyncRequest3(Handle session)
 
| Stubbed
 
| Stubbed
| No
+
|
| Result SendSyncRequest3(Handle session)
 
 
|-
 
|-
 
| 0x31  
 
| 0x31  
 +
| style="background: green" | Yes
 +
| style="background: red" | No
 +
| style="background: red" | No
 +
| Result SendSyncRequest4(Handle session)
 
| Stubbed
 
| Stubbed
| No
+
|
| Result SendSyncRequest4(Handle session)
 
 
|-
 
|-
 
| 0x32  
 
| 0x32  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| Result SendSyncRequest(Handle session)
+
| style="background: red" | No
 +
| Result [[IPC|SendSyncRequest]](Handle session)
 +
|
 
|-
 
|-
 
| 0x33  
 
| 0x33  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
 +
| style="background: red" | No
 
| Result OpenProcess(Handle* process, u32 processId)
 
| Result OpenProcess(Handle* process, u32 processId)
 +
|
 
|-
 
|-
 
| 0x34  
 
| 0x34  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| Result OpenThread(Handle* thread, Handle process, u32 threadId)
+
| style="background: red" | No
 +
| Result [[Multi-threading#OpenThread|OpenThread]](Handle* thread, Handle process, u32 threadId)
 +
|
 
|-
 
|-
 
| 0x35  
 
| 0x35  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: red" | No
 +
| style="background: green" | Yes
 
| Result GetProcessId(u32* processId, Handle process)
 
| Result GetProcessId(u32* processId, Handle process)
 +
|
 
|-
 
|-
 
| 0x36  
 
| 0x36  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| Result GetProcessIdOfThread(u32* processId, Handle thread)
+
| style="background: red" | No
 +
| Result [[Multi-threading#GetProcessIdOfThread|GetProcessIdOfThread]](u32* processId, Handle thread)
 +
|
 
|-
 
|-
 
| 0x37  
 
| 0x37  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
| Result GetThreadId(u32* threadId, Handle thread)
+
| style="background: green" | Yes
 +
| Result [[Multi-threading#GetThreadId|GetThreadId]](u32* threadId, Handle thread)
 +
|
 
|-
 
|-
 
| 0x38  
 
| 0x38  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
 +
| style="background: red" | No
 
| Result GetResourceLimit(Handle* resourceLimit, Handle process)
 
| Result GetResourceLimit(Handle* resourceLimit, Handle process)
 +
|
 
|-
 
|-
 
| 0x39  
 
| 0x39  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
 +
| style="background: red" | No
 
| Result GetResourceLimitLimitValues(s64* values, Handle resourceLimit, LimitableResource* names, s32 nameCount)
 
| Result GetResourceLimitLimitValues(s64* values, Handle resourceLimit, LimitableResource* names, s32 nameCount)
 +
|
 
|-
 
|-
 
| 0x3A  
 
| 0x3A  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
 +
| style="background: red" | No
 
| Result GetResourceLimitCurrentValues(s64* values, Handle resourceLimit, LimitableResource* names, s32 nameCount)
 
| Result GetResourceLimitCurrentValues(s64* values, Handle resourceLimit, LimitableResource* names, s32 nameCount)
 +
|
 
|-
 
|-
 
| 0x3B  
 
| 0x3B  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| Result GetThreadContext(ThreadContext* context, Handle thread) (Stubbed)
+
| style="background: red" | No
 +
| Result [[Multi-threading#GetThreadContext|GetThreadContext]](ThreadContext* context, Handle thread)
 +
| Stubbed
 
|-
 
|-
 
| 0x3C  
 
| 0x3C  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
| Break(BreakReason)
+
| style="background: green" | Yes
|- style="border-top: double"
+
| Break(BreakReason reason)
 +
Break(BreakReason debugReason, const void* croInfo, u32 croInfoSize)
 +
|
 +
|-
 
| 0x3D  
 
| 0x3D  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
| OutputDebugString(void const, int) (Does nothing on non-debug units)
+
| style="background: green" | Yes
 +
| OutputDebugString(void const, int)
 +
| Does nothing on non-debug units.
 
|-
 
|-
 
| 0x3E  
 
| 0x3E  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
 +
| style="background: red" | No
 
| ControlPerformanceCounter(unsigned long long, int, unsigned int, unsigned long long)
 
| ControlPerformanceCounter(unsigned long long, int, unsigned int, unsigned long long)
|-
+
|
 +
|- style="border-top: double"
 
| 0x47  
 
| 0x47  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| Result CreatePort(Handle* portServer, Handle* portClient,  const char* name, s32 maxSessions)
+
| style="background: red" | No
 +
| Result [[IPC|CreatePort]](Handle* portServer, Handle* portClient,  const char* name, s16 maxSessions)
 +
| Setting name=NULL creates a private port not accessible from svcConnectToPort.
 
|-
 
|-
 
| 0x48  
 
| 0x48  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| Result CreateSessionToPort(Handle* session, Handle port)
+
| style="background: red" | No
 +
| Result [[IPC|CreateSessionToPort]](Handle* session, Handle port)
 +
|
 
|-
 
|-
 
| 0x49  
 
| 0x49  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| Result CreateSession(Handle* sessionServer, Handle* sessionClient)
+
| style="background: red" | No
 +
| Result [[IPC|CreateSession]](Handle* sessionServer, Handle* sessionClient)
 +
|
 
|-
 
|-
 
| 0x4A  
 
| 0x4A  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| Result AcceptSession(Handle* session, Handle port)
+
| style="background: red" | No
 +
| Result [[IPC|AcceptSession]](Handle* session, Handle port)
 +
|
 
|-
 
|-
 
| 0x4B  
 
| 0x4B  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| Result ReplyAndReceive1(s32* index, Handle* handles, s32 handleCount, Handle replyTarget) (Stubbed)
+
| style="background: red" | No
 +
| Result ReplyAndReceive1(s32* index, Handle* handles, s32 handleCount, Handle replyTarget)
 +
| Stubbed.
 
|-
 
|-
 
| 0x4C  
 
| 0x4C  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| Result ReplyAndReceive2(s32* index, Handle* handles, s32 handleCount, Handle replyTarget) (Stubbed)
+
| style="background: red" | No
 +
| Result ReplyAndReceive2(s32* index, Handle* handles, s32 handleCount, Handle replyTarget)
 +
| Stubbed.
 
|-
 
|-
 
| 0x4D  
 
| 0x4D  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| Result ReplyAndReceive3(s32* index, Handle* handles, s32 handleCount, Handle replyTarget) (Stubbed)
+
| style="background: red" | No
 +
| Result ReplyAndReceive3(s32* index, Handle* handles, s32 handleCount, Handle replyTarget)
 +
| Stubbed.
 
|-
 
|-
 
| 0x4E  
 
| 0x4E  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| Result ReplyAndReceive4(s32* index, Handle* handles, s32 handleCount, Handle replyTarget) (Stubbed)
+
| style="background: red" | No
 +
| Result ReplyAndReceive4(s32* index, Handle* handles, s32 handleCount, Handle replyTarget)
 +
| Stubbed.
 
|-
 
|-
 
| 0x4F  
 
| 0x4F  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| Result ReplyAndReceive(s32* index, Handle* handles, s32 handleCount, Handle replyTarget)
+
| style="background: red" | No
 +
| Result [[IPC#svcReplyAndReceive|ReplyAndReceive]](s32* index, Handle* handles, s32 handleCount, Handle replyTarget)
 +
|
 
|-
 
|-
 
| 0x50  
 
| 0x50  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
| Result BindInterrupt(Interrupt name, Handle syncObject, s32 priority, bool isManualClear)
+
| style="background: green" | Yes
 +
| Result [[#Interrupt Handling|BindInterrupt]](Interrupt name, Handle eventOrSemaphore, s32 priority, bool isLevelHighActive)
 +
|
 
|-
 
|-
 
| 0x51  
 
| 0x51  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
| Result UnbindInterrupt(Interrupt name, Handle syncObject)
+
| style="background: green" | Yes
 +
| Result UnbindInterrupt(Interrupt name, Handle eventOrSemaphore)
 +
|
 
|-
 
|-
 
| 0x52  
 
| 0x52  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
 +
| style="background: green" | Yes
 
| Result InvalidateProcessDataCache(Handle process, void* addr, u32 size)
 
| Result InvalidateProcessDataCache(Handle process, void* addr, u32 size)
 +
|
 
|-
 
|-
 
| 0x53  
 
| 0x53  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
 +
| style="background: green" | Yes
 
| Result StoreProcessDataCache(Handle process, void const* addr, u32 size)
 
| Result StoreProcessDataCache(Handle process, void const* addr, u32 size)
 +
|
 
|-
 
|-
 
| 0x54  
 
| 0x54  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
 +
| style="background: green" | Yes
 
| Result FlushProcessDataCache(Handle process, void const* addr, u32 size)
 
| Result FlushProcessDataCache(Handle process, void const* addr, u32 size)
 +
|
 
|-
 
|-
 
| 0x55  
 
| 0x55  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
| Result StartInterProcessDma(Handle* dma, Handle dstProcess, void* dst, Handle srcProcess, const void* src, u32 size, const DmaConfig& config )
+
| style="background: green" | Yes
 +
| Result [[Corelink DMA Engines|StartInterProcessDma]](Handle* dma, Handle dstProcess, void* dst, Handle srcProcess, const void* src, u32 size, const DmaConfig* config)
 +
|
 
|-
 
|-
 
| 0x56  
 
| 0x56  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
 +
| style="background: green" | Yes
 
| Result StopDma(Handle dma)
 
| Result StopDma(Handle dma)
 +
|
 
|-
 
|-
 
| 0x57  
 
| 0x57  
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
 +
| style="background: green" | Yes
 
| Result GetDmaState(DmaState* state, Handle dma)
 
| Result GetDmaState(DmaState* state, Handle dma)
 +
|
 
|-
 
|-
 
| 0x58
 
| 0x58
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
| RestartDma(nn::Handle, void *, void  const*, unsigned int, signed char)
+
| style="background: green" | Yes
 +
| RestartDma(Handle, void *, void  const*, unsigned int, signed char)
 +
|
 +
|-
 +
| 0x59
 +
| style="background: green" | Yes
 +
| style="background: red" | No?
 +
| style="background: red" | No
 +
| SetGpuProt(s8 input_flag). Implemented with [[11.3.0-36|11.3.0-X]], see below.
 
|-
 
|-
 +
| 0x5A
 +
| style="background: green" | Yes
 +
| style="background: red" | No?
 +
| style="background: red" | No
 +
| SetWifiEnabled(s0 input_flag). Implemented with [[11.4.0-37|11.4.0-X]], see below.
 +
|- style="border-top: double"
 
| 0x60  
 
| 0x60  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
 +
| style="background: red" | No
 
| Result DebugActiveProcess(Handle* debug, u32 processID)
 
| Result DebugActiveProcess(Handle* debug, u32 processID)
 +
|
 
|-
 
|-
 
| 0x61  
 
| 0x61  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
 +
| style="background: red" | No
 
| Result BreakDebugProcess(Handle debug)
 
| Result BreakDebugProcess(Handle debug)
 +
|
 
|-
 
|-
 
| 0x62  
 
| 0x62  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
 +
| style="background: red" | No
 
| Result TerminateDebugProcess(Handle debug)
 
| Result TerminateDebugProcess(Handle debug)
 +
|
 
|-
 
|-
 
| 0x63  
 
| 0x63  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
 +
| style="background: red" | No
 
| Result GetProcessDebugEvent(DebugEventInfo* info, Handle debug)
 
| Result GetProcessDebugEvent(DebugEventInfo* info, Handle debug)
 +
|
 
|-
 
|-
 
| 0x64  
 
| 0x64  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
 +
| style="background: red" | No
 
| Result ContinueDebugEvent(Handle debug, u32 flags)
 
| Result ContinueDebugEvent(Handle debug, u32 flags)
 +
|
 
|-
 
|-
 
| 0x65  
 
| 0x65  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
 +
| style="background: red" | No
 
| Result GetProcessList(s32* processCount, u32* processIds, s32 processIdMaxCount)
 
| Result GetProcessList(s32* processCount, u32* processIds, s32 processIdMaxCount)
 +
|
 
|-
 
|-
 
| 0x66  
 
| 0x66  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
 +
| style="background: red" | No
 
| Result GetThreadList(s32* threadCount, u32* threadIds, s32 threadIdMaxCount, Handle domain)
 
| Result GetThreadList(s32* threadCount, u32* threadIds, s32 threadIdMaxCount, Handle domain)
 +
|
 
|-
 
|-
 
| 0x67  
 
| 0x67  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
 +
| style="background: red" | No
 
| Result GetDebugThreadContext(ThreadContext* context, Handle debug, u32 threadId, u32 controlFlags)
 
| Result GetDebugThreadContext(ThreadContext* context, Handle debug, u32 threadId, u32 controlFlags)
 +
|
 
|-
 
|-
 
| 0x68  
 
| 0x68  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| Result SetDebugThreadContext(Handle debug, u32 threadId, ThreadContext* context, u32 controlFlags)
+
| style="background: red" | No
 +
| Result SetDebugThreadContext(Handle debug, u32 threadId, const ThreadContext* context, u32 controlFlags)
 +
|
 
|-
 
|-
 
| 0x69  
 
| 0x69  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| Result QueryDebugProcessMemory(MemoryInfo* blockInfo, PageInfo* pageInfo, Handle process, u32 addr)
+
| style="background: red" | No
 +
| Result QueryDebugProcessMemory(MemoryInfo* blockInfo, PageInfo* pageInfo, Handle debug, u32 addr)
 +
|
 
|-
 
|-
 
| 0x6A  
 
| 0x6A  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
 +
| style="background: red" | No
 
| Result ReadProcessMemory(void* buffer, Handle debug, u32 addr, u32 size)
 
| Result ReadProcessMemory(void* buffer, Handle debug, u32 addr, u32 size)
 +
|
 
|-
 
|-
 
| 0x6B  
 
| 0x6B  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
 +
| style="background: red" | No
 
| Result WriteProcessMemory(Handle debug, void const* buffer, u32 addr, u32 size)
 
| Result WriteProcessMemory(Handle debug, void const* buffer, u32 addr, u32 size)
 +
|
 
|-
 
|-
 
| 0x6C  
 
| 0x6C  
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
 +
| style="background: red" | No
 
| Result SetHardwareBreakPoint(s32 registerId, u32 control, u32 value)
 
| Result SetHardwareBreakPoint(s32 registerId, u32 control, u32 value)
 +
|
 
|-
 
|-
 
| 0x6D
 
| 0x6D
 +
| style="background: green" | Yes
 +
| style="background: red" | No
 +
| style="background: red" | No
 +
| [[Multi-threading#GetDebugThreadParam|GetDebugThreadParam]](s64* unused, u32* out, Handle kdebug, u32 threadId, DebugThreadParameter param)
 
|  
 
|  
| No
+
|- style="border-top: double"
| GetDebugThreadParam(long long *, int *, nn::Handle, unsigned int, nn::dmnt::DebugThreadParam) (Disabled on regular kernel)
 
|-
 
 
| 0x70
 
| 0x70
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| ControlProcessMemory(Handle KProcess, unsigned int Addr0, unsigned int Addr1, unsigned int Size, unsigned int Type, unsigned int Permissions)
+
| style="background: red" | No
 +
| Result ControlProcessMemory(Handle KProcess, unsigned int Addr0, unsigned int Addr1, unsigned int Size, unsigned int Type, unsigned int Permissions)
 +
|
 
|-
 
|-
 
| 0x71
 
| 0x71
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| MapProcessMemory(Handle KProcess, unsigned int StartAddr, unsigned int EndAddr)
+
| style="background: red" | No
 +
| Result [[Memory Management#Memory_Mapping|MapProcessMemory]](Handle process, u32 startAddr, u32 size)
 +
|
 
|-
 
|-
 
| 0x72
 
| 0x72
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| UnmapProcessMemory(Handle KProcess, unsigned int StartAddr, unsigned int EndAddr)
+
| style="background: red" | No
 +
| Result [[Memory Management#Memory_Mapping|UnmapProcessMemory]](Handle process, u32 startAddr, u32 size)
 +
|
 
|-
 
|-
 
| 0x73
 
| 0x73
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| CreateProcess(Handle* HandleInfo_out, struct CreateProcessInfo, u32 code_ptr, u32 ro_ptr, u32 data_ptr)
+
| style="background: red" | No
 +
| Result [[Multi-threading#CreateCodeSet|CreateCodeSet]](Handle* handle_out, struct CodeSetInfo, u32 code_ptr, u32 ro_ptr, u32 data_ptr)
 +
|
 
|-
 
|-
 
| 0x74
 
| 0x74
 +
| style="background: green" | Yes
 +
| style="background: red" | No
 +
| style="background: red" | No
 +
| Result RandomStub()
 
| Stubbed
 
| Stubbed
| No
 
|
 
 
|-
 
|-
 
| 0x75
 
| 0x75
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| SetupProcess(Handle* KProcess_out, Handle HandleInfo_in, u32 arm11kernelcaps_ptr, u32 arm11kernelcaps_num)
+
| style="background: red" | No
 +
| Result [[Multi-threading#CreateProcess|CreateProcess]](Handle* handle_out, Handle codeset_handle, u32 [[NCCH/Extended_Header#ARM11_Kernel_Capabilities|arm11kernelcaps_ptr]], u32 arm11kernelcaps_num)
 +
|
 
|-
 
|-
 
| 0x76
 
| 0x76
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
 +
| style="background: red" | No
 
| TerminateProcess(Handle)
 
| TerminateProcess(Handle)
 +
|
 
|-
 
|-
 
| 0x77
 
| 0x77
 +
| style="background: green" | Yes
 +
| style="background: red" | No
 +
| style="background: red" | No
 +
| Result SetProcessResourceLimits(Handle KProcess, Handle KResourceLimit)
 
|  
 
|  
| No
 
| (Handle KProcess, Handle KResourceLimit)
 
 
|-
 
|-
 
| 0x78
 
| 0x78
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| CreateResourceLimit(Handle *KResourceLimit)
+
| style="background: red" | No
 +
| Result CreateResourceLimit(Handle *KResourceLimit)
 +
|
 
|-
 
|-
 
| 0x79
 
| 0x79
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| ?
+
| style="background: red" | No
 +
| Result SetResourceLimitLimitValues(Handle res_limit, LimitableResource* resource_type_list, s64* resource_list, u32 count)
 +
|
 
|-
 
|-
 
| 0x7A
 
| 0x7A
| Stubbed beginning with [[2.0.0-2]]
+
| style="background: green" | Yes
| Yes
+
| style="background: red" | No
| AddCodeSegment? (unsigned int Addr, unsigned int Size)
+
| style="background: green" | Yes
 +
| AddCodeSegment (unsigned int Addr, unsigned int Size)
 +
| Stubbed on NATIVE_FIRM beginning with [[2.0.0-2]]. Used during TWL_FIRM boot.
 
|-
 
|-
 
| 0x7B
 
| 0x7B
| Available(normally not accessible due to SVC-access-control).
+
| style="background: green" | Yes
| No
+
| style="background: green" | Yes
| Backdoor(unsigned int Addr)
+
| style="background: red" | No
 +
| Backdoor(unsigned int CodeAddress)
 +
| This is used on ARM9 NATIVE_FIRM.
 +
No ARM11 processes have access to it without some form of kernelhax, and this was removed on [[11.0.0-33]] (for ARM11).
 +
 
 
|-
 
|-
 
| 0x7C
 
| 0x7C
|  
+
| style="background: green" | Yes
| Yes
+
| style="background: green" | Yes
| KernelSetState(unsigned int Type, unsigned int Param0, unsigned int Param1, unsigned int Param2) (The Type determines the usage of each param)
+
| style="background: green" | Yes
 +
| KernelSetState(unsigned int Type, ...)
 +
| The type determines the args to be passed
 
|-
 
|-
 
| 0x7D
 
| 0x7D
|  
+
| style="background: green" | Yes
| No
+
| style="background: red" | No
| QueryProcessMemory(MemInfo *Info, unsigned int *Out, Handle KProcess, unsigned int Addr)
+
| style="background: red" | No
 +
| Result QueryProcessMemory(MemInfo *Info, unsigned int *Out, Handle KProcess, unsigned int Addr)
 +
|
 +
|- style="border-top: double"
 +
| 0xFF
 +
| style="background: green" | Yes
 +
| style="background: green" | Yes
 +
| style="background: green" | Yes
 +
| Stop point
 +
| The svcaccesscontrol mask doesn't apply for this SVC. This svc doesn't check the "debug mode enabled" flag either. Does nothing if there is no [[KDebug]] object associated to the current process. Stubbed on ARM9 NATIVE_FIRM.
 +
|}
 +
NF: NATIVE_FIRM. TF: TWL_FIRM.
 +
 
 +
Note that "stubbed" here means that the SVC only returns an error, as in the following snippet:
 +
 
 +
<pre>ROM:FFF04D98                LDR            R0, =0xF8C007F4
 +
ROM:FFF04D9C                BX              LR</pre>
 +
 
 +
= Types and structures =
 +
 
 +
== enum ResetType ==
 +
 
 +
{| class="wikitable" border="1"
 +
!  Reset type
 +
!  Id
 +
|-
 +
| ONESHOT
 +
| 0
 +
|-
 +
| STICKY
 +
| 1
 
|-
 
|-
| 0xFF
+
| PULSE
|  
+
| 2
| Yes
 
| Debug related (The Syscall access control mask doesn't apply for this SVC)
 
 
|}
 
|}
  
== CreateThread ==
+
Timers/Events may be waited on by a thread using svcWaitSynchronization. Once the timer runs out/the event gets signaled, threads waiting on the respective handles until the timer/event is reset. STICKY timers/events wake up threads until they are explicitly reset by some thread. ONESHOT timers/events will wake up exactly one thread and then are reset automatically. PULSE timers will be reset after waking up one thread too, but will also be started again immediately. It's unknown whether PULSE is a valid reset type for events.
R0=s32 threadpriority
 
R1=func entrypoint
 
R2=u32 arg
 
R3=u32 stacktop
 
R4=s32 processorid
 
  
  Result result=R0
+
== struct StartupInfo ==
  Handle* thread=R1
+
{| class="wikitable" border="1"
 +
! Type
 +
! Field
 +
|-
 +
| s32
 +
| Priority
 +
|-
 +
| u32
 +
| Stack size
 +
|-
 +
| s32
 +
| argc
 +
|-
 +
| s16*
 +
| argv
 +
|-
 +
| s16*
 +
| envp
 +
|}
  
This processorid is a bitmask for which processors the thread can be run on. Bit value zero enables thread execution for this CPUID, bit value one disables thread execution for this CPUID. Bit0-bit1 are for CPUID0-CPUID1. The s32 processorid must be <=2. The thread priority value must be in the following range: 0x0..0x3F.
+
== enum BreakReason ==
 +
{| class="wikitable" border="1"
 +
! Break Reason
 +
! Value
 +
|-
 +
| PANIC
 +
| 0
 +
|-
 +
| ASSERT
 +
| 1
 +
|-
 +
| USER
 +
| 2
 +
|}
  
The stacktop must be aligned to 0x8-bytes, otherwise when not aligned to 0x8-bytes the ARM11 kernel clears the low 3-bits of the stacktop address.
+
== struct DebugEventInfo ==
 +
Size: 0x28 bytes
  
= Types and structures =
+
When using svcGetProcessDebugEvent, the kernel fetches the first [[KEventInfo]] instance of the process's [[KDebug]]. The debug event is handled and parsed into this structure.
 +
 
 +
{| class="wikitable" border="1"
 +
!  Type
 +
!  Field
 +
|-
 +
| u32
 +
| Event type
 +
|-
 +
| u32
 +
| Thread ID (not used in all events)
 +
|-
 +
| u32
 +
| Flags. Bit0 means that svcContinueDebugEvent needs to be called for this event
 +
|-
 +
| u8[4]
 +
| Remnants of the corresponding flags in [[KEventInfo]], always 0 here
 +
|-
 +
| u32[6]
 +
| Event-specific data (see below)
 +
|}
  
== enum MemoryState ==
 
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Memory state flags
+
Event type
Bit
+
Id
 
|-
 
|-
| FREE
+
| ATTACH PROCESS
 
| 0
 
| 0
 
|-
 
|-
| RESERVED
+
| ATTACH THREAD
 
| 1
 
| 1
 
|-
 
|-
| IO
+
| EXIT THREAD
 
| 2
 
| 2
 
|-
 
|-
| STATIC
+
| EXIT PROCESS (1)
 
| 3
 
| 3
 
|-
 
|-
| CODE
+
| EXCEPTION
 
| 4
 
| 4
 
|-
 
|-
| PRIVATE
+
| DLL LOAD (3)
 
| 5
 
| 5
 
|-
 
|-
| SHARED
+
| DLL UNLOAD (3)
 
| 6
 
| 6
 
|-
 
|-
| CONTINUOUS
+
| SCHEDULE IN (1) (2)
 
| 7
 
| 7
 
|-
 
|-
| ALIASED
+
| SCHEDULE OUT (1) (2)
 
| 8
 
| 8
 
|-
 
|-
| ALIAS
+
| SYSCALL IN (1) (2)
 
| 9
 
| 9
 
|-
 
|-
| ALIAS CODE
+
| SYSCALL OUT (1) (2)
 
| 10
 
| 10
 
|-
 
|-
| LOCKED
+
| OUTPUT STRING
 
| 11
 
| 11
 +
|-
 +
| MAP (1) (2)
 +
| 12
 +
|}
 +
 +
<nowiki>(1)</nowiki> Non-blocking: all other events preempt and block all the threads of their process until they are continued.
 +
 +
<nowiki>(2)</nowiki> There is handling code in the kernel but nothing signal those events.
 +
 +
<nowiki>(3)</nowiki> Completely removed from the kernel, but referenced in DMNT. Stubbed relocation code (e.g., in Process9 and in PXI sysmodule) and even whole libraries (e.g., in PXI sysmodule's .rodata section) seem to indicate that Nintendo used dynamic libraries early in system development.
 +
 +
When calling svcDebugActiveProcess, an ATTACH PROCESS debug event is signaled, then ATTACH THREAD for each of its opened threads, then finally ATTACH BREAK.
 +
 +
ATTACH THREAD events are also emitted when a thread is created from an attached process.
 +
 +
=== ATTACH PROCESS event ===
 +
 +
{| class="wikitable" border="1"
 +
!  Type
 +
!  Field
 +
|-
 +
| u64
 +
| Program ID
 +
|-
 +
| char[8]
 +
| Process name
 +
|-
 +
| u32
 +
| Process ID
 +
|-
 +
| u32
 +
| "Other" flag. Always 0 in available kernel versions
 
|}
 
|}
  
== enum PageFlags ==
+
=== ATTACH THREAD event ===
 +
 
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Page flags
+
Type
Bit
+
Field
 
|-
 
|-
| LOCKED
+
| u32
 +
| Creator thread ID (0 if attached by svcDebugActiveProcess)
 +
|-
 +
| void *
 +
| Thread local storage
 +
|-
 +
| u32 *
 +
| Entrypoint = .text load address of the parent process
 +
|}
 +
 
 +
=== EXIT THREAD/PROCESS events ===
 +
 
 +
A single u32 reason field is used.
 +
 
 +
Thread exit reasons:
 +
{| class="wikitable" border="1"
 +
!  Reason
 +
!  Id
 +
|-
 +
| (None)
 
| 0
 
| 0
 
|-
 
|-
| CHANGED
+
| TERMINATE
 
| 1
 
| 1
 +
|-
 +
| EXIT PROCESS
 +
| 2
 +
|-
 +
| TERMINATE PROCESS
 +
| 3
 
|}
 
|}
  
== enum MemoryOperation ==
+
Process exit reasons:
 +
{| class="wikitable" border="1"
 +
!  Reason
 +
!  Id
 +
|-
 +
| (None)
 +
| 0
 +
|-
 +
| TERMINATE
 +
| 1
 +
|-
 +
| DEBUG TERMINATE
 +
| 2
 +
|}
 +
 
 +
=== EXCEPTION event ===
  
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Memory operation
+
Type
 +
!  Field
 +
|-
 +
| u32
 +
| Exception type
 +
|-
 +
| u32
 +
| Exception address
 +
|-
 +
| u32[4]
 +
| Type-specific data, see below
 +
|}
 +
 
 +
Exception types:
 +
{| class="wikitable" border="1"
 +
!  Exception type
 
!  Id
 
!  Id
 
|-
 
|-
| FREE
+
| UNDEFINED INSTRUCTION
 +
| 0
 +
|-
 +
| PREFETCH ABORT
 
| 1
 
| 1
 
|-
 
|-
| RESERVE
+
| DATA ABORT
 
| 2
 
| 2
 
|-
 
|-
| COMMIT
+
| UNALIGNED DATA ACCESS
 
| 3
 
| 3
 
|-
 
|-
| MAP
+
| ATTACH BREAK
 
| 4
 
| 4
 
|-
 
|-
| UNMAP
+
| STOP POINT
 
| 5
 
| 5
 
|-
 
|-
| PROTECT
+
| USER BREAK
 
| 6
 
| 6
 
|-
 
|-
| REGION APP
+
| DEBUGGER BREAK
| 0x100
+
| 7
 +
|-
 +
| UNDEFINED SYSCALL
 +
| 8
 +
|}
 +
 
 +
==== UNDEFINED INSTRUCTION/PREFETCH ABORT/DATA ABORT/UNALIGNED DATA ACCESS/UNDEFINED SYSCALL events ====
 +
{| class="wikitable" border="1"
 +
!  Type
 +
!  Field
 
|-
 
|-
| REGION SYSTEM
+
| u32
| 0x200
+
| Fault information: Fault Address Register (for DATA ABORT and UNALIGNED DATA ACCESS),
 +
attempted SVC ID (for UNDEFINED SYSCALL), otherwise 0
 +
|}
 +
 
 +
==== STOP POINT event ====
 +
{| class="wikitable" border="1"
 +
!  Type
 +
!  Field
 
|-
 
|-
| REGION BASE
+
| u32
| 0x300
+
| Stop point type that caused the event: 0 = svc 0xFF, 1 = breakpoint, 2 = watchpoint
 
|-
 
|-
| LINEAR
+
| u32
| 0x10000
+
| Fault information: FAR for watchpoints, 0 otherwise
 
|}
 
|}
  
The LINEAR memory-operation indicates that the mapped physical address is always MappedVAddr+0x0C000000, thus this memory can be used for hardware devices' DMA(such as the [[GPU]]). Addr0+size for this must be within the 0x14000000-0x1C000000 range when Addr0 is non-zero(Addr1 must be zero), Addr0 isn't actually used by svcControlMemory for mapping memory since the kernel determines what vaddr to map. LINEAR memory is allocated in FCRAM the same way as any other virtual memory(like the regular process heap, etc).
+
==== USER BREAK event ====
 
+
{| class="wikitable" border="1"
The input mem-region value for svcControlMemory is only used(when non-zero) when the PID is value 1, for the [[FIRM]] ARM11 "loader" module.
+
!  Type
 
+
!  Field
== enum MemoryPermission ==
+
|-
 +
| u32
 +
| Break reason
 +
|-
 +
| u32[2]
 +
| Info for LOAD_RO and UNLOAD_RO
 +
|}
  
 +
User break types:
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Memory permission
+
Reason
 
!  Id
 
!  Id
 
|-
 
|-
| NONE
+
| PANIC
 
| 0
 
| 0
 
|-
 
|-
| READ
+
| ASSERT
 
| 1
 
| 1
 
|-
 
|-
| WRITE
+
| USER
 
| 2
 
| 2
 
|-
 
|-
| READWRITE
+
| LOAD_RO
 
| 3
 
| 3
 
|-
 
|-
| DONTCARE
+
| UNLOAD_RO
| 0x10000000
+
| 4
 
|}
 
|}
  
 +
==== DEBUGGER BREAK event ====
 +
{| class="wikitable" border="1"
 +
!  Type
 +
!  Field
 +
|-
 +
| s32[4]
 +
| IDs of the attached process's threads that were running on each core at the time of the @ref svcBreakDebugProcess call, or -1 (only the first 2 values are meaningful on O3DS).
 +
|}
  
== enum ResetType ==
+
=== SCHEDULE/SYSCALL IN/OUT events ===
  
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Reset type
+
Type
Id
+
Field
 +
|-
 +
| u64
 +
| Clock tick
 
|-
 
|-
| ONESHOT
+
| u32
| 0
+
| CPU ID (SCHEDULE events) Syscall (SYSCALL events)
 +
|}
 +
 
 +
=== OUTPUT STRING event ===
 +
 
 +
{| class="wikitable" border="1"
 +
!  Type
 +
!  Field
 
|-
 
|-
| STICKY
+
| u32
| 1
+
| String address
 
|-
 
|-
| PULSE
+
| u32
| 2
+
| String size
 
|}
 
|}
  
== struct MemoryInfo ==
+
=== MAP event ===
 +
 
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
!  Type
 
!  Type
Line 709: Line 1,153:
 
|-
 
|-
 
| u32
 
| u32
| Base address
+
| Mapped address
 
|-
 
|-
 
| u32
 
| u32
| Size
+
| Mapped size
 
|-
 
|-
 
| u32
 
| u32
| Permission
+
| MemoryPermission
 
|-
 
|-
| enum MemoryState
+
| u32
| State
+
| MemoryState
 
|}
 
|}
  
== struct PageInfo ==
+
== struct ThreadContext ==
 +
 
 +
Size: 0xCC bytes
 +
 
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
!  Type
 
!  Field
 
 
|-
 
|-
| u32
+
!  Offset
| Flags
+
! Type
 +
!  Description
 +
|-
 +
| 0x0
 +
| CpuRegisters
 +
| Saved CPU registers (r0-r12, sp, lr, pc, cpsr)
 +
|-
 +
| 0x44
 +
| FpuRegisters
 +
| Saved FPU registers (d0-d15, fpscr, fpexc)
 
|}
 
|}
  
== struct StartupInfo ==
+
The user needs to adjust pc for exceptions that occured while in Thumb mode.
 +
 
 +
'''Flags for svcGetDebugThreadContext/svcSetDebugThreadContext''':
 +
 
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
!  Type
 
!  Field
 
 
|-
 
|-
| s32
+
! Bit
| Priority
+
! Description
 +
|-
 +
| 0
 +
| Get/set CPU GPRs (r0-r12)
 +
|-
 +
| 1
 +
| Get/set CPU SPRs (sp, lr, pc, cpsr)
 +
|-
 +
| 2
 +
| Get/set FPU GPRs (d0-d15 aka. f0-f31)
 +
|-
 +
| 3
 +
| Get/set FPU SPRs (fpscr, fpexc)
 +
|}
 +
 
 +
When setting CPSR, the following assignment is done: <code>ctx->cpsr = ctx->cpsr & 0x7F0FDFF | userCtx->cpuRegisters.cpsr & 0xF80F0200;</code>. This is to avoid obvious security issues.
 +
 
 +
== enum DebugThreadParameter ==
 +
 
 +
{| class="wikitable" border="1"
 +
!  Parameter
 +
!  Id
 
|-
 
|-
| u32
+
| PRIORITY
| Stack size
+
| 0
 
|-
 
|-
| s32
+
| SCHEDULING_MASK_LOW
| argc
+
| 1
 
|-
 
|-
| s16*
+
| CPU_IDEAL
| argv
+
| 2
 
|-
 
|-
| s16*
+
| CPU_CREATOR
| envp
+
| 3
 
|}
 
|}
  
 +
== typedef Handle ==
  
 +
User-visible references to internal objects are represented by 32-bit integers called handles. Handles are only valid in the process they have been created in; hence, they cannot be exchanged between processes directly (the [[IPC]] functions provide a mean to copy handles to other processes, though).
  
= Processes =
+
There are a number of special-purpose handles, which provide easy access to information on objects in the current process:
Each process can only use SVCs which are enabled in the [[NCCH#CXI|exheader]] for this process. The ARM11 kernel SVC handler checks whether the SVC is enabled in the syscall access control mask stored on the SVC-mode stack, when the SVC isn't enabled a kernelpanic() is triggered. Each process has a separate SVC-mode stack, this stack and the syscall access mask stored here is initialized when the process is started. Applications normally only have access to SVCs <=0x3D, however not all SVCs <=0x3D are accessible to the application. The majority of the SVCs accessible to applications are unused by the application.
+
{| class="wikitable" border="1"
 +
!  Handle
 +
!  Description
 +
|-
 +
| 0xFFFF8000
 +
| Handle to the active thread
 +
|-
 +
| 0xFFFF8001
 +
| Handle to the active process
 +
|}
 +
 
 +
=svcSetHardwareBreakPoint=
 +
This is essentially an interface for writing values to the debug-unit (B/W)RP registers. registerId range 0..5 = breakpoints(BRP0-5), 0x100..0x101 = watchpoints(WRP0-1), anything outside of these ranges will result in an error. This is used for both adding and removing/disabling breakpoints/watchpoints, hence the raw control value parameter.
  
Each process has a separate handle-table, the size of this table is stored in the exheader. The handles in a handle-table can't be used in the context of other processes, since those handles don't exist in other handle-tables.
+
Here the kernel sets bit15 in the DSCR, to enable monitor-mode debugging.
  
0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for the current KThread.
+
Regardless of whether this is for a BRP, when bit21 is set in the control input parameter(BRP type = contextID), the kernel will load the target process [[KProcess|contextID]] and use that internally for the value field. The target process is specified via a [[KDebug]] handle passed as the "value" parameter.
  
Calling svcBreak on retail will only terminate the process which called this SVC.
+
Lastly, the kernel disables the specified (B/W)RP, then writes the value parameter / loaded contextID to the (B/W)VR, then writes the input control value to the (B/W)CR.
  
= Threads =
+
= [[DMA]] =
For svcCreateThread the input address used for Entrypoint_Param and StackTop are normally the same, however these can be arbitrary. For the main thread the Entrypoint_Param is value 0.
+
The CTRSDK code for using svcStartInterProcessDma will execute svcBreak when svcStartInterProcessDma returns an error(except for certain error value(s)). Therefore on retail, triggering a svcStartInterProcessDma via a system-module which results in an error from svcStartInterProcessDma will result in the system-module terminating.
  
Using CloseHandle() with a KThread handle will terminate the specified thread.
+
= Interrupt Handling =
  
= Memory Mapping =
+
svcBindInterrupt registers the given event or semaphore corresponding to the handle to the global [[ARM11_Interrupts#Interrupt_Table_.28New3DS.29|"interrupt table"]] for the given interrupt ID. Interrupts 0-14 and 16-31 can never be mapped regardless of the [[NCCH/Extended_Header#ARM11_Kernel_Capabilities|interrupt flags of the process's exheader]], and the latter are not checked when mapping interrupt 15. The "is level high active"/"is manual clear" parameter must be false when binding a semaphore handle (otherwise 0xD8E007EE "invalid combination" is returned).
ControlMemory and MapMemoryBlock can be used to map memory pages, these two SVCs only support mapping execute-never R/W pages. The input permissions parameter for these SVCs must be <=3, where value zero is used when un-mapping memory. Bitmask 0xf00 for ControlMemory parameter MemoryType is the memory-type, when this is zero the memory-type is loaded from the kernel flags stored in the exheader ARM11 kernel descriptors, for the process using the SVC. ControlMemory parameter MemoryType with value 0x10003 is used for mapping the GSP [[Memory_layout|heap]]. The low 8-bits are the type: 1 is for un-mapping memory, 3 for mapping memory. Type4 is used to mirror the RW memory at Addr1, to Addr0. Type4 will return an error if Addr1 is located in read-only memory. Addr1 is not used for type1 and type3.
 
  
The ARM11 kernel does not allow processes to create shared memory blocks via svcCreateMemoryBlock, when the process memorytype(from the kernel flags stored in the exheader kernel descriptor) is the application memorytype, and when addr=0. It's unknown how the kernel handles addr=0 when the memorytype is not the application memorytype. When addr is non-zero, it must be located in memory which is already mapped.
+
If something was already registered for the given ID, svcBindInterrupt returns error 0xD8E007F0. See [[KBaseInterruptEvent]] for more information on what happens on receipt of an interrupt.
  
ControlProcessMemory maps memory in the specified process, this is the only SVC which allows mapping executable memory. Format of the permissions field for memory mapping SVCs: bit0=R, bit1=W, bit2=X. Type6 sets the Addr0 memory permissions to the input permissions, for already mapped memory. Type is the MemoryOperation enum, without the memory-type/memory-region. ControlProcessMemory only supports type4, type5, and type6. ControlProcessMemory does not support using the current KProcess handle alias.
+
Applications hence can wait for specific interrupts to happen by calling WaitSynchronization(N) on the event or semaphore handles.
  
MapProcessMemory maps RW memory starting at address 0x00100000 in the specified KProcess, at the specified StartAddr in the current process. MapProcessMemory then maps 0x08000000 in the specified process, to StartAddr+0x7f00000 in the current process. UnmapProcessMemory unmaps the memory which was mapped by MapProcessMemory.
+
The set of existing ARM11 interrupts is listed on [[ARM11 Interrupts|this page]].
  
 
= Debugging =
 
= Debugging =
 
DebugActiveProcess is used to attach to a process for debugging. This SVC can only be used when the target process' ARM11 descriptors stored in the exheader have the kernel flag for "Enable debug" set. Otherwise when that flag is clear, the kernel flags for the process using this SVC must have the "Force debug" flag set.
 
DebugActiveProcess is used to attach to a process for debugging. This SVC can only be used when the target process' ARM11 descriptors stored in the exheader have the kernel flag for "Enable debug" set. Otherwise when that flag is clear, the kernel flags for the process using this SVC must have the "Force debug" flag set.
 +
 +
This SVC can only be used when a certain kernel state debug flag is non-zero(it's set to zero for retail).
  
 
= KernelSetState =
 
= KernelSetState =
 +
KernelSetState uses the 6th [[ARM11_Interrupts#Private_Interrupts|software-generated interrupt]] for any operation involving synchronization between cores.
 +
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 790: Line 1,283:
 
| Yes
 
| Yes
 
| No
 
| No
| This initializes the programID for launching [[FIRM]], then triggers launching [[FIRM]]. Param0 and Param2 are unused. Param1 is the programID-low, and the programID-high is 0x00040138.
+
| Arguments : <code>u64 firmTitleID</code> (the high 32-bits of that title ID (0 when using N3DS pm) have a special meaning on N3DS, they're otherwise ignored, see below).
 +
This initializes the programID for launching [[FIRM]], then triggers launching [[FIRM]]. With New3DS kernel, it forces the firm title ID to be the New3DS NATIVE_FIRM, when the input firm title ID is 2. The high firm title ID is always set to 0x40138. On New3DS, the kernel disables the additional New3DS cache hw prior to calling the firmlaunch function from the <handler for the KernelSetState-types called via funcptr>.
 
|-
 
|-
 
| 1
 
| 1
 
| Yes
 
| Yes
 
| Yes
 
| Yes
| Unknown, does nothing with the TWL_FIRM ARM11 kernel.
+
| Does nothing.
 
|-
 
|-
 
| 2
 
| 2
 
| Yes
 
| Yes
 
| Yes
 
| Yes
| ?
+
| Powers down the GPU and syncs with Process9 (waits for <code>*(vu8 *)PXI_SYNC11</code> to be 1) during the process.
 +
On New3DS, the kernel disables the additional New3DS cache hw, when it's actually enabled, prior to executing the rest of the code from the <handler for the KernelSetState-types called via funcptr>.
 
|-
 
|-
 
| 3
 
| 3
 
| Yes
 
| Yes
 
| No
 
| No
| This used for initializing the 0x1000-byte buffer used by the launched [[FIRM]]. Param2 is unused. When Param0 is value 1, this buffer is copied to the beginning of FCRAM at 0xF0000000, and Param1 is unused. When Param0 is value 0, this kernel buffer is mapped to process address Param1.
+
| Arguments: <code>0, void* address</code> or <code>1</code>
 +
This used for initializing the 0x1000-byte buffer used by the launched [[FIRM]]. When the first parameter is 1, this buffer is copied to the beginning of FCRAM at 0xE0000000. When it is 0, this kernel buffer is mapped to the process address specified by the second argument.
 
|-
 
|-
 
| 4
 
| 4
 
| No
 
| No
 
| Yes
 
| Yes
| Param0-Param3 are unused. This unmaps(?) the following virtual memory by writing value physaddr(where physaddr base is 0x80000000) to the L1 MMU table entries: 0x00300000..0x04300000, 0x08000000..0x0FE00000, and 0x10000000..0xF8000000.
+
| This unmaps(?) the following virtual memory by writing value physaddr (where physaddr base is 0x80000000) to the L1 MMU table entries: 0x00300000..0x04300000, 0x08000000..0x0FE00000, and 0x10000000..0xF8000000.
 
|-
 
|-
 
| 5
 
| 5
 
| Yes
 
| Yes
 
| Yes
 
| Yes
| ?
+
| Power state change. Takes one u32 parameter.
 +
 
 +
0: shutdown/reboot. hangs the Arm11. Used by kernelpanic and PTM. This makes all cores enter a WFI/B infinite loop.
 
|-
 
|-
 
| 6
 
| 6
 
| Yes
 
| Yes
 
| No
 
| No
| Debug related?
+
| Arguments: <code>u32 what, u64 val</code>
 +
UNITINFO needs to be non-zero for <code>what</code> 1 and 2.
 +
 
 +
If <code>what</code> is 0 or any invalid value, nothing is done.
 +
 
 +
If it is 1, <code>val != 0</code> is written to the global variable enabling ERR:F-format register dumps on user-mode CPU/VFP exceptions (the VFP exception handler acts as if this variable was always true and works on retail environments). The user handler, stack pointer to use for exception handling, and pointer to use for the exception info structure are contiguously located in either the thread's TLS, or if the handler is NULL, in the main thread's TLS, at offset 0x40. If the specified stack pointer is 1, sp_usr - 0x5c is used instead; if the specified exception info buffer is 1, sp_usr - 0x5c is used instead, and if it is 0, <specified stack> - 0x5c is used (0x5c is the size of the exception info structure that is being pushed). Configured by NS on startup on dev-units (default being 0 on non-debugger/jtag units) using the 0x000F0000 configuration block in the [[Config_Savegame|config savegame]].
 +
 
 +
If 2, kernelpanic will be called when svcBreak is used by a non-attached process. Configured by NS on startup on dev-units (default being 0 on non-debugger/jtag units) using the 0x000F0000 configuration block in the [[Config_Savegame|config savegame]].
 +
 
 +
If 3, this changes the scheduling/preemption mode (when no threads are being preempted, otherwise returns error 0xC8A01414), see [[KResourceLimit]] for more details.
 
|-
 
|-
 
| 7
 
| 7
 
| Yes
 
| Yes
 
| No
 
| No
| This triggers ARM11 kernel [[I2C]] code, Param0-Param3 are unused. This ARM11 kernel I2C code will never return. Device address 0x4a via the second I2C bus is used here. This triggers a hardware system reboot via poking an I2C MCU register: register address 0x20 is written to with value 4.
+
| This triggers an MCU (hard) reboot. This reboot is triggered via device address 0x4A on the second [[I2C]] bus (the MCU). Register address 0x20 is written to with value 4. This code will not return.
 +
On New3DS, the kernel disables the additional New3DS cache hw prior to calling the reboot function from the <handler for the KernelSetState-types called via funcptr>.
 
|-
 
|-
 
| 8
 
| 8
 
| Yes
 
| Yes
 
| No
 
| No
| Alternate unused FIRM launch code-path, with different [[PXI]] FIFO word constants.
+
| Hangs the Arm9, using a code path similar to the one used on firmlaunch. Used by PTM on shutdown/reboot.
 
|-
 
|-
 
| 9
 
| 9
 
| Yes, implemented at some point after system-version v4.5.
 
| Yes, implemented at some point after system-version v4.5.
 
| ?
 
| ?
| Unknown
+
| Argumens: <code>u64 titleID</code>.
 +
When creating a process, if the process has a non-zero TID equal to the parameter above (which is stored in a global variable), then KProcessHwInfo+0x32 ("process is the currently running app") is set to <code>true</code>.
 +
Used by NS conditionally based on the contents of the [[NS CFA]].
 +
|-
 +
| 10
 +
| Yes
 +
| ?
 +
| Arguments: <code>u32 config</code>
 +
ConfigureNew3DSCPU. Only available for the [[New_3DS]] kernel. The actual code for processing this runs under the <handler for the KernelSetState-types called via funcptr>, which runs on all ARM11 cores. Only bit0-1 of the argument are used here. Bit 0 enables higher core clock, and bit 1 enables additional (L2) cache. This configures the hardware [[PDN_Registers|register]] for the flags listed [[NCCH/Extended_Header#Flag1|here]], among other code which uses the MPCore private memory region registers.
 
|}
 
|}
  
Line 859: Line 1,375:
 
| 3
 
| 3
 
| This writes the total used memory size in the BASE memory region to out.
 
| This writes the total used memory size in the BASE memory region to out.
 +
|-
 +
| 2
 +
| Unused
 +
| This writes the FCRAM memory [[Memory_Allocation#FCRAM_Region_Data|used by the kernel]] to out.
 +
|-
 +
| 25
 +
| Unused
 +
| This writes the total number of threads which were directly launched by the kernel, to out. No longer exists with some kernel version?
 
|-
 
|-
 
| 26
 
| 26
Line 865: Line 1,389:
 
|}
 
|}
  
= CreateProcess =
+
= GetProcessInfo =
  struct CreateProcessInfo {
+
Input:
// All addresses are given virtual for the process to be created.
+
R0 = unused
// All sizes/offsets are in given in 0x1000-pages.
+
R1 = Handle process
u8  codeset_name[8];
+
R2 = ProcessInfoType type
u32 text_addr;
+
 
u32 text_size;
+
Output:
u32 ro_addr;
+
R0 = Result
u32 ro_size;
+
R1 = output value lower word
u32 data_addr;
+
  R2 = output value upper word
u32 data_size;
+
 
u32 ro_offset;
+
{| class="wikitable" border="1"
u32 data_offset;
+
!  ProcessInfoType value
u32 bss_size+data_size;
+
!  Available since system version
u8  program_id[8];
+
!  Description
u32 hmm?[2];
+
|-
  }
+
| 0
 +
|
 +
| Returns the amount of private (code, data, regular heap) and shared memory used by the process + total supervisor-mode stack size + page-rounded size of the external handle table. This is the amount of physical memory the process is using, minus TLS, main thread stack and linear memory.
 +
|-
 +
| 1
 +
|
 +
| Returns the amount of <related unused field> + total supervisor-mode stack size + page-rounded size of the external handle table
 +
|-
 +
| 2
 +
|
 +
| Returns the amount of private (code, data, heap) memory used by the process + total supervisor-mode stack size + page-rounded size of the external handle table
 +
|-
 +
| 3
 +
|
 +
| Returns the amount of <related unused field> + total supervisor-mode stack size + page-rounded size of the external handle table
 +
|-
 +
| 4
 +
|
 +
| Returns the amount of handles in use by the process.
 +
|-
 +
| 5
 +
|
 +
| Returns the highest count of handles that have been open at once by the process
 +
|-
 +
| 6
 +
|
 +
| Returns <code>*(u32*)(KProcess+0x234)</code> which is always 0
 +
|-
 +
| 7
 +
|
 +
| Returns the number of threads of the process
 +
|-
 +
| 8
 +
|
 +
| Returns the maximum number of threads which can be opened by this process (always 0)
 +
|-
 +
| 9-18
 +
| [[8.0.0-18]]
 +
| This only returns error 0xD8E007ED.
 +
|-
 +
| 19
 +
| Stub: [[8.0.0-18]]. Implementation: [[11.3.0-36|11.3.0-X]].
 +
| Originally this only returned 0xD8E007ED. Now with v11.3 this returns the memregion for the process: out low u32 = [[KProcess]] "Kernel flags from the exheader kernel descriptors" & 0xF00 (memory region flag). High out u32 = 0.
 +
|-
 +
| 20
 +
| [[8.0.0-18]]
 +
| low u32 = (0x20000000 - <LINEAR virtual-memory base for this process>). That is, the output value is the value which can be added to LINEAR memory vaddrs for converting to physical-memory addrs.
 +
|-
 +
| 21
 +
| [[8.0.0-18]]. N3DS only.
 +
| Returns the VA -> PA conversion offset for the QTM static mem block reserved in the exheader (0x800000), otherwise 0 (+ error 0xE0E01BF4) if it doesn't exist
 +
|-
 +
| 22
 +
| [[8.0.0-18]]. N3DS only.
 +
| Returns the base VA of the QTM static mem block reserved in the exheader, otherwise 0 (+ error 0xE0E01BF4) if it doesn't exist
 +
|-
 +
| 23
 +
| [[8.0.0-18]]. N3DS only.
 +
| Returns the size of the QTM static mem block reserved in the exheader, otherwise 0 (+ error 0xE0E01BF4) if it doesn't exist
 +
|}
 +
 
 +
= GetHandleInfo =
 +
 
 +
{| class="wikitable" border="1"
 +
!  HandleInfoType value
 +
!  Description
 +
|-
 +
| 0
 +
| This returns the time in ticks the KProcess referenced by the handle was created. If a KProcess handle was not given, it will write whatever was in r5, r6 when the svc was called.
 +
|-
 +
| 1
 +
| Get internal refcount for kernel object (not counting the one this SVC adds internally to operate), sign-extended to 64 bits.
 +
|-
 +
| 2
 +
| Unimplemented, returns an uninitialized u64 variable (corresponding to r5-r6, which were not altered outside of userland).
 +
|-
 +
| 0x32107
 +
| Returns (u64) 0.
 +
|}
 +
 
 +
= svc7B Backdoor =
 +
This saves SVC-mode SP+LR on the user-mode stack, then sets the SVC-mode SP to the user-mode SP. This then calls the specified code in SVC-mode. Once the called code returns, this pops the saved SP+LR off the stack for restoring the SVC-mode SP, then returns from the svc7b handler. Note that this svc7b handler does not disable IRQs, if any IRQs/context-switches occur while the SVC-mode SP is set to the user-mode one here, the ARM11-kernel will crash(which hangs the whole ARM11-side system).
 +
 
 +
= svc 0x59 =
 +
Implemented with [[11.3.0-36|11.3.0-X]]. Used with GSP module starting with that version. This always returns 0.
 +
 
 +
When input_flag is not 0x1, it will use value 0x0 internally. When a state field already matches input_flag, this will immediately return. Otherwise, after this SVC finishes running, it will write input_flag to this state field. GSP module uses 0x0 for APPLICATION-memregionid and 0x1 for non-APPLICATION-memregionid.
 +
 
 +
This writes "<nowiki>0x100 | <val></nowiki>" to [[CONFIG11_Registers#CFG11_GPUPROT|pdnregbase+0x140]], where val depends on input_flag and a kernel state field for [[Configuration_Memory|APPMEMTYPE]].
 +
 
 +
When input_flag is 0x1 val is fixed:
 +
* Old3DS: 0x3
 +
* New3DS: 0x460
 +
 
 +
Otherwise, val depends on the kernel APPMEMTYPE state field:
 +
{| class="wikitable" border="1"
 +
|-
 +
!  FIRM
 +
!  [[Memory_layout|APPMEMTYPE]]
 +
! val
 +
|-
 +
| Old3DS
 +
| 2
 +
| 0x3
 +
|-
 +
| Old3DS
 +
| 3
 +
| 0x5
 +
|-
 +
| Old3DS
 +
| 4
 +
| 0x6
 +
|-
 +
| Old3DS
 +
| Non-value-{2/3/4}
 +
| 0x7
 +
|-
 +
| New3DS
 +
| 7
 +
| 0x490
 +
|-
 +
| New3DS
 +
| Non-value-7
 +
| 0x4F0
 +
|}
 +
 
 +
This same register is also initialized during kernel boot starting with [[3.0.0-5]], with the following values:
 +
* Old3DS: 0x103
 +
* New3DS: 0x550
 +
 
 +
= svc 0x5A =
 +
Like what NWM did previously, this one does the following:
 +
 
 +
  if (in_flag)
 +
    CFG11_WIFICNT |= 1;
 +
  else
 +
    CFG11_WIFICNT &= ~1;
  
 
= Kernel error-codes =
 
= Kernel error-codes =
Line 889: Line 1,549:
 
!  Error-code value
 
!  Error-code value
 
!  Description
 
!  Description
 +
|-
 +
| 0x09401BFE
 +
| Timeout occurred with svcWaitSynchronization*, when timeout is not ~0.
 +
|-
 +
| 0xC8601801
 +
| No more unused/free synchronization objects left to use in a given object's linked list.  (KEvent, KMutex, KTimer, KSemaphore, KAddressArbiter, KThread)
 +
|-
 +
| 0xC8601802
 +
| No more unused/free KSharedMemory objects left to use in the KSharedMemory linked list - out of blocks
 +
|-
 +
| 0xC8601809
 +
| No more unused/free KSessions left to use in the KSession linked list - out of sessions
 
|-
 
|-
 
| 0xC860180A
 
| 0xC860180A
Line 894: Line 1,566:
 
|-
 
|-
 
| 0xC920181A
 
| 0xC920181A
| The session was closed due to the other process terminating / calling svcBreak.
+
| The session was closed by the other process..
 +
|-
 +
| 0xD0401834
 +
| Max connections to port have been exceeded
 +
|-
 +
| 0xD8609013
 +
| Unknown, probably reslimit related?
 +
|-
 +
| 0xD88007FA
 +
| Returned if no KObjectName object in the linked list  of such objects matches the port name provided to the svc.
 +
|-
 +
| 0xD8E007ED
 +
| This indicates that a value is outside of the enum being used.
 +
|-
 +
| 0xD8E007F1
 +
| This error indicates Misaligned address.
 
|-
 
|-
 
| 0xD8E007F7
 
| 0xD8E007F7
| This error indicates Misaligned address.
+
| This error indicates that the input handle used with the SVC does not exist in the process handle-table, or that the handle kernel object type does not match the type used by the SVC.
 +
|-
 +
| 0xD9000402
 +
| Invalid memory permissions for input/output buffers, for svcStartInterProcessDma.
 +
|-
 +
| 0xD9001814
 +
| Failed unprivileged load or store - wrong permissions on memory
 +
|-
 +
| 0xD9001BF7
 +
| This error is returned when the kernel retrieves a pointer to a kernel object, but the object type doesn't match the desired one.
 
|-
 
|-
 
| 0xD92007EA
 
| 0xD92007EA
 
| This error is returned when a process attempts to use svcCreateMemoryBlock when the process memorytype is the application memorytype, and when addr=0.
 
| This error is returned when a process attempts to use svcCreateMemoryBlock when the process memorytype is the application memorytype, and when addr=0.
 
|-
 
|-
| 0xD8E007F1
+
| 0xE0E01BF5
| This error indicates that the input handle used with the SVC does not exist in the process handle-table, or that the handle kernel object type does not match the type used by the SVC.
+
| This indicates an invalid address was used.
 
|-
 
|-
 
| 0xF8C007F4
 
| 0xF8C007F4
| Invalid type/param0-param3 input for svcKernelSetState.
+
| Invalid type/param0-param3 input for svcKernelSetState. This is also returned for those syscalls marked as stubs.
 
|}
 
|}

Latest revision as of 01:35, 30 November 2023

System calls[edit]

Note: The argument-lists here apply to the official syscall wrapper-functions that are found in userland processes. The actual ordering passed to the kernel via the SVC instruction is documented in Kernel ABI.

Id NF ARM11 NF ARM9 TF ARM11 Description Notes
0x01 Yes No No Result ControlMemory(u32* outaddr, u32 addr0, u32 addr1, u32 size, MemoryOperation operation, MemoryPermission permissions) Outaddr is usually the same as the input addr0.
0x02 Yes No No Result QueryMemory(MemoryInfo* info, PageInfo* out, u32 Addr)
0x03 Yes No No void ExitProcess(void)
0x04 Yes No No Result GetProcessAffinityMask(u8* affinitymask, Handle process, s32 processorcount)
0x05 Yes No No Result SetProcessAffinityMask(Handle process, u8* affinitymask, s32 processorcount)
0x06 Yes No No Result GetProcessIdealProcessor(s32 *idealprocessor, Handle process)
0x07 Yes No No Result SetProcessIdealProcessor(Handle process, s32 idealprocessor)
0x08 Yes Yes Yes Result CreateThread(Handle* thread, func entrypoint, u32 arg, u32 stacktop, s32 threadpriority, s32 processorid)
0x09 Yes Yes Yes void ExitThread(void)
0x0A Yes Yes Yes void SleepThread(s64 nanoseconds)
0x0B Yes Yes Yes Result GetThreadPriority(s32* priority, Handle thread)
0x0C Yes Yes Yes Result SetThreadPriority(Handle thread, s32 priority)
0x0D Yes No No Result GetThreadAffinityMask(u8* affinitymask, Handle thread, s32 processorcount)
0x0E Yes No No Result SetThreadAffinityMask(Handle thread, u8* affinitymask, s32 processorcount) Replaced with a stub in ARM11 NATIVE_FIRM kernel beginning with 8.0.0-18.
0x0F Yes No No Result GetThreadIdealProcessor(s32* processorid, Handle thread)
0x10 Yes No No Result SetThreadIdealProcessor(Handle thread, s32 processorid) Replaced with a stub in ARM11 NATIVE_FIRM kernel beginning with 8.0.0-18.
0x11 Yes No No s32 GetCurrentProcessorNumber(void)
0x12 Yes No No Result Run(Handle process, StartupInfo* info) This starts the main() thread. Buf+0 is main-thread priority, Buf+4 is main-thread stack-size.
0x13 Yes Yes Yes Result CreateMutex(Handle* mutex, bool initialLocked)
0x14 Yes Yes Yes Result ReleaseMutex(Handle mutex)
0x15 Yes Yes Yes Result CreateSemaphore(Handle* semaphore, s32 initialCount, s32 maxCount)
0x16 Yes Yes Yes Result ReleaseSemaphore(s32* count, Handle semaphore, s32 releaseCount)
0x17 Yes Yes Yes Result CreateEvent(Handle* event, ResetType resettype)
0x18 Yes Yes Yes Result SignalEvent(Handle event)
0x19 Yes Yes Yes Result ClearEvent(Handle event)
0x1A Yes Yes Yes Result CreateTimer(Handle* timer, ResetType resettype)
0x1B Yes Yes Yes Result SetTimer(Handle timer, s64 initial_nanoseconds, s64 interval)
0x1C Yes Yes Yes Result CancelTimer(Handle timer)
0x1D Yes Yes Yes Result ClearTimer(Handle timer)
0x1E Yes No No Result CreateMemoryBlock(Handle* memblock, u32 addr, u32 size, MemoryPermission mypermission, MemoryPermission otherpermission)
0x1F Yes No No Result MapMemoryBlock(Handle memblock, u32 addr, MemoryPermission mypermissions, MemoryPermission otherpermission)
0x20 Yes No No Result UnmapMemoryBlock(Handle memblock, u32 addr)
0x21 Yes Yes Yes Result CreateAddressArbiter(Handle* arbiter)
0x22 Yes Yes Yes Result ArbitrateAddress(Handle arbiter, u32 addr, ArbitrationType type, s32 value, s64 nanoseconds)
0x23 Yes Yes Yes Result CloseHandle(Handle handle)
0x24 Yes Yes Yes Result WaitSynchronization1(Handle handle, s64 timeout_nanoseconds)
0x25 Yes Yes Yes Result WaitSynchronizationN(s32* out, Handle* handles, s32 handlecount, bool waitAll, s64 timeout_nanoseconds)
0x26 Yes No No Result SignalAndWait(s32* out, Handle signal, Handle* handles, s32 handleCount, bool waitAll, s64 nanoseconds) Stubbed
0x27 Yes Yes Yes Result DuplicateHandle(Handle* out, Handle original)
0x28 Yes Yes Yes s64 GetSystemTick(void) (This returns the total CPU ticks elapsed since the CPU was powered-on)
0x29 Yes No No Result GetHandleInfo(s64* out, Handle handle, HandleInfoType type)
0x2A Yes Yes Yes Result GetSystemInfo(s64* out, SystemInfoType type, s32 param)
0x2B Yes Yes Yes Result GetProcessInfo(s64* out, Handle process, ProcessInfoType type)
0x2C Yes Yes Yes Result GetThreadInfo(s64* out, Handle thread, ThreadInfoType type)
0x2D Yes No No Result ConnectToPort(Handle* out, const char* portName)
0x2E Yes No No Result SendSyncRequest1(Handle session) Stubbed
0x2F Yes No No Result SendSyncRequest2(Handle session) Stubbed
0x30 Yes No No Result SendSyncRequest3(Handle session) Stubbed
0x31 Yes No No Result SendSyncRequest4(Handle session) Stubbed
0x32 Yes No No Result SendSyncRequest(Handle session)
0x33 Yes No No Result OpenProcess(Handle* process, u32 processId)
0x34 Yes No No Result OpenThread(Handle* thread, Handle process, u32 threadId)
0x35 Yes No Yes Result GetProcessId(u32* processId, Handle process)
0x36 Yes No No Result GetProcessIdOfThread(u32* processId, Handle thread)
0x37 Yes Yes Yes Result GetThreadId(u32* threadId, Handle thread)
0x38 Yes No No Result GetResourceLimit(Handle* resourceLimit, Handle process)
0x39 Yes No No Result GetResourceLimitLimitValues(s64* values, Handle resourceLimit, LimitableResource* names, s32 nameCount)
0x3A Yes No No Result GetResourceLimitCurrentValues(s64* values, Handle resourceLimit, LimitableResource* names, s32 nameCount)
0x3B Yes No No Result GetThreadContext(ThreadContext* context, Handle thread) Stubbed
0x3C Yes Yes Yes Break(BreakReason reason)

Break(BreakReason debugReason, const void* croInfo, u32 croInfoSize)

0x3D Yes Yes Yes OutputDebugString(void const, int) Does nothing on non-debug units.
0x3E Yes No No ControlPerformanceCounter(unsigned long long, int, unsigned int, unsigned long long)
0x47 Yes No No Result CreatePort(Handle* portServer, Handle* portClient, const char* name, s16 maxSessions) Setting name=NULL creates a private port not accessible from svcConnectToPort.
0x48 Yes No No Result CreateSessionToPort(Handle* session, Handle port)
0x49 Yes No No Result CreateSession(Handle* sessionServer, Handle* sessionClient)
0x4A Yes No No Result AcceptSession(Handle* session, Handle port)
0x4B Yes No No Result ReplyAndReceive1(s32* index, Handle* handles, s32 handleCount, Handle replyTarget) Stubbed.
0x4C Yes No No Result ReplyAndReceive2(s32* index, Handle* handles, s32 handleCount, Handle replyTarget) Stubbed.
0x4D Yes No No Result ReplyAndReceive3(s32* index, Handle* handles, s32 handleCount, Handle replyTarget) Stubbed.
0x4E Yes No No Result ReplyAndReceive4(s32* index, Handle* handles, s32 handleCount, Handle replyTarget) Stubbed.
0x4F Yes No No Result ReplyAndReceive(s32* index, Handle* handles, s32 handleCount, Handle replyTarget)
0x50 Yes Yes Yes Result BindInterrupt(Interrupt name, Handle eventOrSemaphore, s32 priority, bool isLevelHighActive)
0x51 Yes Yes Yes Result UnbindInterrupt(Interrupt name, Handle eventOrSemaphore)
0x52 Yes Yes Yes Result InvalidateProcessDataCache(Handle process, void* addr, u32 size)
0x53 Yes Yes Yes Result StoreProcessDataCache(Handle process, void const* addr, u32 size)
0x54 Yes Yes Yes Result FlushProcessDataCache(Handle process, void const* addr, u32 size)
0x55 Yes Yes Yes Result StartInterProcessDma(Handle* dma, Handle dstProcess, void* dst, Handle srcProcess, const void* src, u32 size, const DmaConfig* config)
0x56 Yes Yes Yes Result StopDma(Handle dma)
0x57 Yes Yes Yes Result GetDmaState(DmaState* state, Handle dma)
0x58 Yes Yes Yes RestartDma(Handle, void *, void const*, unsigned int, signed char)
0x59 Yes No? No SetGpuProt(s8 input_flag). Implemented with 11.3.0-X, see below.
0x5A Yes No? No SetWifiEnabled(s0 input_flag). Implemented with 11.4.0-X, see below.
0x60 Yes No No Result DebugActiveProcess(Handle* debug, u32 processID)
0x61 Yes No No Result BreakDebugProcess(Handle debug)
0x62 Yes No No Result TerminateDebugProcess(Handle debug)
0x63 Yes No No Result GetProcessDebugEvent(DebugEventInfo* info, Handle debug)
0x64 Yes No No Result ContinueDebugEvent(Handle debug, u32 flags)
0x65 Yes No No Result GetProcessList(s32* processCount, u32* processIds, s32 processIdMaxCount)
0x66 Yes No No Result GetThreadList(s32* threadCount, u32* threadIds, s32 threadIdMaxCount, Handle domain)
0x67 Yes No No Result GetDebugThreadContext(ThreadContext* context, Handle debug, u32 threadId, u32 controlFlags)
0x68 Yes No No Result SetDebugThreadContext(Handle debug, u32 threadId, const ThreadContext* context, u32 controlFlags)
0x69 Yes No No Result QueryDebugProcessMemory(MemoryInfo* blockInfo, PageInfo* pageInfo, Handle debug, u32 addr)
0x6A Yes No No Result ReadProcessMemory(void* buffer, Handle debug, u32 addr, u32 size)
0x6B Yes No No Result WriteProcessMemory(Handle debug, void const* buffer, u32 addr, u32 size)
0x6C Yes No No Result SetHardwareBreakPoint(s32 registerId, u32 control, u32 value)
0x6D Yes No No GetDebugThreadParam(s64* unused, u32* out, Handle kdebug, u32 threadId, DebugThreadParameter param)
0x70 Yes No No Result ControlProcessMemory(Handle KProcess, unsigned int Addr0, unsigned int Addr1, unsigned int Size, unsigned int Type, unsigned int Permissions)
0x71 Yes No No Result MapProcessMemory(Handle process, u32 startAddr, u32 size)
0x72 Yes No No Result UnmapProcessMemory(Handle process, u32 startAddr, u32 size)
0x73 Yes No No Result CreateCodeSet(Handle* handle_out, struct CodeSetInfo, u32 code_ptr, u32 ro_ptr, u32 data_ptr)
0x74 Yes No No Result RandomStub() Stubbed
0x75 Yes No No Result CreateProcess(Handle* handle_out, Handle codeset_handle, u32 arm11kernelcaps_ptr, u32 arm11kernelcaps_num)
0x76 Yes No No TerminateProcess(Handle)
0x77 Yes No No Result SetProcessResourceLimits(Handle KProcess, Handle KResourceLimit)
0x78 Yes No No Result CreateResourceLimit(Handle *KResourceLimit)
0x79 Yes No No Result SetResourceLimitLimitValues(Handle res_limit, LimitableResource* resource_type_list, s64* resource_list, u32 count)
0x7A Yes No Yes AddCodeSegment (unsigned int Addr, unsigned int Size) Stubbed on NATIVE_FIRM beginning with 2.0.0-2. Used during TWL_FIRM boot.
0x7B Yes Yes No Backdoor(unsigned int CodeAddress) This is used on ARM9 NATIVE_FIRM.

No ARM11 processes have access to it without some form of kernelhax, and this was removed on 11.0.0-33 (for ARM11).

0x7C Yes Yes Yes KernelSetState(unsigned int Type, ...) The type determines the args to be passed
0x7D Yes No No Result QueryProcessMemory(MemInfo *Info, unsigned int *Out, Handle KProcess, unsigned int Addr)
0xFF Yes Yes Yes Stop point The svcaccesscontrol mask doesn't apply for this SVC. This svc doesn't check the "debug mode enabled" flag either. Does nothing if there is no KDebug object associated to the current process. Stubbed on ARM9 NATIVE_FIRM.

NF: NATIVE_FIRM. TF: TWL_FIRM.

Note that "stubbed" here means that the SVC only returns an error, as in the following snippet:

ROM:FFF04D98                 LDR             R0, =0xF8C007F4
ROM:FFF04D9C                 BX              LR

Types and structures[edit]

enum ResetType[edit]

Reset type Id
ONESHOT 0
STICKY 1
PULSE 2

Timers/Events may be waited on by a thread using svcWaitSynchronization. Once the timer runs out/the event gets signaled, threads waiting on the respective handles until the timer/event is reset. STICKY timers/events wake up threads until they are explicitly reset by some thread. ONESHOT timers/events will wake up exactly one thread and then are reset automatically. PULSE timers will be reset after waking up one thread too, but will also be started again immediately. It's unknown whether PULSE is a valid reset type for events.

struct StartupInfo[edit]

Type Field
s32 Priority
u32 Stack size
s32 argc
s16* argv
s16* envp

enum BreakReason[edit]

Break Reason Value
PANIC 0
ASSERT 1
USER 2

struct DebugEventInfo[edit]

Size: 0x28 bytes

When using svcGetProcessDebugEvent, the kernel fetches the first KEventInfo instance of the process's KDebug. The debug event is handled and parsed into this structure.

Type Field
u32 Event type
u32 Thread ID (not used in all events)
u32 Flags. Bit0 means that svcContinueDebugEvent needs to be called for this event
u8[4] Remnants of the corresponding flags in KEventInfo, always 0 here
u32[6] Event-specific data (see below)
Event type Id
ATTACH PROCESS 0
ATTACH THREAD 1
EXIT THREAD 2
EXIT PROCESS (1) 3
EXCEPTION 4
DLL LOAD (3) 5
DLL UNLOAD (3) 6
SCHEDULE IN (1) (2) 7
SCHEDULE OUT (1) (2) 8
SYSCALL IN (1) (2) 9
SYSCALL OUT (1) (2) 10
OUTPUT STRING 11
MAP (1) (2) 12

(1) Non-blocking: all other events preempt and block all the threads of their process until they are continued.

(2) There is handling code in the kernel but nothing signal those events.

(3) Completely removed from the kernel, but referenced in DMNT. Stubbed relocation code (e.g., in Process9 and in PXI sysmodule) and even whole libraries (e.g., in PXI sysmodule's .rodata section) seem to indicate that Nintendo used dynamic libraries early in system development.

When calling svcDebugActiveProcess, an ATTACH PROCESS debug event is signaled, then ATTACH THREAD for each of its opened threads, then finally ATTACH BREAK.

ATTACH THREAD events are also emitted when a thread is created from an attached process.

ATTACH PROCESS event[edit]

Type Field
u64 Program ID
char[8] Process name
u32 Process ID
u32 "Other" flag. Always 0 in available kernel versions

ATTACH THREAD event[edit]

Type Field
u32 Creator thread ID (0 if attached by svcDebugActiveProcess)
void * Thread local storage
u32 * Entrypoint = .text load address of the parent process

EXIT THREAD/PROCESS events[edit]

A single u32 reason field is used.

Thread exit reasons:

Reason Id
(None) 0
TERMINATE 1
EXIT PROCESS 2
TERMINATE PROCESS 3

Process exit reasons:

Reason Id
(None) 0
TERMINATE 1
DEBUG TERMINATE 2

EXCEPTION event[edit]

Type Field
u32 Exception type
u32 Exception address
u32[4] Type-specific data, see below

Exception types:

Exception type Id
UNDEFINED INSTRUCTION 0
PREFETCH ABORT 1
DATA ABORT 2
UNALIGNED DATA ACCESS 3
ATTACH BREAK 4
STOP POINT 5
USER BREAK 6
DEBUGGER BREAK 7
UNDEFINED SYSCALL 8

UNDEFINED INSTRUCTION/PREFETCH ABORT/DATA ABORT/UNALIGNED DATA ACCESS/UNDEFINED SYSCALL events[edit]

Type Field
u32 Fault information: Fault Address Register (for DATA ABORT and UNALIGNED DATA ACCESS),

attempted SVC ID (for UNDEFINED SYSCALL), otherwise 0

STOP POINT event[edit]

Type Field
u32 Stop point type that caused the event: 0 = svc 0xFF, 1 = breakpoint, 2 = watchpoint
u32 Fault information: FAR for watchpoints, 0 otherwise

USER BREAK event[edit]

Type Field
u32 Break reason
u32[2] Info for LOAD_RO and UNLOAD_RO

User break types:

Reason Id
PANIC 0
ASSERT 1
USER 2
LOAD_RO 3
UNLOAD_RO 4

DEBUGGER BREAK event[edit]

Type Field
s32[4] IDs of the attached process's threads that were running on each core at the time of the @ref svcBreakDebugProcess call, or -1 (only the first 2 values are meaningful on O3DS).

SCHEDULE/SYSCALL IN/OUT events[edit]

Type Field
u64 Clock tick
u32 CPU ID (SCHEDULE events) Syscall (SYSCALL events)

OUTPUT STRING event[edit]

Type Field
u32 String address
u32 String size

MAP event[edit]

Type Field
u32 Mapped address
u32 Mapped size
u32 MemoryPermission
u32 MemoryState

struct ThreadContext[edit]

Size: 0xCC bytes

Offset Type Description
0x0 CpuRegisters Saved CPU registers (r0-r12, sp, lr, pc, cpsr)
0x44 FpuRegisters Saved FPU registers (d0-d15, fpscr, fpexc)

The user needs to adjust pc for exceptions that occured while in Thumb mode.

Flags for svcGetDebugThreadContext/svcSetDebugThreadContext:

Bit Description
0 Get/set CPU GPRs (r0-r12)
1 Get/set CPU SPRs (sp, lr, pc, cpsr)
2 Get/set FPU GPRs (d0-d15 aka. f0-f31)
3 Get/set FPU SPRs (fpscr, fpexc)

When setting CPSR, the following assignment is done: ctx->cpsr = ctx->cpsr & 0x7F0FDFF | userCtx->cpuRegisters.cpsr & 0xF80F0200;. This is to avoid obvious security issues.

enum DebugThreadParameter[edit]

Parameter Id
PRIORITY 0
SCHEDULING_MASK_LOW 1
CPU_IDEAL 2
CPU_CREATOR 3

typedef Handle[edit]

User-visible references to internal objects are represented by 32-bit integers called handles. Handles are only valid in the process they have been created in; hence, they cannot be exchanged between processes directly (the IPC functions provide a mean to copy handles to other processes, though).

There are a number of special-purpose handles, which provide easy access to information on objects in the current process:

Handle Description
0xFFFF8000 Handle to the active thread
0xFFFF8001 Handle to the active process

svcSetHardwareBreakPoint[edit]

This is essentially an interface for writing values to the debug-unit (B/W)RP registers. registerId range 0..5 = breakpoints(BRP0-5), 0x100..0x101 = watchpoints(WRP0-1), anything outside of these ranges will result in an error. This is used for both adding and removing/disabling breakpoints/watchpoints, hence the raw control value parameter.

Here the kernel sets bit15 in the DSCR, to enable monitor-mode debugging.

Regardless of whether this is for a BRP, when bit21 is set in the control input parameter(BRP type = contextID), the kernel will load the target process contextID and use that internally for the value field. The target process is specified via a KDebug handle passed as the "value" parameter.

Lastly, the kernel disables the specified (B/W)RP, then writes the value parameter / loaded contextID to the (B/W)VR, then writes the input control value to the (B/W)CR.

DMA[edit]

The CTRSDK code for using svcStartInterProcessDma will execute svcBreak when svcStartInterProcessDma returns an error(except for certain error value(s)). Therefore on retail, triggering a svcStartInterProcessDma via a system-module which results in an error from svcStartInterProcessDma will result in the system-module terminating.

Interrupt Handling[edit]

svcBindInterrupt registers the given event or semaphore corresponding to the handle to the global "interrupt table" for the given interrupt ID. Interrupts 0-14 and 16-31 can never be mapped regardless of the interrupt flags of the process's exheader, and the latter are not checked when mapping interrupt 15. The "is level high active"/"is manual clear" parameter must be false when binding a semaphore handle (otherwise 0xD8E007EE "invalid combination" is returned).

If something was already registered for the given ID, svcBindInterrupt returns error 0xD8E007F0. See KBaseInterruptEvent for more information on what happens on receipt of an interrupt.

Applications hence can wait for specific interrupts to happen by calling WaitSynchronization(N) on the event or semaphore handles.

The set of existing ARM11 interrupts is listed on this page.

Debugging[edit]

DebugActiveProcess is used to attach to a process for debugging. This SVC can only be used when the target process' ARM11 descriptors stored in the exheader have the kernel flag for "Enable debug" set. Otherwise when that flag is clear, the kernel flags for the process using this SVC must have the "Force debug" flag set.

This SVC can only be used when a certain kernel state debug flag is non-zero(it's set to zero for retail).

KernelSetState[edit]

KernelSetState uses the 6th software-generated interrupt for any operation involving synchronization between cores.

Type Enabled for the NATIVE_FIRM ARM11 kernel Enabled for the TWL_FIRM ARM11 kernel Description
0 Yes No Arguments : u64 firmTitleID (the high 32-bits of that title ID (0 when using N3DS pm) have a special meaning on N3DS, they're otherwise ignored, see below).

This initializes the programID for launching FIRM, then triggers launching FIRM. With New3DS kernel, it forces the firm title ID to be the New3DS NATIVE_FIRM, when the input firm title ID is 2. The high firm title ID is always set to 0x40138. On New3DS, the kernel disables the additional New3DS cache hw prior to calling the firmlaunch function from the <handler for the KernelSetState-types called via funcptr>.

1 Yes Yes Does nothing.
2 Yes Yes Powers down the GPU and syncs with Process9 (waits for *(vu8 *)PXI_SYNC11 to be 1) during the process.

On New3DS, the kernel disables the additional New3DS cache hw, when it's actually enabled, prior to executing the rest of the code from the <handler for the KernelSetState-types called via funcptr>.

3 Yes No Arguments: 0, void* address or 1

This used for initializing the 0x1000-byte buffer used by the launched FIRM. When the first parameter is 1, this buffer is copied to the beginning of FCRAM at 0xE0000000. When it is 0, this kernel buffer is mapped to the process address specified by the second argument.

4 No Yes This unmaps(?) the following virtual memory by writing value physaddr (where physaddr base is 0x80000000) to the L1 MMU table entries: 0x00300000..0x04300000, 0x08000000..0x0FE00000, and 0x10000000..0xF8000000.
5 Yes Yes Power state change. Takes one u32 parameter.

0: shutdown/reboot. hangs the Arm11. Used by kernelpanic and PTM. This makes all cores enter a WFI/B infinite loop.

6 Yes No Arguments: u32 what, u64 val

UNITINFO needs to be non-zero for what 1 and 2.

If what is 0 or any invalid value, nothing is done.

If it is 1, val != 0 is written to the global variable enabling ERR:F-format register dumps on user-mode CPU/VFP exceptions (the VFP exception handler acts as if this variable was always true and works on retail environments). The user handler, stack pointer to use for exception handling, and pointer to use for the exception info structure are contiguously located in either the thread's TLS, or if the handler is NULL, in the main thread's TLS, at offset 0x40. If the specified stack pointer is 1, sp_usr - 0x5c is used instead; if the specified exception info buffer is 1, sp_usr - 0x5c is used instead, and if it is 0, <specified stack> - 0x5c is used (0x5c is the size of the exception info structure that is being pushed). Configured by NS on startup on dev-units (default being 0 on non-debugger/jtag units) using the 0x000F0000 configuration block in the config savegame.

If 2, kernelpanic will be called when svcBreak is used by a non-attached process. Configured by NS on startup on dev-units (default being 0 on non-debugger/jtag units) using the 0x000F0000 configuration block in the config savegame.

If 3, this changes the scheduling/preemption mode (when no threads are being preempted, otherwise returns error 0xC8A01414), see KResourceLimit for more details.

7 Yes No This triggers an MCU (hard) reboot. This reboot is triggered via device address 0x4A on the second I2C bus (the MCU). Register address 0x20 is written to with value 4. This code will not return.

On New3DS, the kernel disables the additional New3DS cache hw prior to calling the reboot function from the <handler for the KernelSetState-types called via funcptr>.

8 Yes No Hangs the Arm9, using a code path similar to the one used on firmlaunch. Used by PTM on shutdown/reboot.
9 Yes, implemented at some point after system-version v4.5. ? Argumens: u64 titleID.

When creating a process, if the process has a non-zero TID equal to the parameter above (which is stored in a global variable), then KProcessHwInfo+0x32 ("process is the currently running app") is set to true. Used by NS conditionally based on the contents of the NS CFA.

10 Yes ? Arguments: u32 config

ConfigureNew3DSCPU. Only available for the New_3DS kernel. The actual code for processing this runs under the <handler for the KernelSetState-types called via funcptr>, which runs on all ARM11 cores. Only bit0-1 of the argument are used here. Bit 0 enables higher core clock, and bit 1 enables additional (L2) cache. This configures the hardware register for the flags listed here, among other code which uses the MPCore private memory region registers.

GetSystemInfo[edit]

SystemInfoType value s32 param Description
0 0 This writes the total used memory size in the following memory regions to out: APPLICATION, SYSTEM, and BASE.
0 1 This writes the total used memory size in the APPLICATION memory region to out.
0 2 This writes the total used memory size in the SYSTEM memory region to out.
0 3 This writes the total used memory size in the BASE memory region to out.
2 Unused This writes the FCRAM memory used by the kernel to out.
25 Unused This writes the total number of threads which were directly launched by the kernel, to out. No longer exists with some kernel version?
26 Unused This writes the total number of processes which were directly launched by the kernel, to out. For the NATIVE_FIRM/SAFE_MODE_FIRM ARM11 kernel, this is normally 5, for processes sm, fs, pm, loader, and pxi.

GetProcessInfo[edit]

Input:

R0 = unused
R1 = Handle process
R2 = ProcessInfoType type

Output:

R0 = Result
R1 = output value lower word
R2 = output value upper word
ProcessInfoType value Available since system version Description
0 Returns the amount of private (code, data, regular heap) and shared memory used by the process + total supervisor-mode stack size + page-rounded size of the external handle table. This is the amount of physical memory the process is using, minus TLS, main thread stack and linear memory.
1 Returns the amount of <related unused field> + total supervisor-mode stack size + page-rounded size of the external handle table
2 Returns the amount of private (code, data, heap) memory used by the process + total supervisor-mode stack size + page-rounded size of the external handle table
3 Returns the amount of <related unused field> + total supervisor-mode stack size + page-rounded size of the external handle table
4 Returns the amount of handles in use by the process.
5 Returns the highest count of handles that have been open at once by the process
6 Returns *(u32*)(KProcess+0x234) which is always 0
7 Returns the number of threads of the process
8 Returns the maximum number of threads which can be opened by this process (always 0)
9-18 8.0.0-18 This only returns error 0xD8E007ED.
19 Stub: 8.0.0-18. Implementation: 11.3.0-X. Originally this only returned 0xD8E007ED. Now with v11.3 this returns the memregion for the process: out low u32 = KProcess "Kernel flags from the exheader kernel descriptors" & 0xF00 (memory region flag). High out u32 = 0.
20 8.0.0-18 low u32 = (0x20000000 - <LINEAR virtual-memory base for this process>). That is, the output value is the value which can be added to LINEAR memory vaddrs for converting to physical-memory addrs.
21 8.0.0-18. N3DS only. Returns the VA -> PA conversion offset for the QTM static mem block reserved in the exheader (0x800000), otherwise 0 (+ error 0xE0E01BF4) if it doesn't exist
22 8.0.0-18. N3DS only. Returns the base VA of the QTM static mem block reserved in the exheader, otherwise 0 (+ error 0xE0E01BF4) if it doesn't exist
23 8.0.0-18. N3DS only. Returns the size of the QTM static mem block reserved in the exheader, otherwise 0 (+ error 0xE0E01BF4) if it doesn't exist

GetHandleInfo[edit]

HandleInfoType value Description
0 This returns the time in ticks the KProcess referenced by the handle was created. If a KProcess handle was not given, it will write whatever was in r5, r6 when the svc was called.
1 Get internal refcount for kernel object (not counting the one this SVC adds internally to operate), sign-extended to 64 bits.
2 Unimplemented, returns an uninitialized u64 variable (corresponding to r5-r6, which were not altered outside of userland).
0x32107 Returns (u64) 0.

svc7B Backdoor[edit]

This saves SVC-mode SP+LR on the user-mode stack, then sets the SVC-mode SP to the user-mode SP. This then calls the specified code in SVC-mode. Once the called code returns, this pops the saved SP+LR off the stack for restoring the SVC-mode SP, then returns from the svc7b handler. Note that this svc7b handler does not disable IRQs, if any IRQs/context-switches occur while the SVC-mode SP is set to the user-mode one here, the ARM11-kernel will crash(which hangs the whole ARM11-side system).

svc 0x59[edit]

Implemented with 11.3.0-X. Used with GSP module starting with that version. This always returns 0.

When input_flag is not 0x1, it will use value 0x0 internally. When a state field already matches input_flag, this will immediately return. Otherwise, after this SVC finishes running, it will write input_flag to this state field. GSP module uses 0x0 for APPLICATION-memregionid and 0x1 for non-APPLICATION-memregionid.

This writes "0x100 | <val>" to pdnregbase+0x140, where val depends on input_flag and a kernel state field for APPMEMTYPE.

When input_flag is 0x1 val is fixed:

  • Old3DS: 0x3
  • New3DS: 0x460

Otherwise, val depends on the kernel APPMEMTYPE state field:

FIRM APPMEMTYPE val
Old3DS 2 0x3
Old3DS 3 0x5
Old3DS 4 0x6
Old3DS Non-value-{2/3/4} 0x7
New3DS 7 0x490
New3DS Non-value-7 0x4F0

This same register is also initialized during kernel boot starting with 3.0.0-5, with the following values:

  • Old3DS: 0x103
  • New3DS: 0x550

svc 0x5A

Like what NWM did previously, this one does the following:

 if (in_flag)
    CFG11_WIFICNT |= 1;
 else
    CFG11_WIFICNT &= ~1;

Kernel error-codes[edit]

See Error codes.

Error-code value Description
0x09401BFE Timeout occurred with svcWaitSynchronization*, when timeout is not ~0.
0xC8601801 No more unused/free synchronization objects left to use in a given object's linked list. (KEvent, KMutex, KTimer, KSemaphore, KAddressArbiter, KThread)
0xC8601802 No more unused/free KSharedMemory objects left to use in the KSharedMemory linked list - out of blocks
0xC8601809 No more unused/free KSessions left to use in the KSession linked list - out of sessions
0xC860180A Not enough free memory available for memory allocation.
0xC920181A The session was closed by the other process..
0xD0401834 Max connections to port have been exceeded
0xD8609013 Unknown, probably reslimit related?
0xD88007FA Returned if no KObjectName object in the linked list of such objects matches the port name provided to the svc.
0xD8E007ED This indicates that a value is outside of the enum being used.
0xD8E007F1 This error indicates Misaligned address.
0xD8E007F7 This error indicates that the input handle used with the SVC does not exist in the process handle-table, or that the handle kernel object type does not match the type used by the SVC.
0xD9000402 Invalid memory permissions for input/output buffers, for svcStartInterProcessDma.
0xD9001814 Failed unprivileged load or store - wrong permissions on memory
0xD9001BF7 This error is returned when the kernel retrieves a pointer to a kernel object, but the object type doesn't match the desired one.
0xD92007EA This error is returned when a process attempts to use svcCreateMemoryBlock when the process memorytype is the application memorytype, and when addr=0.
0xE0E01BF5 This indicates an invalid address was used.
0xF8C007F4 Invalid type/param0-param3 input for svcKernelSetState. This is also returned for those syscalls marked as stubs.