mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-17 17:36:44 +00:00
exo/mariko fatal: print descriptor for fatal error report
This commit is contained in:
parent
8ba1cdeef2
commit
5382011b0d
6 changed files with 4913 additions and 15 deletions
|
@ -16,6 +16,8 @@
|
||||||
#include <exosphere.hpp>
|
#include <exosphere.hpp>
|
||||||
#include "fatal_device_page_table.hpp"
|
#include "fatal_device_page_table.hpp"
|
||||||
#include "fatal_registers_di.hpp"
|
#include "fatal_registers_di.hpp"
|
||||||
|
#include "fatal_display.hpp"
|
||||||
|
#include "fatal_print.hpp"
|
||||||
|
|
||||||
namespace ams::secmon::fatal {
|
namespace ams::secmon::fatal {
|
||||||
|
|
||||||
|
@ -28,10 +30,6 @@ namespace ams::secmon::fatal {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
/* Helpful defines. */
|
/* Helpful defines. */
|
||||||
constexpr size_t FrameBufferHeight = 768;
|
|
||||||
constexpr size_t FrameBufferWidth = 1280;
|
|
||||||
constexpr size_t FrameBufferSize = FrameBufferHeight * FrameBufferWidth * sizeof(u32);
|
|
||||||
|
|
||||||
constexpr int DsiWaitForCommandMilliSecondsMax = 250;
|
constexpr int DsiWaitForCommandMilliSecondsMax = 250;
|
||||||
constexpr int DsiWaitForCommandCompletionMilliSeconds = 5;
|
constexpr int DsiWaitForCommandCompletionMilliSeconds = 5;
|
||||||
constexpr int DsiWaitForHostControlMilliSecondsMax = 150;
|
constexpr int DsiWaitForHostControlMilliSecondsMax = 150;
|
||||||
|
@ -179,6 +177,89 @@ namespace ams::secmon::fatal {
|
||||||
/* We don't actually support finalizing the framebuffer, so do nothing here. */
|
/* We don't actually support finalizing the framebuffer, so do nothing here. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr const char *GetErrorDescription(u32 error_desc) {
|
||||||
|
switch (error_desc) {
|
||||||
|
case 0x100:
|
||||||
|
return "Instruction Abort";
|
||||||
|
case 0x101:
|
||||||
|
return "Data Abort";
|
||||||
|
case 0x102:
|
||||||
|
return "PC Misalignment";
|
||||||
|
case 0x103:
|
||||||
|
return "SP Misalignment";
|
||||||
|
case 0x104:
|
||||||
|
return "Trap";
|
||||||
|
case 0x106:
|
||||||
|
return "SError";
|
||||||
|
case 0x301:
|
||||||
|
return "Bad SVC";
|
||||||
|
case 0xF00:
|
||||||
|
return "Kernel Panic";
|
||||||
|
case 0xFFD:
|
||||||
|
return "Stack overflow";
|
||||||
|
case 0xFFE:
|
||||||
|
return "std::abort() called";
|
||||||
|
default:
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintSuggestedErrorFix(const ams::impl::FatalErrorContext *f_ctx) {
|
||||||
|
/* Try to recognize certain errors automatically, and suggest fixes for them. */
|
||||||
|
const char *suggestion = nullptr;
|
||||||
|
|
||||||
|
constexpr u64 ProgramIdAmsMitm = UINT64_C(0x010041544D530000);
|
||||||
|
constexpr u64 ProgramIdBoot = UINT64_C(0x0100000000000005);
|
||||||
|
if (f_ctx->error_desc == 0xFFE) {
|
||||||
|
if (f_ctx->program_id == ProgramIdAmsMitm) {
|
||||||
|
/* When a user has archive bits set improperly, attempting to create an automatic backup will fail */
|
||||||
|
/* to create the file path with error 0x202 */
|
||||||
|
if (f_ctx->gprs[0] == fs::ResultPathNotFound().GetValue()) {
|
||||||
|
/* When the archive bit error is occurring, it manifests as failure to create automatic backup. */
|
||||||
|
/* Thus, we can search the stack for the automatic backups path. */
|
||||||
|
const char * const automatic_backups_prefix = "automatic_backups/X" /* ..... */;
|
||||||
|
const int prefix_len = std::strlen(automatic_backups_prefix);
|
||||||
|
|
||||||
|
for (size_t i = 0; i + prefix_len < f_ctx->stack_dump_size; ++i) {
|
||||||
|
if (std::memcmp(&f_ctx->stack_dump[i], automatic_backups_prefix, prefix_len) == 0) {
|
||||||
|
suggestion = "The atmosphere directory may improperly have archive bits set.\n"
|
||||||
|
"Please try running an archive bit fixer tool for example, the one in Hekate).\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (f_ctx->gprs[0] == fs::ResultExFatUnavailable().GetValue()) {
|
||||||
|
/* When a user installs non-exFAT firm but has an exFAT formatted SD card, this error will */
|
||||||
|
/* be returned on attempt to access the SD card. */
|
||||||
|
suggestion = "Your console has non-exFAT firmware installed, but your SD card\n"
|
||||||
|
"is formatted as exFAT. Format your SD card as FAT32, or manually\n"
|
||||||
|
"flash exFAT firmware to package2.\n";
|
||||||
|
}
|
||||||
|
} else if (f_ctx->program_id == ProgramIdBoot) {
|
||||||
|
/* 9.x -> 10.x updated the API for SvcQueryIoMapping. */
|
||||||
|
/* This can cause the kernel to reject incorrect-ABI calls by boot when a partial update is applied */
|
||||||
|
/* (older kernel in package2, for some reason). */
|
||||||
|
for (size_t i = 0; i < 8; ++i) {
|
||||||
|
if (f_ctx->gprs[i] == svc::ResultNotFound().GetValue()) {
|
||||||
|
suggestion = "A partial update may have been improperly performed.\n"
|
||||||
|
"To fix, try manually flashing latest package2 to MMC.\n"
|
||||||
|
"\n"
|
||||||
|
"For help doing this, seek support in the ReSwitched or\n"
|
||||||
|
"Nintendo Homebrew discord servers.\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (f_ctx->error_desc == 0xF00) { /* Kernel Panic */
|
||||||
|
suggestion = "Please contact SciresM#0524 on Discord, or create an issue on the Atmosphere\n"
|
||||||
|
"GitHub issue tracker. Thank you very much for helping to test mesosphere.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we found a suggestion, print it. */
|
||||||
|
if (suggestion != nullptr) {
|
||||||
|
Print("%s", suggestion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FinalizeDisplay() {
|
void FinalizeDisplay() {
|
||||||
|
@ -425,20 +506,26 @@ namespace ams::secmon::fatal {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShowDisplay(const ams::impl::FatalErrorContext *f_ctx, const Result save_result) {
|
void ShowDisplay(const ams::impl::FatalErrorContext *f_ctx, const Result save_result) {
|
||||||
/* Draw the image to the screen. */
|
/* Initialize the console. */
|
||||||
std::memset(g_frame_buffer, 0, FrameBufferSize);
|
InitializeConsole(g_frame_buffer);
|
||||||
{
|
{
|
||||||
/* TODO: Actually print the contents of the report. */
|
Print("%s\n", "A fatal error occurred when running Atmosph\xe8re.");
|
||||||
AMS_UNUSED(f_ctx, save_result);
|
Print("Program ID: %016" PRIx64 "\n", f_ctx->program_id);
|
||||||
for (size_t n = 0; n < 8; n++) {
|
Print("Error Desc: %s (0x%x)\n", GetErrorDescription(f_ctx->error_desc), f_ctx->error_desc);
|
||||||
const size_t x = n * (FrameBufferWidth / 8);
|
Print("\n");
|
||||||
for (size_t cur_y = 0; cur_y < FrameBufferHeight; cur_y++) {
|
|
||||||
for (size_t cur_x = 0; cur_x < (FrameBufferWidth / 8); cur_x++) {
|
if (R_SUCCEEDED(save_result)) {
|
||||||
g_frame_buffer[(FrameBufferWidth - (x + cur_x)) * FrameBufferHeight + 0 + cur_y] = ((0x20 * n) | 0x1F);
|
Print("Report saved to /atmosphere/fatal_errors/report_%016" PRIx64 ".bin", f_ctx->report_identifier);
|
||||||
}
|
} else {
|
||||||
}
|
Print("Failed to save report to the SD card! (%08x)\n", save_result.GetValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PrintSuggestedErrorFix(f_ctx);
|
||||||
|
|
||||||
|
Print("\nPress POWER to reboot.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ensure the device will see consistent data. */
|
||||||
hw::FlushDataCache(g_frame_buffer, FrameBufferSize);
|
hw::FlushDataCache(g_frame_buffer, FrameBufferSize);
|
||||||
|
|
||||||
/* Enable backlight. */
|
/* Enable backlight. */
|
||||||
|
|
|
@ -18,6 +18,10 @@
|
||||||
|
|
||||||
namespace ams::secmon::fatal {
|
namespace ams::secmon::fatal {
|
||||||
|
|
||||||
|
constexpr inline size_t FrameBufferHeight = 768;
|
||||||
|
constexpr inline size_t FrameBufferWidth = 1280;
|
||||||
|
constexpr inline size_t FrameBufferSize = FrameBufferHeight * FrameBufferWidth * sizeof(u32);
|
||||||
|
|
||||||
void InitializeDisplay();
|
void InitializeDisplay();
|
||||||
void ShowDisplay(const ams::impl::FatalErrorContext *f_ctx, const Result save_result);
|
void ShowDisplay(const ams::impl::FatalErrorContext *f_ctx, const Result save_result);
|
||||||
void FinalizeDisplay();
|
void FinalizeDisplay();
|
||||||
|
|
4655
exosphere/mariko_fatal/source/fatal_font.inc
Normal file
4655
exosphere/mariko_fatal/source/fatal_font.inc
Normal file
File diff suppressed because it is too large
Load diff
127
exosphere/mariko_fatal/source/fatal_print.cpp
Normal file
127
exosphere/mariko_fatal/source/fatal_print.cpp
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
#include "fatal_display.hpp"
|
||||||
|
#include "fatal_print.hpp"
|
||||||
|
|
||||||
|
namespace ams::secmon::fatal {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
#include "fatal_font.inc"
|
||||||
|
|
||||||
|
constexpr inline const u32 TextColor = 0xFFA0A0A0;
|
||||||
|
|
||||||
|
constexpr inline const size_t ConsoleWidth = FrameBufferWidth / FontWidth;
|
||||||
|
constexpr inline const size_t ConsoleHeight = FrameBufferHeight / FontHeight;
|
||||||
|
|
||||||
|
constinit u32 *g_frame_buffer = nullptr;
|
||||||
|
constinit size_t g_col = 1;
|
||||||
|
constinit size_t g_row = 0;
|
||||||
|
|
||||||
|
void SetPixel(size_t x, size_t y, u32 color) {
|
||||||
|
g_frame_buffer[(FrameBufferWidth - x) * FrameBufferHeight + y] = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PutCarriageReturn() {
|
||||||
|
g_col = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PutNewLine() {
|
||||||
|
g_col = 1;
|
||||||
|
++g_row;
|
||||||
|
|
||||||
|
/* TODO: Support scrolling? */
|
||||||
|
}
|
||||||
|
|
||||||
|
void PutCharImpl(const char c) {
|
||||||
|
/* Get the character data for the font. */
|
||||||
|
const u8 * cdata = FontData + c * (FontHeight * util::DivideUp(FontWidth, BITSIZEOF(u8)));
|
||||||
|
|
||||||
|
/* Determine where to start drawing. */
|
||||||
|
const size_t x = g_col * FontWidth;
|
||||||
|
const size_t y = g_row * FontHeight;
|
||||||
|
|
||||||
|
for (size_t cur_y = 0; cur_y < FontHeight; ++cur_y) {
|
||||||
|
size_t cur_x = 0;
|
||||||
|
int wbits = FontWidth;
|
||||||
|
while (wbits > 0) {
|
||||||
|
const auto bits = *(cdata++);
|
||||||
|
|
||||||
|
SetPixel(x + cur_x + 0, y + cur_y, FontDrawTable[(bits >> 4) & 0xF][0] & TextColor);
|
||||||
|
SetPixel(x + cur_x + 1, y + cur_y, FontDrawTable[(bits >> 4) & 0xF][1] & TextColor);
|
||||||
|
SetPixel(x + cur_x + 2, y + cur_y, FontDrawTable[(bits >> 4) & 0xF][2] & TextColor);
|
||||||
|
SetPixel(x + cur_x + 3, y + cur_y, FontDrawTable[(bits >> 4) & 0xF][3] & TextColor);
|
||||||
|
SetPixel(x + cur_x + 4, y + cur_y, FontDrawTable[(bits >> 0) & 0xF][0] & TextColor);
|
||||||
|
SetPixel(x + cur_x + 5, y + cur_y, FontDrawTable[(bits >> 0) & 0xF][1] & TextColor);
|
||||||
|
SetPixel(x + cur_x + 6, y + cur_y, FontDrawTable[(bits >> 0) & 0xF][2] & TextColor);
|
||||||
|
SetPixel(x + cur_x + 7, y + cur_y, FontDrawTable[(bits >> 0) & 0xF][3] & TextColor);
|
||||||
|
|
||||||
|
cur_x += BITSIZEOF(u8);
|
||||||
|
wbits -= BITSIZEOF(u8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PutChar(const char c) {
|
||||||
|
switch (c) {
|
||||||
|
case '\r':
|
||||||
|
PutCarriageReturn();
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
PutNewLine();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PutCharImpl(c);
|
||||||
|
if ((++g_col) >= ConsoleWidth) {
|
||||||
|
PutNewLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeConsole(u32 *frame_buffer) {
|
||||||
|
/* Setup the console variables. */
|
||||||
|
g_frame_buffer = frame_buffer;
|
||||||
|
g_col = 1;
|
||||||
|
g_row = 0;
|
||||||
|
|
||||||
|
/* Clear the console. */
|
||||||
|
std::memset(g_frame_buffer, 0, FrameBufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Print(const char *fmt, ...) {
|
||||||
|
/* Generate the string. */
|
||||||
|
char log_str[1_KB];
|
||||||
|
{
|
||||||
|
std::va_list vl;
|
||||||
|
va_start(vl, fmt);
|
||||||
|
util::TVSNPrintf(log_str, sizeof(log_str), fmt, vl);
|
||||||
|
va_end(vl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print each character. */
|
||||||
|
const size_t len = std::strlen(log_str);
|
||||||
|
for (size_t i = 0; i < len; ++i) {
|
||||||
|
PutChar(log_str[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flush the console. */
|
||||||
|
hw::FlushDataCache(g_frame_buffer, FrameBufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
24
exosphere/mariko_fatal/source/fatal_print.hpp
Normal file
24
exosphere/mariko_fatal/source/fatal_print.hpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* 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 <exosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::secmon::fatal {
|
||||||
|
|
||||||
|
void InitializeConsole(u32 *frame_buffer);
|
||||||
|
void Print(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
|
||||||
|
|
||||||
|
}
|
|
@ -257,6 +257,7 @@ namespace ams::fs {
|
||||||
R_DEFINE_ERROR_RESULT(GptHeaderVerificationFailed, 4662);
|
R_DEFINE_ERROR_RESULT(GptHeaderVerificationFailed, 4662);
|
||||||
|
|
||||||
R_DEFINE_ERROR_RANGE(FatFileSystemCorrupted, 4681, 4699);
|
R_DEFINE_ERROR_RANGE(FatFileSystemCorrupted, 4681, 4699);
|
||||||
|
R_DEFINE_ERROR_RESULT(ExFatUnavailable, 4685);
|
||||||
|
|
||||||
R_DEFINE_ERROR_RANGE(HostFileSystemCorrupted, 4701, 4719);
|
R_DEFINE_ERROR_RANGE(HostFileSystemCorrupted, 4701, 4719);
|
||||||
R_DEFINE_ERROR_RESULT(HostEntryCorrupted, 4702);
|
R_DEFINE_ERROR_RESULT(HostEntryCorrupted, 4702);
|
||||||
|
|
Loading…
Reference in a new issue