fatal: Draw GPRs + Backtrace to screen.

This commit is contained in:
Michael Scire 2018-11-13 17:53:26 -08:00
parent f16423c413
commit 20026587fd
6 changed files with 253 additions and 14 deletions

View file

@ -48,6 +48,28 @@ IEvent *GetFatalSettingsEvent() {
return g_fatal_settings_event;
}
static void SetupConfigLanguages() {
FatalConfig *config = GetFatalConfig();
/* Defaults. */
config->error_msg = u8"Error Code: 2%03d-%04d (0x%x)\n";
if (config->quest_flag) {
config->error_desc = u8"Please call 1-800-875-1852 for service.\n";
} else {
config->error_desc = u8"An error has occured.\n\n"
u8"Please press the POWER Button to restart the console. If you are\n"
u8"unable to restart the console, hold the POWER Button for 12 seconds\n"
u8"to turn the console off.\n\n"
u8"If the problem persists, refer to the Nintendo Support Website.\n"
u8"nintendo.com/switch/error\n";
}
/* TODO: Try to load dynamically. */
/* FsStorage message_storage; */
/* TODO: if (R_SUCCEEDED(fsOpenDataStorageByDataId(0x010000000000081D, "fatal_msg"))) { ... } */
}
void InitializeFatalConfig() {
FatalConfig *config = GetFatalConfig();
@ -61,4 +83,6 @@ void InitializeFatalConfig() {
setsysGetSettingsItemValue("fatal", "quest_reboot_interval_second", &config->quest_reboot_interval_second, sizeof(config->quest_reboot_interval_second));
setsysGetFlag(SetSysFlag_Quest, &config->quest_flag);
SetupConfigLanguages();
}

View file

@ -26,6 +26,9 @@ struct FatalConfig {
bool transition_to_fatal;
bool show_extra_info;
bool quest_flag;
const char *error_msg;
const char *error_desc;
const char *quest_desc;
};
IEvent *GetFatalSettingsEvent();

View file

@ -32,7 +32,7 @@ static u16 *g_fb = nullptr;
static u32 (*g_unswizzle_func)(u32, u32) = nullptr;
static u16 g_font_color = 0xFFFF;
static float g_font_sz = 16.0f;
static u32 g_cur_x = 0, g_cur_y = 0;
static u32 g_line_x = 0, g_cur_x = 0, g_cur_y = 0;
static PlFontData g_font;
static PlFontData g_fonts[PlSharedFontType_Total];
@ -70,7 +70,7 @@ static void DrawGlyph(FT_Bitmap *bitmap, u32 x, u32 y) {
}
}
void FontManager::PrintLine(const char *str) {
static void DrawString(const char *str, bool add_line) {
FT_UInt glyph_index;
FT_GlyphSlot slot = g_face->glyph;
@ -78,9 +78,14 @@ void FontManager::PrintLine(const char *str) {
u32 cur_x = g_cur_x, cur_y = g_cur_y;
ON_SCOPE_EXIT {
/* Advance to next line. */
/* g_cur_x = g_cur_x; */
g_cur_y = cur_y + (g_face->size->metrics.height >> 6);
if (add_line) {
/* Advance to next line. */
g_cur_x = g_line_x;
g_cur_y = cur_y + (g_face->size->metrics.height >> 6);
} else {
g_cur_x = cur_x;
g_cur_y = cur_y;
}
};
for (u32 i = 0; i < len; ) {
@ -90,7 +95,7 @@ void FontManager::PrintLine(const char *str) {
i += unit_count;
if (cur_char == '\n') {
cur_x = g_cur_x;
cur_x = g_line_x;
cur_y += g_face->size->metrics.height >> 6;
continue;
}
@ -114,6 +119,10 @@ void FontManager::PrintLine(const char *str) {
}
}
void FontManager::PrintLine(const char *str) {
return DrawString(str, true);
}
void FontManager::PrintFormatLine(const char *format, ...) {
va_list va_arg;
va_start(va_arg, format);
@ -124,21 +133,46 @@ void FontManager::PrintFormatLine(const char *format, ...) {
PrintLine(char_buf);
}
void FontManager::Print(const char *str) {
return DrawString(str, false);
}
void FontManager::PrintFormat(const char *format, ...) {
va_list va_arg;
va_start(va_arg, format);
char char_buf[0x400];
vsnprintf(char_buf, sizeof(char_buf), format, va_arg);
Print(char_buf);
}
void FontManager::SetFontColor(u16 color) {
g_font_color = color;
}
void FontManager::SetPosition(u32 x, u32 y) {
g_line_x = x;
g_cur_x = x;
g_cur_y = y;
}
u32 FontManager::GetX() {
return g_cur_x;
}
u32 FontManager::GetY() {
return g_cur_y;
}
void FontManager::SetFontSize(float fsz) {
g_font_sz = fsz;
g_ft_err = FT_Set_Char_Size(g_face, 0, static_cast<u32>(g_font_sz * 64.0f), 96, 96);
}
void FontManager::AddSpacingLines(float num_lines) {
g_cur_x = g_line_x;
g_cur_y += static_cast<u32>((static_cast<float>(g_face->size->metrics.height) * num_lines) / 64.0f);
}

View file

@ -31,8 +31,12 @@ class FontManager {
static void SetFontColor(u16 color);
static void SetPosition(u32 x, u32 y);
static u32 GetX();
static u32 GetY();
static void SetFontSize(float fsz);
static void AddSpacingLines(float num_lines);
static void PrintLine(const char *str);
static void PrintFormatLine(const char *format, ...);
static void Print(const char *str);
static void PrintFormat(const char *format, ...);
};

View file

@ -172,6 +172,7 @@ Result ShowFatalTask::PrepareScreenForDrawing() {
Result ShowFatalTask::ShowFatal() {
Result rc = 0;
const FatalConfig *config = GetFatalConfig();
if (R_FAILED((rc = PrepareScreenForDrawing()))) {
*(volatile u32 *)(0xCAFEBABE) = rc;
@ -196,17 +197,132 @@ Result ShowFatalTask::ShowFatal() {
/* Draw the atmosphere logo in the bottom right corner. */
for (size_t y = 0; y < AMS_LOGO_HEIGHT; y++) {
for (size_t x = 0; x < AMS_LOGO_WIDTH; x++) {
tiled_buf[GetPixelOffset(FatalScreenWidth - AMS_LOGO_WIDTH - 32 + x, FatalScreenHeight - AMS_LOGO_HEIGHT - 32 + y)] = AMS_LOGO_BIN[y * AMS_LOGO_WIDTH + x];
tiled_buf[GetPixelOffset(FatalScreenWidth - AMS_LOGO_WIDTH - 32 + x, 32 + y)] = AMS_LOGO_BIN[y * AMS_LOGO_WIDTH + x];
}
}
/* TODO: Actually draw meaningful shit here. */
FontManager::SetPosition(32, 64);
FontManager::PrintFormatLine(u8"A fatal error occurred: 2%03d-%04d", R_MODULE(this->ctx->error_code), R_DESCRIPTION(this->ctx->error_code));
FontManager::SetFontSize(16.0f);
FontManager::PrintFormatLine("Title: %016lx", this->title_id);
FontManager::AddSpacingLines(0.5f);
FontManager::PrintFormatLine(u8"Firmware: %s (Atmosphère %u.%u.%u-%s)", GetFatalConfig()->firmware_version.display_version,
CURRENT_ATMOSPHERE_VERSION, GetAtmosphereGitRevision());
FontManager::PrintFormatLine(config->error_msg, R_MODULE(this->ctx->error_code), R_DESCRIPTION(this->ctx->error_code), this->ctx->error_code);
FontManager::PrintLine(config->error_desc);
FontManager::AddSpacingLines(0.5f);
FontManager::PrintFormatLine(u8"Firmware: %s (Atmosphère %u.%u.%u-%s)", GetFatalConfig()->firmware_version.display_version, CURRENT_ATMOSPHERE_VERSION, GetAtmosphereGitRevision());
/* Add a line. */
for (size_t x = 32; x < FatalScreenWidth - 32; x++) {
tiled_buf[GetPixelOffset(x, FontManager::GetY())] = 0xFFFF;
}
FontManager::AddSpacingLines(1.5f);
u32 backtrace_y = FontManager::GetY();
u32 backtrace_x = 0;
/* Print GPRs. */
FontManager::SetFontSize(14.0f);
FontManager::PrintLine("General Purpose Registers");
FontManager::AddSpacingLines(0.5f);
if (this->ctx->cpu_ctx.is_aarch32) {
for (size_t i = 0; i < (NumAarch32Gprs / 2); i++) {
u32 x = FontManager::GetX();
FontManager::PrintFormat("%s:", Aarch32GprNames[i]);
FontManager::SetPosition(x + 47, FontManager::GetY());
FontManager::PrintFormat("0x%08x ", this->ctx->cpu_ctx.aarch32_ctx.r[i]);
x = FontManager::GetX();
FontManager::PrintFormat("%s:", Aarch32GprNames[i + (NumAarch32Gprs / 2)]);
FontManager::SetPosition(x + 47, FontManager::GetY());
FontManager::PrintFormat("0x%08x ", this->ctx->cpu_ctx.aarch32_ctx.r[i]);
FontManager::PrintLine("");
FontManager::SetPosition(32, FontManager::GetY());
}
} else {
for (size_t i = 0; i < NumAarch64Gprs / 2; i++) {
u32 x = FontManager::GetX();
FontManager::PrintFormat("%s:", Aarch64GprNames[i]);
FontManager::SetPosition(x + 47, FontManager::GetY());
FontManager::PrintFormat("0x%016lx ", this->ctx->cpu_ctx.aarch64_ctx.x[i]);
x = FontManager::GetX();
FontManager::PrintFormat("%s:", Aarch64GprNames[i + (NumAarch64Gprs / 2)]);
FontManager::SetPosition(x + 47, FontManager::GetY());
FontManager::PrintFormat("0x%016lx ", this->ctx->cpu_ctx.aarch64_ctx.x[i]);
if (i == (NumAarch64Gprs / 2) - 1) {
FontManager::Print(" ");
backtrace_x = FontManager::GetX();
}
FontManager::PrintLine("");
FontManager::SetPosition(32, FontManager::GetY());
}
}
/* Print Backtrace. */
FontManager::SetPosition(backtrace_x, backtrace_y);
if (this->ctx->cpu_ctx.is_aarch32) {
FontManager::PrintFormatLine("Backtrace (Start Address = 0x%08x)", this->ctx->cpu_ctx.aarch32_ctx.start_address);
FontManager::AddSpacingLines(0.5f);
for (u32 i = 0; i < Aarch32CpuContext::MaxStackTraceDepth / 2; i++) {
u32 bt_cur = 0, bt_next = 0;
if (i < this->ctx->cpu_ctx.aarch32_ctx.stack_trace_size) {
bt_cur = this->ctx->cpu_ctx.aarch32_ctx.stack_trace[i];
}
if (i + Aarch32CpuContext::MaxStackTraceDepth / 2 < this->ctx->cpu_ctx.aarch32_ctx.stack_trace_size) {
bt_next = this->ctx->cpu_ctx.aarch32_ctx.stack_trace[i + Aarch32CpuContext::MaxStackTraceDepth / 2];
}
if (i < this->ctx->cpu_ctx.aarch32_ctx.stack_trace_size) {
u32 x = FontManager::GetX();
FontManager::PrintFormat("BT[%02X]: ", i);
FontManager::SetPosition(x + 76, FontManager::GetY());
FontManager::PrintFormat("0x%08x ", bt_cur);
}
if (i + Aarch32CpuContext::MaxStackTraceDepth / 2 < this->ctx->cpu_ctx.aarch32_ctx.stack_trace_size) {
u32 x = FontManager::GetX();
FontManager::PrintFormat("BT[%02X]: ", i + Aarch32CpuContext::MaxStackTraceDepth / 2);
FontManager::SetPosition(x + 76, FontManager::GetY());
FontManager::PrintFormat("0x%08x ", bt_next);
}
FontManager::PrintLine("");
FontManager::SetPosition(backtrace_x, FontManager::GetY());
}
} else {
FontManager::PrintFormatLine("Backtrace (Start Address = 0x%016lx)", this->ctx->cpu_ctx.aarch64_ctx.start_address);
FontManager::AddSpacingLines(0.5f);
for (u32 i = 0; i < Aarch64CpuContext::MaxStackTraceDepth / 2; i++) {
u64 bt_cur = 0, bt_next = 0;
if (i < this->ctx->cpu_ctx.aarch64_ctx.stack_trace_size) {
bt_cur = this->ctx->cpu_ctx.aarch64_ctx.stack_trace[i];
}
if (i + Aarch64CpuContext::MaxStackTraceDepth / 2 < this->ctx->cpu_ctx.aarch64_ctx.stack_trace_size) {
bt_next = this->ctx->cpu_ctx.aarch64_ctx.stack_trace[i + Aarch64CpuContext::MaxStackTraceDepth / 2];
}
if (i < this->ctx->cpu_ctx.aarch64_ctx.stack_trace_size) {
u32 x = FontManager::GetX();
FontManager::PrintFormat("BT[%02X]: ", i);
FontManager::SetPosition(x + 76, FontManager::GetY());
FontManager::PrintFormat("0x%016lx ", bt_cur);
}
if (i + Aarch64CpuContext::MaxStackTraceDepth / 2 < this->ctx->cpu_ctx.aarch64_ctx.stack_trace_size) {
u32 x = FontManager::GetX();
FontManager::PrintFormat("BT[%02X]: ", i + Aarch64CpuContext::MaxStackTraceDepth / 2);
FontManager::SetPosition(x + 76, FontManager::GetY());
FontManager::PrintFormat("0x%016lx ", bt_next);
}
FontManager::PrintLine("");
FontManager::SetPosition(backtrace_x, FontManager::GetY());
}
}
/* Enqueue the buffer. */
framebufferEnd(&fb);

View file

@ -26,13 +26,16 @@ enum FatalResult : Result {
FatalResult_InRepairWithoutTimeReviserCartridge = 0xCA3,
};
static constexpr size_t NumAarch64Gprs = 32;
static constexpr size_t NumAarch32Gprs = 16;
struct Aarch64CpuContext {
using RegisterType = u64;
static constexpr size_t MaxStackTraceDepth = 0x20;
/* Registers, exception context. N left names for these fields in fatal .rodata. */
union {
RegisterType x[31];
RegisterType x[NumAarch64Gprs];
struct {
RegisterType _x[29];
RegisterType fp;
@ -60,9 +63,9 @@ struct Aarch32CpuContext {
/* Registers, exception context. N left names for these fields in fatal .rodata. */
union {
RegisterType r[16];
RegisterType r[NumAarch32Gprs];
struct {
RegisterType _x[11];
RegisterType _r[11];
RegisterType fp;
RegisterType ip;
RegisterType sp;
@ -86,7 +89,7 @@ struct Aarch32CpuContext {
struct FatalCpuContext {
union {
Aarch64CpuContext aarch64_ctx;
Aarch64CpuContext aarch32_ctx;
Aarch32CpuContext aarch32_ctx;
};
bool is_aarch32;
@ -102,3 +105,58 @@ static_assert(sizeof(Aarch64CpuContext) == 0x248, "Aarch64CpuContext definition!
static_assert(sizeof(Aarch32CpuContext) == 0xE0, "Aarch32CpuContext definition!");
static_assert(sizeof(FatalCpuContext) == 0x250, "FatalCpuContext definition!");
static_assert(std::is_pod_v<FatalCpuContext>, "FatalCpuContext definition!");
static constexpr const char *Aarch64GprNames[NumAarch64Gprs] = {
u8"X0",
u8"X1",
u8"X2",
u8"X3",
u8"X4",
u8"X5",
u8"X6",
u8"X7",
u8"X8",
u8"X9",
u8"X10",
u8"X11",
u8"X12",
u8"X13",
u8"X14",
u8"X15",
u8"X16",
u8"X17",
u8"X18",
u8"X19",
u8"X20",
u8"X22",
u8"X23",
u8"X24",
u8"X25",
u8"X26",
u8"X27",
u8"X28",
u8"FP",
u8"LR",
u8"SP",
u8"PC",
};
static constexpr const char *Aarch32GprNames[NumAarch32Gprs] = {
u8"R0",
u8"R1",
u8"R2",
u8"R3",
u8"R4",
u8"R5",
u8"R6",
u8"R7",
u8"R8",
u8"R9",
u8"R10",
u8"FP",
u8"IP",
u8"LR",
u8"SP",
u8"PC",
};