Line 139:
Line 139:
| 0x4C || [4.0.0+] [[#ControlCodeMemory]] || ||
| 0x4C || [4.0.0+] [[#ControlCodeMemory]] || ||
|-
|-
−
| 0x4D || [[#SleepSystem]] ||||
+
| 0x4D || [[#SleepSystem]] || ||
|-
|-
| 0x4E || [[#ReadWriteRegister]] || ||
| 0x4E || [[#ReadWriteRegister]] || ||
Line 171:
Line 171:
| 0x5C || [[#UnmapDeviceAddressSpace]] || ||
| 0x5C || [[#UnmapDeviceAddressSpace]] || ||
|-
|-
−
| 0x5D || InvalidateProcessDataCache || W0=process_handle, X1=addr, X2=size
+
| 0x5D || [[#InvalidateProcessDataCache]] || ||
−
R0=process_handle, R1=size_lower32, R2=addr_lower32, R3=addr_upper32, R4=size_upper32
−
|| W0=size
|-
|-
−
| 0x5E || StoreProcessDataCache || W0=process_handle, X1=addr, X2=size
+
| 0x5E || [[#StoreProcessDataCache]] || ||
−
R0=process_handle, R1=size_lower32, R2=addr_lower32, R3=addr_upper32, R4=size_upper32
−
|| W0=size
|-
|-
−
| 0x5F || FlushProcessDataCache || W0=process_handle, X1=addr, X2=size
+
| 0x5F || [[#FlushProcessDataCache]] || ||
−
R0=process_handle, R1=size_lower32, R2=addr_lower32, R3=addr_upper32, R4=size_upper32
−
|| W0=size
|-
|-
−
| 0x60 || DebugActiveProcess || X1=pid
+
| 0x60 || [[#DebugActiveProcess]] || ||
−
R2=pid_lower32, R3=pid_upper32
−
|| W0=result, W1=debug_handle
|-
|-
−
| 0x61 || BreakDebugProcess || W0=debug_handle || W0=result
+
| 0x61 || [[#BreakDebugProcess]] || ||
|-
|-
−
| 0x62 || TerminateDebugProcess || W0=debug_handle || W0=result
+
| 0x62 || [[#TerminateDebugProcess]] || ||
|-
|-
−
| 0x63 || GetDebugEvent || X0=[[#DebugEventInfo]]*, W1=debug_handle || W0=result
+
| 0x63 || [[#GetDebugEvent]] || ||
|-
|-
−
| 0x64 || [[#ContinueDebugEvent]] || [1.0.0-2.3.0] W0=debug_handle, W1=[[#ContinueDebugFlagsOld]], X2=thread_id
+
| 0x64 || [[#ContinueDebugEvent]] || ||
−
R0=debug_handle, R1=[[#ContinueDebugFlagsOld]], R2=thread_id_lower32, R3=thread_id_upper32
−
−
[3.0.0+] W0=debug_handle, W1=[[#ContinueDebugFlags]], X2=thread_id_list(u64 *), W3=num_tids (max 64, 0 means "all threads")
−
|| W0=result
|-
|-
−
| 0x65 || [[#GetProcessList]] || X1=pids_out_ptr, W2=max_out || W0=result, W1=num_out
+
| 0x65 || [[#GetProcessList]] || ||
|-
|-
−
| 0x66 || GetThreadList || X1=tids_out_ptr, W2=max_out, W3=debug_handle_or_zero || W0=result, X1=num_out
+
| 0x66 || [[#GetThreadList]] || ||
|-
|-
−
| 0x67 || GetDebugThreadContext || X0=ThreadContext*, X1=debug_handle, X2=thread_id, W3=[[#ThreadContextFlags]]
+
| 0x67 || [[#GetDebugThreadContext]] || ||
−
R0=ThreadContext*, R1=debug_handle, R2=thread_id_lower32, R3=thread_id_upper32, R4=[[#ThreadContextFlags]]
−
|| W0=result
|-
|-
−
| 0x68 || SetDebugThreadContext || W0=debug_handle, X1=thread_id, X2=ThreadContext*, W3=[[#ThreadContextFlags]]
+
| 0x68 || [[#SetDebugThreadContext]] || ||
−
R0=debug_handle, R1=ThreadContext*, R2=thread_id_lower32, R3=thread_id_upper32, R4=[[#ThreadContextFlags]]
−
|| W0=result
|-
|-
−
| 0x69 || QueryDebugProcessMemory || X0=[[#MemoryInfo]]*, X2=debug_handle, X3=addr || W0=result, W1=PageInfo
+
| 0x69 || [[#QueryDebugProcessMemory]] || ||
|-
|-
−
| 0x6A || ReadDebugProcessMemory || X0=buffer*, X1=debug_handle, X2=src_addr, X3=size || W0=result
+
| 0x6A || [[#ReadDebugProcessMemory]] || ||
|-
|-
−
| 0x6B || WriteDebugProcessMemory || X0=debug_handle, X1=buffer*, X2=dst_addr, X3=size || W0=result
+
| 0x6B || [[#WriteDebugProcessMemory]] || ||
|-
|-
−
| 0x6C || [[#SetHardwareBreakPoint]] || W0=HardwareBreakpointId, X1=watchpoint_flags/breakpoint_flags, X2=watchpoint_value/debug_handle
+
| 0x6C || [[#SetHardwareBreakPoint]] || ||
−
R0=HardwareBreakpointId, R1=value_lower32, R2=flags_lower32, R3=flags_upper32, R4=value_upper32
−
|| W0=result
|-
|-
−
| 0x6D || GetDebugThreadParam || X2=debug_handle, X3=thread_id, W4=[[#DebugThreadParam]]
+
| 0x6D || [[#GetDebugThreadParam]] || ||
−
R0=thread_id_lower32, R1=thread_id_upper32, R2=debug_handle, R3=[[#DebugThreadParam]]
−
|| W0=result, X1=out0, W2=out1
−
R0=result, R1=out0_lower32, R2=out0_upper32, R3=out1
|- style="border-top: double"
|- style="border-top: double"
−
| 0x6F || [5.0.0+] [[#GetSystemInfo]] || X1=info_id, X2=handle, X3=info_sub_id
+
| 0x6F || [5.0.0+] [[#GetSystemInfo]] || ||
−
R1=info_sub_id_lower32, R2=info_id, R3=handle, R4=info_sub_id_upper32
−
|| W0=result, X1=out
−
R0=result, R1=out_lower32, R2=out_upper32
|-
|-
| 0x70 || CreatePort || W2=max_sessions, W3=is_light, X4=name_ptr
| 0x70 || CreatePort || W2=max_sessions, W3=is_light, X4=name_ptr
Line 2,020:
Line 1,996:
Unmaps an attached device address space from an userspace address.
Unmaps an attached device address space from an userspace address.
−
== ContinueDebugEvent ==
+
== InvalidateProcessDataCache ==
<div style="display: inline-block;">
<div style="display: inline-block;">
{| class="wikitable" border="1"
{| class="wikitable" border="1"
|-
|-
−
! [1.0.0-2.3.0] Argument64 || Argument32 || Type || Name
+
! Argument64 || Argument32 || Type || Name
|-
|-
−
| (In) W0 || R0 || Handle<Debug> || DebugHandle
+
| (In) W0 || R0 || Handle<Process> || ProcessHandle
|-
|-
−
| (In) W1 || R1 || [[#ContinueDebugFlagsOld]] || DebugFlags
+
| (In) X1 || R2, R3 || u64 || Address
|-
|-
−
| (In) X2 || R2, R3 || u64 || ThreadId
+
| (In) X2 || R1, R4 || u64 || Size
|-
|-
| (Out) W0 || R0 || [[#Result]] || Result
| (Out) W0 || R0 || [[#Result]] || Result
Line 2,036:
Line 2,012:
</div>
</div>
−
<div style="display: inline-block; vertical-align:top;">
+
== StoreProcessDataCache ==
+
<div style="display: inline-block;">
{| class="wikitable" border="1"
{| class="wikitable" border="1"
|-
|-
−
! [3.0.0+] Argument64 || Argument32 || Type || Name
+
! Argument64 || Argument32 || Type || Name
|-
|-
−
| (In) W0 || R0 || Handle<Debug> || DebugHandle
+
| (In) W0 || R0 || Handle<Process> || ProcessHandle
|-
|-
−
| (In) W1 || R1 || [[#ContinueDebugFlags]] || DebugFlags
+
| (In) X1 || R2, R3 || u64 || Address
|-
|-
−
| (In) X2 || R2 || u64* || ThreadIdList
+
| (In) X2 || R1, R4 || u64 || Size
|-
|-
−
| (In) X3 || R3 || size_t || NumTids (max 64 - 0 means "all threads")
+
| (Out) W0 || R0 || [[#Result]] || Result
−
|-
−
| (Out) W0 || R0 || [[#Result]] || Ret
|}
|}
</div>
</div>
−
=== Result codes ===
+
== FlushProcessDataCache ==
−
'''0x0:''' Success. The process has been resumed.
−
−
'''0xe401:''' Invalid debug handle.
−
−
'''0xf401:''' Process has debug events queued or is already running.
−
−
== GetProcessList ==
<div style="display: inline-block;">
<div style="display: inline-block;">
{| class="wikitable" border="1"
{| class="wikitable" border="1"
Line 2,066:
Line 2,034:
! Argument64 || Argument32 || Type || Name
! Argument64 || Argument32 || Type || Name
|-
|-
−
| (In) X1 || R1 || u64* || PidBuffer
+
| (In) W0 || R0 || Handle<Process> || ProcessHandle
|-
|-
−
| (In) X2 || R2 || size_t || PidBufferSize
+
| (In) X1 || R2, R3 || u64 || Address
|-
|-
−
| (Out) X0 || R0 || [[#Result]] || Result
+
| (In) X2 || R1, R4 || u64 || Size
|-
|-
−
| (Out) X1 || R1 || size_t || NumProcesses
+
| (Out) W0 || R0 || [[#Result]] || Result
|}
|}
</div>
</div>
−
Fills the provided array with the pids of currently living processes. A process "lives" so long as it is currently running or a handle to it still exists.
+
== DebugActiveProcess ==
−
+
<div style="display: inline-block;">
−
It returns the total number of processes currently alive. If this number is bigger than the size of PidBuffer, the user won't have all the pids.
+
{| class="wikitable" border="1"
−
+
|-
−
=== Result codes ===
+
! Argument64 || Argument32 || Type || Name
−
'''0x0:''' Success.
+
|-
−
+
| (In) X1 || R2, R3 || u64 || ProcessId
−
'''0xd401:''' The provided buffer is outside the process address space.
+
|-
−
+
| (Out) W0 || R0 || [[#Result]] || Result
−
'''0xe601:''' copyToUser failed. The provided buffer is not user-accessible.
+
|-
−
+
| (Out) W1 || R1 || Handle<Debug> || DebugHandle
−
'''0xee01:''' The provided buffer size is too big. Max value is 0xFFFFFFF.
+
|}
+
</div>
−
== SetHardwareBreakPoint ==
+
== BreakDebugProcess ==
<div style="display: inline-block;">
<div style="display: inline-block;">
{| class="wikitable" border="1"
{| class="wikitable" border="1"
|-
|-
−
! Argument64 || Argument32 || Type || Name
+
! Argument || Type || Name
|-
|-
−
| (In) W0 || R0 || u32 || Id
+
| (In) W0 || Handle<Debug> || DebugHandle
|-
|-
−
| (In) X1 || R2, R3 || u64 || Flags
+
| (Out) W0 || [[#Result]] || Result
−
|-
−
| (In) X2 || R1, R4 || u64 || Value
−
|-
−
| (Out) W0 || R0 || [[#Result]] || Result
|}
|}
</div>
</div>
−
Sets one of the AArch64 hardware breakpoints. The nintendo switch has 6 hardware breakpoints, and 4 hardware watchpoints. The syscall has two behaviors depending on the value of hardware_breakpoint_id:
+
== TerminateDebugProcess ==
−
+
<div style="display: inline-block;">
−
If hardware_breakpoint_id < 0x10, then it sets one of the AArch64 hardware breakpoints. Flags will go to DBGBCRn_EL1, and value to DBGBVRn_EL1. The only flags the user is allowed to set are those in the bitmask 0x7F01E1. Furthermore, the kernel will or it with 0x4004, in order to set various security flags to guarantee the watchpoints only triggers for code in EL0. If the user asks for a Breakpoint Type of ContextIDR match, the kernel shall use the given debug_handle to set DBGBVRn_EL1 to the ContextID of the debugged process.
+
{| class="wikitable" border="1"
−
+
|-
−
If hardware_breakpoint_id is between 0x10 and 0x20 (exclusive), then it sets one of the AArch64 hardware watchpoints. Flags will go to DBGWCRn_EL1, and the value to DBGWVRn_EL1. The only flags the user is allowed to set are those in the bitmask 0xFF0F1FF9. Furthermore, the kernel will or it with 0x104004. This will set various security flags, and set the watchpoint type to be a Linked Watchpoint. This means that you need to link it to a Linked ContextIDR breakpoint. Check the ARM documentation for more information.
+
! Argument || Type || Name
+
|-
+
| (In) W0 || Handle<Debug> || DebugHandle
+
|-
+
| (Out) W0 || [[#Result]] || Result
+
|}
+
</div>
−
Note that hardware_breakpoint_id 0 to 4 match only to Virtual Address, while hardware_breakpoint_id 5 and 6 match against either Virtual Address, ContextID, or VMID. As such, if you are configuring a breakpoint to link for a watchpoint, make sure you use hardware_breakpoint_id 5 or 6.
+
== GetDebugEvent ==
+
<div style="display: inline-block;">
+
{| class="wikitable" border="1"
+
|-
+
! Argument || Type || Name
+
|-
+
| (In) X0 || [[#DebugEventInfo]]* || DebugEvents
+
|-
+
| (In) W1 || Handle<Debug> || DebugHandle
+
|-
+
| (Out) W0 || [[#Result]] || Result
+
|}
+
</div>
+
+
== ContinueDebugEvent ==
+
<div style="display: inline-block;">
+
{| class="wikitable" border="1"
+
|-
+
! Argument64 || Argument32 || Type || Name
+
|-
+
| (In) W0 || R0 || Handle<Debug> || DebugHandle
+
|-
+
| (In) W1 || R1 || [[#ContinueDebugFlags]] ([1.0.0-2.3.0] [[#ContinueDebugFlagsOld]]) || DebugFlags
+
|-
+
| (In) X2 || R2 ([1.0.0-2.3.0] R2, R3) || u64* ([1.0.0-2.3.0] u64)|| ThreadIdList ([1.0.0-2.3.0] ThreadId)
+
|-
+
| (In) X3 || R3 || size_t || [3.0.0+] NumTids
+
|-
+
| (Out) W0 || R0 || [[#Result]] || Result
+
|}
+
</div>
+
+
Maximum NumTids is 64. 0 means "all threads".
+
+
=== Result codes ===
+
'''0x0:''' Success. The process has been resumed.
+
+
'''0xe401:''' Invalid debug handle.
+
+
'''0xf401:''' Process has debug events queued or is already running.
+
+
== GetProcessList ==
+
<div style="display: inline-block;">
+
{| class="wikitable" border="1"
+
|-
+
! Argument64 || Argument32 || Type || Name
+
|-
+
| (In) X1 || R1 || u64* || ProcessIdBuffer
+
|-
+
| (In) W2 || R2 || size_t || ProcessIdBufferSize
+
|-
+
| (Out) X0 || R0 || [[#Result]] || Result
+
|-
+
| (Out) W1 || R1 || size_t || NumProcesses
+
|}
+
</div>
+
+
Fills the provided array with the pids of currently living processes. A process "lives" so long as it is currently running or a handle to it still exists.
+
+
It returns the total number of processes currently alive. If this number is bigger than the size of PidBuffer, the user won't have all the pids.
+
+
=== Result codes ===
+
'''0x0:''' Success.
+
+
'''0xd401:''' The provided buffer is outside the process address space.
+
+
'''0xe601:''' copyToUser failed. The provided buffer is not user-accessible.
+
+
'''0xee01:''' The provided buffer size is too big. Max value is 0xFFFFFFF.
+
+
== GetThreadList ==
+
<div style="display: inline-block;">
+
{| class="wikitable" border="1"
+
|-
+
! Argument64 || Argument32 || Type || Name
+
|-
+
| (In) X1 || R1 || u64* || ThreadIdBuffer
+
|-
+
| (In) W2 || R2 || size_t || ThreadIdBufferSize
+
|-
+
| (In) W3 || R3 || Handle<Debug> || DebugHandle
+
|-
+
| (Out) X0 || R0 || [[#Result]] || Result
+
|-
+
| (Out) W1 || R1 || size_t || NumThreads
+
|}
+
</div>
+
+
== GetDebugThreadContext ==
+
<div style="display: inline-block;">
+
{| class="wikitable" border="1"
+
|-
+
! Argument64 || Argument32 || Type || Name
+
|-
+
| (In) X0 || R0 || ThreadContext* || ThreadContextBuffer
+
|-
+
| (In) X1 || R1 || Handle<Debug> || DebugHandle
+
|-
+
| (In) X2 || R2, R3 || u64 || ThreadId
+
|-
+
| (In) W3 || R4 || u32 || [[#ThreadContextFlags]]
+
|-
+
| (Out) W0 || R0 || [[#Result]] || Result
+
|}
+
</div>
+
+
== SetDebugThreadContext ==
+
<div style="display: inline-block;">
+
{| class="wikitable" border="1"
+
|-
+
! Argument64 || Argument32 || Type || Name
+
|-
+
| (In) W0 || R0 || Handle<Debug> || DebugHandle
+
|-
+
| (In) X1 || R2, R3 || u64 || ThreadId
+
|-
+
| (In) X2 || R1 || ThreadContext* || ThreadContextBuffer
+
|-
+
| (In) W3 || R4 || u32 || [[#ThreadContextFlags]]
+
|-
+
| (Out) W0 || R0 || [[#Result]] || Result
+
|}
+
</div>
+
+
== QueryDebugProcessMemory ==
+
<div style="display: inline-block;">
+
{| class="wikitable" border="1"
+
|-
+
! Argument || Type || Name
+
|-
+
| (In) X0 || [[#MemoryInfo]]* || MemoryInfoBuffer
+
|-
+
| (In) W2 || Handle<Debug> || DebugHandle
+
|-
+
| (In) X3 || u64 || Address
+
|-
+
| (Out) W0 || [[#Result]] || Result
+
|-
+
| (Out) W1 || PageInfo || PageInfo
+
|}
+
</div>
+
+
== ReadDebugProcessMemory ==
+
<div style="display: inline-block;">
+
{| class="wikitable" border="1"
+
|-
+
! Argument || Type || Name
+
|-
+
| (In) X0 || u64 || MemoryBuffer
+
|-
+
| (In) W1 || Handle<Debug> || DebugHandle
+
|-
+
| (In) X2 || u64 || SrcAddress
+
|-
+
| (In) X3 || u64 || Size
+
|-
+
| (Out) W0 || [[#Result]] || Result
+
|}
+
</div>
+
+
== WriteDebugProcessMemory ==
+
<div style="display: inline-block;">
+
{| class="wikitable" border="1"
+
|-
+
! Argument || Type || Name
+
|-
+
| (In) W0 || Handle<Debug> || DebugHandle
+
|-
+
| (In) X1 || u64 || MemoryBuffer
+
|-
+
| (In) X2 || u64 || DstAddress
+
|-
+
| (In) X3 || u64 || Size
+
|-
+
| (Out) W0 || [[#Result]] || Result
+
|}
+
</div>
+
+
== SetHardwareBreakPoint ==
+
<div style="display: inline-block;">
+
{| class="wikitable" border="1"
+
|-
+
! Argument64 || Argument32 || Type || Name
+
|-
+
| (In) W0 || R0 || HardwareBreakPointRegisterName || Name
+
|-
+
| (In) X1 || R2, R3 || u64 || Flags
+
|-
+
| (In) X2 || R1, R4 || u64 || Value
+
|-
+
| (Out) W0 || R0 || [[#Result]] || Result
+
|}
+
</div>
+
+
Sets one of the AArch64 hardware breakpoints. The nintendo switch has 6 hardware breakpoints, and 4 hardware watchpoints. The syscall has two behaviors depending on the value of HardwareBreakPointRegisterName:
+
+
If HardwareBreakPointRegisterName < 0x10, then it sets one of the AArch64 hardware breakpoints. Flags will go to DBGBCRn_EL1, and value to DBGBVRn_EL1. The only flags the user is allowed to set are those in the bitmask 0x7F01E1. Furthermore, the kernel will or it with 0x4004, in order to set various security flags to guarantee the watchpoints only triggers for code in EL0. If the user asks for a Breakpoint Type of ContextIDR match, the kernel shall use the given DebugHandle to set DBGBVRn_EL1 to the ContextID of the debugged process.
+
+
If HardwareBreakPointRegisterName is between 0x10 and 0x20 (exclusive), then it sets one of the AArch64 hardware watchpoints. Flags will go to DBGWCRn_EL1, and the value to DBGWVRn_EL1. The only flags the user is allowed to set are those in the bitmask 0xFF0F1FF9. Furthermore, the kernel will or it with 0x104004. This will set various security flags, and set the watchpoint type to be a Linked Watchpoint. This means that you need to link it to a Linked ContextIDR breakpoint. Check the ARM documentation for more information.
+
+
Note that HardwareBreakPointRegisterName 0 to 4 match only to Virtual Address, while HardwareBreakPointRegisterName 5 and 6 match against either Virtual Address, ContextID, or VMID. As such, if you are configuring a breakpoint to link for a watchpoint, make sure you use hardware_breakpoint_id 5 or 6.
For more documentation for hardware breakpoints, check out the AArch64 documentation for the [http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0488h/way1382455558968.html DBGBCRn_EL1 register] and the [http://infocenter.arm.com/help/topic/com.arm.doc.ddi0488h/way1382455560629.html DBGWCRn_EL1 register]
For more documentation for hardware breakpoints, check out the AArch64 documentation for the [http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0488h/way1382455558968.html DBGBCRn_EL1 register] and the [http://infocenter.arm.com/help/topic/com.arm.doc.ddi0488h/way1382455560629.html DBGWCRn_EL1 register]
+
+
== GetDebugThreadParam ==
+
<div style="display: inline-block;">
+
{| class="wikitable" border="1"
+
|-
+
! Argument64 || Argument32 || Type || Name
+
|-
+
| (In) X2 || R2 || Handle<Debug> || DebugHandle
+
|-
+
| (In) X3 || R0, R1 || u64 || ThreadId
+
|-
+
| (In) W4 || R3 || [[#DebugThreadParam]] || Param
+
|-
+
| (Out) W0 || R0 || [[#Result]] || Result
+
|-
+
| (Out) X1 || R1, R2 || u64 || Out0
+
|-
+
| (Out) W2 || R3 || u32 || Out1
+
|}
+
</div>
== GetSystemInfo ==
== GetSystemInfo ==