Difference between revisions of "SVC"

From 3dbrew
Jump to navigation Jump to search
(Move some DMA stuff to its own page)
Line 1,356: Line 1,356:
 
Note that with the MAP MemoryOperation, the kernel will refuse to MAP memory for the specified addr1, when addr1 was already used with another MAP operation as addr1. The kernel also doesn't allow memory to be freed via the FREE MemoryOperation, when other virtual-memory is mapped to this same memory(when the MAP MemoryOperation was used with this memory with addr1).
 
Note that with the MAP MemoryOperation, the kernel will refuse to MAP memory for the specified addr1, when addr1 was already used with another MAP operation as addr1. The kernel also doesn't allow memory to be freed via the FREE MemoryOperation, when other virtual-memory is mapped to this same memory(when the MAP MemoryOperation was used with this memory with addr1).
  
= DMA =
+
= [[DMA]] =
 
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.
 
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.
 
==DmaConfig==
 
Size of struct is 24 bytes.
 
 
struct DmaConfig {
 
    sint8_t channel_sel; // @0 Selects which DMA channel to use: 0-7, -1 = don't care.
 
    uint8_t endian_swap_size; // @1 Accepted values: 0=none,2=16bit,4=32bit,8=64bit.
 
    uint8_t flags;      // @2 bit0: DST_CFG, bit1: SRC_CFG, bit2: SHALL_BLOCK, bit3: ???, bit6: DST_ALT_CFG, bit7: SRC_ALT_CFG
 
    uint8_t padding;
 
    uint8_t dst_cfg[10];
 
    // @5 Accepted values (u8): 4, 8, 12, 15.
 
    // @15 Accepted values (u8): 4, 8, 12, 15.
 
    uint8_t src_cfg[10]; // @14
 
}
 
 
If SRC_CFG/DST_CFG is set in the flags field, the configuration for src/dst is loaded from src_cfg/dst_cfg respectively. If the *_ALT_CFG flag is set same thing goes, except byte0 of each cfg is forced to 0xFF. ALT_CFG has priority over CFG.
 
 
If CFG or ALT_CFG is not set, default configuration is loaded:
 
FF 0F 80 00 00 00 80 00 00 00
 
 
If SHALL_BLOCK is set, the thread will sleep until the DMA engine is ready. If not set, the SVC will return 0xD04007F0 if the DMA channel is busy.
 
 
The format of src_cfg/dst_cfg is unknown, but both have the same format. Checks suggest that the second byte of cfg equalling 4 means NO_INCREMENT (don't increment after read/write).
 
 
Each src/dst config:
 
struct DmaSubConfig {
 
    uint8_t peripheral_id;  // @0
 
    uint8_t unk2;  // @1 Seen: 2
 
    uint16_t unk3; // @2
 
    uint16_t transfer_size?; // @4
 
    uint16_t unk4; // @6
 
    uint16_t unk5; // @8
 
}
 
 
The generated bytecode starts with a FLUSHP on the peripheral_ids for src/dst (if specified). After that, it always moves 0 into DAR. Then it moves the src/dst addresses into SAR/DAR respectively...
 
  
 
= Debugging =
 
= Debugging =

Revision as of 21:31, 7 June 2015

System calls

Id NF ARM11 NF ARM9 TF ARM11 Description Notes
0x01 Yes No No Result ControlMemory(u32* outaddr, u32 addr0, u32 addr1, u32 size, u32 operation, u32 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, 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, u32 mypermission, u32 otherpermission)
0x1F Yes No No Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 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 nanoseconds)
0x25 Yes Yes Yes Result WaitSynchronizationN(s32* out, Handle* handles, s32 handlecount, bool waitAll, s64 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)
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, s32 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 syncObject, s32 priority, bool isManualClear)
0x51 Yes Yes Yes Result UnbindInterrupt(Interrupt name, Handle syncObject)
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(nn::Handle, void *, void const*, unsigned int, signed char)
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, ThreadContext* context, u32 controlFlags)
0x69 Yes No No Result QueryDebugProcessMemory(MemoryInfo* blockInfo, PageInfo* pageInfo, Handle process, 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(long long *, int *, nn::Handle, unsigned int, nn::dmnt::DebugThreadParam) Disabled on regular kernel.
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 KProcess, unsigned int StartAddr, unsigned int EndAddr)
0x72 Yes No No Result UnmapProcessMemory(Handle KProcess, unsigned int StartAddr, unsigned int EndAddr)
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 SetResourceLimitValues(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.
0x7C Yes Yes Yes KernelSetState(unsigned int Type, unsigned int Param0, unsigned int Param1, unsigned int Param2) The type determines the meaning of each param
0x7D Yes No No Result QueryProcessMemory(MemInfo *Info, unsigned int *Out, Handle KProcess, unsigned int Addr)
0xFF Yes Yes Yes ??? Debug related? The svcaccesscontrol mask doesn't apply for this SVC. 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

enum MemoryState

Memory state flags Value
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 0x10000

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: Addr0 is not used by the kernel after doing address-range checks. The kernel determines what physical-address to use by allocating memory from FCRAM(about the same way as other memory), which is then used to determine the virtual-address.

8.0.0-18 added a new memory mapping(0x30000000-0x38000000) for LINEAR memory, this replaces the original mapping for newer titles. The kernel uses the new mapping when the process memory-region is BASE, or when the process kernel-release-version field is >=0x022c(2.44 / system-version 8.0.0-18).

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.

enum MemoryPermission

Memory permission Id
NONE 0
R 1
W 2
RW 3
X 4
RX 5
WX 6
RWX 7
DONTCARE 0x10000000

enum ResetType

Reset type Id
ONESHOT 0
STICKY 1
PULSE 2

struct MemoryInfo

Type Field
u32 Base process virtual 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

enum ArbitrationType

Address arbitration type Value
FREE 0
AQUIRE 1
KERNEL2 2
AQUIRE_TIMEOUT 3
KERNEL4 4

enum BreakReason

Break Reason Value
PANIC 0
ASSERT 1
USER 2

struct CodeSetInfo

All addresses are given virtual for the process to be created. All sizes are given in 0x1000-pages.

Type Field
u8[8] Codeset Name
u16 Unknown, this is written to field 0x5A of KCodeSet
u16 Unknown/padding
u32 Unknown/padding
u32 .text addr
u32 .text size
u32 .rodata start
u32 .rodata size
u32 RW addr (.data + .bss)
u32 RW size (.data + .bss)
u32 Total .text pages
u32 Total .rodata pages
u32 Total RW pages (.data + .bss)
u32 Unknown/padding
u8[8] Program ID

struct DebugEventInfo

Type Field
u32 Event type
u32 Thread ID (not used in all events)
u32[2] Unknown/padding
u32[6] Event-specific data (see below)
Event type Id
PROCESS 0
CREATE THREAD 1
EXIT THREAD 2
EXIT PROCESS 3
EXCEPTION 4
DLL LOAD 5
DLL UNLOAD 6
SCHEDULE IN 7
SCHEDULE OUT 8
SYSCALL IN 9
SYSCALL OUT 10
OUTPUT STRING 11
MAP 12

PROCESS event

Type Field
u64 Program ID
char[8] Process name
u32 Process ID
u32 0 = newly created process, 1 = attached process

CREATE THREAD event

Type Field
u32 Creator thread ID
u32 Base address (?)
u32 Entrypoint

EXIT THREAD/PROCESS events

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
UNHANDLED EXCEPTION 2

EXCEPTION event

Type Field
u32 Exception type
u32 Exception address
u32 Argument (type-specific)

Exception types:

Reason Id Argument
UNDEFINED INSTRUCTION 0 (None)
(Unknown) 1 (None)
(Unknown, mem-related) 2 Address
(Unknown, mem-related) 3 Address
ATTACH BREAK 4 (None)
BREAKPOINT 5 (None)
USER BREAK 6 User break type
DEBUGGER BREAK 7 (None)
UNDEFINED SYSCALL 8 Attempted syscall ID

User break types:

Reason Id
PANIC 0
ASSERT 1
USER 2

SCHEDULER/SYSCALL IN/OUT events

Type Field
u64 Clock tick
u32 Syscall (only for SYSCALL events)

OUTPUT STRING event

Type Field
u32 String address
u32 String size

MAP event

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

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, only if the reference count reaches 0.

Lower priority values give the thread higher priority. For userland apps, priorities between 0x18 and 0x3F are allowed. The priority of the app's main thread seems to be 0x30.

The thread scheduler is cooperative, therefore if a thread takes up all the CPU time (for example if it enters an endless loop), all the other threads that run on the same CPU core won't get a chance to run. The main way of yielding another thread is using an address arbiter.

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 therefore be <=3, where value zero is used when un-mapping memory. Furthermore it appears that only regular heap pages can be mirrored (it won't work for TLS, stack, .data, .text, for example).

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.

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. Furthermore, it appears that only regular heap pages (allocated using svcControlMemory op=COMMIT) are accepted as valid addrs.

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.

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.

Note that with the MAP MemoryOperation, the kernel will refuse to MAP memory for the specified addr1, when addr1 was already used with another MAP operation as addr1. The kernel also doesn't allow memory to be freed via the FREE MemoryOperation, when other virtual-memory is mapped to this same memory(when the MAP MemoryOperation was used with this memory with addr1).

DMA

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.

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

Type Enabled for the NATIVE_FIRM ARM11 kernel Enabled for the TWL_FIRM ARM11 kernel Description
0 Yes No This initializes the programID for launching FIRM, then triggers launching FIRM. Param0 is unused. Param1 is the programID-low, and the programID-high is 0x00040138. Param2 is used only with the New_3DS kernel, pm-module uses value 0 with this. With New3DS kernel, it forces the programIDlow to be the New3DS NATIVE_FIRM, when the input programIDlow is for the Old3DS NATIVE_FIRM and Param2==0.
1 Yes Yes Unknown, does nothing with the TWL_FIRM ARM11 kernel.
2 Yes Yes ?
3 Yes 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.
4 No 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.
5 Yes Yes ?
6 Yes No Debug related?
7 Yes 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.
8 Yes No Alternate unused FIRM launch code-path, with different PXI FIFO word constants.
9 Yes, implemented at some point after system-version v4.5. ? Unknown
10 Yes ? Only available for the New_3DS kernel. It's unknown what this is used for.

GetSystemInfo

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.
25 Unused This writes the total number of threads which were directly launched by the kernel, to out.
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

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
9-19 8.0.0-18 This only returns error 0xD8E007ED.
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-23 8.0.0-18 This only returns error 0xE0E01BF4.

GetHandleInfo

HandleInfoType value Description
0 This writes back two (unknown) u32 fields from the KProcess object. If not a KProcess handle is given, it will write whatever was in r5, r7 when the svc was called.
1 Get internal refcount-1 for kernel object (u32), and also a boolean if the refcount-1 is negative (u32).
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).

Kernel error-codes

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