From 5498d3e0c7619498e5d9503b755ee07fd1e5bc96 Mon Sep 17 00:00:00 2001 From: TuxSH Date: Sun, 16 Sep 2018 00:53:24 +0200 Subject: [PATCH] Add ThreadContext, RegisterGroup, svcGetThreadContext3, threadDumpContext --- nx/include/switch/arm/thread_context.h | 61 ++++++++++++++++++++++++++ nx/include/switch/kernel/svc.h | 13 +++++- nx/include/switch/kernel/thread.h | 10 +++++ nx/source/kernel/svc.s | 7 ++- 4 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 nx/include/switch/arm/thread_context.h diff --git a/nx/include/switch/arm/thread_context.h b/nx/include/switch/arm/thread_context.h new file mode 100644 index 00000000..1a596d1c --- /dev/null +++ b/nx/include/switch/arm/thread_context.h @@ -0,0 +1,61 @@ +/** + * @file thread_context.h + * @brief AArch64 register dump format and related definitions. + * @author TuxSH + * @copyright libnx Authors + */ + +#pragma once +#include "../types.h" + +/// Armv8 CPU register. +typedef union { + u64 x; ///< 64-bit AArch64 register view. + u32 w; ///< 32-bit AArch64 register view. + u32 r; ///< AArch32 register view. +} CpuRegister; + +/// Armv8 NEON register. +typedef union { + u128 v; ///< 128-bit vector view. + double d; ///< 64-bit double-precision view. + float s; ///< 32-bit single-precision view. +} FpuRegister; + +/// Armv8 register group. @ref svcGetThreadContext3 uses @ref RegisterGroup_All. +typedef enum { + RegisterGroup_CpuGprs = BIT(0), ///< General-purpose CPU registers (x0..x28 or r0..r10,r12). + RegisterGroup_CpuSprs = BIT(1), ///< Special-purpose CPU registers (fp, lr, sp, pc, PSTATE or cpsr, TPIDR_EL0). + RegisterGroup_FpuGprs = BIT(2), ///< General-purpose NEON registers. + RegisterGroup_FpuSprs = BIT(3), ///< Special-purpose NEON registers. + + RegisterGroup_CpuAll = RegisterGroup_CpuGprs | RegisterGroup_CpuSprs, ///< All CPU registers. + RegisterGroup_FpuAll = RegisterGroup_FpuGprs | RegisterGroup_FpuSprs, ///< All NEON registers. + RegisterGroup_All = RegisterGroup_CpuAll | RegisterGroup_FpuAll, ///< All registers. +} RegisterGroup; + +/// Thread context structure (register dump) +typedef struct { + CpuRegister cpu_gprs[29]; ///< GPRs 0..28. Note: also contains AArch32 SPRs. + u64 fp; ///< Frame pointer (x29) (AArch64). For AArch32, check r11. + u64 lr; ///< Link register (x30) (AArch64). For AArch32, check r14. + u64 sp; ///< Stack pointer (AArch64). For AArch32, check r13. + CpuRegister pc; ///< Program counter. + u32 psr; ///< PSTATE or cpsr. + + FpuRegister fpu_gprs[32]; ///< 32 general-purpose NEON registers. + u32 fpcr; ///< Floating-point control register. + u32 fpsr; ///< Floating-point status register. + + u64 tpidr; ///< EL0 Read/Write Software Thread ID Register. +} ThreadContext; + +/** + * @brief Determines whether a thread context belong to an AArch64 process based on the PSR. + * @param[in] ctx Thread context to which PSTATE/cspr has been dumped to. + * @return true if and only if the thread context belongs to an AArch64 process. + */ +static inline bool threadContextIsAArch64(const ThreadContext *ctx) +{ + return (ctx->psr & 0x10) == 0; +} diff --git a/nx/include/switch/kernel/svc.h b/nx/include/switch/kernel/svc.h index 9c795874..516fbf07 100644 --- a/nx/include/switch/kernel/svc.h +++ b/nx/include/switch/kernel/svc.h @@ -5,6 +5,7 @@ */ #pragma once #include "../types.h" +#include "../arm/thread_context.h" /// Pseudo handle for the current process. #define CUR_PROCESS_HANDLE 0xFFFF8001 @@ -575,6 +576,16 @@ Result svcGetResourceLimitCurrentValue(u64 *out, Handle reslimit_h, LimitableRes */ Result svcSetThreadActivity(Handle thread, bool paused); +/** + * @brief Dumps the registers of a thread paused by @ref svcSetThreadActivity (register groups: all). + * @param[out] ctx Output thread context (register dump). + * @param[in] thread Thread handle. + * @return Result code. + * @note Syscall number 0x33. + * @warning Official kernel will not dump x0..x18 if the thread is currently executing a system call, and prior to 6.0.0 doesn't dump TPIDR_EL0. + */ +Result svcGetThreadContext3(ThreadContext* ctx, Handle thread); + ///@} ///@name Inter-process communication (IPC) @@ -937,7 +948,7 @@ Result svcGetSystemInfo(u64* out, u64 id0, Handle handle, u64 id1); ///@name Inter-process communication (IPC) ///@{ - + /** * @brief Creates a port. * @return Result code. diff --git a/nx/include/switch/kernel/thread.h b/nx/include/switch/kernel/thread.h index 80e0972d..4a858f6c 100644 --- a/nx/include/switch/kernel/thread.h +++ b/nx/include/switch/kernel/thread.h @@ -6,6 +6,7 @@ */ #pragma once #include "../types.h" +#include "../arm/thread_context.h" /// Thread information structure. typedef struct { @@ -63,3 +64,12 @@ Result threadPause(Thread* t); * @return Result code. */ Result threadResume(Thread* t); + +/** + * @brief Dumps the registers of a thread paused by @ref threadPause (register groups: all). + * @param[out] ctx Output thread context (register dump). + * @param t Thread information structure. + * @return Result code. + * @warning Official kernel will not dump x0..x18 if the thread is currently executing a system call, and prior to 6.0.0 doesn't dump TPIDR_EL0. + */ +Result threadDumpContext(ThreadContext* ctx, Thread* t); diff --git a/nx/source/kernel/svc.s b/nx/source/kernel/svc.s index afebca48..3263e9a9 100644 --- a/nx/source/kernel/svc.s +++ b/nx/source/kernel/svc.s @@ -274,6 +274,11 @@ SVC_BEGIN svcSetThreadActivity ret SVC_END +SVC_BEGIN svcGetThreadContext3 + svc 0x33 + ret +SVC_END + SVC_BEGIN svcCreateSession stp x0, x1, [sp, #-16]! svc 0x40 @@ -370,7 +375,7 @@ SVC_BEGIN svcUnmapTransferMemory ret SVC_END -SVC_BEGIN svcCreateInterruptEvent +SVC_BEGIN svcCreateInterruptEvent str x0, [sp, #-16]! svc 0x53 ldr x2, [sp], #16