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) {