From eb27c36709d0c99111148236b71e5c4db5fe65e9 Mon Sep 17 00:00:00 2001
From: TuxSH <1922548+TuxSH@users.noreply.github.com>
Date: Fri, 2 Aug 2019 05:12:24 +0200
Subject: [PATCH] thermosphere: impl stage2 translation
---
thermosphere/Makefile | 2 +-
thermosphere/src/arm.h | 1 +
thermosphere/src/arm.s | 24 +++
thermosphere/src/core_ctx.c | 6 +-
thermosphere/src/core_ctx.h | 4 +-
thermosphere/src/main.c | 4 +-
thermosphere/src/mmu.h | 12 +-
.../src/platform/memory_map_mmu_cfg.c | 34 ++++-
thermosphere/src/platform/qemu/memory_map.c | 54 +++++--
thermosphere/src/platform/qemu/memory_map.h | 12 +-
thermosphere/src/platform/tegra/memory_map.c | 55 +++++--
thermosphere/src/platform/tegra/memory_map.h | 13 +-
thermosphere/src/shadow_page_tables.c | 138 ------------------
thermosphere/src/shadow_page_tables.h | 22 ---
thermosphere/src/start.s | 3 +
thermosphere/src/sysreg_traps.c | 37 -----
thermosphere/src/traps.c | 4 -
thermosphere/src/utils.h | 17 +--
18 files changed, 174 insertions(+), 268 deletions(-)
delete mode 100644 thermosphere/src/shadow_page_tables.c
delete mode 100644 thermosphere/src/shadow_page_tables.h
diff --git a/thermosphere/Makefile b/thermosphere/Makefile
index 1da06deec..07cb2db81 100644
--- a/thermosphere/Makefile
+++ b/thermosphere/Makefile
@@ -33,7 +33,7 @@ PLATFORM_DEFINES := -DPLATFORM_TEGRA -DPLATFORM_TEGRA_T210_ARM_TF
else
-export PLATFORM := tegra
+export PLATFORM := tegra-t210-nintendo
PLATFORM_SOURCES := src/platform/tegra
PLATFORM_DEFINES := -DPLATFORM_TEGRA -D DPLATFORM_TEGRA_T210_NINTENDO
diff --git a/thermosphere/src/arm.h b/thermosphere/src/arm.h
index 8a6a569cd..1f9a8354b 100644
--- a/thermosphere/src/arm.h
+++ b/thermosphere/src/arm.h
@@ -12,3 +12,4 @@ void invalidate_icache_all_inner_shareable(void);
void invalidate_icache_all(void);
void set_memory_registers_enable_mmu(uintptr_t ttbr0, u64 tcr, u64 mair);
+void set_memory_registers_enable_stage2(uintptr_t vttbr, u64 vtcr);
diff --git a/thermosphere/src/arm.s b/thermosphere/src/arm.s
index 22bf1cdf6..3831a816e 100644
--- a/thermosphere/src/arm.s
+++ b/thermosphere/src/arm.s
@@ -237,4 +237,28 @@ set_memory_registers_enable_mmu:
dsb sy
isb
+ ret
+
+.section .text.set_memory_registers_enable_stage2, "ax", %progbits
+.type set_memory_registers_enable_stage2, %function
+.global set_memory_registers_enable_stage2
+set_memory_registers_enable_stage2:
+ msr vttbr_el2, x0
+ msr vtcr_el2, x1
+
+ dsb sy
+ isb
+ // Flushes all stage 1&2 entries, EL1
+ tlbi alle1
+ dsb sy
+ isb
+
+ // Enable stage2
+ mrs x0, hcr_el2
+ orr x0, x0, #1
+ msr hcr_el2, x0
+
+ dsb sy
+ isb
+
ret
\ No newline at end of file
diff --git a/thermosphere/src/core_ctx.c b/thermosphere/src/core_ctx.c
index e19af510a..60f2bcb67 100644
--- a/thermosphere/src/core_ctx.c
+++ b/thermosphere/src/core_ctx.c
@@ -29,14 +29,14 @@ CoreCtx g_coreCtxs[4] = {
{ .coreId = 3 },
};
-void coreCtxInit(u32 coreId, bool isColdbootCore, u64 argument)
+void coreCtxInit(u32 coreId, bool isBootCore, u64 argument)
{
size_t crashStackSize = (__crash_stacks_top__ - __stacks_top__) / 4;
currentCoreCtx = &g_coreCtxs[coreId];
- currentCoreCtx->isColdbootCore = isColdbootCore;
+ currentCoreCtx->isBootCore = isBootCore;
currentCoreCtx->kernelArgument = argument;
currentCoreCtx->crashStack = __crash_stacks_top__ - crashStackSize * coreId;
- if (isColdbootCore && currentCoreCtx->kernelEntrypoint == 0) {
+ if (isBootCore && currentCoreCtx->kernelEntrypoint == 0) {
currentCoreCtx->kernelEntrypoint = g_initialKernelEntrypoint;
}
}
diff --git a/thermosphere/src/core_ctx.h b/thermosphere/src/core_ctx.h
index a65263f5d..4f41430c0 100644
--- a/thermosphere/src/core_ctx.h
+++ b/thermosphere/src/core_ctx.h
@@ -23,10 +23,10 @@ typedef struct CoreCtx {
u8 *crashStack; // @0x10
u64 scratch; // @0x18
u32 coreId; // @0x20
- bool isColdbootCore; // @0x24
+ bool isBootCore; // @0x24
} CoreCtx;
extern CoreCtx g_coreCtxs[4];
register CoreCtx *currentCoreCtx asm("x18");
-void coreCtxInit(u32 coreId, bool isColdbootCore, u64 argument);
+void coreCtxInit(u32 coreId, bool isBootCore, u64 argument);
diff --git a/thermosphere/src/main.c b/thermosphere/src/main.c
index 081bdcae1..0eb878ad7 100644
--- a/thermosphere/src/main.c
+++ b/thermosphere/src/main.c
@@ -4,6 +4,7 @@
#include "platform/uart.h"
#include "semihosting.h"
#include "traps.h"
+#include "sysreg.h"
extern const u8 __start__[];
@@ -34,7 +35,7 @@ int main(void)
{
enableTraps();
- if (currentCoreCtx->isColdbootCore) {
+ if (currentCoreCtx->isBootCore) {
uartInit(115200);
DEBUG("EL2: core %u reached main first!\n", currentCoreCtx->coreId);
if (currentCoreCtx->kernelEntrypoint == 0) {
@@ -49,6 +50,7 @@ int main(void)
}
else {
DEBUG("EL2: core %u reached main!\n", currentCoreCtx->coreId);
+ DEBUG("Test 0x%08llx %016llx\n", get_physical_address_el1_stage12(0x08010000ull), GET_SYSREG(par_el1));
}
return 0;
diff --git a/thermosphere/src/mmu.h b/thermosphere/src/mmu.h
index 583535edf..e08284ec8 100644
--- a/thermosphere/src/mmu.h
+++ b/thermosphere/src/mmu.h
@@ -90,7 +90,7 @@
#define MMU_AP_RO (3ull << 6)
/*
- * S2AP[2:1] (for stage2 translations; secmon doesn't use it)
+ * S2AP[1:0] (for stage2 translations; secmon doesn't use it)
*/
#define MMU_S2AP_NONE (0ull << 6)
#define MMU_S2AP_RO (1ull << 6)
@@ -103,10 +103,19 @@
#define MMU_PMD_ATTRINDX(t) ((uint64_t)((t) << 2))
#define MMU_PMD_ATTRINDX_MASK (7ull << 2)
+/*
+ * MemAttr[3:0] (stage2)
+ *
+ */
+#define MMU_MEMATTR(x) ((x) << 2)
+#define MMU_MEMATTR_DEVICE_NGNRE MMU_MEMATTR(2)
+#define MMU_MEMATTR_NORMAL_CACHEABLE_OR_UNCHANGED MMU_MEMATTR(0xF)
+
/*
* TCR flags.
*/
#define TCR_T0SZ(x) ((64 - (x)) << 0)
+#define VTCR_SL0(x) ((x) << 6)
#define TCR_IRGN_NC (0 << 8)
#define TCR_IRGN_WBWA (1 << 8)
#define TCR_IRGN_WT (2 << 8)
@@ -128,6 +137,7 @@
#define TCR_EL1_RSVD BIT(31)
#define TCR_EL2_RSVD (BIT(31) | BIT(23))
+#define VTCR_EL2_RSVD BIT(31)
#define TCR_EL3_RSVD (BIT(31) | BIT(23))
// We define those:
diff --git a/thermosphere/src/platform/memory_map_mmu_cfg.c b/thermosphere/src/platform/memory_map_mmu_cfg.c
index 21fe01789..d889d4ec5 100644
--- a/thermosphere/src/platform/memory_map_mmu_cfg.c
+++ b/thermosphere/src/platform/memory_map_mmu_cfg.c
@@ -18,6 +18,7 @@
#include "../sysreg.h"
#include "../arm.h"
#include "../mmu.h"
+#include "../debug_log.h"
#include "memory_map_mmu_cfg.h"
void configureMemoryMapEnableMmu(void)
@@ -26,16 +27,15 @@ void configureMemoryMapEnableMmu(void)
uintptr_t ttbr0 = configureMemoryMap(&addrSpaceSize);
u32 ps = GET_SYSREG(id_aa64mmfr0_el1) & 0xF;
-
/*
- PA size: from ID_AA64MMFR0_EL1
- Granule size: 4KB
- - Shareability attribute for memory associated with translation table walks using TTBR0_EL3: Inner Shareable
- - Outer cacheability attribute for memory associated with translation table walks using TTBR0_EL3: Normal memory, Outer Write-Back Read-Allocate Write-Allocate Cacheable
- - Inner cacheability attribute for memory associated with translation table walks using TTBR0_EL3: Normal memory, Inner Write-Back Read-Allocate Write-Allocate Cacheable
+ - Shareability attribute for memory associated with translation table walks using TTBR0_EL2: Inner Shareable
+ - Outer cacheability attribute for memory associated with translation table walks using TTBR0_EL2: Normal memory, Outer Write-Back Read-Allocate Write-Allocate Cacheable
+ - Inner cacheability attribute for memory associated with translation table walks using TTBR0_EL2: Normal memory, Inner Write-Back Read-Allocate Write-Allocate Cacheable
- T0SZ = from configureMemoryMap
*/
- u64 tcr = TCR_EL2_RSVD | TCR_PS(ps) | TCR_TG0_4K | TCR_SHARED_INNER | TCR_ORGN_WBWA | TCR_IRGN_WBWA | TCR_T0SZ(64 - addrSpaceSize);
+ u64 tcr = TCR_EL2_RSVD | TCR_PS(ps) | TCR_TG0_4K | TCR_SHARED_INNER | TCR_ORGN_WBWA | TCR_IRGN_WBWA | TCR_T0SZ(addrSpaceSize);
/*
@@ -49,4 +49,26 @@ void configureMemoryMapEnableMmu(void)
invalidate_icache_all();
set_memory_registers_enable_mmu(ttbr0, tcr, mair);
-}
\ No newline at end of file
+}
+
+void configureMemoryMapEnableStage2(void)
+{
+ u32 addrSpaceSize;
+ uintptr_t vttbr = configureStage2MemoryMap(&addrSpaceSize);
+
+ u32 ps = GET_SYSREG(id_aa64mmfr0_el1) & 0xF;
+ /*
+ - PA size: from ID_AA64MMFR0_EL1
+ - Granule size: 4KB
+ - Shareability attribute for memory associated with translation table walks using VTTBR_EL2: Inner Shareable
+ - Outer cacheability attribute for memory associated with translation table walks using VTTBR_EL2: Normal memory, Outer Write-Back Read-Allocate Write-Allocate Cacheable
+ - Inner cacheability attribute for memory associated with translation table walks using VTTBR_EL2: Normal memory, Inner Write-Back Read-Allocate Write-Allocate Cacheable
+ - SL0 = start at level 1
+ - T0SZ = from configureMemoryMap
+ */
+ u64 vtcr = VTCR_EL2_RSVD | TCR_PS(ps) | TCR_TG0_4K | TCR_SHARED_INNER | TCR_ORGN_WBWA | TCR_IRGN_WBWA | VTCR_SL0(1) | TCR_T0SZ(addrSpaceSize);
+ flush_dcache_all();
+ invalidate_icache_all();
+
+ set_memory_registers_enable_stage2(vttbr, vtcr);
+}
diff --git a/thermosphere/src/platform/qemu/memory_map.c b/thermosphere/src/platform/qemu/memory_map.c
index 4207068e3..1eba99311 100644
--- a/thermosphere/src/platform/qemu/memory_map.c
+++ b/thermosphere/src/platform/qemu/memory_map.c
@@ -19,28 +19,64 @@
#include "../../mmu.h"
#include "../../core_ctx.h"
-// Older QEMU have a 4GB RAM limit, let's just assume a 12GB RAM limit/32-bit addr space (even though PASZ corresponds to 1TB)
-
-#define ADDRSPACESZ 32
+// QEMU presently advertises 44-bit PAs we'll only use 39 of them to avoid level 0 tables.
+#define ADDRSPACESZ 39
+#define ADDRSPACESZ2 ADDRSPACESZ
static ALIGN(0x1000) u64 g_ttbl[BIT(ADDRSPACESZ - 30)] = {0};
+static ALIGN(0x1000) u64 g_vttbl[BIT(ADDRSPACESZ2 - 30)] = {0};
+static TEMPORARY ALIGN(0x1000) u64 g_vttbl_l2_mmio_0_0[512] = {0};
+static TEMPORARY ALIGN(0x1000) u64 g_vttbl_l3_0[512] = {0};
+
static inline void identityMapL1(u64 *tbl, uintptr_t addr, size_t size, u64 attribs)
{
mmu_map_block_range(1, tbl, addr, addr, size, attribs | MMU_PTE_BLOCK_INNER_SHAREBLE);
}
+static inline void identityMapL2(u64 *tbl, uintptr_t addr, size_t size, u64 attribs)
+{
+ mmu_map_block_range(2, tbl, addr, addr, size, attribs | MMU_PTE_BLOCK_INNER_SHAREBLE);
+}
+
+static inline void identityMapL3(u64 *tbl, uintptr_t addr, size_t size, u64 attribs)
+{
+ mmu_map_block_range(3, tbl, addr, addr, size, attribs | MMU_PTE_BLOCK_INNER_SHAREBLE);
+}
+
uintptr_t configureMemoryMap(u32 *addrSpaceSize)
{
// QEMU virt RAM address space starts at 0x40000000
*addrSpaceSize = ADDRSPACESZ;
-
- if (currentCoreCtx->isColdbootCore) {
- identityMapL1(g_ttbl, 0x00000000ull, 1ull << 30, ATTRIB_MEMTYPE_DEVICE);
- identityMapL1(g_ttbl, 0x40000000ull, 1ull << 30, ATTRIB_MEMTYPE_NORMAL);
- identityMapL1(g_ttbl, 0x80000000ull, 1ull << 30, ATTRIB_MEMTYPE_NORMAL);
- identityMapL1(g_ttbl, 0xC0000000ull, 1ull << 30, ATTRIB_MEMTYPE_NORMAL);
+ static bool initialized = false;
+ if (currentCoreCtx->isBootCore && !initialized) {
+ identityMapL1(g_ttbl, 0x00000000ull, BITL(30), ATTRIB_MEMTYPE_DEVICE);
+ identityMapL1(g_ttbl, 0x40000000ull, (BITL(ADDRSPACESZ - 30) - 1ull) << 30, ATTRIB_MEMTYPE_NORMAL);
+ initialized = true;
}
return (uintptr_t)g_ttbl;
+}
+
+uintptr_t configureStage2MemoryMap(u32 *addrSpaceSize)
+{
+ *addrSpaceSize = ADDRSPACESZ2;
+ static const u64 devattrs = MMU_S2AP_RW | MMU_MEMATTR_DEVICE_NGNRE;
+ static const u64 unchanged = MMU_S2AP_RW | MMU_MEMATTR_NORMAL_CACHEABLE_OR_UNCHANGED;
+
+ if (currentCoreCtx->isBootCore) {
+ identityMapL1(g_vttbl, 0, 4ull << 30, unchanged);
+ identityMapL1(g_vttbl, 0x40000000ull, (BITL(ADDRSPACESZ2 - 30) - 1ull) << 30, unchanged);
+ mmu_map_table(1, g_vttbl, 0x00000000ull, g_vttbl_l2_mmio_0_0, 0);
+
+ identityMapL2(g_vttbl_l2_mmio_0_0, 0x08000000ull, BITL(30), unchanged);
+ mmu_map_table(2, g_vttbl_l2_mmio_0_0, 0x08000000ull, g_vttbl_l3_0, 0);
+
+ identityMapL3(g_vttbl_l3_0, 0x08000000ull, BITL(21), unchanged);
+
+ // GICv2 CPU -> vCPU interface
+ mmu_map_page_range(g_vttbl_l3_0, 0x08010000ull, 0x08040000ull, 0x10000ull, devattrs);
+ }
+
+ return (uintptr_t)g_vttbl;
}
\ No newline at end of file
diff --git a/thermosphere/src/platform/qemu/memory_map.h b/thermosphere/src/platform/qemu/memory_map.h
index 8a0956e23..fc608ac8b 100644
--- a/thermosphere/src/platform/qemu/memory_map.h
+++ b/thermosphere/src/platform/qemu/memory_map.h
@@ -18,15 +18,5 @@
#include "../../types.h"
-static inline u64 transformKernelAddress(u64 pa)
-{
- switch (pa) {
- // GICv2 CPU -> vCPU interface
- case 0x08010000:
- return 0x08040000;
- default:
- return pa;
- }
-}
-
uintptr_t configureMemoryMap(u32 *addrSpaceSize);
+uintptr_t configureStage2MemoryMap(u32 *addrSpaceSize);
diff --git a/thermosphere/src/platform/tegra/memory_map.c b/thermosphere/src/platform/tegra/memory_map.c
index 9cf49737e..13a75b788 100644
--- a/thermosphere/src/platform/tegra/memory_map.c
+++ b/thermosphere/src/platform/tegra/memory_map.c
@@ -19,30 +19,63 @@
#include "../../mmu.h"
#include "../../core_ctx.h"
-// Limit ourselves to 34-bit addr space even if the tegra support up to 36 in theory
+// Tegra PA size is 36-bit... should we limit ourselves to 34?
// i.e. 14GB of dram max
-#define ADDRSPACESZ 34
+#define ADDRSPACESZ 36
+#define ADDRSPACESZ2 ADDRSPACESZ
static ALIGN(0x1000) u64 g_ttbl[BIT(ADDRSPACESZ - 30)] = {0};
+static ALIGN(0x1000) u64 g_vttbl[BIT(ADDRSPACESZ2 - 30)] = {0};
+static TEMPORARY ALIGN(0x1000) u64 g_vttbl_l2_mmio_0[512] = {0};
+static TEMPORARY ALIGN(0x1000) u64 g_vttbl_l3_0[512] = {0};
+
static inline void identityMapL1(u64 *tbl, uintptr_t addr, size_t size, u64 attribs)
{
mmu_map_block_range(1, tbl, addr, addr, size, attribs | MMU_PTE_BLOCK_INNER_SHAREBLE);
}
+static inline void identityMapL2(u64 *tbl, uintptr_t addr, size_t size, u64 attribs)
+{
+ mmu_map_block_range(2, tbl, addr, addr, size, attribs | MMU_PTE_BLOCK_INNER_SHAREBLE);
+}
+
+static inline void identityMapL3(u64 *tbl, uintptr_t addr, size_t size, u64 attribs)
+{
+ mmu_map_block_range(3, tbl, addr, addr, size, attribs | MMU_PTE_BLOCK_INNER_SHAREBLE);
+}
+
uintptr_t configureMemoryMap(u32 *addrSpaceSize)
{
- // QEMU virt RAM address space starts at 0x40000000
*addrSpaceSize = ADDRSPACESZ;
-
- if (currentCoreCtx->isColdbootCore) {
- identityMapL1(g_ttbl, 0x00000000ull, 1ull << 30, ATTRIB_MEMTYPE_DEVICE);
- identityMapL1(g_ttbl, 0x40000000ull, 1ull << 30, ATTRIB_MEMTYPE_DEVICE);
-
- for (u64 i = 2; i < 16; i++) {
- identityMapL1(g_ttbl, i << 30, 1ull << 30, ATTRIB_MEMTYPE_NORMAL);
- }
+ static bool initialized = false;
+ if (currentCoreCtx->isBootCore && !initialized) {
+ identityMapL1(g_ttbl, 0x00000000ull, 2 * BITL(30), ATTRIB_MEMTYPE_DEVICE);
+ identityMapL1(g_ttbl, 0x80000000ull, (BITL(ADDRSPACESZ - 30) - 2ull) << 30, ATTRIB_MEMTYPE_NORMAL);
+ initialized = true;
}
return (uintptr_t)g_ttbl;
+}
+
+uintptr_t configureStage2MemoryMap(u32 *addrSpaceSize)
+{
+ *addrSpaceSize = ADDRSPACESZ2;
+ static const u64 devattrs = MMU_S2AP_RW | MMU_MEMATTR_DEVICE_NGNRE;
+ static const u64 unchanged = MMU_S2AP_RW | MMU_MEMATTR_NORMAL_CACHEABLE_OR_UNCHANGED;
+ if (currentCoreCtx->isBootCore) {
+ identityMapL1(g_vttbl, 0x00000000ull, BITL(30), unchanged);
+ identityMapL1(g_vttbl, 0x80000000ull, (BITL(ADDRSPACESZ2 - 30) - 2ull) << 30, unchanged);
+ mmu_map_table(1, g_vttbl, 0x40000000ull, g_vttbl_l2_mmio_0, 0);
+
+ identityMapL2(g_vttbl_l2_mmio_0, 0x40000000ull, BITL(30), unchanged);
+ mmu_map_table(2, g_vttbl_l2_mmio_0, 0x50000000ull, g_vttbl_l3_0, 0);
+
+ identityMapL3(g_vttbl_l3_0, 0x00000000ull, BITL(21), unchanged);
+
+ // GICv2 CPU -> vCPU interface
+ mmu_map_page_range(g_vttbl_l3_0, 0x50042000ull, 0x50046000ull, 0x2000ull, devattrs);
+ }
+
+ return (uintptr_t)g_vttbl;
}
\ No newline at end of file
diff --git a/thermosphere/src/platform/tegra/memory_map.h b/thermosphere/src/platform/tegra/memory_map.h
index 20a2b176d..d2478da87 100644
--- a/thermosphere/src/platform/tegra/memory_map.h
+++ b/thermosphere/src/platform/tegra/memory_map.h
@@ -18,15 +18,6 @@
#include "../../types.h"
-static inline u64 transformKernelAddress(u64 pa)
-{
- switch (pa) {
- // GICv2 CPU -> vCPU interface
- case 0x50042000:
- return 0x50046000;
- default:
- return pa;
- }
-}
-
uintptr_t configureMemoryMap(u32 *addrSpaceSize);
+uintptr_t configureStage2MemoryMap(u32 *addrSpaceSize);
+
diff --git a/thermosphere/src/shadow_page_tables.c b/thermosphere/src/shadow_page_tables.c
deleted file mode 100644
index 0e24120db..000000000
--- a/thermosphere/src/shadow_page_tables.c
+++ /dev/null
@@ -1,138 +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 "shadow_page_tables.h"
-#include "platform/memory_map_mmu_cfg.h"
-#include "debug_log.h"
-
-#ifdef A32_SUPPORTED
-static void replacePageTableShortL2(u32 *ttbl)
-{
- u32 inc;
- for (u32 i = 0; i < BIT(8); i += inc) {
- u32 type = ttbl[i] & 3;
- switch (type) {
- case 0:
- // Fault
- inc = 1;
- break;
- case 1:
- // Large page
- // Nothing to replace at this granularity level
- inc = 16;
- break;
- case 2:
- case 3:
- // Section or supersection
- // Nothing to replace at this granularity level yet
- // TODO
- inc = 1;
- break;
- }
- }
-}
-
-void replacePageTableShort(u32 *ttbl, u32 n)
-{
- //u32 mask = MASK2(31 - n, 20);
- u32 inc;
- for (u32 i = 0; i < BIT(12 - n); i += inc) {
- u32 type = ttbl[i] & 3;
- switch (type) {
- case 0:
- // Fault
- inc = 1;
- break;
- case 1:
- // L2 tbl
- replacePageTableShortL2((u32 *)(uintptr_t)(ttbl[i] & ~MASK(10)));
- inc = 1;
- break;
- case 2:
- case 3:
- // Section or supersection
- // Nothing to replace at this granularity level yet
- inc = (ttbl[i] & BIT(18)) ? 16 : 0;
- break;
- }
- }
-}
-#endif
-
-static void replacePageTableLongImpl(u64 *ttbl, u32 level, u32 nbits)
-{
- for (u32 i = 0; i < BIT(nbits); i++) {
- u64 type = ttbl[i] & 3;
- switch (type) {
- case 0:
- case 2:
- // Fault
- break;
- case 1:
- // Block (L1 or L2) or invalid (L0 or L3)
- // Nothing to do at this granularity level anyway.
- break;
- case 3: {
- // Lower-level table or page
- if (level < 3) {
- uintptr_t addr = ttbl[i] & MASK2L(47, 12);
- replacePageTableLongImpl((u64 *)addr, level + 1, 9);
- } else {
- u64 pa = ttbl[i] & MASK2L(47, 12);
- u64 newPa = transformKernelAddress(pa);
- if (pa != newPa) {
- // Note: unreachable on QEMU yet
- DEBUG("EL1 in-place page-table entry swap: 0x%08llx => 0x%08llx\n", pa, newPa);
- ttbl[i] = (ttbl[i] & ~MASK2L(47, 12)) | newPa;
- }
- }
-
- break;
- }
-
- default:
- __builtin_unreachable();
- break;
- }
- }
-}
-
-void replacePageTableLong(u64 *ttbl, u32 txsz)
-{
- u32 startBit = 63 - txsz;
-
- // Initial level 3 for 4KB granule: "c. Only available if ARMv8.4-TTST is implemented, while the PE is executing in AArch64 state." (Arm Arm).
- // This means there is a maximum value for TxSz...
-
- if (startBit >= 48) {
- // Invalid
- return;
- } else if (startBit >= 39) {
- replacePageTableLongImpl(ttbl, 0, startBit - 38);
- } else if (startBit >= 30) {
- replacePageTableLongImpl(ttbl, 1, startBit - 29);
- } else if (startBit >= 21) {
- replacePageTableLongImpl(ttbl, 2, startBit - 20);
- } else if (startBit >= 12) {
- replacePageTableLongImpl(ttbl, 3, startBit - 11);
- }
-}
-
-void replaceKernelPageTables(void)
-{
-
-}
\ No newline at end of file
diff --git a/thermosphere/src/shadow_page_tables.h b/thermosphere/src/shadow_page_tables.h
deleted file mode 100644
index f4c0def78..000000000
--- a/thermosphere/src/shadow_page_tables.h
+++ /dev/null
@@ -1,22 +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"
-
-void replacePageTableLong(u64 *ttbl, u32 txsz);
diff --git a/thermosphere/src/start.s b/thermosphere/src/start.s
index 810e9acf8..112b7227e 100644
--- a/thermosphere/src/start.s
+++ b/thermosphere/src/start.s
@@ -93,7 +93,10 @@ _startCommon:
_enable_mmu:
+ // Enable EL2 address translation and caches
bl configureMemoryMapEnableMmu
+ // Enable EL1 Stage2 intermediate physical address translation
+ bl configureMemoryMapEnableStage2
dsb sy
isb
diff --git a/thermosphere/src/sysreg_traps.c b/thermosphere/src/sysreg_traps.c
index 64dae81a3..76709e3b8 100644
--- a/thermosphere/src/sysreg_traps.c
+++ b/thermosphere/src/sysreg_traps.c
@@ -19,7 +19,6 @@
#include "sysreg.h"
#include "arm.h"
#include "debug_log.h"
-#include "shadow_page_tables.h"
static void doSystemRegisterRwImpl(u64 *val, u32 iss)
{
@@ -91,42 +90,6 @@ void doSystemRegisterWrite(ExceptionStackFrame *frame, u32 iss, u32 reg1, u32 re
// Hooks go here:
switch (iss) {
- case ENCODE_SYSREG_ISS(SCTLR_EL1): {
- DEBUG("Hooked sysreg write: SCTLR_EL1 = %0x016llx\n", val);
- // Possible MMU (re)-enablement
- if (val & 1) {
- u64 tcr = GET_SYSREG(tcr_el1);
- if (((tcr >> 14) & 3) == 0) {
- // 4KB granule
- replacePageTableLong((u64 *)(GET_SYSREG(ttbr0_el1) & MASK2L(47, 1)), (u32)(tcr & 0x3F));
- replacePageTableLong((u64 *)(GET_SYSREG(ttbr1_el1) & MASK2L(47, 1)), (u32)((tcr >> 16) & 0x3F));
- }
- }
-
- break;
- }
- case ENCODE_SYSREG_ISS(TTBR1_EL1): {
- DEBUG("Hooked sysreg write: TTBR1_EL1 = %0x016llx\n", val);
- u64 tcr = GET_SYSREG(tcr_el1);
- // MMU enabled & 4KB granule
- if ((GET_SYSREG(sctlr_el1) & 1) && ((tcr >> 14) & 3) == 0) {
- // Note: lack of ttbr0 intentional here
- replacePageTableLong((u64 *)(val & MASK2L(47, 1)), (u32)((tcr >> 16) & 0x3F));
- }
- break;
- }
- case ENCODE_SYSREG_ISS(TCR_EL1): {
- DEBUG("Hooked sysreg write: TCR_EL1 = %0x016llx\n", val);
- u64 tcr = val;
- // MMU enabled & 4KB granule
- if ((GET_SYSREG(sctlr_el1) & 1) && ((tcr >> 14) & 3) == 0) {
- // Note: lack of ttbr0 intentional here
- replacePageTableLong((u64 *)(GET_SYSREG(ttbr1_el1) & MASK2L(47, 1)), (u32)((tcr >> 16) & 0x3F));
- }
- break;
- }
- // Note: TTBR0_EL1 deliberately not hooked
-
default:
break;
}
diff --git a/thermosphere/src/traps.c b/thermosphere/src/traps.c
index b471d0d2a..85a142f01 100644
--- a/thermosphere/src/traps.c
+++ b/thermosphere/src/traps.c
@@ -35,10 +35,6 @@ void enableTraps(void)
{
u64 hcr = GET_SYSREG(hcr_el2);
- // Trap *writes* to memory control registers
- // Note: QEMU doesn't support this bit as of August 2019...
- hcr |= HCR_TVM;
-
// Trap SMC instructions
hcr |= HCR_TSC;
diff --git a/thermosphere/src/utils.h b/thermosphere/src/utils.h
index a6f2095e7..f604519bb 100644
--- a/thermosphere/src/utils.h
+++ b/thermosphere/src/utils.h
@@ -33,21 +33,16 @@
#define ALINLINE __attribute__((always_inline))
+#define TEMPORARY __attribute__((section(".temp")))
+
bool overlaps(u64 as, u64 ae, u64 bs, u64 be);
-
-static inline uintptr_t get_physical_address(const void *vaddr) {
+static inline uintptr_t get_physical_address_el1_stage12(const uintptr_t el1_vaddr) {
+ // NOTE: interrupt must be disabled when calling this func
uintptr_t PAR;
- __asm__ __volatile__ ("at s1e3r, %0" :: "r"(vaddr));
+ __asm__ __volatile__ ("at s12e1r, %0" :: "r"(el1_vaddr));
__asm__ __volatile__ ("mrs %0, par_el1" : "=r"(PAR));
- return (PAR & 1) ? 0ull : (PAR & MASK2L(40, 12)) | ((uintptr_t)vaddr & MASKL(12));
-}
-
-static inline uintptr_t get_physical_address_el0(const uintptr_t el0_vaddr) {
- uintptr_t PAR;
- __asm__ __volatile__ ("at s1e0r, %0" :: "r"(el0_vaddr));
- __asm__ __volatile__ ("mrs %0, par_el1" : "=r"(PAR));
- return (PAR & 1) ? 0ull : (PAR & MASK2L(40, 12)) | ((uintptr_t)el0_vaddr & MASKL(12));
+ return (PAR & 1) ? 0ull : (PAR & MASK2L(40, 12)) | ((uintptr_t)el1_vaddr & MASKL(12));
}
static inline u32 read32le(const volatile void *dword, size_t offset) {