Changes

Jump to navigation Jump to search
6,167 bytes added ,  01:35, 30 November 2023
m
Correct svc name from switchbrew
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"
 
|-
 
|-
Line 13: Line 15:  
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
| Result ControlMemory(u32* outaddr, u32 addr0, u32 addr1, u32 size, u32 operation, u32 permissions)
+
| 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.
 
| Outaddr is usually the same as the input addr0.
 
|-
 
|-
Line 20: Line 22:  
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
| Result QueryMemory(MemoryInfo* info, PageInfo* out, u32 Addr)
+
| Result [[Memory Management|QueryMemory]]([[Memory Management#struct MemoryInfo|MemoryInfo]]* info, [[Memory Management#struct PageInfo|PageInfo]]* out, u32 Addr)
 
|
 
|
 
|-
 
|-
Line 132: Line 134:  
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
| Result Run(Handle process, StartupInfo* info)
+
| 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.
 
| This starts the main() thread. Buf+0 is main-thread priority, Buf+4 is main-thread stack-size.
 
|-
 
|-
Line 195: Line 197:  
| style="background: green" | Yes
 
| style="background: green" | Yes
 
| style="background: green" | Yes
 
| style="background: green" | Yes
| Result SetTimer(Handle timer, s64 initial, s64 interval)
+
| Result SetTimer(Handle timer, s64 initial_nanoseconds, s64 interval)
 
|
 
|
 
|-
 
|-
Line 216: Line 218:  
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
| Result CreateMemoryBlock(Handle* memblock, u32 addr, u32 size, u32 mypermission, u32 otherpermission)
+
| Result [[Memory Management|CreateMemoryBlock]](Handle* memblock, u32 addr, u32 size, [[Memory Management#enum_MemoryPermission|MemoryPermission]] mypermission, [[Memory Management#enum_MemoryPermission|MemoryPermission]] otherpermission)
 
|
 
|
 
|-
 
|-
Line 223: Line 225:  
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
| Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherpermission)
+
| Result [[Memory Management|MapMemoryBlock]](Handle memblock, u32 addr, [[Memory Management#enum_MemoryPermission|MemoryPermission]] mypermissions, [[Memory Management#enum_MemoryPermission|MemoryPermission]] otherpermission)
 
|
 
|
 
|-
 
|-
Line 230: Line 232:  
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
| Result UnmapMemoryBlock(Handle memblock, u32 addr)
+
| Result [[Memory Management|UnmapMemoryBlock]](Handle memblock, u32 addr)
 
|
 
|
 
|-
 
|-
Line 237: Line 239:  
| style="background: green" | Yes
 
| style="background: green" | Yes
 
| style="background: green" | Yes
 
| style="background: green" | Yes
| Result CreateAddressArbiter(Handle* arbiter)
+
| Result [[Multi-threading#Address_Arbiters|CreateAddressArbiter]](Handle* arbiter)
 
|
 
|
 
|-
 
|-
Line 244: Line 246:  
| style="background: green" | Yes
 
| style="background: green" | Yes
 
| style="background: green" | Yes
 
| style="background: green" | Yes
| Result ArbitrateAddress(Handle arbiter, u32 addr, ArbitrationType type, s32 value, s64 nanoseconds)
+
| Result [[Multi-threading#Address_Arbiters|ArbitrateAddress]](Handle arbiter, u32 addr, ArbitrationType type, s32 value, s64 nanoseconds)
 
|
 
|
 
|-
 
|-
Line 258: Line 260:  
| style="background: green" | Yes
 
| style="background: green" | Yes
 
| style="background: green" | Yes
 
| style="background: green" | Yes
| Result WaitSynchronization1(Handle handle, s64 nanoseconds)
+
| Result WaitSynchronization1(Handle handle, s64 timeout_nanoseconds)
 
|
 
|
 
|-
 
|-
Line 265: Line 267:  
| style="background: green" | Yes
 
| style="background: green" | Yes
 
| style="background: green" | Yes
 
| style="background: green" | Yes
| Result WaitSynchronizationN(s32* out, Handle* handles, s32 handlecount, bool waitAll, s64 nanoseconds)
+
| Result WaitSynchronizationN(s32* out, Handle* handles, s32 handlecount, bool waitAll, s64 timeout_nanoseconds)
 
|
 
|
 
|-
 
|-
Line 321: Line 323:  
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
| Result ConnectToPort(Handle* out, const char* portName)
+
| Result [[IPC|ConnectToPort]](Handle* out, const char* portName)
 
|
 
|
 
|-
 
|-
Line 360: Line 362:  
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
| Result SendSyncRequest(Handle session)
+
| Result [[IPC|SendSyncRequest]](Handle session)
 
|
 
|
 
|-
 
|-
Line 430: Line 432:  
| style="background: green" | Yes
 
| style="background: green" | Yes
 
| style="background: green" | Yes
 
| style="background: green" | Yes
| Break(BreakReason)
+
| Break(BreakReason reason)
 +
Break(BreakReason debugReason, const void* croInfo, u32 croInfoSize)
 
|
 
|
 
|-
 
|-
Line 451: Line 454:  
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
| Result CreatePort(Handle* portServer, Handle* portClient,  const char* name, s32 maxSessions)
+
| Result [[IPC|CreatePort]](Handle* portServer, Handle* portClient,  const char* name, s16 maxSessions)
 
| Setting name=NULL creates a private port not accessible from svcConnectToPort.
 
| Setting name=NULL creates a private port not accessible from svcConnectToPort.
 
|-
 
|-
Line 458: Line 461:  
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
| Result CreateSessionToPort(Handle* session, Handle port)
+
| Result [[IPC|CreateSessionToPort]](Handle* session, Handle port)
 
|
 
|
 
|-
 
|-
Line 465: Line 468:  
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
| Result CreateSession(Handle* sessionServer, Handle* sessionClient)
+
| Result [[IPC|CreateSession]](Handle* sessionServer, Handle* sessionClient)
 
|
 
|
 
|-
 
|-
Line 472: Line 475:  
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
| Result AcceptSession(Handle* session, Handle port)
+
| Result [[IPC|AcceptSession]](Handle* session, Handle port)
 
|
 
|
 
|-
 
|-
Line 507: Line 510:  
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
| Result ReplyAndReceive(s32* index, Handle* handles, s32 handleCount, Handle replyTarget)
+
| Result [[IPC#svcReplyAndReceive|ReplyAndReceive]](s32* index, Handle* handles, s32 handleCount, Handle replyTarget)
 
|
 
|
 
|-
 
|-
Line 514: Line 517:  
| style="background: green" | Yes
 
| style="background: green" | Yes
 
| style="background: green" | Yes
 
| style="background: green" | Yes
| Result BindInterrupt(Interrupt name, Handle syncObject, s32 priority, bool isManualClear)
+
| Result [[#Interrupt Handling|BindInterrupt]](Interrupt name, Handle eventOrSemaphore, s32 priority, bool isLevelHighActive)
 
|
 
|
 
|-
 
|-
Line 521: Line 524:  
| style="background: green" | Yes
 
| style="background: green" | Yes
 
| style="background: green" | Yes
 
| style="background: green" | Yes
| Result UnbindInterrupt(Interrupt name, Handle syncObject)
+
| Result UnbindInterrupt(Interrupt name, Handle eventOrSemaphore)
 
|
 
|
 
|-
 
|-
Line 549: Line 552:  
| style="background: green" | Yes
 
| style="background: green" | Yes
 
| style="background: green" | Yes
 
| style="background: green" | Yes
| Result StartInterProcessDma(Handle* dma, Handle dstProcess, void* dst, Handle srcProcess, const void* src, u32 size, const DmaConfig& config)
+
| Result [[Corelink DMA Engines|StartInterProcessDma]](Handle* dma, Handle dstProcess, void* dst, Handle srcProcess, const void* src, u32 size, const DmaConfig* config)
 
|
 
|
 
|-
 
|-
Line 570: Line 573:  
| style="background: green" | Yes
 
| style="background: green" | Yes
 
| style="background: green" | Yes
 
| style="background: green" | Yes
| RestartDma(nn::Handle, void *, void  const*, unsigned int, signed char)
+
| 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"
 
|- style="border-top: double"
 
| 0x60  
 
| 0x60  
Line 633: Line 648:  
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
| Result SetDebugThreadContext(Handle debug, u32 threadId, ThreadContext* context, u32 controlFlags)
+
| Result SetDebugThreadContext(Handle debug, u32 threadId, const ThreadContext* context, u32 controlFlags)
 
|
 
|
 
|-
 
|-
Line 640: Line 655:  
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
| Result QueryDebugProcessMemory(MemoryInfo* blockInfo, PageInfo* pageInfo, Handle process, u32 addr)
+
| Result QueryDebugProcessMemory(MemoryInfo* blockInfo, PageInfo* pageInfo, Handle debug, u32 addr)
 
|
 
|
 
|-
 
|-
Line 668: Line 683:  
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
| [[Multi-threading#GetDebugThreadParam|GetDebugThreadParam]](long long *, int *, nn::Handle, unsigned int, nn::dmnt::DebugThreadParam)
+
| [[Multi-threading#GetDebugThreadParam|GetDebugThreadParam]](s64* unused, u32* out, Handle kdebug, u32 threadId, DebugThreadParameter param)
| Disabled on regular kernel.
+
|  
 
|- style="border-top: double"
 
|- style="border-top: double"
 
| 0x70
 
| 0x70
Line 682: Line 697:  
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
| Result MapProcessMemory(Handle KProcess, unsigned int StartAddr, unsigned int EndAddr)
+
| Result [[Memory Management#Memory_Mapping|MapProcessMemory]](Handle process, u32 startAddr, u32 size)
 
|
 
|
 
|-
 
|-
Line 689: Line 704:  
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
| Result UnmapProcessMemory(Handle KProcess, unsigned int StartAddr, unsigned int EndAddr)
+
| Result [[Memory Management#Memory_Mapping|UnmapProcessMemory]](Handle process, u32 startAddr, u32 size)
 
|
 
|
 
|-
 
|-
Line 696: Line 711:  
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
| Result CreateCodeSet(Handle* handle_out, struct CodeSetInfo, u32 code_ptr, u32 ro_ptr, u32 data_ptr)
+
| Result [[Multi-threading#CreateCodeSet|CreateCodeSet]](Handle* handle_out, struct CodeSetInfo, u32 code_ptr, u32 ro_ptr, u32 data_ptr)
 
|
 
|
 
|-
 
|-
Line 710: Line 725:  
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
| Result CreateProcess(Handle* handle_out, Handle codeset_handle, u32 arm11kernelcaps_ptr, u32 arm11kernelcaps_num)
+
| Result [[Multi-threading#CreateProcess|CreateProcess]](Handle* handle_out, Handle codeset_handle, u32 [[NCCH/Extended_Header#ARM11_Kernel_Capabilities|arm11kernelcaps_ptr]], u32 arm11kernelcaps_num)
 
|
 
|
 
|-
 
|-
Line 738: Line 753:  
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
 
| style="background: red" | No
| Result SetResourceLimitValues(Handle res_limit, LimitableResource* resource_type_list, s64* resource_list, u32 count)
+
| Result SetResourceLimitLimitValues(Handle res_limit, LimitableResource* resource_type_list, s64* resource_list, u32 count)
 
|
 
|
 
|-
 
|-
Line 753: Line 768:  
| style="background: red" | No
 
| style="background: red" | No
 
| Backdoor(unsigned int CodeAddress)
 
| Backdoor(unsigned int CodeAddress)
| This is used on ARM9 NATIVE_FIRM. No ARM11 processes have access to it without some form of kernelhax.
+
| 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
Line 759: Line 776:  
| style="background: green" | Yes
 
| style="background: green" | Yes
 
| style="background: green" | Yes
 
| style="background: green" | Yes
| KernelSetState(unsigned int Type, unsigned int Param0, unsigned int Param1, unsigned int Param2)
+
| KernelSetState(unsigned int Type, ...)
| The type determines the meaning of each param
+
| The type determines the args to be passed
 
|-
 
|-
 
| 0x7D
 
| 0x7D
Line 773: Line 790:  
| style="background: green" | Yes
 
| style="background: green" | Yes
 
| style="background: green" | Yes
 
| style="background: green" | Yes
| ???
+
| Stop point
| Debug related? The svcaccesscontrol mask doesn't apply for this SVC. Stubbed on ARM9 NATIVE_FIRM.
+
| 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.
 
NF: NATIVE_FIRM. TF: TWL_FIRM.
Line 782: Line 799:  
<pre>ROM:FFF04D98                LDR            R0, =0xF8C007F4
 
<pre>ROM:FFF04D98                LDR            R0, =0xF8C007F4
 
ROM:FFF04D9C                BX              LR</pre>
 
ROM:FFF04D9C                BX              LR</pre>
 +
 
= Types and structures =
 
= Types and structures =
  −
== enum MemoryState ==
  −
{| class="wikitable" border="1"
  −
!  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 ==
  −
{| class="wikitable" border="1"
  −
!  Page flags
  −
!  Bit
  −
|-
  −
| LOCKED
  −
| 0
  −
|-
  −
| CHANGED
  −
| 1
  −
|}
  −
  −
== enum MemoryOperation ==
  −
  −
{| class="wikitable" border="1"
  −
!  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 ==
  −
  −
{| class="wikitable" border="1"
  −
!  Memory permission
  −
!  Id
  −
|-
  −
| NONE
  −
| 0
  −
|-
  −
| R
  −
| 1
  −
|-
  −
| W
  −
| 2
  −
|-
  −
| RW
  −
| 3
  −
|-
  −
| X
  −
| 4
  −
|-
  −
| RX
  −
| 5
  −
|-
  −
| WX
  −
| 6
  −
|-
  −
| RWX
  −
| 7
  −
|-
  −
| DONTCARE
  −
| 0x10000000
  −
|}
      
== enum ResetType ==
 
== enum ResetType ==
Line 931: Line 818:  
|}
 
|}
   −
== struct MemoryInfo ==
+
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.
{| class="wikitable" border="1"
  −
!  Type
  −
!  Field
  −
|-
  −
| u32
  −
| Base process virtual address
  −
|-
  −
| u32
  −
| Size
  −
|-
  −
| u32
  −
| Permission
  −
|-
  −
| enum MemoryState
  −
| State
  −
|}
  −
 
  −
== struct PageInfo ==
  −
{| class="wikitable" border="1"
  −
!  Type
  −
!  Field
  −
|-
  −
| u32
  −
| Flags
  −
|}
      
== struct StartupInfo ==
 
== struct StartupInfo ==
Line 977: Line 839:  
| s16*
 
| s16*
 
| envp
 
| envp
|}
  −
  −
== enum ArbitrationType ==
  −
{| class="wikitable" border="1"
  −
!  Address arbitration type
  −
!  Value
  −
|-
  −
| FREE
  −
| 0
  −
|-
  −
| AQUIRE
  −
| 1
  −
|-
  −
| KERNEL2
  −
| 2
  −
|-
  −
| AQUIRE_TIMEOUT
  −
| 3
  −
|-
  −
| KERNEL4
  −
| 4
   
|}
 
|}
   Line 1,015: Line 856:  
|}
 
|}
   −
== struct CodeSetInfo ==
+
== struct DebugEventInfo ==
All addresses are given virtual for the process to be created.
+
Size: 0x28 bytes
All sizes are given in 0x1000-pages.
     −
{| class="wikitable" border="1"
+
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
  −
|-
  −
| 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 ==
      
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 1,081: Line 871:  
| Thread ID (not used in all events)
 
| Thread ID (not used in all events)
 
|-
 
|-
| u32[2]
+
| u32
| Unknown/padding
+
| 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]
 
| u32[6]
Line 1,092: Line 885:  
!  Id
 
!  Id
 
|-
 
|-
| PROCESS
+
| ATTACH PROCESS
 
| 0
 
| 0
 
|-
 
|-
| CREATE THREAD
+
| ATTACH THREAD
 
| 1
 
| 1
 
|-
 
|-
Line 1,101: Line 894:  
| 2
 
| 2
 
|-
 
|-
| EXIT PROCESS
+
| EXIT PROCESS (1)
 
| 3
 
| 3
 
|-
 
|-
Line 1,107: Line 900:  
| 4
 
| 4
 
|-
 
|-
| DLL LOAD
+
| DLL LOAD (3)
 
| 5
 
| 5
 
|-
 
|-
| DLL UNLOAD
+
| DLL UNLOAD (3)
 
| 6
 
| 6
 
|-
 
|-
| SCHEDULE IN
+
| SCHEDULE IN (1) (2)
 
| 7
 
| 7
 
|-
 
|-
| SCHEDULE OUT
+
| SCHEDULE OUT (1) (2)
 
| 8
 
| 8
 
|-
 
|-
| SYSCALL IN
+
| SYSCALL IN (1) (2)
 
| 9
 
| 9
 
|-
 
|-
| SYSCALL OUT
+
| SYSCALL OUT (1) (2)
 
| 10
 
| 10
 
|-
 
|-
Line 1,128: Line 921:  
| 11
 
| 11
 
|-
 
|-
| MAP
+
| MAP (1) (2)
 
| 12
 
| 12
 
|}
 
|}
   −
=== PROCESS event ===
+
<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"
 
{| class="wikitable" border="1"
Line 1,148: Line 951:  
|-
 
|-
 
| u32
 
| u32
| 0 = newly created process, 1 = attached process
+
| "Other" flag. Always 0 in available kernel versions
 
|}
 
|}
   −
=== CREATE THREAD event ===
+
=== ATTACH THREAD event ===
    
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 1,158: Line 961:  
|-
 
|-
 
| u32
 
| u32
| Creator thread ID
+
| Creator thread ID (0 if attached by svcDebugActiveProcess)
 
|-
 
|-
| u32
+
| void *
| Base address (?)
+
| Thread local storage
 
|-
 
|-
| u32
+
| u32 *
| Entrypoint
+
| Entrypoint = .text load address of the parent process
 
|}
 
|}
   Line 1,200: Line 1,003:  
| 1
 
| 1
 
|-
 
|-
| UNHANDLED EXCEPTION
+
| DEBUG TERMINATE
 
| 2
 
| 2
 
|}
 
|}
Line 1,216: Line 1,019:  
| Exception address
 
| Exception address
 
|-
 
|-
| u32
+
| u32[4]
| Argument (type-specific)
+
| Type-specific data, see below
 
|}
 
|}
    
Exception types:
 
Exception types:
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Reason
+
Exception type
 
!  Id
 
!  Id
!  Argument
   
|-
 
|-
 
| UNDEFINED INSTRUCTION
 
| UNDEFINED INSTRUCTION
 
| 0
 
| 0
| (None)
   
|-
 
|-
| (Unknown)
+
| PREFETCH ABORT
 
| 1
 
| 1
| (None)
   
|-
 
|-
| (Unknown, mem-related)
+
| DATA ABORT
 
| 2
 
| 2
| Address
   
|-
 
|-
| (Unknown, mem-related)
+
| UNALIGNED DATA ACCESS
 
| 3
 
| 3
| Address
   
|-
 
|-
 
| ATTACH BREAK
 
| ATTACH BREAK
 
| 4
 
| 4
| (None)
   
|-
 
|-
| BREAKPOINT
+
| STOP POINT
 
| 5
 
| 5
| (None)
   
|-
 
|-
 
| USER BREAK
 
| USER BREAK
 
| 6
 
| 6
| User break type
   
|-
 
|-
 
| DEBUGGER BREAK
 
| DEBUGGER BREAK
 
| 7
 
| 7
| (None)
   
|-
 
|-
 
| UNDEFINED SYSCALL
 
| UNDEFINED SYSCALL
 
| 8
 
| 8
| Attempted syscall ID
+
|}
 +
 
 +
==== UNDEFINED INSTRUCTION/PREFETCH ABORT/DATA ABORT/UNALIGNED DATA ACCESS/UNDEFINED SYSCALL events ====
 +
{| class="wikitable" border="1"
 +
!  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 ====
 +
{| class="wikitable" border="1"
 +
!  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 ====
 +
{| class="wikitable" border="1"
 +
!  Type
 +
!  Field
 +
|-
 +
| u32
 +
| Break reason
 +
|-
 +
| u32[2]
 +
| Info for LOAD_RO and UNLOAD_RO
 
|}
 
|}
   Line 1,276: Line 1,103:  
| USER
 
| USER
 
| 2
 
| 2
 +
|-
 +
| LOAD_RO
 +
| 3
 +
|-
 +
| UNLOAD_RO
 +
| 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).
 
|}
 
|}
   −
=== SCHEDULER/SYSCALL IN/OUT events ===
+
=== SCHEDULE/SYSCALL IN/OUT events ===
    
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 1,288: Line 1,130:  
|-
 
|-
 
| u32
 
| u32
| Syscall (only for SYSCALL events)
+
| CPU ID (SCHEDULE events) Syscall (SYSCALL events)
 
|}
 
|}
   Line 1,323: Line 1,165:  
|}
 
|}
   −
= Processes =
+
== struct ThreadContext ==
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.
     −
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.
+
Size: 0xCC bytes
   −
0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for the current KThread.
+
{| class="wikitable" border="1"
 +
|-
 +
!  Offset
 +
! Type
 +
!  Description
 +
|-
 +
| 0x0
 +
| CpuRegisters
 +
| Saved CPU registers (r0-r12, sp, lr, pc, cpsr)
 +
|-
 +
| 0x44
 +
| FpuRegisters
 +
| Saved FPU registers (d0-d15, fpscr, fpexc)
 +
|}
   −
Calling svcBreak on retail will only terminate the process which called this SVC.
+
The user needs to adjust pc for exceptions that occured while in Thumb mode.
   −
= Threads =
+
'''Flags for svcGetDebugThreadContext/svcSetDebugThreadContext''':
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.
+
{| class="wikitable" border="1"
 +
|-
 +
! 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)
 +
|}
   −
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.
+
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.
   −
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.
+
== enum DebugThreadParameter ==
 +
 
 +
{| class="wikitable" border="1"
 +
!  Parameter
 +
!  Id
 +
|-
 +
| PRIORITY
 +
| 0
 +
|-
 +
| SCHEDULING_MASK_LOW
 +
| 1
 +
|-
 +
| CPU_IDEAL
 +
| 2
 +
|-
 +
| CPU_CREATOR
 +
| 3
 +
|}
   −
= Memory Mapping =
+
== typedef Handle ==
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.
+
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).
   −
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.
+
There are a number of special-purpose handles, which provide easy access to information on objects in the current process:
 +
{| class="wikitable" border="1"
 +
!  Handle
 +
!  Description
 +
|-
 +
| 0xFFFF8000
 +
| Handle to the active thread
 +
|-
 +
| 0xFFFF8001
 +
| Handle to the active process
 +
|}
   −
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.
+
=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.
   −
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.
+
Here the kernel sets bit15 in the DSCR, to enable monitor-mode debugging.
   −
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.
+
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.
   −
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).
+
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 =
+
= [[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==
+
= Interrupt Handling =
Size of struct is 24 bytes.
     −
struct DmaConfig {
+
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).
    sint8_t channel_sel; // @0 Selects which DMA channel to use: 0-7, -1 = don't care.
  −
    uint8_t unk1;        // @1 Accepted values: 0,2,4,8.
  −
    uint8_t flags;      // @2 bit0: DST_CFG, bit1: SRC_CFG, bit2: SHALL_BLOCK, bit3: ???, bit6: DST_ALT_CFG, bit7: SRC_ALT_CFG
  −
    uint8_t unk2;
  −
    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 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.
   −
If CFG or ALT_CFG is not set, default configuration is loaded:
+
Applications hence can wait for specific interrupts to happen by calling WaitSynchronization(N) on the event or semaphore handles.
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 set of existing ARM11 interrupts is listed on [[ARM11 Interrupts|this page]].
 
  −
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).
      
= 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 1,396: Line 1,283:  
| Yes
 
| Yes
 
| No
 
| 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.
+
| 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
 
| 10
 
| Yes
 
| Yes
 
| ?
 
| ?
| Only available for the [[New_3DS]] kernel. It's unknown what this is used for.
+
| 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 1,470: 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
 
| 25
 
| Unused
 
| Unused
| This writes the total number of threads which were directly launched by the kernel, to out.
+
| 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 1,496: Line 1,405:  
!  Description
 
!  Description
 
|-
 
|-
| 9-19
+
| 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]]
 
| [[8.0.0-18]]
 
| This only returns error 0xD8E007ED.
 
| 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
 
| 20
Line 1,504: Line 1,453:  
| 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.
 
| 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
+
| 21
| [[8.0.0-18]]
+
| [[8.0.0-18]]. N3DS only.
| This only returns error 0xE0E01BF4.
+
| 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 =
 
= GetHandleInfo =
 +
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
!  HandleInfoType value
 
!  HandleInfoType value
Line 1,515: Line 1,473:  
|-
 
|-
 
| 0
 
| 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.
+
| 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
 
| 1
| Get internal refcount-1 for kernel object (u32), and also a boolean if the refcount-1 is negative (u32).
+
| 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
 
| 0x32107
Line 1,526: Line 1,487:  
= svc7B Backdoor =
 
= 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).
 
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 1,533: Line 1,549:  
!  Error-code value
 
!  Error-code value
 
!  Description
 
!  Description
 +
|-
 +
| 0x09401BFE
 +
| Timeout occurred with svcWaitSynchronization*, when timeout is not ~0.
 
|-
 
|-
 
| 0xC8601801
 
| 0xC8601801
Line 1,551: Line 1,570:  
| 0xD0401834
 
| 0xD0401834
 
| Max connections to port have been exceeded
 
| Max connections to port have been exceeded
 +
|-
 +
| 0xD8609013
 +
| Unknown, probably reslimit related?
 
|-
 
|-
 
| 0xD88007FA
 
| 0xD88007FA
Trusted
34

edits

Navigation menu