stratosphere: custom exception handlers (reboot to fusee)

This commit is contained in:
Michael Scire 2019-04-12 15:28:46 -07:00
parent b03a778611
commit ac07971211
23 changed files with 307 additions and 11 deletions

View file

@ -53,6 +53,7 @@ dist: all
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000036 mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000036
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000034 mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000034
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032 mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032
mkdir -p atmosphere-$(AMSVER)/atmosphere/fatal_errors
cp fusee/fusee-primary/fusee-primary.bin atmosphere-$(AMSVER)/atmosphere/reboot_payload.bin cp fusee/fusee-primary/fusee-primary.bin atmosphere-$(AMSVER)/atmosphere/reboot_payload.bin
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/010000000000000D mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/010000000000000D
cp fusee/fusee-secondary/fusee-secondary.bin atmosphere-$(AMSVER)/atmosphere/fusee-secondary.bin cp fusee/fusee-secondary/fusee-secondary.bin atmosphere-$(AMSVER)/atmosphere/fusee-secondary.bin

View file

@ -90,9 +90,6 @@ static void setup_env(void) {
/* Initialize hardware. */ /* Initialize hardware. */
nx_hwinit(); nx_hwinit();
/* Check for panics. */
check_and_display_panic();
/* Zero-fill the framebuffer and register it as printk provider. */ /* Zero-fill the framebuffer and register it as printk provider. */
video_init(g_framebuffer); video_init(g_framebuffer);
@ -139,6 +136,9 @@ int main(void) {
/* Initialize the display, console, etc. */ /* Initialize the display, console, etc. */
setup_env(); setup_env();
/* Check for panics. */
check_and_display_panic();
/* Load the BCT0 configuration ini off of the SD. */ /* Load the BCT0 configuration ini off of the SD. */
bct0 = load_config(); bct0 = load_config();

View file

@ -14,15 +14,75 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stdio.h>
#include "panic.h" #include "panic.h"
#include "di.h" #include "di.h"
#include "pmc.h" #include "pmc.h"
#include "fuse.h" #include "fuse.h"
#include "utils.h" #include "utils.h"
#include "fs_utils.h"
#include "lib/log.h"
static uint32_t g_panic_code = 0; static uint32_t g_panic_code = 0;
static const char *get_error_desc_str(uint32_t 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";
default:
return "Unknown";
}
}
static void _check_and_display_atmosphere_fatal_error(void) {
/* Check for valid magic. */
if (ATMOSPHERE_FATAL_ERROR_CONTEXT->magic != ATMOSPHERE_REBOOT_TO_FATAL_MAGIC) {
return;
}
{
/* Copy fatal error context to the stack. */
atmosphere_fatal_error_ctx ctx = *(ATMOSPHERE_FATAL_ERROR_CONTEXT);
/* Change magic to invalid, to prevent double-display of error/bootlooping. */
ATMOSPHERE_FATAL_ERROR_CONTEXT->magic = 0xCCCCCCCC;
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "A fatal error occurred when running Atmosph\xe8re.\n");
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "Title ID: %016llx\n", ctx.title_id);
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "Error Desc: %s (0x%x)\n", get_error_desc_str(ctx.error_desc), ctx.error_desc);
/* Save context to the SD card. */
{
char filepath[0x40];
snprintf(filepath, sizeof(filepath) - 1, "/atmosphere/fatal_errors/report_%016llx.bin", ctx.report_identifier);
filepath[sizeof(filepath)-1] = 0;
write_to_file(&ctx, sizeof(ctx), filepath);
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX,"Report saved to %s\n", filepath);
}
/* Display error. */
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX,"\nPress POWER to reboot\n");
}
wait_for_button_and_reboot();
}
void check_and_display_panic(void) { void check_and_display_panic(void) {
/* Handle a panic sent via a stratosphere module. */
_check_and_display_atmosphere_fatal_error();
/* We also handle our own panics. */ /* We also handle our own panics. */
/* In the case of our own panics, we assume that the display has already been initialized. */ /* In the case of our own panics, we assume that the display has already been initialized. */
bool has_panic = APBDEV_PMC_RST_STATUS_0 != 0 || g_panic_code != 0; bool has_panic = APBDEV_PMC_RST_STATUS_0 != 0 || g_panic_code != 0;

View file

@ -28,6 +28,35 @@
#define PANIC_CODE_SAFEMODE 0x00000020 #define PANIC_CODE_SAFEMODE 0x00000020
/* Atmosphere reboot-to-fatal-error. */
typedef struct {
uint32_t magic;
uint32_t error_desc;
uint64_t title_id;
union {
uint64_t gprs[32];
struct {
uint64_t _gprs[29];
uint64_t fp;
uint64_t lr;
uint64_t sp;
};
};
uint64_t pc;
uint64_t padding;
uint32_t pstate;
uint32_t afsr0;
uint32_t afsr1;
uint32_t esr;
uint64_t far;
uint64_t report_identifier; /* Normally just system tick. */
} atmosphere_fatal_error_ctx;
/* "AFE0" */
#define ATMOSPHERE_REBOOT_TO_FATAL_MAGIC 0x30454641
#define ATMOSPHERE_FATAL_ERROR_CONTEXT ((volatile atmosphere_fatal_error_ctx *)(0x4003E000))
void check_and_display_panic(void); void check_and_display_panic(void);
__attribute__ ((noreturn)) void panic(uint32_t code); __attribute__ ((noreturn)) void panic(uint32_t code);

View file

@ -71,6 +71,7 @@
"svcMapDeviceAddressSpaceAligned": "0x5a", "svcMapDeviceAddressSpaceAligned": "0x5a",
"svcUnmapDeviceAddressSpace": "0x5c", "svcUnmapDeviceAddressSpace": "0x5c",
"svcGetSystemInfo": "0x6f", "svcGetSystemInfo": "0x6f",
"svcManageNamedPort": "0x71",
"svcCallSecureMonitor": "0x7F" "svcCallSecureMonitor": "0x7F"
} }
} }

View file

@ -38,8 +38,23 @@ extern "C" {
void __libnx_initheap(void); void __libnx_initheap(void);
void __appInit(void); void __appInit(void);
void __appExit(void); void __appExit(void);
/* Exception handling. */
alignas(16) u8 __nx_exception_stack[0x1000];
u64 __nx_exception_stack_size = sizeof(__nx_exception_stack);
void __libnx_exception_handler(ThreadExceptionDump *ctx);
u64 __stratosphere_title_id = 0x010041544D530000ul;
void __libstratosphere_exception_handler(AtmosphereFatalErrorContext *ctx);
} }
void __libnx_exception_handler(ThreadExceptionDump *ctx) {
StratosphereCrashHandler(ctx);
}
void __libstratosphere_exception_handler(AtmosphereFatalErrorContext *ctx) {
/* We're bpc-mitm (or ams_mitm, anyway), so manually reboot to fatal error. */
Utils::RebootToFatalError(ctx);
}
void __libnx_initheap(void) { void __libnx_initheap(void) {
void* addr = nx_inner_heap; void* addr = nx_inner_heap;

View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2018-2019 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 <mutex>
#include <switch.h>
#include <stratosphere.hpp>
#include "bpc_ams_service.hpp"
#include "bpcmitm_reboot_manager.hpp"
Result BpcAtmosphereService::RebootToFatalError(InBuffer<AtmosphereFatalErrorContext> ctx) {
if (ctx.buffer == nullptr || ctx.num_elements != 1) {
return ResultKernelConnectionClosed;
}
/* Reboot to fusee with the input context. */
BpcRebootManager::RebootForFatalError(ctx.buffer);
return ResultSuccess;
}

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2018-2019 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 <switch.h>
#include <stratosphere.hpp>
#include "../utils.hpp"
enum BpcAtmosphereCmd : u32 {
BpcAtmosphereCmd_RebootToFatalError = 65000,
};
class BpcAtmosphereService : public IServiceObject {
private:
Result RebootToFatalError(InBuffer<AtmosphereFatalErrorContext> ctx);
public:
DEFINE_SERVICE_DISPATCH_TABLE {
MakeServiceCommandMeta<BpcAtmosphereCmd_RebootToFatalError, &BpcAtmosphereService::RebootToFatalError>(),
};
};

View file

@ -25,6 +25,7 @@
#include "bpcmitm_main.hpp" #include "bpcmitm_main.hpp"
#include "bpc_mitm_service.hpp" #include "bpc_mitm_service.hpp"
#include "bpc_ams_service.hpp"
#include "bpcmitm_reboot_manager.hpp" #include "bpcmitm_reboot_manager.hpp"
#include "../utils.hpp" #include "../utils.hpp"
@ -46,6 +47,10 @@ void BpcMitmMain(void *arg) {
} }
AddMitmServerToManager<BpcMitmService>(server_manager, service_name, 13); AddMitmServerToManager<BpcMitmService>(server_manager, service_name, 13);
/* Extension: Allow for reboot-to-error. */
/* Must be managed port in order for sm to be able to access. */
server_manager->AddWaitable(new ManagedPortServer<BpcAtmosphereService>("bpc:ams", 1));
/* Loop forever, servicing our services. */ /* Loop forever, servicing our services. */
server_manager->Process(); server_manager->Process();

View file

@ -64,8 +64,8 @@ static void ClearIram() {
memset(g_work_page, 0xFF, sizeof(g_work_page)); memset(g_work_page, 0xFF, sizeof(g_work_page));
/* Overwrite all of IRAM with FFs. */ /* Overwrite all of IRAM with FFs. */
for (size_t ofs = 0; ofs < IRAM_PAYLOAD_MAX_SIZE; ofs += sizeof(g_work_page)) { for (size_t ofs = 0; ofs < IRAM_SIZE; ofs += sizeof(g_work_page)) {
CopyToIram(IRAM_PAYLOAD_BASE + ofs, g_work_page, sizeof(g_work_page)); CopyToIram(IRAM_BASE + ofs, g_work_page, sizeof(g_work_page));
} }
} }
@ -99,3 +99,24 @@ Result BpcRebootManager::PerformReboot() {
return ResultSuccess; return ResultSuccess;
} }
} }
void BpcRebootManager::RebootForFatalError(AtmosphereFatalErrorContext *ctx) {
/* If we don't actually have a payload loaded, just go to RCM. */
if (!g_payload_loaded) {
RebootToRcm();
}
/* Ensure clean IRAM state. */
ClearIram();
/* Copy in payload. */
for (size_t ofs = 0; ofs < sizeof(g_reboot_payload); ofs += 0x1000) {
CopyToIram(IRAM_PAYLOAD_BASE + ofs, &g_reboot_payload[ofs], 0x1000);
}
memcpy(g_work_page, ctx, sizeof(*ctx));
CopyToIram(IRAM_PAYLOAD_BASE + IRAM_PAYLOAD_MAX_SIZE, g_work_page, sizeof(g_work_page));
RebootToIramPayload();
}

View file

@ -18,7 +18,9 @@
#include <switch.h> #include <switch.h>
#include <stratosphere.hpp> #include <stratosphere.hpp>
#define IRAM_PAYLOAD_MAX_SIZE 0x2F000 #define IRAM_BASE 0x40000000ull
#define IRAM_SIZE 0x40000
#define IRAM_PAYLOAD_MAX_SIZE 0x2E000
#define IRAM_PAYLOAD_BASE 0x40010000ull #define IRAM_PAYLOAD_BASE 0x40010000ull
enum class BpcRebootType : u32 { enum class BpcRebootType : u32 {
@ -31,4 +33,5 @@ class BpcRebootManager {
public: public:
static void Initialize(); static void Initialize();
static Result PerformReboot(); static Result PerformReboot();
static void RebootForFatalError(AtmosphereFatalErrorContext *ctx);
}; };

View file

@ -25,6 +25,7 @@
#include "ini.h" #include "ini.h"
#include "set_mitm/setsys_settings_items.hpp" #include "set_mitm/setsys_settings_items.hpp"
#include "bpc_mitm/bpcmitm_reboot_manager.hpp"
static FsFileSystem g_sd_filesystem = {0}; static FsFileSystem g_sd_filesystem = {0};
static HosSignal g_sd_signal; static HosSignal g_sd_signal;
@ -652,3 +653,7 @@ Result Utils::GetSettingsItemBooleanValue(const char *name, const char *key, boo
} }
return rc; return rc;
} }
void Utils::RebootToFatalError(AtmosphereFatalErrorContext *ctx) {
BpcRebootManager::RebootForFatalError(ctx);
}

View file

@ -87,6 +87,9 @@ class Utils {
static Result GetSettingsItemValue(const char *name, const char *key, void *out, size_t max_size, u64 *out_size); static Result GetSettingsItemValue(const char *name, const char *key, void *out, size_t max_size, u64 *out_size);
static Result GetSettingsItemBooleanValue(const char *name, const char *key, bool *out); static Result GetSettingsItemBooleanValue(const char *name, const char *key, bool *out);
/* Error occurred. */
static void RebootToFatalError(AtmosphereFatalErrorContext *ctx);
private: private:
static void RefreshConfiguration(); static void RefreshConfiguration();
}; };

View file

@ -49,6 +49,17 @@ extern "C" {
void __libnx_initheap(void); void __libnx_initheap(void);
void __appInit(void); void __appInit(void);
void __appExit(void); void __appExit(void);
/* Exception handling. */
alignas(16) u8 __nx_exception_stack[0x1000];
u64 __nx_exception_stack_size = sizeof(__nx_exception_stack);
void __libnx_exception_handler(ThreadExceptionDump *ctx);
u64 __stratosphere_title_id = TitleId_Boot;
void __libstratosphere_exception_handler(AtmosphereFatalErrorContext *ctx);
}
void __libnx_exception_handler(ThreadExceptionDump *ctx) {
StratosphereCrashHandler(ctx);
} }
void __libnx_initheap(void) { void __libnx_initheap(void) {

View file

@ -38,6 +38,17 @@ extern "C" {
void __libnx_initheap(void); void __libnx_initheap(void);
void __appInit(void); void __appInit(void);
void __appExit(void); void __appExit(void);
/* Exception handling. */
alignas(16) u8 __nx_exception_stack[0x1000];
u64 __nx_exception_stack_size = sizeof(__nx_exception_stack);
void __libnx_exception_handler(ThreadExceptionDump *ctx);
u64 __stratosphere_title_id = TitleId_Creport;
void __libstratosphere_exception_handler(AtmosphereFatalErrorContext *ctx);
}
void __libnx_exception_handler(ThreadExceptionDump *ctx) {
StratosphereCrashHandler(ctx);
} }

View file

@ -40,6 +40,17 @@ extern "C" {
void __libnx_initheap(void); void __libnx_initheap(void);
void __appInit(void); void __appInit(void);
void __appExit(void); void __appExit(void);
/* Exception handling. */
alignas(16) u8 __nx_exception_stack[0x1000];
u64 __nx_exception_stack_size = sizeof(__nx_exception_stack);
void __libnx_exception_handler(ThreadExceptionDump *ctx);
u64 __stratosphere_title_id = TitleId_Dmnt;
void __libstratosphere_exception_handler(AtmosphereFatalErrorContext *ctx);
}
void __libnx_exception_handler(ThreadExceptionDump *ctx) {
StratosphereCrashHandler(ctx);
} }

View file

@ -35,6 +35,17 @@ extern "C" {
void __libnx_initheap(void); void __libnx_initheap(void);
void __appInit(void); void __appInit(void);
void __appExit(void); void __appExit(void);
/* Exception handling. */
alignas(16) u8 __nx_exception_stack[0x1000];
u64 __nx_exception_stack_size = sizeof(__nx_exception_stack);
void __libnx_exception_handler(ThreadExceptionDump *ctx);
u64 __stratosphere_title_id = TitleId_Eclct;
void __libstratosphere_exception_handler(AtmosphereFatalErrorContext *ctx);
}
void __libnx_exception_handler(ThreadExceptionDump *ctx) {
StratosphereCrashHandler(ctx);
} }

View file

@ -45,6 +45,17 @@ extern "C" {
void __libnx_initheap(void); void __libnx_initheap(void);
void __appInit(void); void __appInit(void);
void __appExit(void); void __appExit(void);
/* Exception handling. */
alignas(16) u8 __nx_exception_stack[0x1000];
u64 __nx_exception_stack_size = sizeof(__nx_exception_stack);
void __libnx_exception_handler(ThreadExceptionDump *ctx);
u64 __stratosphere_title_id = TitleId_Fatal;
void __libstratosphere_exception_handler(AtmosphereFatalErrorContext *ctx);
}
void __libnx_exception_handler(ThreadExceptionDump *ctx) {
StratosphereCrashHandler(ctx);
} }

@ -1 +1 @@
Subproject commit 1f9e2d042cb028cee1777b3d63a7cda06d2cffd0 Subproject commit b9724cdcadd5ea5fbead8f1a9c9b7de11daf6b60

View file

@ -41,6 +41,16 @@ extern "C" {
void __appInit(void); void __appInit(void);
void __appExit(void); void __appExit(void);
/* Exception handling. */
alignas(16) u8 __nx_exception_stack[0x1000];
u64 __nx_exception_stack_size = sizeof(__nx_exception_stack);
void __libnx_exception_handler(ThreadExceptionDump *ctx);
u64 __stratosphere_title_id = TitleId_Loader;
void __libstratosphere_exception_handler(AtmosphereFatalErrorContext *ctx);
}
void __libnx_exception_handler(ThreadExceptionDump *ctx) {
StratosphereCrashHandler(ctx);
} }

View file

@ -42,6 +42,17 @@ extern "C" {
void __libnx_initheap(void); void __libnx_initheap(void);
void __appInit(void); void __appInit(void);
void __appExit(void); void __appExit(void);
/* Exception handling. */
alignas(16) u8 __nx_exception_stack[0x1000];
u64 __nx_exception_stack_size = sizeof(__nx_exception_stack);
void __libnx_exception_handler(ThreadExceptionDump *ctx);
u64 __stratosphere_title_id = TitleId_Pm;
void __libstratosphere_exception_handler(AtmosphereFatalErrorContext *ctx);
}
void __libnx_exception_handler(ThreadExceptionDump *ctx) {
StratosphereCrashHandler(ctx);
} }

View file

@ -39,6 +39,17 @@ extern "C" {
void __libnx_initheap(void); void __libnx_initheap(void);
void __appInit(void); void __appInit(void);
void __appExit(void); void __appExit(void);
/* Exception handling. */
alignas(16) u8 __nx_exception_stack[0x1000];
u64 __nx_exception_stack_size = sizeof(__nx_exception_stack);
void __libnx_exception_handler(ThreadExceptionDump *ctx);
u64 __stratosphere_title_id = TitleId_Sm;
void __libstratosphere_exception_handler(AtmosphereFatalErrorContext *ctx);
}
void __libnx_exception_handler(ThreadExceptionDump *ctx) {
StratosphereCrashHandler(ctx);
} }