Changes

Jump to navigation Jump to search
8,232 bytes added ,  16:00, 7 December 2018
m
Fix offset in CreateProcessInfo
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 79: Line 79:  
| 0x25 || svcGetThreadId || W1=thread_handle || W0=result, X1=out
 
| 0x25 || svcGetThreadId || W1=thread_handle || W0=result, X1=out
 
|-
 
|-
| 0x26 || [[#svcBreak]] || X0=break_reason,X1,X2=info || ?
+
| 0x26 || [[#svcBreak]] || X0=break_reason,X1,X2=info || W0=result = 0
 
|-
 
|-
 
| 0x27 || svcOutputDebugString || X0=str, X1=size || W0=result
 
| 0x27 || svcOutputDebugString || X0=str, X1=size || W0=result
Line 183: Line 183:  
| 0x63 || svcGetDebugEvent || X0=[[#DebugEventInfo]]*, W1=debug_handle || W0=result
 
| 0x63 || svcGetDebugEvent || X0=[[#DebugEventInfo]]*, W1=debug_handle || W0=result
 
|-
 
|-
| 0x64 || svcContinueDebugEvent || [Until 3.0.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 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 231: Line 231:  
| 0x7B || svcTerminateProcess || W0=process_handle || W0=result
 
| 0x7B || svcTerminateProcess || W0=process_handle || W0=result
 
|-
 
|-
| 0x7C || [[#svcGetProcessInfo]] || W0=process_handle || W0=result, X1=[[#ProcessState]]
+
| 0x7C || [[#svcGetProcessInfo]] || W0=process_handle, W1=[[#ProcessInfoType]] || W0=result, X1=[[#ProcessState]]
 
|-
 
|-
 
| 0x7D || svcCreateResourceLimit || None || W0=result, W1=reslimit_handle  
 
| 0x7D || svcCreateResourceLimit || None || W0=result, W1=reslimit_handle  
Line 256: Line 256:  
'''Description:''' Set the process heap to a given Size. It can both extend and shrink the heap.
 
'''Description:''' Set the process heap to a given Size. It can both extend and shrink the heap.
   −
Size must be a multiple of 0x200000.
+
Size must be a multiple of 0x200000 (2MB).
    
On success, the heap base-address (which is fixed by kernel, aslr'd) is written to OutAddr.
 
On success, the heap base-address (which is fixed by kernel, aslr'd) is written to OutAddr.
Line 262: Line 262:  
Uses current process pool partition.
 
Uses current process pool partition.
   −
[2.0.0+] Size must be less than 0x18000000.
+
[2.0.0+] Size must be less than or equal to 4GB.
    
== svcSetMemoryPermission ==
 
== svcSetMemoryPermission ==
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]]).
 +
 
 +
'''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.
   −
'''Session (server-side):''' 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.
 +
 
 +
'''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 671: 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.
 +
 
 +
=== Result codes ===
 +
 
 +
'''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.
 
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.
Line 698: 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 713: Line 782:  
| (In) X2 || u64 || Info
 
| (In) X2 || u64 || Info
 
|-
 
|-
| (Out) ? || ? || ?
+
| (Out) W0 || Result || 0 (Success)
 
|}
 
|}
 
</div>
 
</div>
   −
When used on retail where inx0 bit31 is clear, the system will throw a [[Error_codes|fatal-error]]. Otherwise when bit31 is set, it will return 0 and notify the debugger?
+
If the process is attached, report the Break event. Then, if svcContinueDebugEvent didn't apply IgnoreException on the thread: if TPIDR_EL0 is 0, adjust ELR_EL1 to retry to svc instruction (and set TPIDR_EL0 to 1).
 +
 
 +
Otherwise, if bit31 in reason isn't set, perform crash reporting (see Exception Handling section below), if it doesn't terminate the process adjust ELR_EL1 as well.
 +
 
 +
Otherwise just return 0.
    
== svcGetInfo ==
 
== svcGetInfo ==
Line 745: 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 769: 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 851: Line 924:  
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,546: Line 1,621:  
|}
 
|}
   −
== ProcessEvent ==
+
== ProcessInfoType ==
 +
 
 +
{| class=wikitable
 +
! Value || Name
 +
|-
 +
| 0 || [[#ProcessState|ProcessInfoType_ProcessState]]
 +
|-
 +
|}
 +
 
 +
== ProcessState ==
 
{| class=wikitable
 
{| class=wikitable
 
! Value || Name || Notes
 
! Value || Name || Notes
 
|-
 
|-
| 0 || ProcessEvent_Created ||
+
| 0 || ProcessState_Created ||
 
|-
 
|-
| 1 || ProcessEvent_DebugAttached ||
+
| 1 || ProcessState_CreatedAttached ||
 
|-
 
|-
| 2 || ProcessEvent_DebugDetached ||
+
| 2 || ProcessState_Started ||
 
|-
 
|-
| 3 || ProcessEvent_Crashed || Processes will not enter this state unless they were created with [[#CreateProcessInfo|EnableDebug]].
+
| 3 || ProcessState_Crashed || Processes will not enter this state unless they were created with [[#CreateProcessInfo|EnableDebug]].
 
|-
 
|-
| 4 || ProcessEvent_Running ||
+
| 4 || ProcessState_StartedAttached ||
 
|-
 
|-
| 5 || ProcessEvent_Exiting ||
+
| 5 || ProcessState_Exiting ||
 
|-
 
|-
| 6 || ProcessEvent_Exited ||
+
| 6 || ProcessState_Exited ||
 
|-
 
|-
| 7 || ProcessEvent_DebugSuspended ||
+
| 7 || ProcessState_DebugSuspended ||
 
|}
 
|}
   Line 1,599: Line 1,683:  
| 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,623: Line 1,707:  
| || || 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
+
| 0x28 || 4 || || ResourceLimitHandle or zero
 
|-
 
|-
 
| 0x2C || 4 || || [3.0.0+] PersonalMmHeapNumPages
 
| 0x2C || 4 || || [3.0.0+] PersonalMmHeapNumPages
Line 1,633: Line 1,717:     
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 [6.0.0] (maybe lower?) a zero ResourceLimitHandle defaults to sysmodule limits and 0x12300000 bytes of memory.
    
=== AddressSpaceType ===
 
=== AddressSpaceType ===
Line 1,752: Line 1,838:  
| 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,767: Line 1,853:  
| 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,817: Line 1,903:     
== ContinueDebugFlagsOld ==
 
== ContinueDebugFlagsOld ==
Until [[3.0.0]]:
+
[1.0.0-2.3.0]
    
{| class=wikitable
 
{| class=wikitable
Line 1,830: Line 1,916:     
== ContinueDebugFlags ==
 
== ContinueDebugFlags ==
Starting from [[3.0.0]]:
+
[3.0.0+]
    
{| class=wikitable
 
{| class=wikitable
Line 1,837: Line 1,923:  
| 0 || 1 || IgnoreException (note: doesn't need to be set in the same call than Resume)
 
| 0 || 1 || IgnoreException (note: doesn't need to be set in the same call than Resume)
 
|-
 
|-
| 1 || 2 || SwallowException
+
| 1 || 2 || DontCatchExceptions
 
|-
 
|-
 
| 2 || 4 || Resume
 
| 2 || 4 || Resume
 
|-
 
|-
| 3 || 8 || IgnoreExceptionInverted
+
| 3 || 8 || IgnoreOtherThreadsExceptions
 
|}
 
|}
   −
IgnoreExceptionInverted is like CancelSynchronization but acts on all threads that aren't in the input list.
+
IgnoreExceptionsOfOthers is like IgnoreException but acts on all threads that aren't in the input list. The affected threads are resumed.
 +
 
 +
Only one of of Resume and IgnoreOtherThreadsExceptions can be set at a time.
    
If the input number of threads is 0, this means "all threads".
 
If the input number of threads is 0, this means "all threads".
    
== DebugEventInfo ==
 
== DebugEventInfo ==
 +
 +
The below table is for the Aarch64 version of the system call. For A32, all u64 fields but title/process/thread id are actually u32, making the structure 0x28-byte-big (0x40 for a64).
    
Size: 0x40
 
Size: 0x40
Line 1,894: Line 1,984:  
! Offset || Length || Description
 
! Offset || Length || Description
 
|-
 
|-
| 0x10 || u32|| Type (0=PausedThread, 1=RunningThread, 2=TerminatedProcess)
+
| 0x10 || u32|| Type (0=PausedThread, 1=RunningThread, 2=ExitedProcess, 3=TerminatedProcess)
 
|}
 
|}
   Line 1,916: Line 2,006:  
| 1 || DebugEvent_AttachThread
 
| 1 || DebugEvent_AttachThread
 
|-
 
|-
| 2 ||
+
| 2 || DebugEvent_ExitProcess
 
|-
 
|-
| 3 || DebugEvent_Exit
+
| 3 || DebugEvent_ExitThread
 
|-
 
|-
 
| 4 || DebugEvent_Exception
 
| 4 || DebugEvent_Exception
Line 1,927: Line 2,017:  
! Value || Name
 
! Value || Name
 
|-
 
|-
| 0 || Exception_UndefinedInstruction
+
| 0 || Exception_Trap (*)
 
|-
 
|-
 
| 1 || Exception_InstructionAbort
 
| 1 || Exception_InstructionAbort
 
|-
 
|-
| 2 || Exception_DataAbortMisc
+
| 2 || Exception_DataAbortMisc (**)
 
|-
 
|-
 
| 3 || Exception_PcSpAlignmentFault
 
| 3 || Exception_PcSpAlignmentFault
Line 1,945: Line 2,035:  
| 8 || Exception_BadSvcId
 
| 8 || Exception_BadSvcId
 
|-
 
|-
| 9 || Exception_SError
+
| 9 || Exception_SError [not in 1.0.0]
 
|}
 
|}
   −
UndefinedInstruction specifics:
+
<nowiki>*</nowiki> Undefined instructions, software breakpoints, some other traps.
 +
 
 +
<nowiki>**</nowiki> Data aborts, FP traps, and everything else that doesn't belong to any of the above.
 +
 
 +
Trap specifics:
 
{| class=wikitable
 
{| class=wikitable
 
! Offset || Length || Description
 
! Offset || Length || Description
Line 1,981: Line 2,075:     
= Exception handling =
 
= Exception handling =
There is userland code for handling exceptions, however this doesn't seem to be executed on retail mode.
+
First of all, a function that might be called by synchronous exception handler and that is called by the SError handler fetches the exception info, adjusts PC, panics on exceptions taken from EL1, then dispatches the exception.
 +
 
 +
The dispatcher has two mutually exclusive exception reporting methods:
 +
* by storing information at the start of the process's TLS memregion (TPIDRRO_EL0) and jumping back to the crt0
 +
* by using KDebug
 +
 
 +
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)
 +
* 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
 +
** IllegalState
 +
** SupervisorCallA32
 +
** SupervisorCallA64
 +
** PCAlignment
 +
** SPAlignment
 +
** SError
 +
** BreakpointLowerEl
 +
** SoftwareStepLowerEl (note: no way set single-step flag; not parsed)
 +
** WatchpointLowerEl
 +
** SoftwareBreakpointA32 (note: not parsed)
 +
** SoftwareBreakpointA64 (note: not parsed)
 +
   
 +
In all other cases the userland-handled exception path is taken.
 +
 
 +
KDebug path:
 +
 
 +
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, 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 creport attaches to it and reports the crashes. Otherwise, just terminate.
 +
 
 +
Userland reporting path and svcReturnFromException:
 +
 
 +
TLS region start (A64):
 +
 
 +
{| class=wikitable
 +
! Offset || Length || Description
 +
|-
 +
| 0x0 || 0x148 || Exception stack
 +
|-
 +
| 0x148 || 0x78 || ExceptionFrameA64
 +
|}
 +
 
 +
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
 +
|}
 +
 
 +
TLS region start (A32):
 +
 
 +
{| class=wikitable
 +
! Offset || Length || Description
 +
|-
 +
| 0x0 || 0x178 || Exception stack
 +
|-
 +
| 0x148 || 0x44 || ExceptionFrameA32
 +
|}
 +
 
 +
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)
 +
 
 +
 
 +
{| class=wikitable
 +
! Desc. code || Meaning
 +
|-
 +
| 0x100 || Instruction abort
 +
|-
 +
| 0x102 || Misaligned PC
 +
|-
 +
| 0x103 || Misaligned SP
 +
|-
 +
| 0x106 || SError [not in 1.0.0?]
 +
|-
 +
| 0x301 || Bad SVC
 +
|-
 +
| 0x104 || Uncategorized, CP15RTTrap, CP15RRTTrap, CP14RTTrap, CP14RRTTrap, IllegalState, SystemRegisterTrap
 +
|-
 +
| 0x101 || None of the above, EC <= 0x34 and not a breakpoint
 +
|-
 +
|}
 +
 
 +
(During normal app boot the process is invoked with X0=0 and X1=main_thread_handle. The crt0 of retail apps determines whether to boot normally or handle an exception if X0 is set to 0 or not)
 +
 
 +
The application is supposed to promptly update the contents of elr_el1 to a user handler (and any other regs it sees fit) and call svcReturnFromException (error code) to call that handler. The latter is then expected to promptly abort the program.
 +
 
 +
svcReturnFromException updates the contents of the kernel stack frame with what the user provided in the TLS structure, sets TPIDR_EL0 to 1, then:
 +
* 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)
   −
When a usermode exception occurs, it jumps to the main code binary entrypoint (main_binary_address + 0 == '''_start''').
+
If an exception occurs from the above user handler, the entire exception handling process will repeat with the new exception.
   −
During normal boot '''_start''' is invoked with X0=0 and X1=main_thread_handle (triggering normal crt0 setup).
+
Note that if a thread that wasn't faulting calls svcReturnFromException, it signals an "invalid syscall" exception
During an usermode exception '''_start''' is invoked with X0=exception_info0_ptr and X1=exception_info1_ptr instead.
     −
The '''_start''' method determines whether to boot normally or handle an exception if X0 is set to 0 or not.
+
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?
151

edits

Navigation menu