diff --git a/Makefile b/Makefile index 1ebf1c635..e38f766b9 100644 --- a/Makefile +++ b/Makefile @@ -53,6 +53,7 @@ dist: all mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000036 mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000034 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 mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/010000000000000D cp fusee/fusee-secondary/fusee-secondary.bin atmosphere-$(AMSVER)/atmosphere/fusee-secondary.bin diff --git a/fusee/fusee-primary/src/main.c b/fusee/fusee-primary/src/main.c index 30d494246..3b4614bc8 100644 --- a/fusee/fusee-primary/src/main.c +++ b/fusee/fusee-primary/src/main.c @@ -90,9 +90,6 @@ static void setup_env(void) { /* Initialize hardware. */ nx_hwinit(); - /* Check for panics. */ - check_and_display_panic(); - /* Zero-fill the framebuffer and register it as printk provider. */ video_init(g_framebuffer); @@ -138,6 +135,9 @@ int main(void) { /* Initialize the display, console, etc. */ setup_env(); + + /* Check for panics. */ + check_and_display_panic(); /* Load the BCT0 configuration ini off of the SD. */ bct0 = load_config(); diff --git a/fusee/fusee-primary/src/panic.c b/fusee/fusee-primary/src/panic.c index cbd81bfb2..706955ced 100644 --- a/fusee/fusee-primary/src/panic.c +++ b/fusee/fusee-primary/src/panic.c @@ -14,15 +14,75 @@ * along with this program. If not, see . */ +#include #include "panic.h" #include "di.h" #include "pmc.h" #include "fuse.h" #include "utils.h" +#include "fs_utils.h" +#include "lib/log.h" 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) { + /* Handle a panic sent via a stratosphere module. */ + _check_and_display_atmosphere_fatal_error(); + /* We also handle our own panics. */ /* 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; diff --git a/fusee/fusee-primary/src/panic.h b/fusee/fusee-primary/src/panic.h index 848a3fd81..27d1f4982 100644 --- a/fusee/fusee-primary/src/panic.h +++ b/fusee/fusee-primary/src/panic.h @@ -28,6 +28,35 @@ #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); __attribute__ ((noreturn)) void panic(uint32_t code); diff --git a/stratosphere/ams_mitm/ams_mitm.json b/stratosphere/ams_mitm/ams_mitm.json index e2efc65e9..431a1f5f0 100644 --- a/stratosphere/ams_mitm/ams_mitm.json +++ b/stratosphere/ams_mitm/ams_mitm.json @@ -71,6 +71,7 @@ "svcMapDeviceAddressSpaceAligned": "0x5a", "svcUnmapDeviceAddressSpace": "0x5c", "svcGetSystemInfo": "0x6f", + "svcManageNamedPort": "0x71", "svcCallSecureMonitor": "0x7F" } } diff --git a/stratosphere/ams_mitm/source/amsmitm_main.cpp b/stratosphere/ams_mitm/source/amsmitm_main.cpp index 99f342602..d244d3246 100644 --- a/stratosphere/ams_mitm/source/amsmitm_main.cpp +++ b/stratosphere/ams_mitm/source/amsmitm_main.cpp @@ -38,8 +38,23 @@ extern "C" { void __libnx_initheap(void); void __appInit(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* addr = nx_inner_heap; diff --git a/stratosphere/ams_mitm/source/bpc_mitm/bpc_ams_service.cpp b/stratosphere/ams_mitm/source/bpc_mitm/bpc_ams_service.cpp new file mode 100644 index 000000000..77b9ed30c --- /dev/null +++ b/stratosphere/ams_mitm/source/bpc_mitm/bpc_ams_service.cpp @@ -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 . + */ + +#include +#include +#include +#include "bpc_ams_service.hpp" +#include "bpcmitm_reboot_manager.hpp" + +Result BpcAtmosphereService::RebootToFatalError(InBuffer ctx) { + if (ctx.buffer == nullptr || ctx.num_elements != 1) { + return ResultKernelConnectionClosed; + } + + /* Reboot to fusee with the input context. */ + BpcRebootManager::RebootForFatalError(ctx.buffer); + + return ResultSuccess; +} diff --git a/stratosphere/ams_mitm/source/bpc_mitm/bpc_ams_service.hpp b/stratosphere/ams_mitm/source/bpc_mitm/bpc_ams_service.hpp new file mode 100644 index 000000000..a9dbde26e --- /dev/null +++ b/stratosphere/ams_mitm/source/bpc_mitm/bpc_ams_service.hpp @@ -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 . + */ + +#pragma once +#include +#include + +#include "../utils.hpp" + +enum BpcAtmosphereCmd : u32 { + BpcAtmosphereCmd_RebootToFatalError = 65000, +}; + +class BpcAtmosphereService : public IServiceObject { + private: + Result RebootToFatalError(InBuffer ctx); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMeta(), + }; +}; diff --git a/stratosphere/ams_mitm/source/bpc_mitm/bpc_mitm_service.hpp b/stratosphere/ams_mitm/source/bpc_mitm/bpc_mitm_service.hpp index ab2e9c627..7b6589730 100644 --- a/stratosphere/ams_mitm/source/bpc_mitm/bpc_mitm_service.hpp +++ b/stratosphere/ams_mitm/source/bpc_mitm/bpc_mitm_service.hpp @@ -25,7 +25,7 @@ enum BpcCmd : u32 { BpcCmd_RebootSystem = 1, }; -class BpcMitmService : public IMitmServiceObject { +class BpcMitmService : public IMitmServiceObject { public: BpcMitmService(std::shared_ptr s, u64 pid) : IMitmServiceObject(s, pid) { /* ... */ diff --git a/stratosphere/ams_mitm/source/bpc_mitm/bpcmitm_main.cpp b/stratosphere/ams_mitm/source/bpc_mitm/bpcmitm_main.cpp index 5138b0e8a..36c9c0af8 100644 --- a/stratosphere/ams_mitm/source/bpc_mitm/bpcmitm_main.cpp +++ b/stratosphere/ams_mitm/source/bpc_mitm/bpcmitm_main.cpp @@ -25,6 +25,7 @@ #include "bpcmitm_main.hpp" #include "bpc_mitm_service.hpp" +#include "bpc_ams_service.hpp" #include "bpcmitm_reboot_manager.hpp" #include "../utils.hpp" @@ -46,6 +47,10 @@ void BpcMitmMain(void *arg) { } AddMitmServerToManager(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("bpc:ams", 1)); + /* Loop forever, servicing our services. */ server_manager->Process(); diff --git a/stratosphere/ams_mitm/source/bpc_mitm/bpcmitm_reboot_manager.cpp b/stratosphere/ams_mitm/source/bpc_mitm/bpcmitm_reboot_manager.cpp index ef91ea801..4c6c71d66 100644 --- a/stratosphere/ams_mitm/source/bpc_mitm/bpcmitm_reboot_manager.cpp +++ b/stratosphere/ams_mitm/source/bpc_mitm/bpcmitm_reboot_manager.cpp @@ -64,8 +64,8 @@ static void ClearIram() { memset(g_work_page, 0xFF, sizeof(g_work_page)); /* Overwrite all of IRAM with FFs. */ - for (size_t ofs = 0; ofs < IRAM_PAYLOAD_MAX_SIZE; ofs += sizeof(g_work_page)) { - CopyToIram(IRAM_PAYLOAD_BASE + ofs, g_work_page, sizeof(g_work_page)); + for (size_t ofs = 0; ofs < IRAM_SIZE; ofs += sizeof(g_work_page)) { + CopyToIram(IRAM_BASE + ofs, g_work_page, sizeof(g_work_page)); } } @@ -99,3 +99,24 @@ Result BpcRebootManager::PerformReboot() { 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(); +} \ No newline at end of file diff --git a/stratosphere/ams_mitm/source/bpc_mitm/bpcmitm_reboot_manager.hpp b/stratosphere/ams_mitm/source/bpc_mitm/bpcmitm_reboot_manager.hpp index a8feda168..4eecce70a 100644 --- a/stratosphere/ams_mitm/source/bpc_mitm/bpcmitm_reboot_manager.hpp +++ b/stratosphere/ams_mitm/source/bpc_mitm/bpcmitm_reboot_manager.hpp @@ -18,7 +18,9 @@ #include #include -#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 enum class BpcRebootType : u32 { @@ -31,4 +33,5 @@ class BpcRebootManager { public: static void Initialize(); static Result PerformReboot(); + static void RebootForFatalError(AtmosphereFatalErrorContext *ctx); }; \ No newline at end of file diff --git a/stratosphere/ams_mitm/source/utils.cpp b/stratosphere/ams_mitm/source/utils.cpp index 10d795d85..5d50fa178 100644 --- a/stratosphere/ams_mitm/source/utils.cpp +++ b/stratosphere/ams_mitm/source/utils.cpp @@ -25,6 +25,7 @@ #include "ini.h" #include "set_mitm/setsys_settings_items.hpp" +#include "bpc_mitm/bpcmitm_reboot_manager.hpp" static FsFileSystem g_sd_filesystem = {0}; static HosSignal g_sd_signal; @@ -652,3 +653,7 @@ Result Utils::GetSettingsItemBooleanValue(const char *name, const char *key, boo } return rc; } + +void Utils::RebootToFatalError(AtmosphereFatalErrorContext *ctx) { + BpcRebootManager::RebootForFatalError(ctx); +} diff --git a/stratosphere/ams_mitm/source/utils.hpp b/stratosphere/ams_mitm/source/utils.hpp index d44b9219f..04e1faadf 100644 --- a/stratosphere/ams_mitm/source/utils.hpp +++ b/stratosphere/ams_mitm/source/utils.hpp @@ -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 GetSettingsItemBooleanValue(const char *name, const char *key, bool *out); + + /* Error occurred. */ + static void RebootToFatalError(AtmosphereFatalErrorContext *ctx); private: static void RefreshConfiguration(); }; \ No newline at end of file diff --git a/stratosphere/boot/source/boot_main.cpp b/stratosphere/boot/source/boot_main.cpp index 4bf7ffa83..862809d76 100644 --- a/stratosphere/boot/source/boot_main.cpp +++ b/stratosphere/boot/source/boot_main.cpp @@ -49,6 +49,17 @@ extern "C" { void __libnx_initheap(void); void __appInit(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) { diff --git a/stratosphere/creport/source/creport_main.cpp b/stratosphere/creport/source/creport_main.cpp index 610e47e84..662705fbc 100644 --- a/stratosphere/creport/source/creport_main.cpp +++ b/stratosphere/creport/source/creport_main.cpp @@ -38,6 +38,17 @@ extern "C" { void __libnx_initheap(void); void __appInit(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); } diff --git a/stratosphere/dmnt/source/dmnt_main.cpp b/stratosphere/dmnt/source/dmnt_main.cpp index b027e9d89..77571d4ed 100644 --- a/stratosphere/dmnt/source/dmnt_main.cpp +++ b/stratosphere/dmnt/source/dmnt_main.cpp @@ -40,6 +40,17 @@ extern "C" { void __libnx_initheap(void); void __appInit(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); } diff --git a/stratosphere/eclct.stub/source/eclct_stub.cpp b/stratosphere/eclct.stub/source/eclct_stub.cpp index 2dfbcc81e..fd6d73bbe 100644 --- a/stratosphere/eclct.stub/source/eclct_stub.cpp +++ b/stratosphere/eclct.stub/source/eclct_stub.cpp @@ -35,6 +35,17 @@ extern "C" { void __libnx_initheap(void); void __appInit(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); } diff --git a/stratosphere/fatal/source/fatal_main.cpp b/stratosphere/fatal/source/fatal_main.cpp index 554237c62..2f49576f7 100644 --- a/stratosphere/fatal/source/fatal_main.cpp +++ b/stratosphere/fatal/source/fatal_main.cpp @@ -45,6 +45,17 @@ extern "C" { void __libnx_initheap(void); void __appInit(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); } diff --git a/stratosphere/libstratosphere b/stratosphere/libstratosphere index 1f9e2d042..b9724cdca 160000 --- a/stratosphere/libstratosphere +++ b/stratosphere/libstratosphere @@ -1 +1 @@ -Subproject commit 1f9e2d042cb028cee1777b3d63a7cda06d2cffd0 +Subproject commit b9724cdcadd5ea5fbead8f1a9c9b7de11daf6b60 diff --git a/stratosphere/loader/source/ldr_main.cpp b/stratosphere/loader/source/ldr_main.cpp index 2a030552e..a278f6295 100644 --- a/stratosphere/loader/source/ldr_main.cpp +++ b/stratosphere/loader/source/ldr_main.cpp @@ -41,6 +41,16 @@ extern "C" { void __appInit(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); } @@ -103,9 +113,9 @@ struct LoaderServerOptions { int main(int argc, char **argv) { consoleDebugInit(debugDevice_SVC); - + auto server_manager = new WaitableManager(1); - + /* Add services to manager. */ server_manager->AddWaitable(new ServiceServer("ldr:pm", 1)); server_manager->AddWaitable(new ServiceServer("ldr:shel", 3)); diff --git a/stratosphere/pm/source/pm_main.cpp b/stratosphere/pm/source/pm_main.cpp index 4f1e34581..3aac9a359 100644 --- a/stratosphere/pm/source/pm_main.cpp +++ b/stratosphere/pm/source/pm_main.cpp @@ -42,6 +42,17 @@ extern "C" { void __libnx_initheap(void); void __appInit(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); } diff --git a/stratosphere/sm/source/sm_main.cpp b/stratosphere/sm/source/sm_main.cpp index 981a6f777..be0d8815e 100644 --- a/stratosphere/sm/source/sm_main.cpp +++ b/stratosphere/sm/source/sm_main.cpp @@ -39,6 +39,17 @@ extern "C" { void __libnx_initheap(void); void __appInit(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); } @@ -73,7 +84,7 @@ int main(int argc, char **argv) /* TODO: What's a good timeout value to use here? */ auto server_manager = new WaitableManager(1); - + /* Create sm:, (and thus allow things to register to it). */ server_manager->AddWaitable(new ManagedPortServer("sm:", 0x40));