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));