System calls

Id Description
0x1 Result ControlMemory(u32* outaddr, u32 addr0, u32 addr1, u32 size, u32 operation, u32 permissions) (outaddr is usually the same as the input addr0)
0x2 Result QueryMemory(MemoryInfo* info, PageInfo* out, u32 Addr)
0x3 void ExitProcess(void)
0x4 Result GetProcessAffinityMask(u8* affinitymask, Handle process, s32 processorcount)
0x5 Result SetProcessAffinityMask(Handle process, u8* affinitymask, s32 processorcount)
0x6 Result GetProcessIdealProcessor(s32 *idealprocessor, Handle process)
0x7 Result SetProcessIdealProcessor(Handle process, s32 idealprocessor)
0x8 Result CreateThread(Handle* thread, func entrypoint, u32 arg, u32 stacktop, s32 threadpriority, s32 processorid)
0x9 void ExitThread(void)
0xA void SleepThread(s64 nanoseconds)
0xB Result GetThreadPriority(s32* priority, Handle thread)
0xC Result SetThreadPriority(Handle thread, s32 priority)
0xD Result GetThreadAffinityMask(u8* affinitymask, Handle thread, s32 processorcount)
0xE Result SetThreadAffinityMask(Handle thread, u8* affinitymask, s32 processorcount)
0xF Result GetThreadIdealProcessor(s32* processorid, Handle thread)
0x10 Result SetThreadIdealProcessor(Handle thread, s32 processorid)
0x11 s32 GetCurrentProcessorNumber(void)
0x12 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 Result CreateMutex(Handle* mutex, bool initialLocked)
0x14 Result ReleaseMutex(Handle mutex)
0x15 Result CreateSemaphore(Handle* semaphore, s32 initialCount, s32 maxCount)
0x16 Result ReleaseSemaphore(s32* count, Handle semaphore, s32 releaseCount)
0x17 Result CreateEvent(Handle* event, ResetType resettype)
0x18 Result SignalEvent(Handle event)
0x19 Result ClearEvent(Handle event)
0x1A Result CreateTimer(Handle* timer, ResetType resettype)
0x1B Result SetTimer(Handle timer, s64 initial, s64 interval)
0x1C Result CancelTimer(Handle timer)
0x1D Result ClearTimer(Handle timer)
0x1E Result CreateMemoryBlock(Handle* memblock, u32 memory, u32 size, u32 mypermission, u32 otherpermission)
0x1F Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherpermission)
0x20 Result UnmapMemoryBlock(Handle memblock, u32 addr)
0x21 Result CreateAddressArbiter(Handle* arbiter)
0x22 Result ArbitrateAddress(Handle arbiter, u32 addr, ArbitrationType type, s32 value)
0x23 Result CloseHandle(Handle handle)
0x24 Result WaitSynchronization1(Handle handle, s64 nanoseconds)
0x25 Result WaitSynchronizationN(s32* out, Handle* handles, s32 handlecount, bool waitAll, s64 nanoseconds)
0x26 Result SignalAndWait(s32* out, Handle signal, Handle* handles, s32 handleCount, bool waitAll, s64 nanoseconds)
0x27 Result DuplicateHandle(Handle* out, Handle original)
0x28 s64 GetSystemTick(void) (This returns the total CPU ticks elapsed since the CPU was powered-on)
0x29 Result GetHandleInfo(s64* out, Handle handle, HandleInfoType type)
0x2A Result GetSystemInfo(s64* out, SystemInfoType type, s32 param)
0x2B Result GetProcessInfo(s64* out, Handle process, ProcessInfoType type)
0x2C Result GetThreadInfo(s64* out, Handle thread, ThreadInfoType type)
0x2D Result ConnectToPort(Handle* out, const char* portName)
0x2E Result SendSyncRequest1(Handle session) (Stubbed)
0x2F Result SendSyncRequest2(Handle session) (Stubbed)
0x30 Result SendSyncRequest3(Handle session) (Stubbed)
0x31 Result SendSyncRequest4(Handle session) (Stubbed)
0x32 Result SendSyncRequest(Handle session)
0x33 Result OpenProcess(Handle* process, u32 processId)
0x34 Result OpenThread(Handle* thread, Handle process, u32 threadId)
0x35 Result GetProcessId(u32* processId, Handle process)
0x36 Result GetProcessIdOfThread(u32* processId, Handle thread)
0x37 Result GetThreadId(u32* threadId, Handle thread)
0x38 Result GetResourceLimit(Handle* resourceLimit, Handle process)
0x39 Result GetResourceLimitLimitValues(s64* values, Handle resourceLimit, LimitableResource* names, s32 nameCount)
0x3A Result GetResourceLimitCurrentValues(s64* values, Handle resourceLimit, LimitableResource* names, s32 nameCount)
0x3B Result GetThreadContext(ThreadContext* context, Handle thread) (Stubbed)
0x3C Break(BreakReason)
0x3D OutputDebugString(void const, int) (Does nothing on non-debug units)
0x3E ControlPerformanceCounter(unsigned long long, int, unsigned int, unsigned long long)
0x47 Result CreatePort(Handle* portServer, Handle* portClient, const char* name, s32 maxSessions)
0x48 Result CreateSessionToPort(Handle* session, Handle port)
0x49 Result CreateSession(Handle* sessionServer, Handle* sessionClient)
0x4A Result AcceptSession(Handle* session, Handle port)
0x4B Result ReplyAndReceive1(s32* index, Handle* handles, s32 handleCount, Handle replyTarget) (Stubbed)
0x4C Result ReplyAndReceive2(s32* index, Handle* handles, s32 handleCount, Handle replyTarget) (Stubbed)
0x4D Result ReplyAndReceive3(s32* index, Handle* handles, s32 handleCount, Handle replyTarget) (Stubbed)
0x4E Result ReplyAndReceive4(s32* index, Handle* handles, s32 handleCount, Handle replyTarget) (Stubbed)
0x4F Result ReplyAndReceive(s32* index, Handle* handles, s32 handleCount, Handle replyTarget)
0x50 Result BindInterrupt(Interrupt name, Handle syncObject, s32 priority, bool isManualClear)
0x51 Result UnbindInterrupt(Interrupt name, Handle syncObject)
0x52 Result InvalidateProcessDataCache(Handle process, void* addr, u32 size)
0x53 Result StoreProcessDataCache(Handle process, void const* addr, u32 size)
0x54 Result FlushProcessDataCache(Handle process, void const* addr, u32 size)
0x55 Result StartInterProcessDma(Handle* dma, Handle dstProcess, void* dst, Handle srcProcess, const void* src, u32 size, const DmaConfig& config )
0x56 Result StopDma(Handle dma)
0x57 Result GetDmaState(DmaState* state, Handle dma)
0x58 RestartDma(nn::Handle, void *, void const*, unsigned int, signed char)
0x60 Result DebugActiveProcess(Handle* debug, u32 processID)
0x61 Result BreakDebugProcess(Handle debug)
0x62 Result TerminateDebugProcess(Handle debug)
0x63 Result GetProcessDebugEvent(DebugEventInfo* info, Handle debug)
0x64 Result ContinueDebugEvent(Handle debug, u32 flags)
0x65 Result GetProcessList(s32* processCount, u32* processIds, s32 processIdMaxCount)
0x66 Result GetThreadList(s32* threadCount, u32* threadIds, s32 threadIdMaxCount, Handle domain)
0x67 Result GetDebugThreadContext(ThreadContext* context, Handle debug, u32 threadId, u32 controlFlags)
0x68 Result SetDebugThreadContext(Handle debug, u32 threadId, ThreadContext* context, u32 controlFlags)
0x69 Result QueryDebugProcessMemory(MemoryInfo* blockInfo, PageInfo* pageInfo, Handle process, u32 addr)
0x6A Result ReadProcessMemory(void* buffer, Handle debug, u32 addr, u32 size)
0x6B Result WriteProcessMemory(Handle debug, void const* buffer, u32 addr, u32 size)
0x6C Result SetHardwareBreakPoint(s32 registerId, u32 control, u32 value)
0x6D GetDebugThreadParam(long long *, int *, nn::Handle, unsigned int, nn::dmnt::DebugThreadParam) (Disabled on regular kernel)
0x70 ControlProcessMemory(Handle KProcess, unsigned int Addr0, unsigned int Addr1, unsigned int Size, unsigned int Type, unsigned int Permissions)
0x71 MapProcessMemory(Handle KProcess, unsigned int StartAddr, unsigned int EndAddr)
0x72 UnmapProcessMemory(Handle KProcess, unsigned int StartAddr, unsigned int EndAddr)
0x73 ?
0x74 Stubbed on regular kernel
0x75 ?
0x76 TerminateProcess(Handle)
0x77 (Handle KProcess, Handle KResourceLimit)
0x78 CreateResourceLimit(Handle *KResourceLimit)
0x79 ?
0x7A DisableExecuteNever(unsigned int Addr, unsigned int Size) (Stubbed for regular kernel beginning with 2.0.0-2)
0x7C KernelSetState(unsigned int Type, unsigned int Param0, unsigned int Param1, unsigned int Param2) (The Type determines the usage of each param)
0x7D QueryProcessMemory(MemInfo *Info, unsigned int *Out, Handle KProcess, unsigned int Addr)
0xFF Debug related (The Syscall access control mask doesn't apply for this SVC)

CreateThread

R0=s32 threadpriority
R1=func entrypoint
R2=u32 arg
R3=u32 stacktop
R4=s32 processorid
Result result=R0
Handle* thread=R1

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 stacktop must be aligned to 0x10-bytes, otherwise when not aligned to 0x10-bytes the ARM11 kernel clears the low 4-bits of the stacktop address.

Types and structures

enum MemoryState

Memory state flags Bit
FREE 0
RESERVED 1
IO 2
STATIC 3
CODE 4
PRIVATE 5
SHARED 6
CONTINUOUS 7
ALIASED 8
ALIAS 9
ALIAS CODE 10
LOCKED 11

enum PageFlags

Page flags Bit
LOCKED 0
CHANGED 1

enum MemoryOperation

Memory operation Id
FREE 1
RESERVE 2
COMMIT 3
MAP 4
UNMAP 5
PROTECT 6
REGION APP 0x100
REGION SYSTEM 0x200
REGION BASE 0x300
LINEAR 0x1000

enum MemoryPermission

Memory permission Id
NONE 0
READ 1
WRITE 2
READWRITE 3
DONTCARE 0x10000000


enum ResetType

Reset type Id
ONESHOT 0
STICKY 1
PULSE 2

struct MemoryInfo

Type Field
u32 Base address
u32 Size
u32 Permission
enum MemoryState State

struct PageInfo

Type Field
u32 Flags

struct StartupInfo

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


Processes

Each process can only use SVCs which are enabled in the 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.

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.

0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for the current KThread.

Calling svcBreak on retail will only terminate the process which called this SVC.

Threads

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.

Using CloseHandle() with a KThread handle will terminate the specified thread.

Memory Mapping

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

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.

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.

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.

KernelSetState

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

Type3 is 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.

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

GetSystemInfo

Type0 value 26(Type1 is unused) writes the total number of processes which were directly launched by the kernel, to Output. For the NATIVE_FIRM/SAFE_MODE_FIRM ARM11 kernel, this is normally 5, for processes sm, fs, pm, loader, and pxi.

Kernel error-codes

Error-code value Description
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.