Changes

Jump to navigation Jump to search
5,918 bytes added ,  10:13, 5 February 2019
Line 25: Line 25:  
|  0xA || [[#svcExitThread]] || None ||                                                         
 
|  0xA || [[#svcExitThread]] || None ||                                                         
 
|-
 
|-
|  0xB || [[#svcSleepThread]] || X0=nano || W0=result
+
|  0xB || [[#svcSleepThread]] || X0=nano ||
 
|-
 
|-
 
|  0xC || [[#svcGetThreadPriority]] || W1=thread_handle || W0=result, W1=prio
 
|  0xC || [[#svcGetThreadPriority]] || W1=thread_handle || W0=result, W1=prio
Line 53: Line 53:  
| 0x18 || [[#svcWaitSynchronization]] || X1=handles_ptr, W2=num_handles. X3=timeout || W0=result, W1=handle_idx
 
| 0x18 || [[#svcWaitSynchronization]] || X1=handles_ptr, W2=num_handles. X3=timeout || W0=result, W1=handle_idx
 
|-
 
|-
| 0x19 || svcCancelSynchronization || W0=thread_handle || W0=result
+
| 0x19 || [[#svcCancelSynchronization]] || W0=thread_handle || W0=result
 
|-
 
|-
 
| 0x1A || svcArbitrateLock || W0=cur_thread_handle, X1=ptr, W2=req_thread_handle ||                                     
 
| 0x1A || svcArbitrateLock || W0=cur_thread_handle, X1=ptr, W2=req_thread_handle ||                                     
Line 149: Line 149:  
| 0x52 || [[#svcUnmapTransferMemory]] || W0=tmemhandle, X1=addr, X2=size || W0=result
 
| 0x52 || [[#svcUnmapTransferMemory]] || W0=tmemhandle, X1=addr, X2=size || W0=result
 
|-
 
|-
| 0x53 || svcCreateInterruptEvent || X1=irq_num, W2=flag || W0=result, W1=handle
+
| 0x53 || [[#svcCreateInterruptEvent]] || X1=irq_num, W2=flag || W0=result, W1=handle
 
|-
 
|-
 
| 0x54 || [[#svcQueryPhysicalAddress]] || X1=addr || W0=result, X1=physaddr, X2=kerneladdr, X3=size
 
| 0x54 || [[#svcQueryPhysicalAddress]] || X1=addr || W0=result, X1=physaddr, X2=kerneladdr, X3=size
Line 183: Line 183:  
| 0x63 || svcGetDebugEvent || X0=[[#DebugEventInfo]]*, W1=debug_handle || W0=result
 
| 0x63 || svcGetDebugEvent || X0=[[#DebugEventInfo]]*, W1=debug_handle || W0=result
 
|-
 
|-
| 0x64 || svcContinueDebugEvent || [1.0.0-2.3.0] W0=debug_handle, W1=[[#ContinueDebugFlagsOld]], X2=thread_id  
+
| 0x64 || [[#svcContinueDebugEvent]] || [1.0.0-2.3.0] W0=debug_handle, W1=[[#ContinueDebugFlagsOld]], X2=thread_id  
 
[3.0.0+] W0=debug_handle, W1=[[#ContinueDebugFlags]], X2=thread_id_list(u64 *), W3=num_tids (max 64, 0 means "all threads")
 
[3.0.0+] W0=debug_handle, W1=[[#ContinueDebugFlags]], X2=thread_id_list(u64 *), W3=num_tids (max 64, 0 means "all threads")
 
|| W0=result
 
|| W0=result
Line 193: Line 193:  
| 0x67 || svcGetDebugThreadContext || X0=ThreadContext*, X1=debug_handle, X2=thread_id, W3=[[#ThreadContextFlags]] || W0=result
 
| 0x67 || svcGetDebugThreadContext || X0=ThreadContext*, X1=debug_handle, X2=thread_id, W3=[[#ThreadContextFlags]] || W0=result
 
|-
 
|-
| 0x68 || svcSetDebugThreadContext || W0=debug_handle, W1=[[#ThreadContextFlags]], X2=ThreadContext*, X3=thread_id || W0=result
+
| 0x68 || svcSetDebugThreadContext || W0=debug_handle, X1=thread_id, X2=ThreadContext*, W3=[[#ThreadContextFlags]] || W0=result
 
|-
 
|-
 
| 0x69 || svcQueryDebugProcessMemory || X0=[[#MemoryInfo]]*, X2=debug_handle, X3=addr || W0=result, W1=PageInfo
 
| 0x69 || svcQueryDebugProcessMemory || X0=[[#MemoryInfo]]*, X2=debug_handle, X3=addr || W0=result, W1=PageInfo
Line 207: Line 207:  
| 0x6F || [5.0.0+] [[#svcGetSystemInfo]] || X1=info_id, X2=handle, X3=info_sub_id || W0=result, X1=out
 
| 0x6F || [5.0.0+] [[#svcGetSystemInfo]] || X1=info_id, X2=handle, X3=info_sub_id || W0=result, X1=out
 
|-
 
|-
| 0x70 || svcCreatePort || W2=max_sessions, W3=unk_bool, X4=name_ptr || W0=result, W1=clientport_handle, W2=serverport_handle
+
| 0x70 || svcCreatePort || W2=max_sessions, W3=is_light, X4=name_ptr || W0=result, W1=clientport_handle, W2=serverport_handle
 
|-
 
|-
 
| 0x71 || svcManageNamedPort || X1=name_ptr, W2=max_sessions || W0=result, W1=serverport_handle
 
| 0x71 || svcManageNamedPort || X1=name_ptr, W2=max_sessions || W0=result, W1=serverport_handle
Line 345: Line 345:  
Source range gets reprotected to --- (it can no longer be accessed), and bit0 is set in the source [[#MemoryAttribute]].
 
Source range gets reprotected to --- (it can no longer be accessed), and bit0 is set in the source [[#MemoryAttribute]].
   −
If dstaddr >= LowerTreshold, the dst-range is enforced to be within the process' "MapRegion". Code can get the range of this region from [[#svcGetInfo]] id0=2,3.
+
[1.0.0] This could be used to map into either the Alias Region or the Stack region.
   −
In this case, the mapped memory will have state 0x5C3C0B.
+
[2.0.0+] This can only be used to map into the Stack region.
   −
As long as (dstaddr+size) < LowerThreshold, then you can map anywhere but the mapped memory will have state 0x482907 instead.
+
Code can get the range of the Alias region from [[#svcGetInfo]] id0=2,3, and on 2.0.0+ the range of the Stack region via [[#svcGetInfo]] id0=14, 15 (on 1.0.0, the Stack region had hardcoded limits).
   −
LowerTreshold is 0x80000000 for 36-bit address spaces, and 0x40000000 for 32-bit ones.
+
When mapped into the Alias region, the mapped memory will have state 0x482907.
   −
[2.0.0+] Support for the 0x482907 mappings outside the "MapRegion" were removed.
+
When mapped into the Stack region, the mapped memory will have state 0x5C3C0B.
    
== svcUnmapMemory ==
 
== svcUnmapMemory ==
Line 478: Line 478:  
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (In) X0 || u64 || Nano
+
| (In) X0 || s64 || Nanoseconds
 
|-
 
|-
| (Out) W0 || [[#Result]] || Ret
   
|}
 
|}
 
</div>
 
</div>
Line 486: Line 485:  
'''Description:''' Sleep for a specified amount of time, or yield thread.
 
'''Description:''' Sleep for a specified amount of time, or yield thread.
   −
Setting nano=0 means "yield thread".
+
Setting nanoseconds to 0, -1, or -2 indicates a yielding type.
 +
 
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Value || Type
 +
|-
 +
| 0 || Yielding without core migration
 +
|-
 +
| -1 || Yielding with core migration
 +
|-
 +
| -2 || Yielding to any other thread
 +
|-
 +
|}
 +
</div>
    
== svcGetThreadPriority ==
 
== svcGetThreadPriority ==
Line 646: Line 659:  
</div>
 
</div>
   −
Works with num_handles <= 0x40, error on num_handles == 0.
+
Works with num_handles <= 0x40.
 +
 
 +
When zero handles are passed, this will wait forever until either timeout or cancellation occurs.
    
Does not accept 0xFFFF8001 or 0xFFFF8000 as handles.
 
Does not accept 0xFFFF8001 or 0xFFFF8000 as handles.
Line 652: Line 667:  
=== Object types ===
 
=== Object types ===
   −
'''Port:''' signals when there is an incoming connection waiting to be [[#svcAcceptSession|accepted]].
+
'''KDebug:''' signals when there is a new [[#DebugEventInfo|DebugEvent]] (retrievable via [[#svcGetDebugEvent]]).
 +
 
 +
'''KClientPort:''' signals when the number of sessions is less than the maximum allowed.
 +
 
 +
'''KProcess:''' signals when the process undergoes a state change (retrievable via [[#svcGetProcessInfo]]).
   −
'''Session (server-side):''' signals when there is an incoming message waiting to be [[#svcReplyAndReceive|received]] or the pipe is closed.
+
'''KReadableEvent:''' signals when the event's corresponding KWritableEvent has been signaled via svcSignalEvent.
 +
 
 +
'''KServerPort:''' signals when there is an incoming connection waiting to be [[#svcAcceptSession|accepted]].
 +
 
 +
'''KServerSession:''' signals when there is an incoming message waiting to be [[#svcReplyAndReceive|received]] or the pipe is closed.
 +
 
 +
'''KThread:''' signals when the thread has exited.
    
=== Result codes ===
 
=== Result codes ===
   −
'''0x0:''' Success. One of the objects was signalled before the timeout expired. Handle index is updated to indicate which object signalled.
+
'''0x0:''' Success. One of the objects was signaled before the timeout expired, or one of the objects is a Session with a closed remote. Handle index is updated to indicate which object signaled.
 +
 
 +
'''0x7601:''' Thread termination requested. Handle index is not updated.
    
'''0xe401:''' Invalid handle. Returned when one of the handles passed is invalid. Handle index is not updated.
 
'''0xe401:''' Invalid handle. Returned when one of the handles passed is invalid. Handle index is not updated.
   −
'''0xea01:''' Timeout. Returned when no objects have been signalled within the timeout. Handle index is not updated.
+
'''0xe601:''' Invalid address. Returned when the handles pointer is not a readable address. Handle index is not updated.
 +
 
 +
'''0xea01:''' Timeout. Returned when no objects have been signaled within the timeout. Handle index is not updated.
 +
 
 +
'''0xec01:''' Interrupted. Returned when another thread uses [[#svcCancelSynchronization]] to cancel this thread. Handle index is not updated.
   −
'''0xec01:''' Interrupted. Returns when another thread uses [[#svcCancelSynchronization]] to cancel this thread.
+
'''0xee01:''' Too many handles. Returned when the number of handles passed is > 0x40.
   −
== svcGetSystemTick ==
+
== svcCancelSynchronization ==
    
<div style="display: inline-block;">
 
<div style="display: inline-block;">
Line 673: Line 704:  
! Argument || Type || Name
 
! Argument || Type || Name
 
|-
 
|-
| (Out) X0 || u64 || Ticks
+
| (In) W0 || Handle<Thread> || Handle
 +
|-
 +
| (Out) W0 || [[#Result]] || Ret
 
|}
 
|}
 
</div>
 
</div>
   −
Returns the value of cntpct_el0.
+
If the referenced thread is currently in a synchronization call ([[#svcWaitSynchronization]], [[#svcReplyAndReceive]] or [[#svcReplyAndReceiveLight]]), that call will be interrupted and return 0xec01.
 +
If that thread is not currently executing such a synchronization call, the next call to a synchronization call will return 0xec01.
   −
The frequency is 19200000 Hz (constant from official sw).
+
This doesn't take force-pause (activity/debug pause) into account.
   −
Official sw reads cntpct_el0 directly from usermode without using this SVC. [[ExeFS|sdk-nso]] has this SVC, but it's not known to be called anywhere.
+
=== Result codes ===
   −
== svcSendSyncRequestWithUserBuffer ==
+
'''0x0:''' Success. The thread was either interrupted or has had its flag set.
 +
 
 +
'''0xe401:''' Invalid handle. The handle given was either invalid or not a thread handle.
 +
 
 +
== svcGetSystemTick ==
 +
 
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (Out) X0 || u64 || Ticks
 +
|}
 +
</div>
 +
 
 +
Returns the value of cntpct_el0.
 +
 
 +
The frequency is 19200000 Hz (constant from official sw).
 +
 
 +
Official sw reads cntpct_el0 directly from usermode without using this SVC. [[ExeFS|sdk-nso]] has this SVC, but it's not known to be called anywhere.
 +
 
 +
== svcSendSyncRequestWithUserBuffer ==
    
<div style="display: inline-block;">
 
<div style="display: inline-block;">
Line 700: Line 755:  
</div>
 
</div>
   −
Size must be 0x1000-aligned.
+
Size and CmdPtr must be 0x1000-aligned.
 +
 
 +
=== Result codes ===
 +
 
 +
'''0x0:''' Success.
 +
 
 +
'''0xcc01:''' CmdPtr is not 0x1000-aligned.
 +
 
 +
'''0xca01:''' Size is not 0x1000-aligned.
 +
 
 +
'''0xce01:''' KSessionRequest allocation failed (unlikely) or pointer buffer size exceeded.
 +
 
 +
'''0xe401:''' Handles does not exist, or handle is not an instance of KClientSession.
    
== svcBreak ==
 
== svcBreak ==
Line 751: Line 818:  
| Process || 1 || 0 || AllowedThreadPrioBitmask
 
| Process || 1 || 0 || AllowedThreadPrioBitmask
 
|-
 
|-
| Process || 2 || 0 || MapRegionBaseAddr
+
| Process || 2 || 0 || AliasRegionBaseAddr
 
|-
 
|-
| Process || 3 || 0 || MapRegionSize
+
| Process || 3 || 0 || AliasRegionSize
 
|-
 
|-
 
| Process || 4 || 0 || HeapRegionBaseAddr
 
| Process || 4 || 0 || HeapRegionBaseAddr
Line 775: Line 842:  
| Process || 13 || 0 || [2.0.0+] AddressSpaceSize
 
| Process || 13 || 0 || [2.0.0+] AddressSpaceSize
 
|-
 
|-
| Process || 14 || 0 || [2.0.0+] NewMapRegionBaseAddr
+
| Process || 14 || 0 || [2.0.0+] StackRegionBaseAddr
 
|-
 
|-
| Process || 15 || 0 || [2.0.0+] NewMapRegionSize
+
| Process || 15 || 0 || [2.0.0+] StackRegionSize
 
|-
 
|-
 
| Process || 16 || 0 || [3.0.0+] PersonalMmHeapSize
 
| Process || 16 || 0 || [3.0.0+] PersonalMmHeapSize
Line 791: Line 858:  
| Process || 20 || 0 || [5.0.0+] UserExceptionContextAddr
 
| Process || 20 || 0 || [5.0.0+] UserExceptionContextAddr
 
|-
 
|-
| Thread  || 0xF0000002 || 0 || Performance counter related.
+
| Process || 21 || 0 || [6.0.0+] TotalMemoryAvailableWithoutMmHeap
 +
|-
 +
| Process || 22 || 0 || [6.0.0+] TotalMemoryUsedWithoutMmHeap
 +
|-
 +
| Thread  || 0xF0000002 || 0 || Scheduler related.
 
|}
 
|}
   Line 857: Line 928:  
Then it will wait until either of the passed sessions has an incoming message, is closed, a passed port has an incoming connection, or the timeout expires.
 
Then it will wait until either of the passed sessions has an incoming message, is closed, a passed port has an incoming connection, or the timeout expires.
 
If there is an incoming message, it is copied to the TLS.
 
If there is an incoming message, it is copied to the TLS.
 +
 +
If ReplyTarget is zero, the TLS should contain a blank message. If this message has a C descriptor, the buffer it points to will be used as the pointer buffer. See [[IPC_Marshalling#IPC_buffers]]. Note that a pointer buffer cannot be specified if ReplyTarget is not zero.
    
After being validated, passed handles will be enumerated in order; even if a session has been closed, if one that appears earlier in the list has an incoming message, it will take priority and a result code of 0x0 will be returned.
 
After being validated, passed handles will be enumerated in order; even if a session has been closed, if one that appears earlier in the list has an incoming message, it will take priority and a result code of 0x0 will be returned.
Line 1,000: Line 1,073:  
Size must match size given in map syscall, otherwise there's an invalid-size error.
 
Size must match size given in map syscall, otherwise there's an invalid-size error.
   −
== svcQueryPhysicalAddress ==
+
 
 +
== svcCreateInterruptEvent ==
 +
 
 +
<div style="display: inline-block;">
 +
{| class="wikitable" border="1"
 +
|-
 +
! Argument || Type || Name
 +
|-
 +
| (In) X1 || u64 || IrqNum
 +
|-
 +
| (In) W2 || bool || Flags
 +
|-
 +
| (Out) W0 || [[#Result]] || Ret
 +
|-
 +
| (Out) W1 || Handle<ReadableEvent> || ReadableEventHandle
 +
|}
 +
</div>
 +
 
 +
Create an event handle for the given IRQ number. Waiting on this handle will wait until the IRQ is triggered. The flags argument configures the triggering. If it is false, the IRQ is active HIGH level sensitive, if it is true it is rising-edge sensitive.
 +
 
 +
=== Result codes ===
 +
 
 +
'''0x0:''' Success.
 +
 
 +
'''0xF001:''' Flags was > 1
 +
 
 +
'''0xF201:''' IRQ above 0x3FF or outside the [[NPDM#Kernel_Access_Control|IRQ access mask]] was given.
 +
 
 +
'''0xCE01:''' A SlabHeap was exhausted (too many interrupts created).
 +
 
 +
'''0xF401:''' IRQ already has an event registered.
 +
 
 +
'''0xD201:''' The handle table is full. Try closing some handles.
 +
 
 +
 
 +
== svcQueryPhysicalAddress ==
    
<div style="display: inline-block;">
 
<div style="display: inline-block;">
Line 1,171: Line 1,279:     
'''Description:''' Unmaps an attached device address space from an userspace address.
 
'''Description:''' Unmaps an attached device address space from an userspace address.
 +
 +
== svcContinueDebugEvent ==
 +
 +
=== Result codes ===
 +
 +
'''0x0:''' Success. The process has been resumed.
 +
 +
'''0xe401:''' Invalid debug handle.
 +
 +
'''0xf401:''' Process has debug events queued.
    
== svcGetSystemInfo ==
 
== svcGetSystemInfo ==
Line 1,355: Line 1,473:  
| (In) X1 || [[#CreateProcessInfo]]* || InfoPtr
 
| (In) X1 || [[#CreateProcessInfo]]* || InfoPtr
 
|-
 
|-
| (In) X2 || u64 || CapabilitiesPtr
+
| (In) X2 || u32* || CapabilitiesPtr
 
|-
 
|-
 
| (In) X3 || u64 || CapabilitiesNum
 
| (In) X3 || u64 || CapabilitiesNum
Line 1,366: Line 1,484:     
Takes a [[#CreateProcessInfo]] as input.
 
Takes a [[#CreateProcessInfo]] as input.
 +
CapabilitiesPtr points to an array of [[NPDM#Kernel_Access_Control|kernel capabilities]].
 +
CapabilitiesNum is a number of capabilities in the CapabilitiesPtr array (number of element, not number of bytes).
 +
 +
=== Result codes ===
 +
 +
'''0x0:''' Success.
 +
 +
'''0xCA01:''' Attempted to map more code pages than available in address space.
 +
 +
'''0xCC01:''' Provided CodeAddr is invalid (make sure it's in range?)
 +
 +
'''0xE401:''' The resource handle passed is invalid.
 +
 +
'''0xE601:''' Attempt to copy procinfo from user-supplied pointer failed. Attempt to copy capabilities_num from user-supplied pointer failed.
 +
 +
'''0xE801:''' Attempted to create a 32-bit process with a 36-bit address space.
 +
 +
'''0xF001:''' Unused bits are set in mmuflags. Unknown address space type used.
    
== svcGetProcessInfo ==
 
== svcGetProcessInfo ==
Line 1,614: Line 1,750:  
| 0 || 12 || || ProcessName (doesn't have to be null-terminated)
 
| 0 || 12 || || ProcessName (doesn't have to be null-terminated)
 
|-
 
|-
| 0 || 4 || || ProcessCategory (0: regular title, 1: kernel built-in)
+
| 0x0C || 4 || || ProcessCategory (0: regular title, 1: kernel built-in)
 
|-
 
|-
 
| 0x10 || 8 || || TitleId
 
| 0x10 || 8 || || TitleId
Line 1,638: Line 1,774:  
| || || Bit10-7 || [5.0.0+] PoolPartition (0=Application, 1=Applet, 2=Sysmodule, 3=Nvservices)
 
| || || Bit10-7 || [5.0.0+] PoolPartition (0=Application, 1=Applet, 2=Sysmodule, 3=Nvservices)
 
|-
 
|-
| 0x28 || 4 || || ResourceLimitHandle
+
| || || Bit11 || [7.0.0+] Only allowed in combination with bit6.
 +
|-
 +
| 0x28 || 4 || || ResourceLimitHandle or zero
 
|-
 
|-
 
| 0x2C || 4 || || [3.0.0+] PersonalMmHeapNumPages
 
| 0x2C || 4 || || [3.0.0+] PersonalMmHeapNumPages
Line 1,648: Line 1,786:     
On [5.0.0] PoolPartition is specified in CreateProcessArgs. There are now 4 pool partitions.
 
On [5.0.0] PoolPartition is specified in CreateProcessArgs. There are now 4 pool partitions.
 +
 +
On [5.0.0] (maybe lower?) a zero ResourceLimitHandle defaults to sysmodule limits and 0x12300000 bytes of memory.
 +
 +
The PersonalMmHeap are allocated as follows:
 +
* For the application, normal insecure pool is used. Carveout 5 is used to provide protection.
 +
* For the applet, a pre-allocated secure pool segment of size 0x400000 is used.
 +
* For sysmodules, secure pool is allocated.
    
=== AddressSpaceType ===
 
=== AddressSpaceType ===
Line 1,767: Line 1,912:  
| 0x00402006 || MemoryType_SharedMemory || Mapped using [[#svcMapSharedMemory]].
 
| 0x00402006 || MemoryType_SharedMemory || Mapped using [[#svcMapSharedMemory]].
 
|-
 
|-
| 0x00482907 || [1.0.0] MemoryType_WeirdMappedMemory || Mapped using [[#svcMapMemory]].
+
| 0x00482907 || [1.0.0] MemoryType_Alias || Mapped using [[#svcMapMemory]].
 
|-
 
|-
 
| 0x00DD7E08 || MemoryType_ModuleCodeStatic || Mapped using [[#svcMapProcessCodeMemory]].
 
| 0x00DD7E08 || MemoryType_ModuleCodeStatic || Mapped using [[#svcMapProcessCodeMemory]].
Line 1,782: Line 1,927:  
| 0x005C3C0A || [[IPC_Marshalling|MemoryType_IpcBuffer0]] || IPC buffers with descriptor flags=0.
 
| 0x005C3C0A || [[IPC_Marshalling|MemoryType_IpcBuffer0]] || IPC buffers with descriptor flags=0.
 
|-
 
|-
| 0x005C3C0B || MemoryType_MappedMemory || Mapped using [[#svcMapMemory]].
+
| 0x005C3C0B || MemoryType_Stack || Mapped using [[#svcMapMemory]].
 
|-
 
|-
 
| 0x0040200C || [[Thread Local Storage|MemoryType_ThreadLocal]] || Mapped during [[#svcCreateThread]].
 
| 0x0040200C || [[Thread Local Storage|MemoryType_ThreadLocal]] || Mapped during [[#svcCreateThread]].
Line 1,967: Line 2,112:  
|}
 
|}
   −
* Undefined instructions, software breakpoints, some other traps.
+
<nowiki>*</nowiki> Undefined instructions, software breakpoints, some other traps.
** Data aborts, FP traps, and everything else that doesn't belong to any of the above.
+
 
 +
<nowiki>**</nowiki> Data aborts, FP traps, and everything else that doesn't belong to any of the above.
    
Trap specifics:
 
Trap specifics:
Line 2,011: Line 2,157:  
KDebug dispatching is used when at least one of the following conditions are met:
 
KDebug dispatching is used when at least one of the following conditions are met:
 
* SMC ConfigItem KernelMemConfig bit 1 is NOT set (it isn't on retail), unless: this is a software or hardware breakpoint, or a watchpoint, or [4.0.0+?] the process is attached and this is a Google PNaCl trap instruction (see LLVM source)
 
* SMC ConfigItem KernelMemConfig bit 1 is NOT set (it isn't on retail), unless: this is a software or hardware breakpoint, or a watchpoint, or [4.0.0+?] the process is attached and this is a Google PNaCl trap instruction (see LLVM source)
* PC doesn't point to a valid address in mapped-readable CodeStatic memory (i.e. this is the case for NRO and JIT memory) or this one of the following exceptions (it particular, that doesn't include FP exceptions occuring in CodeStatic memory):
+
* FAR doesn't point to a valid address in mapped-readable CodeStatic memory (i.e. this is the case for NRO and JIT memory) or this is one of the following exceptions (it particular, that doesn't include FP exceptions occurring in CodeStatic memory):
 
** Uncategorized
 
** Uncategorized
 
** IllegalState
 
** IllegalState
Line 2,031: Line 2,177:  
If the process is attached, the exception is reported to the KDebug. If the thread was continued using flag IgnoreExceptions, it returns from the exception as if nothing happened.
 
If the process is attached, the exception is reported to the KDebug. If the thread was continued using flag IgnoreExceptions, it returns from the exception as if nothing happened.
   −
If the latter is not the case, or if the process isn't attached, process to [2.0.0+] crash reporting (or in [1.0.0] just terminate the process):  
+
If the latter is not the case, or if the process isn't attached, proceed to [2.0.0+] crash reporting (or in [1.0.0] just terminate the process):  
if EnableDebug is set, and depending on the process state (more than one crash per process isn't permitted) it may signal itself with ProcessState_Crashed so that PM asks NS to start creport so that creports attaches to it and reports the crashes. Otherwise, just terminate.
+
if EnableDebug is set, and depending on the process state (more than one crash per process isn't permitted) it may signal itself with ProcessState_Crashed so that PM asks NS to start creport so that creport attaches to it and reports the crashes. Otherwise, just terminate.
    
Userland reporting path and svcReturnFromException:
 
Userland reporting path and svcReturnFromException:
Line 2,043: Line 2,189:  
| 0x0 || 0x148 || Exception stack
 
| 0x0 || 0x148 || Exception stack
 
|-
 
|-
| 0x148 || 0x78 || Frame: x0..x30, sp, elr_el1=unadjusted PC, pstate & 0xFF0FFE20,
+
| 0x148 || 0x78 || ExceptionFrameA64
afsr0, afsr1, esr, pc (stored using the regs' own size)
+
|}
 +
 
 +
ExceptionFrameA64:
 +
 
 +
{| class=wikitable
 +
! Offset || Length || Description
 +
|-
 +
| 0x0 || 0x48 (8*9) || GPRs 0..8.
 +
|-
 +
| 0x48 || 0x8 || lr
 +
|-
 +
| 0x50 || 0x8 || sp
 +
|-
 +
| 0x58 || 0x8 || pc (elr_el1)
 +
|-
 +
| 0x60 || 0x4 || pstate & 0xFF0FFE20
 +
|-
 +
| 0x64 || 0x4 || afsr0
 +
|-
 +
| 0x68 || 0x4 || afsr1
 +
|-
 +
| 0x6C || 0x4 || esr
 +
|-
 +
| 0x70 || 0x8 || far
 
|}
 
|}
   Line 2,054: Line 2,223:  
| 0x0 || 0x178 || Exception stack
 
| 0x0 || 0x178 || Exception stack
 
|-
 
|-
| 0x148 || 0x30 || Frame: r0..r14, elr_el1=unadjusted PC, tpidr_el0 = 1, cpsr & 0xFF0FFE20,
+
| 0x148 || 0x44 || ExceptionFrameA32
afsr0, afsr1, esr, pc (stored using the regs' own size)
   
|}
 
|}
    +
ExceptionFrameA32:
 +
 +
{| class=wikitable
 +
! Offset || Length || Description
 +
|-
 +
| 0x0 || 0x20 (8*4) || GPRs 0..7.
 +
|-
 +
| 0x20 || 0x4 || sp
 +
|-
 +
| 0x24 || 0x4 || lr
 +
|-
 +
| 0x28 || 0x4 || pc (elr_el1)
 +
|-
 +
| 0x2C || 0x4 || tpidr_el0 = 1
 +
|-
 +
| 0x30 || 0x4 || cpsr & 0xFF0FFE20
 +
|-
 +
| 0x34 || 0x4 || afsr0
 +
|-
 +
| 0x38 || 0x4 || afsr1
 +
|-
 +
| 0x3C || 0x4 || esr
 +
|-
 +
| 0x40 || 0x4 || far
 +
|}
    
In that case, after storing the regs in the TLS, the exception handler returns to the application's crt0 (entrypoint), with X0=<error description code> (see below) and X1=SP=frame=<stack top> (see above)
 
In that case, after storing the regs in the TLS, the exception handler returns to the application's crt0 (entrypoint), with X0=<error description code> (see below) and X1=SP=frame=<stack top> (see above)
Line 2,088: Line 2,281:  
* if the provided error code is 0, gracefully pivots and returns from exception
 
* if the provided error code is 0, gracefully pivots and returns from exception
 
* if it is not, replays the exception and pass it to the KDebug (see above). One can pass 0x10001 to prevent process termination. If the process is attached, this also prevents crash-collection/termination (different from the exception handler behavior)
 
* if it is not, replays the exception and pass it to the KDebug (see above). One can pass 0x10001 to prevent process termination. If the process is attached, this also prevents crash-collection/termination (different from the exception handler behavior)
 +
 +
If an exception occurs from the above user handler, the entire exception handling process will repeat with the new exception.
    
Note that if a thread that wasn't faulting calls svcReturnFromException, it signals an "invalid syscall" exception
 
Note that if a thread that wasn't faulting calls svcReturnFromException, it signals an "invalid syscall" exception
 +
 +
Note that [[SMC|IsDebugMode]] is not used during exception-handling, except for enabling printing a message to UART-A. This UART code causes a system-hang on retail (likely due to a loop that doesn't exit). This printing doesn't seem to run when the process is attached for debugging?

Navigation menu