diff --git a/include/stratosphere.hpp b/include/stratosphere.hpp
index 000656cb..78832a5d 100644
--- a/include/stratosphere.hpp
+++ b/include/stratosphere.hpp
@@ -45,6 +45,7 @@
#include "stratosphere/svc.hpp"
#include "stratosphere/cfg.hpp"
+#include "stratosphere/fatal.hpp"
#include "stratosphere/hid.hpp"
#include "stratosphere/ncm.hpp"
#include "stratosphere/pm.hpp"
diff --git a/include/stratosphere/fatal.hpp b/include/stratosphere/fatal.hpp
new file mode 100644
index 00000000..d3fbb885
--- /dev/null
+++ b/include/stratosphere/fatal.hpp
@@ -0,0 +1,20 @@
+/*
+ * 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 "fatal/fatal_types.hpp"
diff --git a/include/stratosphere/fatal/fatal_types.hpp b/include/stratosphere/fatal/fatal_types.hpp
new file mode 100644
index 00000000..b0fe391d
--- /dev/null
+++ b/include/stratosphere/fatal/fatal_types.hpp
@@ -0,0 +1,340 @@
+/*
+ * 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 "../defines.hpp"
+#include "../results.hpp"
+#include "../ncm/ncm_types.hpp"
+
+namespace sts::fatal {
+
+ namespace aarch64 {
+
+ enum RegisterName {
+ RegisterName_X0 = 0,
+ RegisterName_X1 = 1,
+ RegisterName_X2 = 2,
+ RegisterName_X3 = 3,
+ RegisterName_X4 = 4,
+ RegisterName_X5 = 5,
+ RegisterName_X6 = 6,
+ RegisterName_X7 = 7,
+ RegisterName_X8 = 8,
+ RegisterName_X9 = 9,
+ RegisterName_X10 = 10,
+ RegisterName_X11 = 11,
+ RegisterName_X12 = 12,
+ RegisterName_X13 = 13,
+ RegisterName_X14 = 14,
+ RegisterName_X15 = 15,
+ RegisterName_X16 = 16,
+ RegisterName_X17 = 17,
+ RegisterName_X18 = 18,
+ RegisterName_X19 = 19,
+ RegisterName_X20 = 20,
+ RegisterName_X21 = 21,
+ RegisterName_X22 = 22,
+ RegisterName_X23 = 23,
+ RegisterName_X24 = 24,
+ RegisterName_X25 = 25,
+ RegisterName_X26 = 26,
+ RegisterName_X27 = 27,
+ RegisterName_X28 = 28,
+ RegisterName_FP = 29,
+ RegisterName_LR = 30,
+
+ RegisterName_SP = 31,
+ RegisterName_PC = 32,
+
+ RegisterName_GeneralPurposeCount,
+
+ RegisterName_PState = 33,
+ RegisterName_Afsr0 = 34,
+ RegisterName_Afsr1 = 35,
+ RegisterName_Esr = 36,
+ RegisterName_Far = 37,
+
+ RegisterName_Count,
+ };
+
+ struct CpuContext {
+ using RegisterType = u64;
+ static constexpr size_t MaxStackTraceDepth = 0x20;
+
+ static constexpr const char *RegisterNameStrings[RegisterName_Count] = {
+ 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"X21",
+ u8"X22",
+ u8"X23",
+ u8"X24",
+ u8"X25",
+ u8"X26",
+ u8"X27",
+ u8"X28",
+ u8"FP",
+ u8"LR",
+ u8"SP",
+ u8"PC",
+ u8"PState",
+ u8"Afsr0",
+ u8"Afsr1",
+ u8"Esr",
+ u8"Far",
+ };
+
+ /* Registers, exception context. N left names for these fields in fatal .rodata. */
+ union {
+ struct {
+ union {
+ RegisterType x[RegisterName_GeneralPurposeCount];
+ struct {
+ RegisterType _x[RegisterName_FP];
+ RegisterType fp;
+ RegisterType lr;
+ RegisterType sp;
+ RegisterType pc;
+ };
+ };
+ RegisterType pstate;
+ RegisterType afsr0;
+ RegisterType afsr1;
+ RegisterType esr;
+ RegisterType far;
+ };
+ RegisterType registers[RegisterName_Count];
+ };
+
+ /* Misc. */
+ RegisterType stack_trace[MaxStackTraceDepth];
+ RegisterType base_address;
+ RegisterType register_set_flags;
+ u32 stack_trace_size;
+
+ void ClearState() {
+ std::memset(this, 0, sizeof(*this));
+ }
+
+ void SetTitleIdForAtmosphere(ncm::TitleId title_id) {
+ /* Right now, we mux title ID in through afsr when creport. */
+ /* TODO: Better way to do this? */
+ this->afsr0 = static_cast(title_id);
+ }
+
+ ncm::TitleId GetTitleIdForAtmosphere() const {
+ return ncm::TitleId{this->afsr0};
+ }
+
+ void SetRegisterValue(RegisterName name, RegisterType value) {
+ this->registers[name] = value;
+ this->register_set_flags |= (RegisterType(1) << name);
+ }
+
+ bool HasRegisterValue(RegisterName name) const {
+ return this->register_set_flags & (RegisterType(1) << name);
+ }
+
+ void SetBaseAddress(RegisterType base_addr) {
+ this->base_address = base_addr;
+ }
+ };
+
+ }
+
+ namespace aarch32 {
+
+ enum RegisterName {
+ RegisterName_R0 = 0,
+ RegisterName_R1 = 1,
+ RegisterName_R2 = 2,
+ RegisterName_R3 = 3,
+ RegisterName_R4 = 4,
+ RegisterName_R5 = 5,
+ RegisterName_R6 = 6,
+ RegisterName_R7 = 7,
+ RegisterName_R8 = 8,
+ RegisterName_R9 = 9,
+ RegisterName_R10 = 10,
+ RegisterName_FP = 11,
+ RegisterName_IP = 12,
+ RegisterName_LR = 13,
+ RegisterName_SP = 14,
+ RegisterName_PC = 15,
+
+ RegisterName_GeneralPurposeCount,
+
+ RegisterName_PState = 16,
+ RegisterName_Afsr0 = 17,
+ RegisterName_Afsr1 = 18,
+ RegisterName_Esr = 29,
+ RegisterName_Far = 20,
+
+ RegisterName_Count,
+ };
+
+ struct CpuContext {
+ using RegisterType = u32;
+ static constexpr size_t MaxStackTraceDepth = 0x20;
+
+ static constexpr const char *RegisterNameStrings[RegisterName_Count] = {
+ 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",
+ u8"PState",
+ u8"Afsr0",
+ u8"Afsr1",
+ u8"Esr",
+ u8"Far",
+ };
+
+ /* Registers, exception context. N left names for these fields in fatal .rodata. */
+ union {
+ struct {
+ union {
+ RegisterType r[RegisterName_GeneralPurposeCount];
+ struct {
+ RegisterType _x[RegisterName_FP];
+ RegisterType fp;
+ RegisterType ip;
+ RegisterType lr;
+ RegisterType sp;
+ RegisterType pc;
+ };
+ };
+ RegisterType pstate;
+ RegisterType afsr0;
+ RegisterType afsr1;
+ RegisterType esr;
+ RegisterType far;
+ };
+ RegisterType registers[RegisterName_Count];
+ };
+
+ /* Misc. Yes, stack_trace_size is really laid out differently than aarch64... */
+ RegisterType stack_trace[MaxStackTraceDepth];
+ u32 stack_trace_size;
+ RegisterType base_address;
+ RegisterType register_set_flags;
+
+ void ClearState() {
+ std::memset(this, 0, sizeof(*this));
+ }
+
+ void SetTitleIdForAtmosphere(ncm::TitleId title_id) {
+ /* Right now, we mux title ID in through afsr when creport. */
+ /* TODO: Better way to do this? */
+ this->afsr0 = static_cast(static_cast(title_id) >> 0);
+ this->afsr1 = static_cast(static_cast(title_id) >> 32);
+ }
+
+ ncm::TitleId GetTitleIdForAtmosphere() const {
+ return ncm::TitleId{(static_cast(this->afsr1) << 32ul) | (static_cast(this->afsr0) << 0ul)};
+ }
+
+ void SetRegisterValue(RegisterName name, RegisterType value) {
+ this->registers[name] = value;
+ this->register_set_flags |= (RegisterType(1) << name);
+ }
+
+ bool HasRegisterValue(RegisterName name) const {
+ return this->register_set_flags & (RegisterType(1) << name);
+ }
+
+ void SetBaseAddress(RegisterType base_addr) {
+ this->base_address = base_addr;
+ }
+ };
+
+ }
+
+ struct CpuContext {
+ enum Architecture {
+ Architecture_Aarch64 = 0,
+ Architecture_Aarch32 = 1,
+ };
+
+ union {
+ aarch64::CpuContext aarch64_ctx;
+ aarch32::CpuContext aarch32_ctx;
+ };
+
+ Architecture architecture;
+ u32 type;
+
+ void ClearState() {
+ std::memset(this, 0, sizeof(*this));
+ }
+ };
+
+ static_assert(std::is_pod::value && sizeof(aarch64::CpuContext) == 0x248, "aarch64::CpuContext definition!");
+ static_assert(std::is_pod::value && sizeof(aarch32::CpuContext) == 0xE0, "aarch32::CpuContext definition!");
+ static_assert(std::is_pod::value && sizeof(CpuContext) == 0x250, "CpuContext definition!");
+
+ namespace srv {
+
+ struct ThrowContext {
+ u32 error_code;
+ ncm::TitleId title_id;
+ char proc_name[0xD];
+ bool is_creport;
+ CpuContext cpu_ctx;
+ bool generate_error_report;
+ Event erpt_event;
+ Event battery_event;
+ size_t stack_dump_size;
+ u8 stack_dump[0x100];
+
+ void ClearState() {
+ std::memset(this, 0, sizeof(*this));
+ }
+ };
+
+ }
+
+}
diff --git a/include/stratosphere/results.hpp b/include/stratosphere/results.hpp
index 70970fee..5eddf72f 100644
--- a/include/stratosphere/results.hpp
+++ b/include/stratosphere/results.hpp
@@ -23,6 +23,7 @@
#include "results/creport_results.hpp"
#include "results/debug_results.hpp"
#include "results/dmnt_results.hpp"
+#include "results/err_results.hpp"
#include "results/fatal_results.hpp"
#include "results/fs_results.hpp"
#include "results/hipc_results.hpp"
diff --git a/include/stratosphere/results/err_results.hpp b/include/stratosphere/results/err_results.hpp
new file mode 100644
index 00000000..3aa146c0
--- /dev/null
+++ b/include/stratosphere/results/err_results.hpp
@@ -0,0 +1,23 @@
+/*
+ * 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
+
+static constexpr u32 Module_Err = 162;
+
+static constexpr Result ResultErrApplicationAborted = MAKERESULT(Module_Err, 1);
+static constexpr Result ResultErrSystemModuleAborted = MAKERESULT(Module_Err, 2);