kern: generate fatal error on panic

This commit is contained in:
Michael Scire
2020-09-16 16:44:31 -07:00
committed by SciresM
parent 76957e502d
commit 4acdc899f5
11 changed files with 296 additions and 53 deletions

View File

@@ -532,13 +532,63 @@ namespace ams::kern::board::nintendo::nx {
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) {
/* Display a panic screen via secure monitor. */
/* If we should, instruct the secure monitor to display a panic screen. */
smc::Panic(0xF00);
}
u32 dummy;
smc::init::ReadWriteRegister(std::addressof(dummy), 0x7000E400, 0x10, 0x10);
AMS_INFINITE_LOOP();
}

View File

@@ -24,6 +24,10 @@ namespace ams::kern::board::nintendo::nx::smc {
u64 x[8];
};
enum UserFunctionId : u32 {
UserFunctionId_SetConfig = 0xC3000401,
};
enum FunctionId : u32 {
FunctionId_CpuSuspend = 0xC4000001,
FunctionId_CpuOff = 0x84000002,
@@ -136,6 +140,35 @@ namespace ams::kern::board::nintendo::nx::smc {
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. */
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;
}
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) {

View File

@@ -83,6 +83,12 @@ namespace ams::kern::board::nintendo::nx::smc {
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. */
void GenerateRandomBytes(void *dst, size_t size);
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);
bool ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value);
bool SetConfig(ConfigItem config_item, u64 value);
}
}