From 797cea0ac89aa0ca4ac0ba03fd9fbe72a77e56af Mon Sep 17 00:00:00 2001
From: TuxSH <1922548+TuxSH@users.noreply.github.com>
Date: Mon, 24 Feb 2020 18:26:52 +0000
Subject: [PATCH] thermosphere: trap refactor WIP
---
.../src/cpu/hvisor_cpu_exception_sysregs.hpp | 2 +-
thermosphere/src/data_abort.c | 68 --------------
thermosphere/src/data_abort.h | 42 ---------
.../src/hvisor_exception_dispatcher.cpp | 86 +++++++++---------
.../src/hvisor_exception_dispatcher.hpp | 2 +
thermosphere/src/hvisor_virtual_gic.hpp | 3 +
thermosphere/src/single_step.c | 78 ----------------
thermosphere/src/single_step.h | 34 -------
.../src/traps/hvisor_traps_data_abort.cpp | 89 +++++++++++++++++++
.../hvisor_traps_data_abort.hpp} | 23 +++--
thermosphere/src/traps/hvisor_traps_hvc.cpp | 33 +++++++
.../src/{hvc.h => traps/hvisor_traps_hvc.hpp} | 11 ++-
.../src/traps/hvisor_traps_single_step.cpp | 87 ++++++++++++++++++
.../src/traps/hvisor_traps_single_step.hpp | 37 ++++++++
thermosphere/src/{ => traps}/smc.c | 0
thermosphere/src/{ => traps}/smc.h | 0
thermosphere/src/{ => traps}/sysreg_traps.c | 0
thermosphere/src/{ => traps}/sysreg_traps.h | 0
18 files changed, 311 insertions(+), 284 deletions(-)
delete mode 100644 thermosphere/src/data_abort.c
delete mode 100644 thermosphere/src/data_abort.h
delete mode 100644 thermosphere/src/single_step.c
delete mode 100644 thermosphere/src/single_step.h
create mode 100644 thermosphere/src/traps/hvisor_traps_data_abort.cpp
rename thermosphere/src/{hvc.c => traps/hvisor_traps_data_abort.hpp} (64%)
create mode 100644 thermosphere/src/traps/hvisor_traps_hvc.cpp
rename thermosphere/src/{hvc.h => traps/hvisor_traps_hvc.hpp} (74%)
create mode 100644 thermosphere/src/traps/hvisor_traps_single_step.cpp
create mode 100644 thermosphere/src/traps/hvisor_traps_single_step.hpp
rename thermosphere/src/{ => traps}/smc.c (100%)
rename thermosphere/src/{ => traps}/smc.h (100%)
rename thermosphere/src/{ => traps}/sysreg_traps.c (100%)
rename thermosphere/src/{ => traps}/sysreg_traps.h (100%)
diff --git a/thermosphere/src/cpu/hvisor_cpu_exception_sysregs.hpp b/thermosphere/src/cpu/hvisor_cpu_exception_sysregs.hpp
index faa0053fc..aef223d6a 100644
--- a/thermosphere/src/cpu/hvisor_cpu_exception_sysregs.hpp
+++ b/thermosphere/src/cpu/hvisor_cpu_exception_sysregs.hpp
@@ -101,7 +101,7 @@ namespace ams::hvisor::cpu {
constexpr bool HasValidFar()
{
- return isv && fnv;
+ return isv && !fnv;
}
constexpr size_t GetAccessSize()
{
diff --git a/thermosphere/src/data_abort.c b/thermosphere/src/data_abort.c
deleted file mode 100644
index a73d75f23..000000000
--- a/thermosphere/src/data_abort.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 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 "data_abort.h"
-#include "sysreg.h"
-#include "debug_log.h"
-#include "irq.h"
-#include "vgic.h"
-
-// Lower el
-
-void dumpUnhandledDataAbort(DataAbortIss dabtIss, u64 far, const char *msg)
-{
- char s1[64], s2[32], s3[64] = "";
- (void)s1; (void)s2; (void)s3;
- sprintf(s1, "Unhandled%s %s", msg , dabtIss.wnr ? "write" : "read");
- if (dabtIss.fnv) {
- sprintf(s2, "");
- } else {
- sprintf(s2, "%016lx", far);
- }
-
- if (dabtIss.isv) {
- sprintf(s3, ", size %u Rt=%u", BIT(dabtIss.sas), dabtIss.srt);
- }
-
- DEBUG("%s at %s%s\n", s1, s2, s3);
-}
-
-void handleLowerElDataAbortException(ExceptionStackFrame *frame, ExceptionSyndromeRegister esr)
-{
- DataAbortIss dabtIss;
- u32 iss = esr.iss;
- memcpy(&dabtIss, &iss, 4);
-
- u64 far = GET_SYSREG(far_el2);
- u64 farpg = far & ~0xFFFull;
-
- if (!dabtIss.isv || dabtIss.fnv) {
- dumpUnhandledDataAbort(dabtIss, far, "");
- }
-
- if (farpg == MEMORY_MAP_PA_GICD) {
- handleVgicdMmio(frame, dabtIss, far & 0xFFF);
- } else if (farpg == MEMORY_MAP_PA_GICH) {
- dumpUnhandledDataAbort(dabtIss, far, " GICH");
- } else {
- dumpUnhandledDataAbort(dabtIss, far, "");
- }
-
- // Skip instruction anyway
- skipFaultingInstruction(frame, esr.il == 0 ? 2 : 4);
-}
diff --git a/thermosphere/src/data_abort.h b/thermosphere/src/data_abort.h
deleted file mode 100644
index fc16bcd3b..000000000
--- a/thermosphere/src/data_abort.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 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 "exceptions.h"
-
-typedef struct DataAbortIss {
- u32 dfsc : 6; // Fault status code
-
- u32 wnr : 1; // Write, not Read
- u32 s1ptw : 1; // Stage1 page table walk fault
- u32 cm : 1; // Cache maintenance
- u32 ea : 1; // External abort
- u32 fnv : 1; // FAR not Valid
- u32 set : 2; // Synchronous error type
- u32 vncr : 1; // vncr_el2 trap
-
- u32 ar : 1; // Acquire/release. Bit 14
- u32 sf : 1; // 64-bit register used
- u32 srt : 5; // Syndrome register transfer (register used)
- u32 sse : 1; // Syndrome sign extend
- u32 sas : 2; // Syndrome access size. Bit 23
-
- u32 isv : 1; // Instruction syndrome valid (ISS[23:14] valid)
-} DataAbortIss;
-
-void dumpUnhandledDataAbort(DataAbortIss dabtIss, u64 far, const char *msg);
-void handleLowerElDataAbortException(ExceptionStackFrame *frame, ExceptionSyndromeRegister esr);
diff --git a/thermosphere/src/hvisor_exception_dispatcher.cpp b/thermosphere/src/hvisor_exception_dispatcher.cpp
index 869005ddf..c7068b597 100644
--- a/thermosphere/src/hvisor_exception_dispatcher.cpp
+++ b/thermosphere/src/hvisor_exception_dispatcher.cpp
@@ -21,51 +21,6 @@
#include "debug_manager.h"
-namespace {
-
- void DumpStackFrame(const ams::hvisor::ExceptionStackFrame *frame, bool sameEl)
- {
-#ifndef NDEBUG
- uintptr_t stackTop = memoryMapGetStackTop(ams::hvisor::currentCoreCtx->GetCoreId());
-
- for (u32 i = 0; i < 30; i += 2) {
- DEBUG("x%u\t\t%016llx\t\tx%u\t\t%016llx\n", i, frame->x[i], i + 1, frame->x[i + 1]);
- }
-
- DEBUG("x30\t\t%016llx\n\n", frame->x[30]);
- DEBUG("elr_el2\t\t%016llx\n", frame->elr_el2);
- DEBUG("spsr_el2\t%016llx\n", frame->spsr_el2);
- DEBUG("far_el2\t\t%016llx\n", frame->far_el2);
- if (sameEl) {
- DEBUG("sp_el2\t\t%016llx\n", frame->sp_el2);
- } else {
- DEBUG("sp_el1\t\t%016llx\n", frame->sp_el1);
- }
- DEBUG("sp_el0\t\t%016llx\n", frame->sp_el0);
- DEBUG("cntpct_el0\t%016llx\n", frame->cntpct_el0);
- if (frame == ams::hvisor::currentCoreCtx->GetGuestFrame()) {
- DEBUG("cntp_ctl_el0\t%016llx\n", frame->cntp_ctl_el0);
- DEBUG("cntv_ctl_el0\t%016llx\n", frame->cntv_ctl_el0);
- } else if ((frame->sp_el2 & ~0xFFFul) + 0x1000 == stackTop) {
- // Try to dump the stack (comment if this crashes)
- u64 *sp = (u64 *)frame->sp_el2;
- u64 *spEnd = sp + 0x20;
- u64 *spMax = reinterpret_cast((frame->sp_el2 + 0xFFF) & ~0xFFFul);
- DEBUG("Stack trace:\n");
- while (sp < spEnd && sp < spMax) {
- DEBUG("\t%016lx\n", *sp++);
- }
- } else {
- DEBUG("Stack overflow/double fault detected!\n");
- }
-#else
- (void)frame;
- (void)sameEl;
-#endif
- }
-
-}
-
namespace ams::hvisor {
void EnableGeneralTraps(void)
@@ -89,6 +44,47 @@ namespace ams::hvisor {
EnableGuestTimerTraps();
}
+void DumpStackFrame(ExceptionStackFrame *frame, bool sameEl)
+ {
+#ifndef NDEBUG
+ uintptr_t stackTop = memoryMapGetStackTop(currentCoreCtx->GetCoreId());
+
+ for (u32 i = 0; i < 30; i += 2) {
+ DEBUG("x%u\t\t%016llx\t\tx%u\t\t%016llx\n", i, frame->x[i], i + 1, frame->x[i + 1]);
+ }
+
+ DEBUG("x30\t\t%016llx\n\n", frame->x[30]);
+ DEBUG("elr_el2\t\t%016llx\n", frame->elr_el2);
+ DEBUG("spsr_el2\t%016llx\n", frame->spsr_el2);
+ DEBUG("far_el2\t\t%016llx\n", frame->far_el2);
+ if (sameEl) {
+ DEBUG("sp_el2\t\t%016llx\n", frame->sp_el2);
+ } else {
+ DEBUG("sp_el1\t\t%016llx\n", frame->sp_el1);
+ }
+ DEBUG("sp_el0\t\t%016llx\n", frame->sp_el0);
+ DEBUG("cntpct_el0\t%016llx\n", frame->cntpct_el0);
+ if (frame == currentCoreCtx->GetGuestFrame()) {
+ DEBUG("cntp_ctl_el0\t%016llx\n", frame->cntp_ctl_el0);
+ DEBUG("cntv_ctl_el0\t%016llx\n", frame->cntv_ctl_el0);
+ } else if ((frame->sp_el2 & ~0xFFFul) + 0x1000 == stackTop) {
+ // Try to dump the stack (comment if this crashes)
+ u64 *sp = (u64 *)frame->sp_el2;
+ u64 *spEnd = sp + 0x20;
+ u64 *spMax = reinterpret_cast((frame->sp_el2 + 0xFFF) & ~0xFFFul);
+ DEBUG("Stack trace:\n");
+ while (sp < spEnd && sp < spMax) {
+ DEBUG("\t%016lx\n", *sp++);
+ }
+ } else {
+ DEBUG("Stack overflow/double fault detected!\n");
+ }
+#else
+ (void)frame;
+ (void)sameEl;
+#endif
+ }
+
void ExceptionEntryPostprocess(ExceptionStackFrame *frame, bool isLowerEl)
{
if (frame == currentCoreCtx->GetGuestFrame()) {
diff --git a/thermosphere/src/hvisor_exception_dispatcher.hpp b/thermosphere/src/hvisor_exception_dispatcher.hpp
index 380484ded..65b8616eb 100644
--- a/thermosphere/src/hvisor_exception_dispatcher.hpp
+++ b/thermosphere/src/hvisor_exception_dispatcher.hpp
@@ -23,6 +23,8 @@ namespace ams::hvisor {
void EnableGeneralTraps(void);
+ void DumpStackFrame(const ExceptionStackFrame *frame, bool sameEl);
+
// Called on exception entry (avoids overflowing a vector section)
void ExceptionEntryPostprocess(ExceptionStackFrame *frame, bool isLowerEl);
diff --git a/thermosphere/src/hvisor_virtual_gic.hpp b/thermosphere/src/hvisor_virtual_gic.hpp
index 2dc36363b..ca321c681 100644
--- a/thermosphere/src/hvisor_virtual_gic.hpp
+++ b/thermosphere/src/hvisor_virtual_gic.hpp
@@ -369,6 +369,9 @@ namespace ams::hvisor {
private:
constexpr VirtualGic() = default;
+ public:
+ // For convenience (when trapping lower-el data aborts):
+ static constexpr uintptr_t gicdPhysicalAddress = 0; // fixme pls MEMORY_MAP_PA_GICD;
public:
static bool ValidateGicdRegisterAccess(size_t offset, size_t sz);
public:
diff --git a/thermosphere/src/single_step.c b/thermosphere/src/single_step.c
deleted file mode 100644
index 204e47555..000000000
--- a/thermosphere/src/single_step.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 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 "single_step.h"
-#include "core_ctx.h"
-#include "sysreg.h"
-#include "debug_manager.h"
-
-SingleStepState singleStepGetNextState(ExceptionStackFrame *frame)
-{
- u64 mdscr = GET_SYSREG(mdscr_el1);
- bool mdscrSS = (mdscr & MDSCR_SS) != 0;
- bool pstateSS = (frame->spsr_el2 & PSTATE_SS) != 0;
-
- if (!mdscrSS) {
- return SingleStepState_Inactive;
- } else {
- return pstateSS ? SingleStepState_ActiveNotPending : SingleStepState_ActivePending;
- }
-}
-
-void singleStepSetNextState(ExceptionStackFrame *frame, SingleStepState state)
-{
- u64 mdscr = GET_SYSREG(mdscr_el1);
-
- switch (state) {
- case SingleStepState_Inactive:
- // Unset mdscr_el1.ss
- mdscr &= ~MDSCR_SS;
- break;
- case SingleStepState_ActiveNotPending:
- // Set mdscr_el1.ss and pstate.ss
- mdscr |= MDSCR_SS;
- frame->spsr_el2 |= PSTATE_SS;
- break;
- case SingleStepState_ActivePending:
- // We never use this because pstate.ss is 0 by default...
- // Set mdscr_el1.ss and unset pstate.ss
- mdscr |= MDSCR_SS;
- frame->spsr_el2 &= ~PSTATE_SS;
- break;
- default:
- break;
- }
-
- SET_SYSREG(mdscr_el1, mdscr);
- __isb(); // TRM-mandated
-}
-
-void handleSingleStep(ExceptionStackFrame *frame, ExceptionSyndromeRegister esr)
-{
- uintptr_t addr = frame->elr_el2;
-
- // Stepping range support;
- if (addr >= currentCoreCtx->steppingRangeStartAddr && addr < currentCoreCtx->steppingRangeEndAddr) {
- // Reactivate single-step
- singleStepSetNextState(frame, SingleStepState_ActiveNotPending);
- } else {
- // Disable single-step
- singleStepSetNextState(frame, SingleStepState_Inactive);
- debugManagerReportEvent(DBGEVENT_EXCEPTION);
- }
-
- DEBUG("Single-step exeception ELR = 0x%016llx, ISV = %u, EX = %u\n", frame->elr_el2, (esr.iss >> 24) & 1, (esr.iss >> 6) & 1);
-}
diff --git a/thermosphere/src/single_step.h b/thermosphere/src/single_step.h
deleted file mode 100644
index 5b90fe914..000000000
--- a/thermosphere/src/single_step.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 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 "utils.h"
-#include "exceptions.h"
-
-typedef enum SingleStepState {
- SingleStepState_Inactive = 0, // Single step disabled OR in the debugger
- SingleStepState_ActiveNotPending = 1, // Instruction not yet executed
- SingleStepState_ActivePending = 2, // Instruction executed or return-from-trap, single-step exception is going to be generated soon
-} SingleStepState;
-
-/// Get the single-step state machine state (state after eret)
-SingleStepState singleStepGetNextState(ExceptionStackFrame *frame);
-
-/// Set the single-step state machine state (state after eret). Frame can be NULL iff new state is "inactive"
-void singleStepSetNextState(ExceptionStackFrame *frame, SingleStepState state);
-
-void handleSingleStep(ExceptionStackFrame *frame, ExceptionSyndromeRegister esr);
diff --git a/thermosphere/src/traps/hvisor_traps_data_abort.cpp b/thermosphere/src/traps/hvisor_traps_data_abort.cpp
new file mode 100644
index 000000000..9d0f3bdef
--- /dev/null
+++ b/thermosphere/src/traps/hvisor_traps_data_abort.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2019-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 .
+ */
+
+#include "hvisor_traps_data_abort.hpp"
+
+#include "../hvisor_virtual_gic.hpp"
+
+/*
+#include "../hvisor_core_context.hpp"
+#include "../cpu/hvisor_cpu_sysreg_general.hpp"
+#include "../cpu/hvisor_cpu_instructions.hpp"
+*/
+
+// Lower el
+
+namespace ams::hvisor::traps {
+
+ void DumpUnhandledDataAbort(cpu::DataAbortIss dabtIss, u64 far, const char *msg)
+ {
+ char s1[64], s2[32], s3[64] = "";
+ static_cast(s1);
+ static_cast(s2);
+ static_cast(s3);
+ sprintf(s1, "Unhandled%s %s", msg , dabtIss.wnr ? "write" : "read");
+ if (dabtIss.fnv) {
+ sprintf(s2, "");
+ } else {
+ sprintf(s2, "%016lx", far);
+ }
+
+ if (dabtIss.isv) {
+ sprintf(s3, ", size %u Rt=%u", BIT(dabtIss.sas), dabtIss.srt);
+ }
+
+ DEBUG("%s at %s%s\n", s1, s2, s3);
+ }
+
+ void HandleLowerElDataAbortException(ExceptionStackFrame *frame, cpu::ExceptionSyndromeRegister esr)
+ {
+ cpu::DataAbortIss dabtIss;
+ u32 iss = esr.iss;
+ std::memcpy(&iss, &dabtIss, 4);
+
+ u64 far = frame->far_el2;
+ u64 farpg = far & ~0xFFFull;
+ size_t off = far & 0xFFF;
+ size_t sz = dabtIss.GetAccessSize();
+
+ // We don't support 8-byte writes for MMIO
+ if (!dabtIss.HasValidFar() || sz > 4) {
+ DumpUnhandledDataAbort(dabtIss, far, "");
+ }
+
+ if (farpg == VirtualGic::gicdPhysicalAddress) {
+ if (VirtualGic::ValidateGicdRegisterAccess(off, sz)) {
+ if (dabtIss.wnr) {
+ // Register write
+ u32 reg = frame->ReadFrameRegister(dabtIss.srt);
+ VirtualGic::GetInstance().WriteGicdRegister(reg, off, sz);
+ } else {
+ // Reigster read
+ frame->WriteFrameRegister(dabtIss.srt, VirtualGic::GetInstance().ReadGicdRegister(off, sz));
+ }
+ } else {
+ // Invalid GICD access
+ DumpUnhandledDataAbort(dabtIss, far, "GICD");
+ }
+ } else {
+ DumpUnhandledDataAbort(dabtIss, far, "");
+ }
+
+ // Skip instruction anyway
+ frame->SkipInstruction(esr.il == 0 ? 2 : 4);
+ }
+
+}
\ No newline at end of file
diff --git a/thermosphere/src/hvc.c b/thermosphere/src/traps/hvisor_traps_data_abort.hpp
similarity index 64%
rename from thermosphere/src/hvc.c
rename to thermosphere/src/traps/hvisor_traps_data_abort.hpp
index 5292ae019..111fe3f62 100644
--- a/thermosphere/src/hvc.c
+++ b/thermosphere/src/traps/hvisor_traps_data_abort.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019 Atmosphère-NX
+ * Copyright (c) 2019-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,
@@ -14,16 +14,13 @@
* along with this program. If not, see .
*/
-#include "hvc.h"
-#include "debug_log.h"
+#pragma once
-void handleHypercall(ExceptionStackFrame *frame, ExceptionSyndromeRegister esr)
-{
- u32 id = esr.iss;
- switch (id) {
- default:
- DEBUG("Unhandled hypercall: 0x%x.\n");
- dumpStackFrame(frame, false);
- break;
- }
-}
+#include "../hvisor_exception_stack_frame.hpp"
+
+namespace ams::hvisor::traps {
+
+ void DumpUnhandledDataAbort(cpu::DataAbortIss dabtIss, u64 far, const char *msg);
+ void HandleLowerElDataAbort(ExceptionStackFrame *frame, cpu::ExceptionSyndromeRegister esr);
+
+}
\ No newline at end of file
diff --git a/thermosphere/src/traps/hvisor_traps_hvc.cpp b/thermosphere/src/traps/hvisor_traps_hvc.cpp
new file mode 100644
index 000000000..6cd7c7ac9
--- /dev/null
+++ b/thermosphere/src/traps/hvisor_traps_hvc.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019-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 .
+ */
+
+#include "hvisor_traps_hvc.hpp"
+#include "../hvisor_exception_dispatcher.hpp"
+
+namespace ams::hvisor::traps {
+
+ void HandleHypercall(ExceptionStackFrame *frame, cpu::ExceptionSyndromeRegister esr)
+ {
+ u32 id = esr.iss;
+ switch (id) {
+ default:
+ DEBUG("Unhandled hypercall: 0x%x.\n");
+ DumpStackFrame(frame, false);
+ break;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/thermosphere/src/hvc.h b/thermosphere/src/traps/hvisor_traps_hvc.hpp
similarity index 74%
rename from thermosphere/src/hvc.h
rename to thermosphere/src/traps/hvisor_traps_hvc.hpp
index f26ffb045..8178795f1 100644
--- a/thermosphere/src/hvc.h
+++ b/thermosphere/src/traps/hvisor_traps_hvc.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019 Atmosphère-NX
+ * Copyright (c) 2019-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,
@@ -15,6 +15,11 @@
*/
#pragma once
-#include "exceptions.h"
-void handleHypercall(ExceptionStackFrame *frame, ExceptionSyndromeRegister esr);
+#include "../hvisor_exception_stack_frame.hpp"
+
+namespace ams::hvisor::traps {
+
+ void HandleHypercall(ExceptionStackFrame *frame, cpu::ExceptionSyndromeRegister esr);
+
+}
\ No newline at end of file
diff --git a/thermosphere/src/traps/hvisor_traps_single_step.cpp b/thermosphere/src/traps/hvisor_traps_single_step.cpp
new file mode 100644
index 000000000..974735060
--- /dev/null
+++ b/thermosphere/src/traps/hvisor_traps_single_step.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2019-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 .
+ */
+
+#include "hvisor_traps_single_step.hpp"
+
+#include "../hvisor_core_context.hpp"
+#include "../cpu/hvisor_cpu_sysreg_general.hpp"
+#include "../cpu/hvisor_cpu_instructions.hpp"
+
+#include "../debug_manager.h"
+
+namespace ams::hvisor::traps {
+
+ SingleStepState GetNextSingleStepState(ExceptionStackFrame *frame)
+ {
+ u64 mdscr = THERMOSPHERE_GET_SYSREG(mdscr_el1);
+ bool mdscrSS = (mdscr & cpu::MDSCR_SS) != 0;
+ bool pstateSS = (frame->spsr_el2 & cpu::PSR_SS) != 0;
+
+ if (!mdscrSS) {
+ return SingleStepState::Inactive;
+ } else {
+ return pstateSS ? SingleStepState::ActiveNotPending : SingleStepState::ActivePending;
+ }
+
+ }
+
+ void SetNextSingleStepState(ExceptionStackFrame *frame, SingleStepState state)
+ {
+ u64 mdscr = THERMOSPHERE_GET_SYSREG(mdscr_el1);
+
+ switch (state) {
+ case SingleStepState::Inactive:
+ // Unset mdscr_el1.ss
+ mdscr &= ~cpu::MDSCR_SS;
+ break;
+ case SingleStepState::ActiveNotPending:
+ // Set mdscr_el1.ss and pstate.ss
+ mdscr |= cpu::MDSCR_SS;
+ frame->spsr_el2 |= cpu::PSR_SS;
+ break;
+ case SingleStepState::ActivePending:
+ // We never use this because pstate.ss is 0 by default...
+ // Set mdscr_el1.ss and unset pstate.ss
+ mdscr |= cpu::MDSCR_SS;
+ frame->spsr_el2 &= cpu::PSR_SS;
+ break;
+ default:
+ break;
+ }
+
+ THERMOSPHERE_SET_SYSREG(mdscr_el1, mdscr);
+ cpu::isb(); // TRM-mandated
+ }
+
+ void HandleSingleStep(ExceptionStackFrame *frame, cpu::ExceptionSyndromeRegister esr)
+ {
+ uintptr_t addr = frame->elr_el2;
+
+ // Stepping range support;
+ auto [startAddr, endAddr] = currentCoreCtx->GetSteppingRange();
+ if (addr >= startAddr && addr < endAddr) {
+ // Reactivate single-step
+ SetNextSingleStepState(frame, SingleStepState::ActiveNotPending);
+ } else {
+ // Disable single-step
+ SetNextSingleStepState(frame, SingleStepState::Inactive);
+ debugManagerReportEvent(DBGEVENT_EXCEPTION);
+ }
+
+ DEBUG("Single-step exeception ELR = 0x%016llx, ISV = %u, EX = %u\n", frame->elr_el2, (esr.iss >> 24) & 1, (esr.iss >> 6) & 1);
+ }
+
+}
diff --git a/thermosphere/src/traps/hvisor_traps_single_step.hpp b/thermosphere/src/traps/hvisor_traps_single_step.hpp
new file mode 100644
index 000000000..8865048b2
--- /dev/null
+++ b/thermosphere/src/traps/hvisor_traps_single_step.hpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2019-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 .
+ */
+
+#pragma once
+
+#include "../hvisor_exception_stack_frame.hpp"
+
+namespace ams::hvisor::traps {
+
+ enum class SingleStepState {
+ Inactive = 0, /// Single step disabled OR in the debugger
+ ActiveNotPending = 1, /// Instruction not yet executed
+ ActivePending = 2, /// Instruction executed or return-from-trap, single-step exception is going to be generated soon
+ };
+
+ /// Get the single-step state machine state (state after eret)
+ SingleStepState GetNextSingleStepState(ExceptionStackFrame *frame);
+
+ /// Set the single-step state machine state (state after eret). Frame can be nullptr iff new state is "inactive"
+ void SetNextSingleStepState(ExceptionStackFrame *frame, SingleStepState state);
+
+ void HandleSingleStep(ExceptionStackFrame *frame, cpu::ExceptionSyndromeRegister esr);
+
+}
\ No newline at end of file
diff --git a/thermosphere/src/smc.c b/thermosphere/src/traps/smc.c
similarity index 100%
rename from thermosphere/src/smc.c
rename to thermosphere/src/traps/smc.c
diff --git a/thermosphere/src/smc.h b/thermosphere/src/traps/smc.h
similarity index 100%
rename from thermosphere/src/smc.h
rename to thermosphere/src/traps/smc.h
diff --git a/thermosphere/src/sysreg_traps.c b/thermosphere/src/traps/sysreg_traps.c
similarity index 100%
rename from thermosphere/src/sysreg_traps.c
rename to thermosphere/src/traps/sysreg_traps.c
diff --git a/thermosphere/src/sysreg_traps.h b/thermosphere/src/traps/sysreg_traps.h
similarity index 100%
rename from thermosphere/src/sysreg_traps.h
rename to thermosphere/src/traps/sysreg_traps.h