Compare commits

...

4 Commits

Author SHA1 Message Date
Michael Scire
9b3b08bdeb kern: fix KCodeMemory SVCs when Owner process != Generator process 2020-09-17 08:25:27 -07:00
Michael Scire
84f17f6a3a kern: default to release config 2020-09-16 21:18:02 -07:00
Michael Scire
3b0ed9cdba kern: generate fatal error on panic 2020-09-16 16:47:29 -07:00
Michael Scire
4df583cbb6 kern: add build-define for logging to iram ringbuffer 2020-09-16 16:47:18 -07:00
16 changed files with 354 additions and 59 deletions

View File

@@ -42,6 +42,8 @@ static const char *get_error_desc_str(uint32_t error_desc) {
return "SError"; return "SError";
case 0x301: case 0x301:
return "Bad SVC"; return "Bad SVC";
case 0xF00:
return "Kernel Panic";
case 0xFFD: case 0xFFD:
return "Stack overflow"; return "Stack overflow";
case 0xFFE: case 0xFFE:

View File

@@ -63,7 +63,7 @@ namespace ams::kern::board::nintendo::nx {
/* Power management. */ /* Power management. */
static void SleepSystem(); static void SleepSystem();
static NORETURN void StopSystem(); static NORETURN void StopSystem(void *arg = nullptr);
/* User access. */ /* User access. */
static void CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args); static void CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args);

View File

@@ -15,7 +15,7 @@
*/ */
#pragma once #pragma once
#if 1 || defined(AMS_BUILD_FOR_AUDITING) #if defined(AMS_BUILD_FOR_AUDITING)
#define MESOSPHERE_BUILD_FOR_AUDITING #define MESOSPHERE_BUILD_FOR_AUDITING
#endif #endif
@@ -28,4 +28,5 @@
#define MESOSPHERE_ENABLE_DEBUG_PRINT #define MESOSPHERE_ENABLE_DEBUG_PRINT
#endif #endif
#define MESOSPHERE_BUILD_FOR_TRACING //#define MESOSPHERE_BUILD_FOR_TRACING
#define MESOSPHERE_ENABLE_PANIC_REGISTER_DUMP

View File

@@ -40,7 +40,7 @@ namespace ams::kern {
#ifndef MESOSPHERE_DEBUG_LOG_SELECTED #ifndef MESOSPHERE_DEBUG_LOG_SELECTED
#ifdef ATMOSPHERE_BOARD_NINTENDO_NX #ifdef ATMOSPHERE_BOARD_NINTENDO_NX
#define MESOSPHERE_DEBUG_LOG_USE_UART_C #define MESOSPHERE_DEBUG_LOG_USE_UART_A
#else #else
#error "Unknown board for Default Debug Log Source" #error "Unknown board for Default Debug Log Source"
#endif #endif

View File

@@ -0,0 +1,88 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <mesosphere/kern_build_config.hpp>
#if defined(MESOSPHERE_ENABLE_PANIC_REGISTER_DUMP)
#define MESOSPHERE_GENERATE_PANIC_EXCEPTION_CONTEXT \
/* Save x0/x1 to stack. */ \
stp x0, x1, [sp, #-16]!; \
\
/* Get the exception context for the core. */ \
adr x0, _ZN3ams4kern26g_panic_exception_contextsE; \
mrs x1, mpidr_el1; \
and x1, x1, #0xFF; \
lsl x1, x1, #0x8; \
add x0, x0, x1; \
lsr x1, x1, #0x3; \
add x0, x0, x1; \
\
/* Save x0/x1/sp to the context. */ \
ldr x1, [sp, #(8 * 0)]; \
str x1, [x0, #(8 * 0)]; \
ldr x1, [sp, #(8 * 1)]; \
str x1, [x0, #(8 * 1)]; \
\
/* Save all other registers to the context. */ \
stp x2, x3, [x0, #(8 * 2)]; \
stp x4, x5, [x0, #(8 * 4)]; \
stp x6, x7, [x0, #(8 * 6)]; \
stp x8, x9, [x0, #(8 * 8)]; \
stp x10, x11, [x0, #(8 * 10)]; \
stp x12, x13, [x0, #(8 * 12)]; \
stp x14, x15, [x0, #(8 * 14)]; \
stp x16, x17, [x0, #(8 * 16)]; \
stp x18, x19, [x0, #(8 * 18)]; \
stp x20, x21, [x0, #(8 * 20)]; \
stp x22, x23, [x0, #(8 * 22)]; \
stp x24, x25, [x0, #(8 * 24)]; \
stp x26, x27, [x0, #(8 * 26)]; \
stp x28, x29, [x0, #(8 * 28)]; \
\
add x1, sp, #16; \
stp x30, x1, [x0, #(8 * 30)]; \
\
/* Restore x0/x1. */ \
ldp x0, x1, [sp], #16;
#else
#define MESOSPHERE_GENERATE_PANIC_EXCEPTION_CONTEXT
#endif
/* ams::kern::Panic(const char *file, int line, const char *format, ...) */
.section .text._ZN3ams4kern5PanicEPKciS2_z, "ax", %progbits
.global _ZN3ams4kern5PanicEPKciS2_z
.type _ZN3ams4kern5PanicEPKciS2_z, %function
_ZN3ams4kern5PanicEPKciS2_z:
/* Generate the exception context. */
MESOSPHERE_GENERATE_PANIC_EXCEPTION_CONTEXT
/* Jump to the architecturally-common implementation function. */
b _ZN3ams4kern9PanicImplEPKciS2_z
/* ams::kern::Panic() */
.section .text._ZN3ams4kern5PanicEv, "ax", %progbits
.global _ZN3ams4kern5PanicEv
.type _ZN3ams4kern5PanicEv, %function
_ZN3ams4kern5PanicEv:
/* Generate the exception context. */
MESOSPHERE_GENERATE_PANIC_EXCEPTION_CONTEXT
/* Jump to the architecturally-common implementation function. */
b _ZN3ams4kern9PanicImplEv

View File

@@ -532,13 +532,63 @@ namespace ams::kern::board::nintendo::nx {
KSleepManager::SleepSystem(); KSleepManager::SleepSystem();
} }
void KSystemControl::StopSystem() { void KSystemControl::StopSystem(void *arg) {
if (arg != nullptr) {
/* NOTE: Atmosphere extension; if we received an exception context from Panic(), */
/* generate a fatal error report using it. */
const KExceptionContext *e_ctx = static_cast<const KExceptionContext *>(arg);
auto *f_ctx = GetPointer<::ams::impl::FatalErrorContext>(KMemoryLayout::GetDeviceVirtualAddress(KMemoryRegionType_LegacyLpsIram) + 0x3E000);
/* Clear the fatal context. */
std::memset(f_ctx, 0xCC, sizeof(*f_ctx));
/* Set metadata. */
f_ctx->magic = ::ams::impl::FatalErrorContext::Magic;
f_ctx->error_desc = ::ams::impl::FatalErrorContext::KernelPanicDesc;
f_ctx->program_id = (static_cast<u64>(util::FourCC<'M', 'E', 'S', 'O'>::Code) << 0) | (static_cast<u64>(util::FourCC<'S', 'P', 'H', 'R'>::Code) << 32);
/* Set identifier. */
f_ctx->report_identifier = KHardwareTimer::GetTick();
/* Set module base. */
f_ctx->module_base = KMemoryLayout::GetKernelCodeRegionExtents().GetAddress();
/* Copy registers. */
for (size_t i = 0; i < util::size(e_ctx->x); ++i) {
f_ctx->gprs[i] = e_ctx->x[i];
}
f_ctx->sp = e_ctx->sp;
/* Dump stack trace. */
{
uintptr_t fp = e_ctx->x[29];
for (f_ctx->stack_trace_size = 0; f_ctx->stack_trace_size < ::ams::impl::FatalErrorContext::MaxStackTrace && fp != 0 && util::IsAligned(fp, 0x10) && cpu::GetPhysicalAddressWritable(nullptr, fp, true); ++(f_ctx->stack_trace_size)) {
struct {
uintptr_t fp;
uintptr_t lr;
} *stack_frame = reinterpret_cast<decltype(stack_frame)>(fp);
f_ctx->stack_trace[f_ctx->stack_trace_size] = stack_frame->lr;
fp = stack_frame->fp;
}
}
/* Dump stack. */
{
uintptr_t sp = e_ctx->sp;
for (f_ctx->stack_dump_size = 0; f_ctx->stack_dump_size < ::ams::impl::FatalErrorContext::MaxStackDumpSize && cpu::GetPhysicalAddressWritable(nullptr, sp + f_ctx->stack_dump_size, true); f_ctx->stack_dump_size += sizeof(u64)) {
*reinterpret_cast<u64 *>(f_ctx->stack_dump + f_ctx->stack_dump_size) = *reinterpret_cast<u64 *>(sp + f_ctx->stack_dump_size);
}
}
/* Trigger a reboot to rcm. */
smc::init::SetConfig(smc::ConfigItem::ExosphereNeedsReboot, smc::UserRebootType_ToRcm);
}
if (g_call_smc_on_panic) { if (g_call_smc_on_panic) {
/* Display a panic screen via secure monitor. */ /* If we should, instruct the secure monitor to display a panic screen. */
smc::Panic(0xF00); smc::Panic(0xF00);
} }
u32 dummy;
smc::init::ReadWriteRegister(std::addressof(dummy), 0x7000E400, 0x10, 0x10);
AMS_INFINITE_LOOP(); AMS_INFINITE_LOOP();
} }

View File

@@ -24,6 +24,10 @@ namespace ams::kern::board::nintendo::nx::smc {
u64 x[8]; u64 x[8];
}; };
enum UserFunctionId : u32 {
UserFunctionId_SetConfig = 0xC3000401,
};
enum FunctionId : u32 { enum FunctionId : u32 {
FunctionId_CpuSuspend = 0xC4000001, FunctionId_CpuSuspend = 0xC4000001,
FunctionId_CpuOff = 0x84000002, FunctionId_CpuOff = 0x84000002,
@@ -136,6 +140,35 @@ namespace ams::kern::board::nintendo::nx::smc {
args.x[7] = x7; args.x[7] = x7;
} }
void CallUserSecureMonitorFunctionForInit(SecureMonitorArguments &args) {
/* Load arguments into registers. */
register u64 x0 asm("x0") = args.x[0];
register u64 x1 asm("x1") = args.x[1];
register u64 x2 asm("x2") = args.x[2];
register u64 x3 asm("x3") = args.x[3];
register u64 x4 asm("x4") = args.x[4];
register u64 x5 asm("x5") = args.x[5];
register u64 x6 asm("x6") = args.x[6];
register u64 x7 asm("x7") = args.x[7];
/* Actually make the call. */
__asm__ __volatile__("smc #0"
: "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3), "+r"(x4), "+r"(x5), "+r"(x6), "+r"(x7)
:
: "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "cc", "memory"
);
/* Store arguments to output. */
args.x[0] = x0;
args.x[1] = x1;
args.x[2] = x2;
args.x[3] = x3;
args.x[4] = x4;
args.x[5] = x5;
args.x[6] = x6;
args.x[7] = x7;
}
/* Global lock for generate random bytes. */ /* Global lock for generate random bytes. */
KSpinLock g_generate_random_lock; KSpinLock g_generate_random_lock;
@@ -177,6 +210,12 @@ namespace ams::kern::board::nintendo::nx::smc {
return static_cast<SmcResult>(args.x[0]) == SmcResult::Success; return static_cast<SmcResult>(args.x[0]) == SmcResult::Success;
} }
bool SetConfig(ConfigItem config_item, u64 value) {
SecureMonitorArguments args = { UserFunctionId_SetConfig, static_cast<u32>(config_item), 0, value };
CallUserSecureMonitorFunctionForInit(args);
return static_cast<SmcResult>(args.x[0]) == SmcResult::Success;
}
} }
void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item) { void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item) {

View File

@@ -83,6 +83,12 @@ namespace ams::kern::board::nintendo::nx::smc {
using MemorySize = util::BitPack32::Field<Reserved9::Next, 2, smc::MemorySize>; using MemorySize = util::BitPack32::Field<Reserved9::Next, 2, smc::MemorySize>;
}; };
enum UserRebootType {
UserRebootType_None = 0,
UserRebootType_ToRcm = 1,
UserRebootType_ToPayload = 2,
};
/* TODO: Rest of Secure Monitor API. */ /* TODO: Rest of Secure Monitor API. */
void GenerateRandomBytes(void *dst, size_t size); void GenerateRandomBytes(void *dst, size_t size);
void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item); void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item);
@@ -102,6 +108,8 @@ namespace ams::kern::board::nintendo::nx::smc {
void GenerateRandomBytes(void *dst, size_t size); void GenerateRandomBytes(void *dst, size_t size);
bool ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value); bool ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value);
bool SetConfig(ConfigItem config_item, u64 value);
} }
} }

View File

@@ -18,6 +18,8 @@
namespace ams::kern { namespace ams::kern {
#if defined(MESOSPHERE_DEBUG_LOG_USE_UART_A) || defined(MESOSPHERE_DEBUG_LOG_USE_UART_B) || defined(MESOSPHERE_DEBUG_LOG_USE_UART_C) || defined(MESOSPHERE_DEBUG_LOG_USE_UART_D)
namespace { namespace {
enum UartRegister { enum UartRegister {
@@ -138,4 +140,52 @@ namespace ams::kern {
ReadUartRegister(UartRegister_FCR); ReadUartRegister(UartRegister_FCR);
} }
#elif defined(MESOSPHERE_DEBUG_LOG_USE_IRAM_RINGBUFFER)
namespace {
constinit KVirtualAddress g_debug_iram_address = 0;
constexpr size_t RingBufferSize = 0x5000;
constinit uintptr_t g_offset = 0;
constinit u8 g_saved_buffer[RingBufferSize];
}
bool KDebugLogImpl::Initialize() {
/* Set the base address. */
g_debug_iram_address = KMemoryLayout::GetDeviceVirtualAddress(KMemoryRegionType_LegacyLpsIram) + 0x38000;
std::memset(GetVoidPointer(g_debug_iram_address), 0xFF, RingBufferSize);
return true;
}
void KDebugLogImpl::PutChar(char c) {
GetPointer<char>(g_debug_iram_address)[g_offset++] = c;
if (g_offset == RingBufferSize) {
g_offset = 0;
}
}
void KDebugLogImpl::Flush() {
/* ... */
}
void KDebugLogImpl::Save() {
std::memcpy(g_saved_buffer, GetVoidPointer(g_debug_iram_address), RingBufferSize);
}
void KDebugLogImpl::Restore() {
std::memcpy(GetVoidPointer(g_debug_iram_address), g_saved_buffer, RingBufferSize);
}
#else
#error "Unknown Debug UART device!"
#endif
} }

View File

@@ -133,7 +133,7 @@ namespace ams::kern {
} }
/* Map the memory. */ /* Map the memory. */
R_TRY(GetCurrentProcess().GetPageTable().MapPageGroup(address, GetReference(this->page_group), KMemoryState_GeneratedCode, k_perm)); R_TRY(this->owner->GetPageTable().MapPageGroup(address, GetReference(this->page_group), KMemoryState_GeneratedCode, k_perm));
/* Mark ourselves as mapped. */ /* Mark ourselves as mapped. */
this->is_owner_mapped = true; this->is_owner_mapped = true;
@@ -151,7 +151,7 @@ namespace ams::kern {
KScopedLightLock lk(this->lock); KScopedLightLock lk(this->lock);
/* Unmap the memory. */ /* Unmap the memory. */
R_TRY(GetCurrentProcess().GetPageTable().UnmapPageGroup(address, GetReference(this->page_group), KMemoryState_GeneratedCode)); R_TRY(this->owner->GetPageTable().UnmapPageGroup(address, GetReference(this->page_group), KMemoryState_GeneratedCode));
/* Mark ourselves as unmapped. */ /* Mark ourselves as unmapped. */
MESOSPHERE_ASSERT(this->is_owner_mapped); MESOSPHERE_ASSERT(this->is_owner_mapped);

View File

@@ -34,6 +34,8 @@ namespace ams::kern {
return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006200, 0x100, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap); return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006200, 0x100, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap);
#elif defined(MESOSPHERE_DEBUG_LOG_USE_UART_D) #elif defined(MESOSPHERE_DEBUG_LOG_USE_UART_D)
return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006300, 0x100, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap); return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006300, 0x100, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap);
#elif defined(MESOSPHERE_DEBUG_LOG_USE_IRAM_RINGBUFFER)
return true;
#else #else
#error "Unknown Debug UART device!" #error "Unknown Debug UART device!"
#endif #endif

View File

@@ -27,6 +27,11 @@ namespace ams::result::impl {
namespace ams::kern { namespace ams::kern {
/* NOTE: This is not exposed via a header, but is referenced via assembly. */
/* NOTE: Nintendo does not save register contents on panic; we use this */
/* to generate an atmosphere fatal report on panic. */
constinit KExceptionContext g_panic_exception_contexts[cpu::NumCores];
namespace { namespace {
constexpr std::array<s32, cpu::NumCores> NegativeArray = [] { constexpr std::array<s32, cpu::NumCores> NegativeArray = [] {
@@ -73,18 +78,38 @@ namespace ams::kern {
} while (!g_current_ticket.compare_exchange_weak(compare, desired)); } while (!g_current_ticket.compare_exchange_weak(compare, desired));
} }
ALWAYS_INLINE KExceptionContext *GetPanicExceptionContext(int core_id) {
#if defined(MESOSPHERE_ENABLE_PANIC_REGISTER_DUMP)
return std::addressof(g_panic_exception_contexts[core_id]);
#else
return nullptr;
#endif
}
[[gnu::unused]] void PrintCurrentState() { [[gnu::unused]] void PrintCurrentState() {
/* Wait for it to be our turn to print. */ /* Wait for it to be our turn to print. */
WaitCoreTicket(); WaitCoreTicket();
const s32 core_id = GetCurrentCoreId(); /* Get the current exception context. */
const s32 core_id = GetCurrentCoreId();
const auto *core_ctx = GetPanicExceptionContext(core_id);
/* Print the state. */
MESOSPHERE_RELEASE_LOG("Core[%d] Current State:\n", core_id); MESOSPHERE_RELEASE_LOG("Core[%d] Current State:\n", core_id);
/* TODO: Dump register state. */
#ifdef ATMOSPHERE_ARCH_ARM64 #ifdef ATMOSPHERE_ARCH_ARM64
/* Print registers. */
if (core_ctx != nullptr) {
MESOSPHERE_RELEASE_LOG(" Registers:\n");
for (size_t i = 0; i < util::size(core_ctx->x); ++i) {
MESOSPHERE_RELEASE_LOG(" X[%02zx]: %p\n", i, reinterpret_cast<void *>(core_ctx->x[i]));
}
MESOSPHERE_RELEASE_LOG(" SP: %p\n", reinterpret_cast<void *>(core_ctx->x[30]));
}
/* Print backtrace. */
MESOSPHERE_RELEASE_LOG(" Backtrace:\n"); MESOSPHERE_RELEASE_LOG(" Backtrace:\n");
uintptr_t fp = reinterpret_cast<uintptr_t>(__builtin_frame_address(0)); uintptr_t fp = core_ctx != nullptr ? core_ctx->x[29] : reinterpret_cast<uintptr_t>(__builtin_frame_address(0));
for (size_t i = 0; i < 32 && fp && util::IsAligned(fp, 0x10) && cpu::GetPhysicalAddressWritable(nullptr, fp, true); i++) { for (size_t i = 0; i < 32 && fp && util::IsAligned(fp, 0x10) && cpu::GetPhysicalAddressWritable(nullptr, fp, true); i++) {
struct { struct {
uintptr_t fp; uintptr_t fp;
@@ -107,12 +132,12 @@ namespace ams::kern {
PrintCurrentState(); PrintCurrentState();
#endif #endif
KSystemControl::StopSystem(); KSystemControl::StopSystem(GetPanicExceptionContext(GetCurrentCoreId()));
} }
} }
NORETURN WEAK_SYMBOL void Panic(const char *file, int line, const char *format, ...) { NORETURN void PanicImpl(const char *file, int line, const char *format, ...) {
#ifdef MESOSPHERE_BUILD_FOR_DEBUGGING #ifdef MESOSPHERE_BUILD_FOR_DEBUGGING
/* Wait for it to be our turn to print. */ /* Wait for it to be our turn to print. */
WaitCoreTicket(); WaitCoreTicket();
@@ -133,7 +158,7 @@ namespace ams::kern {
StopSystem(); StopSystem();
} }
NORETURN WEAK_SYMBOL void Panic() { NORETURN void PanicImpl() {
StopSystem(); StopSystem();
} }

View File

@@ -110,7 +110,7 @@ namespace ams::kern::svc {
case ams::svc::CodeMemoryOperation_MapToOwner: case ams::svc::CodeMemoryOperation_MapToOwner:
{ {
/* Check that the region is in range. */ /* Check that the region is in range. */
R_UNLESS(GetCurrentProcess().GetPageTable().CanContain(address, size, KMemoryState_GeneratedCode), svc::ResultInvalidMemoryRegion()); R_UNLESS(code_mem->GetOwner()->GetPageTable().CanContain(address, size, KMemoryState_GeneratedCode), svc::ResultInvalidMemoryRegion());
/* Check the memory permission. */ /* Check the memory permission. */
R_UNLESS(IsValidMapToOwnerCodeMemoryPermission(perm), svc::ResultInvalidNewMemoryPermission()); R_UNLESS(IsValidMapToOwnerCodeMemoryPermission(perm), svc::ResultInvalidNewMemoryPermission());
@@ -122,7 +122,7 @@ namespace ams::kern::svc {
case ams::svc::CodeMemoryOperation_UnmapFromOwner: case ams::svc::CodeMemoryOperation_UnmapFromOwner:
{ {
/* Check that the region is in range. */ /* Check that the region is in range. */
R_UNLESS(GetCurrentProcess().GetPageTable().CanContain(address, size, KMemoryState_GeneratedCode), svc::ResultInvalidMemoryRegion()); R_UNLESS(code_mem->GetOwner()->GetPageTable().CanContain(address, size, KMemoryState_GeneratedCode), svc::ResultInvalidMemoryRegion());
/* Check the memory permission. */ /* Check the memory permission. */
R_UNLESS(IsValidUnmapFromOwnerCodeMemoryPermission(perm), svc::ResultInvalidNewMemoryPermission()); R_UNLESS(IsValidUnmapFromOwnerCodeMemoryPermission(perm), svc::ResultInvalidNewMemoryPermission());

View File

@@ -65,47 +65,9 @@ namespace ams::exosphere {
namespace ams { namespace ams {
struct FatalErrorContext : sf::LargeData, sf::PrefersMapAliasTransferMode { struct FatalErrorContext : ::ams::impl::FatalErrorContext, sf::LargeData, sf::PrefersMapAliasTransferMode {};
static constexpr size_t MaxStackTrace = 0x20;
static constexpr size_t MaxStackDumpSize = 0x100;
static constexpr size_t ThreadLocalSize = 0x100;
static constexpr size_t NumGprs = 29;
static constexpr uintptr_t StdAbortMagicAddress = 0x8;
static constexpr u64 StdAbortMagicValue = 0xA55AF00DDEADCAFEul;
static constexpr u32 StdAbortErrorDesc = 0xFFE;
static constexpr u32 StackOverflowErrorDesc = 0xFFD;
static constexpr u32 DataAbortErrorDesc = 0x101;
static constexpr u32 Magic = util::FourCC<'A', 'F', 'E', '2'>::Code;
u32 magic; static_assert(sizeof(FatalErrorContext) == sizeof(::ams::impl::FatalErrorContext));
u32 error_desc;
u64 program_id;
union {
u64 gprs[32];
struct {
u64 _gprs[29];
u64 fp;
u64 lr;
u64 sp;
};
};
u64 pc;
u64 module_base;
u32 pstate;
u32 afsr0;
u32 afsr1;
u32 esr;
u64 far;
u64 report_identifier; /* Normally just system tick. */
u64 stack_trace_size;
u64 stack_dump_size;
u64 stack_trace[MaxStackTrace];
u8 stack_dump[MaxStackDumpSize];
u8 tls[ThreadLocalSize];
};
static_assert(sizeof(FatalErrorContext) == 0x450, "sizeof(FatalErrorContext)");
static_assert(util::is_pod<FatalErrorContext>::value, "FatalErrorContext");
#ifdef ATMOSPHERE_GIT_BRANCH #ifdef ATMOSPHERE_GIT_BRANCH
NX_CONSTEXPR const char *GetGitBranch() { NX_CONSTEXPR const char *GetGitBranch() {

View File

@@ -27,3 +27,5 @@
#include <vapours/results.hpp> #include <vapours/results.hpp>
#include <vapours/crypto.hpp> #include <vapours/crypto.hpp>
#include <vapours/svc.hpp> #include <vapours/svc.hpp>
#include <vapours/ams/ams_fatal_error_context.hpp>

View File

@@ -0,0 +1,66 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours/includes.hpp>
#include <vapours/defines.hpp>
namespace ams::impl {
struct FatalErrorContext {
static constexpr size_t MaxStackTrace = 0x20;
static constexpr size_t MaxStackDumpSize = 0x100;
static constexpr size_t ThreadLocalSize = 0x100;
static constexpr size_t NumGprs = 29;
static constexpr uintptr_t StdAbortMagicAddress = 0x8;
static constexpr u64 StdAbortMagicValue = 0xA55AF00DDEADCAFEul;
static constexpr u32 StdAbortErrorDesc = 0xFFE;
static constexpr u32 StackOverflowErrorDesc = 0xFFD;
static constexpr u32 KernelPanicDesc = 0xF00;
static constexpr u32 DataAbortErrorDesc = 0x101;
static constexpr u32 Magic = util::FourCC<'A', 'F', 'E', '2'>::Code;
u32 magic;
u32 error_desc;
u64 program_id;
union {
u64 gprs[32];
struct {
u64 _gprs[29];
u64 fp;
u64 lr;
u64 sp;
};
};
u64 pc;
u64 module_base;
u32 pstate;
u32 afsr0;
u32 afsr1;
u32 esr;
u64 far;
u64 report_identifier; /* Normally just system tick. */
u64 stack_trace_size;
u64 stack_dump_size;
u64 stack_trace[MaxStackTrace];
u8 stack_dump[MaxStackDumpSize];
u8 tls[ThreadLocalSize];
};
static_assert(sizeof(FatalErrorContext) == 0x450);
static_assert(std::is_standard_layout<FatalErrorContext>::value);
static_assert(std::is_trivial<FatalErrorContext>::value);
}