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