From 4adb675072d18ecc631683c3074dea578fec81ce Mon Sep 17 00:00:00 2001 From: TuxSH <1922548+TuxSH@users.noreply.github.com> Date: Sat, 22 Feb 2020 00:16:03 +0000 Subject: [PATCH] thermosphere: hvisor_exception_frame.hpp --- thermosphere/src/exceptions.h | 158 -------------------- thermosphere/src/hvisor_exception_frame.hpp | 144 ++++++++++++++++++ thermosphere/src/transport_interface.h | 2 +- 3 files changed, 145 insertions(+), 159 deletions(-) delete mode 100644 thermosphere/src/exceptions.h create mode 100644 thermosphere/src/hvisor_exception_frame.hpp diff --git a/thermosphere/src/exceptions.h b/thermosphere/src/exceptions.h deleted file mode 100644 index 77e57e230..000000000 --- a/thermosphere/src/exceptions.h +++ /dev/null @@ -1,158 +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 "core_ctx.h" - -// Adapted from https://developer.arm.com/docs/ddi0596/a/a64-shared-pseudocode-functions/shared-exceptions-pseudocode -typedef enum ExceptionClass { - Exception_Uncategorized = 0x0, - Exception_WFxTrap = 0x1, - Exception_CP15RTTrap = 0x3, - Exception_CP15RRTTrap = 0x4, - Exception_CP14RTTrap = 0x5, - Exception_CP14DTTrap = 0x6, - Exception_AdvSIMDFPAccessTrap = 0x7, - Exception_FPIDTrap = 0x8, - Exception_PACTrap = 0x9, - Exception_CP14RRTTrap = 0xC, - Exception_BranchTargetException = 0xD, // No official enum field name from Arm yet - Exception_IllegalState = 0xE, - Exception_SupervisorCallA32 = 0x11, - Exception_HypervisorCallA32 = 0x12, - Exception_MonitorCallA32 = 0x13, - Exception_SupervisorCallA64 = 0x15, - Exception_HypervisorCallA64 = 0x16, - Exception_MonitorCallA64 = 0x17, - Exception_SystemRegisterTrap = 0x18, - Exception_SVEAccessTrap = 0x19, - Exception_ERetTrap = 0x1A, - Exception_El3_ImplementationDefined = 0x1F, - Exception_InstructionAbortLowerEl = 0x20, - Exception_InstructionAbortSameEl = 0x21, - Exception_PCAlignment = 0x22, - Exception_DataAbortLowerEl = 0x24, - Exception_DataAbortSameEl = 0x25, - Exception_SPAlignment = 0x26, - Exception_FPTrappedExceptionA32 = 0x28, - Exception_FPTrappedExceptionA64 = 0x2C, - Exception_SError = 0x2F, - Exception_BreakpointLowerEl = 0x30, - Exception_BreakpointSameEl = 0x31, - Exception_SoftwareStepLowerEl = 0x32, - Exception_SoftwareStepSameEl = 0x33, - Exception_WatchpointLowerEl = 0x34, - Exception_WatchpointSameEl = 0x35, - Exception_SoftwareBreakpointA32 = 0x38, - Exception_VectorCatchA32 = 0x3A, - Exception_SoftwareBreakpointA64 = 0x3C, -} ExceptionClass; - -typedef struct ExceptionSyndromeRegister { - u32 iss : 25; // Instruction Specific Syndrome - u32 il : 1; // Instruction Length (16 or 32-bit) - ExceptionClass ec : 6; // Exception Class - u32 res0 : 32; -} ExceptionSyndromeRegister; - -typedef struct ExceptionStackFrame { - u64 x[31]; // x0 .. x30 - u64 sp_el1; - union { - u64 sp_el2; - u64 sp_el0; - }; - u64 elr_el2; - u64 spsr_el2; - ExceptionSyndromeRegister esr_el2; - u64 far_el2; - u64 cntpct_el0; - u64 cntp_ctl_el0; - u64 cntv_ctl_el0; -} ExceptionStackFrame; - -//static_assert(offsetof(ExceptionStackFrame, far_el2) == 0x120, "Wrong definition for ExceptionStackFrame"); -//static_assert(sizeof(ExceptionStackFrame) == 0x140, "Wrong size for ExceptionStackFrame"); - -static inline bool spsrIsA32(u64 spsr) -{ - return (spsr & 0x10) != 0; -} - -static inline bool spsrIsThumb(u64 spsr) -{ - return spsrIsA32(spsr) && (spsr & 0x20) != 0; -} - -static inline u32 spsrGetT32ItFlags(u64 spsr) -{ - return (((spsr >> 10) & 0x3F) << 2) | ((spsr >> 25) & 3); -} - -static inline void spsrSetT32ItFlags(u64 *spsr, u32 itFlags) -{ - static const u32 itMask = (0x3F << 10) | (3 << 25); - *spsr &= ~itMask; - *spsr |= (itFlags & 3) << 25; - *spsr |= ((itFlags >> 2) & 0x3F) << 10; -} - -static inline u64 readFrameRegister(ExceptionStackFrame *frame, u32 id) -{ - return frame->x[id]; -} - -static inline u64 readFrameRegisterZ(ExceptionStackFrame *frame, u32 id) -{ - return id == 31 ? 0 /* xzr */ : frame->x[id]; -} - -static inline void writeFrameRegister(ExceptionStackFrame *frame, u32 id, u64 val) -{ - frame->x[id] = val; -} - -static inline void writeFrameRegisterZ(ExceptionStackFrame *frame, u32 id, u64 val) -{ - if (id != 31) { - // If not xzr - frame->x[id] = val; - } -} - -static inline u64 *exceptionGetSpPtr(ExceptionStackFrame *frame) -{ - // Note: the return value is more or less meaningless if we took an exception from A32... - // We try our best to reflect which privilege level the exception was took from, nonetheless - - bool spEl0; - u64 m = frame->spsr_el2 & 0xF; - if (spsrIsA32(frame->spsr_el2)) { - spEl0 = m == 0; - } else { - u64 el = m >> 2; - spEl0 = el == 2 || el == 0 || (m & 1) == 0; // note: frame->sp_el2 is aliased to frame->sp_el0 - } - - return spEl0 ? &frame->sp_el0 : &frame->sp_el1; -} - -bool spsrEvaluateConditionCode(u64 spsr, u32 conditionCode); -void skipFaultingInstruction(ExceptionStackFrame *frame, u32 size); -void dumpStackFrame(const ExceptionStackFrame *frame, bool sameEl); - -void exceptionEnterInterruptibleHypervisorCode(void); diff --git a/thermosphere/src/hvisor_exception_frame.hpp b/thermosphere/src/hvisor_exception_frame.hpp new file mode 100644 index 000000000..477db88e8 --- /dev/null +++ b/thermosphere/src/hvisor_exception_frame.hpp @@ -0,0 +1,144 @@ +/* + * 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 "cpu/hvisor_cpu_exception_sysregs.hpp" + +namespace ams::hvisor { + + struct alignas(16) ExceptionStackFrame { + u64 x[31]; // x0 .. x30 + union { + u64 sp_el1; + u64 sp_el2; + }; + u64 sp_el0; + u64 elr_el2; + u64 spsr_el2; + cpu::ExceptionSyndromeRegister esr_el2; + u64 far_el2; + u64 cntpct_el0; + u64 cntp_ctl_el0; + u64 cntv_ctl_el0; + + constexpr bool IsA32() const { return (spsr_el2 & cpu::PSR_MODE32) != 0; } + constexpr bool IsThumb() const { return IsA32() && (spsr_el2 & cpu::PSR_AA32_THUMB) != 0; } + + constexpr u32 GetT32ItFlags() const + { + u64 it10 = (spsr_el2 >> cpu::PSR_AA32_IT10_MASK) & cpu::PSR_AA32_IT10_MASK; + u64 it72 = (spsr_el2 >> cpu::PSR_AA32_IT72_MASK) & cpu::PSR_AA32_IT72_MASK; + return it72 << 2 | it10; + } + constexpr void SetT32ItFlags(u32 flags) + { + spsr_el2 &= ~(cpu::PSR_AA32_IT72_MASK << cpu::PSR_AA32_IT72_SHIFT); + spsr_el2 &= ~(cpu::PSR_AA32_IT10_MASK << cpu::PSR_AA32_IT10_SHIFT); + + u64 it10 = flags & cpu::PSR_AA32_IT10_MASK; + u64 it72 = (flags >> 2) & cpu::PSR_AA32_IT72_MASK; + + spsr_el2 |= it72 << cpu::PSR_AA32_IT72_SHIFT; + spsr_el2 |= it10 << cpu::PSR_AA32_IT10_SHIFT; + } + + constexpr bool EvaluateConditionCode(u32 conditionCode) const + { + u64 spsr = spsr_el2; + if (conditionCode == 14) { + // AL + return true; + } else if (conditionCode == 15) { + // Invalid encoding + return false; + } + + // NZCV + bool n = (spsr & BIT(31)) != 0; + bool z = (spsr & BIT(30)) != 0; + bool c = (spsr & BIT(29)) != 0; + bool v = (spsr & BIT(28)) != 0; + + bool tableHalf[] = { + // EQ, CS, MI, VS, HI, GE, GT + z, c, n, v, c && !z, n == v, !z && n == v, + }; + + return (conditionCode & 1) == 0 ? tableHalf[conditionCode / 2] : !tableHalf[conditionCode / 2]; + } + + constexpr void AdvanceItState() + { + u32 it = GetT32ItFlags(); + + // Just in case EL0 is executing A32 (& not sure if fully supported) + if (!IsThumb() || it == 0) { + return; + } + + // Last instruction of the block => wipe, otherwise advance + SetT32ItFlags((it & 7) == 0 ? 0 : (it & 0xE0) | ((it << 1) & 0x1F)); + } + + constexpr void SkipInstruction(size_t size) + { + AdvanceItState(); + elr_el2 += size; + } + + template + constexpr T ReadFrameRegister(u32 id) const + { + static_assert(std::is_integral_v && std::is_unsigned_v); + return id == 31 ? static_cast(0u) /* xzr */ : static_cast(x[id]); + } + constexpr void WriteFrameRegister(u32 id, u64 val) + { + if (id != 31) { + // If not xzr + x[id] = val; + } + } + + constexpr u64 &GetSpRef() + { + // Note: the return value is more or less meaningless if we took an exception from A32... + // We try our best to reflect which privilege level the exception was took from, nonetheless + + bool spEl0 = false; + u64 m = spsr_el2 & 0xF; + if (IsA32()) { + spEl0 = m == 0; + } else { + u64 el = m >> 2; + spEl0 = el == 0 || (m & 1) == 0; // note: frame->sp_el2 is aliased to frame->sp_el1 + } + + return spEl0 ? sp_el0 : sp_el1; + } + + }; + + static_assert(offsetof(ExceptionStackFrame, far_el2) == 0x120, "Wrong definition for ExceptionStackFrame"); + static_assert(sizeof(ExceptionStackFrame) == 0x140, "Wrong size for ExceptionStackFrame"); + + static_assert(std::is_standard_layout_v); + static_assert(std::is_trivial_v); +} + +/*void dumpStackFrame(const ExceptionStackFrame *frame, bool sameEl); +void exceptionEnterInterruptibleHypervisorCode(void);*/ diff --git a/thermosphere/src/transport_interface.h b/thermosphere/src/transport_interface.h index b9f6d1e25..7656e012e 100644 --- a/thermosphere/src/transport_interface.h +++ b/thermosphere/src/transport_interface.h @@ -17,7 +17,7 @@ #pragma once #include "utils.h" -#include "spinlock.h" +//#include "spinlock.h" #define MAX_TRANSPORT_INTERFACES 4