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