From f9ec21e99ea332076c4b59fe36c96cf44a7debd1 Mon Sep 17 00:00:00 2001
From: TuxSH <1922548+TuxSH@users.noreply.github.com>
Date: Wed, 14 Aug 2019 00:33:19 +0200
Subject: [PATCH] thermosphere: handle stage2 data aborts, trap gicd accesses
---
thermosphere/src/data_abort.c | 61 ++++++++++++++++++++
thermosphere/src/data_abort.h | 42 ++++++++++++++
thermosphere/src/exceptions.c | 6 +-
thermosphere/src/exceptions.h | 4 ++
thermosphere/src/platform/qemu/memory_map.c | 3 +-
thermosphere/src/platform/tegra/memory_map.c | 3 +-
6 files changed, 116 insertions(+), 3 deletions(-)
create mode 100644 thermosphere/src/data_abort.c
create mode 100644 thermosphere/src/data_abort.h
diff --git a/thermosphere/src/data_abort.c b/thermosphere/src/data_abort.c
new file mode 100644
index 000000000..6d2a6c758
--- /dev/null
+++ b/thermosphere/src/data_abort.c
@@ -0,0 +1,61 @@
+/*
+ * 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 "data_abort.h"
+#include "sysreg.h"
+#include "debug_log.h"
+#include "irq.h"
+
+// Lower el
+
+void dumpUnhandledDataAbort(DataAbortIss dabtIss, u64 far, const char *msg)
+{
+ DEBUG("Unhandled");
+ DEBUG(" %s ", msg);
+ DEBUG("%s at ", dabtIss.wnr ? "write" : "read");
+ if (dabtIss.fnv) {
+ DEBUG("");
+ } else {
+ DEBUG("%016llx", far);
+ }
+
+ if (dabtIss.isv) {
+ DEBUG(" size %u Rt=%u", BIT(dabtIss.sas), dabtIss.srt);
+ }
+
+ DEBUG("\n");
+}
+
+void handleLowerElDataAbortException(ExceptionStackFrame *frame, ExceptionSyndromeRegister esr)
+{
+ DataAbortIss dabtIss;
+ memcpy(&dabtIss, &esr, 4);
+
+ u64 far = GET_SYSREG(far_el2);
+
+ if (!dabtIss.isv || dabtIss.fnv) {
+ dumpUnhandledDataAbort(dabtIss, far, "");
+ }
+
+ // TODO
+
+ if ((far & ~0xFFFull) == (uintptr_t)g_irqManager.gic.gicd) {
+ // TODO
+ }
+
+ dumpUnhandledDataAbort(dabtIss, far, "(fallback)");
+}
\ No newline at end of file
diff --git a/thermosphere/src/data_abort.h b/thermosphere/src/data_abort.h
new file mode 100644
index 000000000..e5d0e5cf5
--- /dev/null
+++ b/thermosphere/src/data_abort.h
@@ -0,0 +1,42 @@
+/*
+ * 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 : 1; // 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/exceptions.c b/thermosphere/src/exceptions.c
index 7bc209762..473bcf6d5 100644
--- a/thermosphere/src/exceptions.c
+++ b/thermosphere/src/exceptions.c
@@ -20,6 +20,7 @@
#include "smc.h"
#include "core_ctx.h"
#include "single_step.h"
+#include "data_abort.h"
#include "debug_log.h"
@@ -110,7 +111,10 @@ void handleLowerElSyncException(ExceptionStackFrame *frame, ExceptionSyndromeReg
case Exception_SystemRegisterTrap:
handleMsrMrsTrap(frame, esr);
break;
-
+ case Exception_DataAbortLowerEl:
+ // Basically, stage2 translation faults
+ handleLowerElDataAbortException(frame, esr);
+ break;
case Exception_SoftwareStepLowerEl:
handleSingleStep(frame, esr);
break;
diff --git a/thermosphere/src/exceptions.h b/thermosphere/src/exceptions.h
index 6684dc48b..66a1d3b41 100644
--- a/thermosphere/src/exceptions.h
+++ b/thermosphere/src/exceptions.h
@@ -105,3 +105,7 @@ static inline void spsrSetT32ItFlags(u64 *spsr, u32 itFlags)
bool spsrEvaluateConditionCode(u64 spsr, u32 conditionCode);
void skipFaultingInstruction(ExceptionStackFrame *frame, u32 size);
void dumpStackFrame(const ExceptionStackFrame *frame, bool sameEl);
+
+void handleLowerElSyncException(ExceptionStackFrame *frame, ExceptionSyndromeRegister esr);
+void handleSameElSyncException(ExceptionStackFrame *frame, ExceptionSyndromeRegister esr);
+void handleUnknownException(u32 offset);
diff --git a/thermosphere/src/platform/qemu/memory_map.c b/thermosphere/src/platform/qemu/memory_map.c
index 66b348125..95af2393d 100644
--- a/thermosphere/src/platform/qemu/memory_map.c
+++ b/thermosphere/src/platform/qemu/memory_map.c
@@ -72,7 +72,8 @@ uintptr_t configureStage2MemoryMap(u32 *addrSpaceSize)
identityMapL3(g_vttbl_l3_0, 0x08000000ull, BITL(21), unchanged);
- // GICv2 CPU -> vCPU interface
+ // GICD -> trapped, GICv2 CPU -> vCPU interface
+ mmu_unmap_range(3, g_vttbl_l3_0, 0x08000000, 0x10000ull);
mmu_map_page_range(g_vttbl_l3_0, 0x08010000ull, 0x08040000ull, 0x10000ull, devattrs);
}
diff --git a/thermosphere/src/platform/tegra/memory_map.c b/thermosphere/src/platform/tegra/memory_map.c
index eabef083c..4f846012f 100644
--- a/thermosphere/src/platform/tegra/memory_map.c
+++ b/thermosphere/src/platform/tegra/memory_map.c
@@ -71,7 +71,8 @@ uintptr_t configureStage2MemoryMap(u32 *addrSpaceSize)
identityMapL3(g_vttbl_l3_0, 0x00000000ull, BITL(21), unchanged);
- // GICv2 CPU -> vCPU interface
+ // GICD -> trapped, GICv2 CPU -> vCPU interface
+ mmu_unmap_page(g_vttbl_l3_0, 0x50401000ull);
mmu_map_page_range(g_vttbl_l3_0, 0x50042000ull, 0x50046000ull, 0x2000ull, devattrs);
}