diff --git a/nx/include/switch/services/fatal.h b/nx/include/switch/services/fatal.h index 0e145780..f58cd0ef 100644 --- a/nx/include/switch/services/fatal.h +++ b/nx/include/switch/services/fatal.h @@ -14,6 +14,65 @@ typedef enum { FatalType_ErrorScreen = 2 ///< Only available with 3.0.0+. If specified, FatalType_ErrorReportAndErrorScreen will be used instead on pre-3.0.0. } FatalType; +/// Struct for fatal Cpu context, 64-bit. +typedef struct { + union { + u64 x[32]; + struct { + u64 _x[29]; + u64 fp; + u64 lr; + u64 sp; + u64 pc; + }; + }; + u64 pstate; + u64 afsr0; + u64 afsr1; + u64 esr; + u64 far; + + u64 stack_trace[32]; + u64 start_address; ///< Address of first NSO loaded (generally, process entrypoint). + u64 register_set_flags; ///< Bitmask, bit i indicates GPR i has a value. + u32 stack_trace_size; +} FatalAarch64Context; + +/// Struct for fatal Cpu context, 32-bit. +typedef struct { + union { + u32 r[16]; + struct { + u32 _r[11]; + u32 fp; + u32 ip; + u32 sp; + u32 lr; + u32 pc; + }; + }; + u32 pstate; + u32 afsr0; + u32 afsr1; + u32 esr; + u32 far; + + u32 stack_trace[32]; + u32 stack_trace_size; + u32 start_address; ///< Address of first NSO loaded (generally, process entrypoint). + u32 register_set_flags; ///< Bitmask, bit i indicates GPR i has a value. +} FatalAarch32Context; + +typedef struct { + union { + FatalAarch64Context aarch64_ctx; + FatalAarch32Context aarch32_ctx; + }; + + bool is_aarch32; + u32 type; +} FatalContext; + /** * @brief Triggers a system fatal error. * @param err[in] Result code to throw. @@ -25,7 +84,16 @@ void NORETURN fatalSimple(Result err); /** * @brief Triggers a system fatal error with a custom \ref FatalType. * @param err[in] Result code to throw. - * @param err[in] Type of fatal error to throw. + * @param type[in] Type of fatal error to throw. * @note This function may not return, depending on \ref FatalType. */ void fatalWithType(Result err, FatalType type); + +/** + * @brief Triggers a system fatal error with a custom \ref FatalType and \ref FatalContext. + * @param err[in] Result code to throw. + * @param type[in] Type of fatal error to throw. + * @param ctx[in] Cpu context for fatal error to throw. + * @note This function may not return, depending on \ref FatalType. + */ +void fatalWithContext(Result err, FatalType type, FatalContext *ctx); diff --git a/nx/source/services/fatal.c b/nx/source/services/fatal.c index 14f2ef7c..d9a08c7c 100644 --- a/nx/source/services/fatal.c +++ b/nx/source/services/fatal.c @@ -7,14 +7,7 @@ #include "services/fatal.h" #include "services/sm.h" -void NORETURN fatalSimple(Result err) { - /* By default, do not generate an error report. */ - fatalWithType(err, FatalType_ErrorScreen); - svcExitProcess(); - __builtin_unreachable(); -} - -void fatalWithType(Result err, FatalType type) { +static void _fatalImpl(u32 cmd_id, Result err, FatalType type, FatalContext *ctx) { Result rc = 0; //Only 3.0.0+ supports FatalType_ErrorScreen, when specified on pre-3.0.0 use FatalType_ErrorReportAndErrorScreen instead. @@ -36,6 +29,9 @@ void fatalWithType(Result err, FatalType type) { IpcCommand c; ipcInitialize(&c); ipcSendPid(&c); + if (ctx != NULL) { + ipcAddSendBuffer(&c, ctx, sizeof(*ctx), BufferType_Normal); + } struct { u64 magic; @@ -48,7 +44,7 @@ void fatalWithType(Result err, FatalType type) { raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; - raw->cmd_id = 1; + raw->cmd_id = cmd_id; raw->result = err; raw->type = type; raw->pid_placeholder = 0; // Overwritten by fatal with PID descriptor. @@ -67,3 +63,18 @@ void fatalWithType(Result err, FatalType type) { __builtin_unreachable(); } } + +void NORETURN fatalSimple(Result err) { + /* By default, do not generate an error report. */ + fatalWithType(err, FatalType_ErrorScreen); + svcExitProcess(); + __builtin_unreachable(); +} + +void fatalWithType(Result err, FatalType type) { + _fatalImpl(1, err, type, NULL); +} + +void fatalWithContext(Result err, FatalType type, FatalContext *ctx) { + _fatalImpl(2, err, type, ctx); +}