mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
thermosphere: rewrite (host) memory map (wip, need to update start.s anyway)
This commit is contained in:
parent
fccadfdbf6
commit
6f423fcfab
7 changed files with 302 additions and 175 deletions
|
@ -51,9 +51,11 @@ namespace ams::hvisor::cpu {
|
||||||
DECLARE_SINGLE_ASM_INSN2(dsbSy, "dsb sy")
|
DECLARE_SINGLE_ASM_INSN2(dsbSy, "dsb sy")
|
||||||
DECLARE_SINGLE_ASM_INSN(isb)
|
DECLARE_SINGLE_ASM_INSN(isb)
|
||||||
|
|
||||||
|
DECLARE_SINGLE_ASM_INSN2(TlbInvalidateEl2Local, "tlbi alle2")
|
||||||
DECLARE_SINGLE_ASM_INSN2(TlbInvalidateEl2, "tlbi alle2is")
|
DECLARE_SINGLE_ASM_INSN2(TlbInvalidateEl2, "tlbi alle2is")
|
||||||
DECLARE_SINGLE_ASM_INSN2(TlbInvalidateEl1, "tlbi vmalle1is")
|
DECLARE_SINGLE_ASM_INSN2(TlbInvalidateEl1, "tlbi vmalle1is")
|
||||||
DECLARE_SINGLE_ASM_INSN2(TlbInvalidateEl1Stage12, "tlbi alle1is")
|
DECLARE_SINGLE_ASM_INSN2(TlbInvalidateEl1Stage12, "tlbi alle1is")
|
||||||
|
DECLARE_SINGLE_ASM_INSN2(TlbInvalidateEl1Stage12Local, "tlbi alle1")
|
||||||
|
|
||||||
ALWAYS_INLINE void TlbInvalidateEl2Page(uintptr_t addr)
|
ALWAYS_INLINE void TlbInvalidateEl2Page(uintptr_t addr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,10 +20,9 @@
|
||||||
#include "hvisor_synchronization.hpp"
|
#include "hvisor_synchronization.hpp"
|
||||||
#include "hvisor_i_interrupt_task.hpp"
|
#include "hvisor_i_interrupt_task.hpp"
|
||||||
#include "hvisor_exception_stack_frame.hpp"
|
#include "hvisor_exception_stack_frame.hpp"
|
||||||
|
#include "hvisor_memory_map.hpp"
|
||||||
#include "cpu/hvisor_cpu_sysreg_general.hpp"
|
#include "cpu/hvisor_cpu_sysreg_general.hpp"
|
||||||
|
|
||||||
#include "memory_map.h"
|
|
||||||
|
|
||||||
namespace ams::hvisor {
|
namespace ams::hvisor {
|
||||||
|
|
||||||
class IrqManager final {
|
class IrqManager final {
|
||||||
|
@ -33,9 +32,9 @@ namespace ams::hvisor {
|
||||||
static constexpr u8 hostPriority = 0;
|
static constexpr u8 hostPriority = 0;
|
||||||
static constexpr u8 guestPriority = 1;
|
static constexpr u8 guestPriority = 1;
|
||||||
|
|
||||||
static inline volatile auto *const gicd = (volatile GicV2Distributor *)MEMORY_MAP_VA_GICD;
|
static inline volatile auto *const gicd = reinterpret_cast<volatile GicV2Distributor *>(MemoryMap::gicdVa);
|
||||||
static inline volatile auto *const gicc = (volatile GicV2Controller *)MEMORY_MAP_VA_GICC;
|
static inline volatile auto *const gicc = reinterpret_cast<volatile GicV2Controller *>(MemoryMap::giccVa);
|
||||||
static inline volatile auto *const gich = (volatile GicV2VirtualInterfaceController *)MEMORY_MAP_VA_GICH;
|
static inline volatile auto *const gich = reinterpret_cast<volatile GicV2VirtualInterfaceController *>(MemoryMap::gichVa);
|
||||||
|
|
||||||
static bool IsGuestInterrupt(u32 id);
|
static bool IsGuestInterrupt(u32 id);
|
||||||
|
|
||||||
|
|
199
thermosphere/src/hvisor_memory_map.cpp
Normal file
199
thermosphere/src/hvisor_memory_map.cpp
Normal file
|
@ -0,0 +1,199 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "hvisor_memory_map.hpp"
|
||||||
|
#include "hvisor_core_context.hpp"
|
||||||
|
|
||||||
|
#include "cpu/hvisor_cpu_mmu.hpp"
|
||||||
|
#include "cpu/hvisor_cpu_instructions.hpp"
|
||||||
|
|
||||||
|
#include "platform/interrupt_config.h" // TODO remove
|
||||||
|
|
||||||
|
namespace ams::hvisor {
|
||||||
|
|
||||||
|
uintptr_t MemoryMap::currentPlatformMmioPage = MemoryMap::mmioPlatBaseVa;
|
||||||
|
|
||||||
|
void MemoryMap::SetupMmu(const MemoryMap::LoadImageLayout *layout)
|
||||||
|
{
|
||||||
|
using namespace cpu;
|
||||||
|
|
||||||
|
constexpr u64 normalAttribs = MMU_INNER_SHAREABLE | MMU_ATTRINDX(Memtype_Normal);
|
||||||
|
constexpr u64 deviceAttribs = MMU_XN | MMU_INNER_SHAREABLE | MMU_ATTRINDX(Memtype_Device_nGnRE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Layout in physmem:
|
||||||
|
Location1
|
||||||
|
Image (code and data incl. BSS), which size is page-aligned
|
||||||
|
Location2
|
||||||
|
tempbss
|
||||||
|
MMU table (taken from temp physmem)
|
||||||
|
|
||||||
|
Layout in vmem:
|
||||||
|
Location1
|
||||||
|
Image
|
||||||
|
padding
|
||||||
|
tempbss
|
||||||
|
Location2
|
||||||
|
Crash stacks
|
||||||
|
{guard page, stack} * numCores
|
||||||
|
Location3 (all L1, L2, L3 bits set):
|
||||||
|
MMU table
|
||||||
|
|
||||||
|
We map the table into itself at the entry which index has all bits set.
|
||||||
|
This is called "recursive page tables" and means (assuming 39-bit addr space) that:
|
||||||
|
- the table will reuse itself as L2 table for the 0x7FC0000000+ range
|
||||||
|
- the table will reuse itself as L3 table for the 0x7FFFE00000+ range
|
||||||
|
- the table itself will be accessible at 0x7FFFFFF000
|
||||||
|
*/
|
||||||
|
|
||||||
|
using Builder = MmuTableBuilder<3, addressSpaceSize>;
|
||||||
|
uintptr_t mmuTablePa = layout->tempPa + layout->maxTempSize;
|
||||||
|
|
||||||
|
uintptr_t tempVa = imageVa + layout->imageSize;
|
||||||
|
uintptr_t crashStacksPa = layout->tempPa + layout->tempSize;
|
||||||
|
uintptr_t stacksPa = crashStacksPa + crashStacksSize;
|
||||||
|
|
||||||
|
Builder{reinterpret_cast<u64 *>(mmuTablePa)}
|
||||||
|
.InitializeTable()
|
||||||
|
// Image & tempbss & crash stacks
|
||||||
|
.MapBlockRange(imageVa, layout->startPa, layout->imageSize, normalAttribs)
|
||||||
|
.MapBlockRange(tempVa, layout->tempPa, layout->tempSize, normalAttribs)
|
||||||
|
.MapBlockRange(crashStacksBottomVa, crashStacksPa, crashStacksSize, normalAttribs)
|
||||||
|
// Stacks, each with a guard page
|
||||||
|
.MapBlockRange(stacksBottomVa, stacksPa, 0x1000ul * MAX_CORE, normalAttribs, 0x1000)
|
||||||
|
// GICD, GICC, GICH
|
||||||
|
.MapBlock(gicdVa, MEMORY_MAP_PA_GICD, deviceAttribs)
|
||||||
|
.MapBlockRange(giccVa, MEMORY_MAP_PA_GICC, 0x2000, deviceAttribs)
|
||||||
|
.MapBlock(gichVa, MEMORY_MAP_PA_GICH, deviceAttribs)
|
||||||
|
// Recursive page mapping
|
||||||
|
.MapBlock(ttblVa, mmuTablePa, normalAttribs)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<uintptr_t, 2> MemoryMap::EnableMmuGetStacks(const MemoryMap::LoadImageLayout *layout, u32 coreId)
|
||||||
|
{
|
||||||
|
using namespace cpu;
|
||||||
|
uintptr_t mmuTablePa = layout->tempPa + layout->maxTempSize;
|
||||||
|
|
||||||
|
u32 ps = THERMOSPHERE_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_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 = 39
|
||||||
|
*/
|
||||||
|
u64 tcr = TCR_EL2_RSVD | TCR_PS(ps) | TCR_TG0(TranslationGranule_4K) | TCR_SHARED_INNER | TCR_ORGN_WBWA | TCR_IRGN_WBWA | TCR_T0SZ(addressSpaceSize);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
- Attribute 0: Device-nGnRnE memory
|
||||||
|
- Attribute 1: Normal memory, Inner and Outer Write-Back Read-Allocate Write-Allocate Non-transient
|
||||||
|
- Attribute 2: Device-nGnRE memory
|
||||||
|
- Attribute 3: Normal memory, Inner and Outer Noncacheable
|
||||||
|
- Other attributes: Device-nGnRnE memory
|
||||||
|
*/
|
||||||
|
constexpr u64 mair = 0x44FF0400;
|
||||||
|
|
||||||
|
// Set VBAR because we *will* crash (instruction abort because of the value of pc) when enabling the MMU
|
||||||
|
THERMOSPHERE_SET_SYSREG(vbar_el2, layout->vbar);
|
||||||
|
|
||||||
|
// MMU regs config
|
||||||
|
THERMOSPHERE_SET_SYSREG(ttbr0_el2, mmuTablePa);
|
||||||
|
THERMOSPHERE_SET_SYSREG(tcr_el2, tcr);
|
||||||
|
THERMOSPHERE_SET_SYSREG(mair_el2, mair);
|
||||||
|
dsb();
|
||||||
|
isb();
|
||||||
|
|
||||||
|
// TLB invalidation
|
||||||
|
// Whether this does anything before MMU is enabled is impldef, apparently
|
||||||
|
TlbInvalidateEl2Local();
|
||||||
|
dsb();
|
||||||
|
isb();
|
||||||
|
|
||||||
|
// Enable MMU & enable caching. We will crash.
|
||||||
|
u64 sctlr = THERMOSPHERE_GET_SYSREG(sctlr_el2);
|
||||||
|
sctlr |= SCTLR_ELx_I | SCTLR_ELx_C | SCTLR_ELx_M;
|
||||||
|
THERMOSPHERE_SET_SYSREG(sctlr_el2, sctlr);
|
||||||
|
dsb();
|
||||||
|
isb();
|
||||||
|
|
||||||
|
// crashStackTop is fragile, check if crashStacksSize is suitable for MAX_CORE
|
||||||
|
uintptr_t stackTop = stacksBottomVa + 0x2000 * coreId + 0x1000;
|
||||||
|
uintptr_t crashStackTop = crashStacksBottomVa + (crashStacksSize / MAX_CORE) * (1 + coreId);
|
||||||
|
return std::array{stackTop, crashStackTop};
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t MemoryMap::MapPlatformMmio(uintptr_t pa, size_t size)
|
||||||
|
{
|
||||||
|
using namespace cpu;
|
||||||
|
using Builder = MmuTableBuilder<3, addressSpaceSize, true>;
|
||||||
|
constexpr u64 deviceAttribs = MMU_XN | MMU_INNER_SHAREABLE | MMU_ATTRINDX(Memtype_Device_nGnRE);
|
||||||
|
|
||||||
|
uintptr_t va = currentPlatformMmioPage;
|
||||||
|
size = (size + 0xFFF) & ~0xFFFul;
|
||||||
|
Builder{reinterpret_cast<u64 *>(ttblVa)}.MapBlockRange(currentPlatformMmioPage, va, size, deviceAttribs);
|
||||||
|
|
||||||
|
currentPlatformMmioPage += size;
|
||||||
|
return va;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t MemoryMap::MapGuestPage(uintptr_t pa, u64 memAttribs, u64 shareability)
|
||||||
|
{
|
||||||
|
using namespace cpu;
|
||||||
|
using Builder = MmuTableBuilder<3, addressSpaceSize, true>;
|
||||||
|
|
||||||
|
u64 attribs = MMU_XN | MMU_SH(shareability) | MMU_ATTRINDX(Memtype_Guest_Slot);
|
||||||
|
uintptr_t va = guestMemVa + 0x2000 * currentCoreCtx->GetCoreId(); // one guard page
|
||||||
|
|
||||||
|
// Update mair_el2
|
||||||
|
u64 mair = THERMOSPHERE_GET_SYSREG(mair_el2);
|
||||||
|
mair |= memAttribs << (8 * Memtype_Guest_Slot);
|
||||||
|
THERMOSPHERE_SET_SYSREG(mair_el2, mair);
|
||||||
|
isb();
|
||||||
|
|
||||||
|
Builder{reinterpret_cast<u64 *>(ttblVa)}.MapBlock(va, pa, attribs);
|
||||||
|
TlbInvalidateEl2Page(va);
|
||||||
|
dsb();
|
||||||
|
isb();
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t MemoryMap::UnmapGuestPage()
|
||||||
|
{
|
||||||
|
using namespace cpu;
|
||||||
|
using Builder = MmuTableBuilder<3, addressSpaceSize, true>;
|
||||||
|
uintptr_t va = guestMemVa + 0x2000 * currentCoreCtx->GetCoreId();
|
||||||
|
|
||||||
|
dsb();
|
||||||
|
isb();
|
||||||
|
|
||||||
|
Builder{reinterpret_cast<u64 *>(ttblVa)}.Unmap(va);
|
||||||
|
TlbInvalidateEl2Page(va);
|
||||||
|
dsb();
|
||||||
|
isb();
|
||||||
|
|
||||||
|
// Update mair_el2
|
||||||
|
u64 mair = THERMOSPHERE_GET_SYSREG(mair_el2);
|
||||||
|
mair &= ~(0xFF << (8 * Memtype_Guest_Slot));
|
||||||
|
THERMOSPHERE_SET_SYSREG(mair_el2, mair);
|
||||||
|
isb();
|
||||||
|
}
|
||||||
|
}
|
94
thermosphere/src/hvisor_memory_map.hpp
Normal file
94
thermosphere/src/hvisor_memory_map.hpp
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "defines.hpp"
|
||||||
|
|
||||||
|
namespace ams::hvisor {
|
||||||
|
|
||||||
|
class MemoryMap final {
|
||||||
|
NON_COPYABLE(MemoryMap);
|
||||||
|
NON_MOVEABLE(MemoryMap);
|
||||||
|
private:
|
||||||
|
// Maps to AttrIndx[2:0]
|
||||||
|
enum MemType {
|
||||||
|
Memtype_Device_nGnRnE = 0,
|
||||||
|
Memtype_Normal = 1,
|
||||||
|
Memtype_Device_nGnRE = 2,
|
||||||
|
Memtype_Normal_Uncacheable = 3,
|
||||||
|
Memtype_Guest_Slot = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LoadImageLayout {
|
||||||
|
uintptr_t startPa;
|
||||||
|
size_t imageSize; // "image" includes "real" BSS but not tempbss
|
||||||
|
|
||||||
|
uintptr_t tempPa;
|
||||||
|
size_t maxTempSize;
|
||||||
|
size_t tempSize;
|
||||||
|
|
||||||
|
uintptr_t vbar;
|
||||||
|
};
|
||||||
|
static_assert(std::is_standard_layout_v<LoadImageLayout>);
|
||||||
|
static_assert(std::is_trivial_v<LoadImageLayout>);
|
||||||
|
private:
|
||||||
|
static LoadImageLayout imageLayout;
|
||||||
|
static uintptr_t currentPlatformMmioPage;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr u32 addressSpaceSize = 39;
|
||||||
|
|
||||||
|
// The following come from the fact we're using a recursive page table:
|
||||||
|
static constexpr uintptr_t selfL2VaRange = 0x7FC0000000ul; // = 511 << 31
|
||||||
|
static constexpr uintptr_t selfL3VaRange = 0x7FFFE00000ul; // = 511 << 31 | 511 << 21
|
||||||
|
static constexpr uintptr_t ttblVa = 0x7FFFFFF000ul; // = 511 << 31 | 511 << 21 | 511 << 12
|
||||||
|
static constexpr uintptr_t maxVa = 0x7FFFFFFFFFul; // = all 39 bits set
|
||||||
|
|
||||||
|
static constexpr size_t crashStacksSize = 0x1000ul;
|
||||||
|
|
||||||
|
// Do not use the first 0x10000 to allow for L1/L2 mappings...
|
||||||
|
static constexpr uintptr_t imageVa = selfL3VaRange + 0x10000;
|
||||||
|
static constexpr uintptr_t crashStacksBottomVa = selfL3VaRange + 0x40000;
|
||||||
|
static constexpr uintptr_t crashStacksTopVa = crashStacksBottomVa + crashStacksSize;
|
||||||
|
static constexpr uintptr_t guestMemVa = selfL3VaRange + 0x50000;
|
||||||
|
static constexpr uintptr_t stacksBottomVa = selfL3VaRange + 0x60000;
|
||||||
|
|
||||||
|
static constexpr uintptr_t mmioBaseVa = selfL3VaRange + 0x80000;
|
||||||
|
static constexpr uintptr_t gicdVa = mmioBaseVa + 0x0000;
|
||||||
|
static constexpr uintptr_t giccVa = mmioBaseVa + 0x1000;
|
||||||
|
static constexpr uintptr_t gichVa = mmioBaseVa + 0x3000;
|
||||||
|
|
||||||
|
static constexpr uintptr_t mmioPlatBaseVa = selfL3VaRange + 0x90000;
|
||||||
|
|
||||||
|
static uintptr_t GetStartPa() { return imageLayout.startPa; }
|
||||||
|
|
||||||
|
// Called before MMU is enabled. EnableMmu must not use a stack frame
|
||||||
|
static void SetupMmu(const LoadImageLayout *layout);
|
||||||
|
static std::array<uintptr_t, 2> EnableMmuGetStacks(const LoadImageLayout *layout, u32 coreId);
|
||||||
|
|
||||||
|
// Caller is expected to invalidate TLB + barrier at some point
|
||||||
|
static uintptr_t MapPlatformMmio(uintptr_t pa, size_t size);
|
||||||
|
|
||||||
|
// Caller is expected to disable interrupts, etc, etc.
|
||||||
|
static uintptr_t MapGuestPage(uintptr_t pa, u64 memAttribs, u64 shareability);
|
||||||
|
static uintptr_t UnmapGuestPage();
|
||||||
|
|
||||||
|
public:
|
||||||
|
constexpr MemoryMap() = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -20,7 +20,6 @@
|
||||||
#include "hvisor_core_context.hpp"
|
#include "hvisor_core_context.hpp"
|
||||||
#include "cpu/hvisor_cpu_exception_sysregs.hpp"
|
#include "cpu/hvisor_cpu_exception_sysregs.hpp"
|
||||||
#include "hvisor_irq_manager.hpp"
|
#include "hvisor_irq_manager.hpp"
|
||||||
#include "memory_map.h"
|
|
||||||
|
|
||||||
namespace ams::hvisor {
|
namespace ams::hvisor {
|
||||||
|
|
||||||
|
|
|
@ -1,166 +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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "memory_map.h"
|
|
||||||
#include "mmu.h"
|
|
||||||
#include "sysreg.h"
|
|
||||||
#include "platform/interrupt_config.h"
|
|
||||||
|
|
||||||
#define ATTRIB_MEMTYPE_NORMAL MMU_PTE_BLOCK_MEMTYPE(MEMORY_MAP_MEMTYPE_NORMAL)
|
|
||||||
#define ATTRIB_MEMTYPE_DEVICE MMU_PTE_BLOCK_MEMTYPE(MEMORY_MAP_MEMTYPE_DEVICE_NGNRE)
|
|
||||||
|
|
||||||
static uintptr_t g_currentPlatformMmioPage = MEMORY_MAP_VA_MMIO_PLAT_BASE;
|
|
||||||
|
|
||||||
void memoryMapSetupMmu(const LoadImageLayout *layout, u64 *mmuTable)
|
|
||||||
{
|
|
||||||
static const u64 normalAttribs = MMU_PTE_BLOCK_INNER_SHAREBLE | ATTRIB_MEMTYPE_NORMAL;
|
|
||||||
static const u64 deviceAttribs = MMU_PTE_BLOCK_XN | MMU_PTE_BLOCK_INNER_SHAREBLE | ATTRIB_MEMTYPE_DEVICE;
|
|
||||||
|
|
||||||
// mmuTable is currently a PA
|
|
||||||
mmu_init_table(mmuTable, 0x200);
|
|
||||||
|
|
||||||
/*
|
|
||||||
Map the table into itself at the entry which index has all bits set.
|
|
||||||
This is called "recursive page tables" and means (assuming 39-bit addr space) that:
|
|
||||||
- the table will reuse itself as L2 table for the 0x7FC0000000+ range
|
|
||||||
- the table will reuse itself as L3 table for the 0x7FFFE00000+ range
|
|
||||||
- the table itself will be accessible at 0x7FFFFFF000
|
|
||||||
*/
|
|
||||||
mmuTable[0x1FF] = (uintptr_t)mmuTable | MMU_PTE_BLOCK_XN | MMU_PTE_BLOCK_AF | MMU_PTE_TYPE_TABLE;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Layout in physmem:
|
|
||||||
Location1
|
|
||||||
Image (code and data incl. BSS)
|
|
||||||
Location2
|
|
||||||
tempbss
|
|
||||||
MMU table (taken from temp physmem)
|
|
||||||
|
|
||||||
Layout in vmem:
|
|
||||||
Location1
|
|
||||||
Image
|
|
||||||
padding
|
|
||||||
tempbss
|
|
||||||
Location2
|
|
||||||
Crash stacks
|
|
||||||
{guard page, stack} * numCores
|
|
||||||
Location3 (all L1, L2, L3 bits set):
|
|
||||||
MMU table
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Map our code & data (.text/other code, .rodata, .data, .bss) at the bottom of our L3 range, all RWX
|
|
||||||
// Note that the end of "image" is page-aligned
|
|
||||||
// See LD script for more details
|
|
||||||
uintptr_t curVa = MEMORY_MAP_VA_IMAGE;
|
|
||||||
uintptr_t curPa = layout->startPa;
|
|
||||||
|
|
||||||
// Do not map the MMU table in that mapping:
|
|
||||||
mmu_map_page_range(mmuTable, curVa, curPa, layout->imageSize, normalAttribs);
|
|
||||||
|
|
||||||
curVa += layout->imageSize;
|
|
||||||
curPa = layout->tempPa;
|
|
||||||
mmu_map_page_range(mmuTable, curVa, curPa, layout->tempSize , normalAttribs);
|
|
||||||
curPa += layout->tempSize;
|
|
||||||
|
|
||||||
// Map the remaining temporary data as stacks, aligned 0x1000
|
|
||||||
|
|
||||||
// Crash stacks, total size is fixed:
|
|
||||||
curVa = MEMORY_MAP_VA_CRASH_STACKS_BOTTOM;
|
|
||||||
mmu_map_page_range(mmuTable, curVa, curPa, MEMORY_MAP_VA_CRASH_STACKS_SIZE, normalAttribs);
|
|
||||||
curPa += MEMORY_MAP_VA_CRASH_STACKS_SIZE;
|
|
||||||
|
|
||||||
// Regular stacks
|
|
||||||
size_t sizePerStack = 0x1000;
|
|
||||||
curVa = MEMORY_MAP_VA_STACKS_TOP - sizePerStack;
|
|
||||||
for (u32 i = 0; i < 4; i++) {
|
|
||||||
mmu_map_page_range(mmuTable, curVa, curPa, sizePerStack, normalAttribs);
|
|
||||||
curVa -= 2 * sizePerStack;
|
|
||||||
curPa += sizePerStack;
|
|
||||||
}
|
|
||||||
|
|
||||||
// MMIO
|
|
||||||
mmu_map_page(mmuTable, MEMORY_MAP_VA_GICD, MEMORY_MAP_PA_GICD, deviceAttribs);
|
|
||||||
mmu_map_page_range(mmuTable, MEMORY_MAP_VA_GICC, MEMORY_MAP_PA_GICC, 0x2000, deviceAttribs);
|
|
||||||
mmu_map_page(mmuTable, MEMORY_MAP_VA_GICH, MEMORY_MAP_PA_GICH, deviceAttribs);
|
|
||||||
}
|
|
||||||
|
|
||||||
void memoryMapEnableMmu(const LoadImageLayout *layout)
|
|
||||||
{
|
|
||||||
uintptr_t mmuTable = layout->tempPa + layout->maxTempSize;
|
|
||||||
|
|
||||||
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_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 = MEMORY_MAP_VA_SPACE_SIZE = 39
|
|
||||||
*/
|
|
||||||
u64 tcr = TCR_EL2_RSVD | TCR_PS(ps) | TCR_TG0_4K | TCR_SHARED_INNER | TCR_ORGN_WBWA | TCR_IRGN_WBWA | TCR_T0SZ(MEMORY_MAP_VA_SPACE_SIZE);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
- Attribute 0: Device-nGnRnE memory
|
|
||||||
- Attribute 1: Normal memory, Inner and Outer Write-Back Read-Allocate Write-Allocate Non-transient
|
|
||||||
- Attribute 2: Device-nGnRE memory
|
|
||||||
- Attribute 3: Normal memory, Inner and Outer Noncacheable
|
|
||||||
- Other attributes: Device-nGnRnE memory
|
|
||||||
*/
|
|
||||||
u64 mair = 0x44FF0400;
|
|
||||||
|
|
||||||
// Set VBAR because we *will* crash (instruction abort because of the value of pc) when enabling the MMU
|
|
||||||
SET_SYSREG(vbar_el2, layout->vbar);
|
|
||||||
|
|
||||||
// MMU regs config
|
|
||||||
SET_SYSREG(ttbr0_el2, mmuTable);
|
|
||||||
SET_SYSREG(tcr_el2, tcr);
|
|
||||||
SET_SYSREG(mair_el2, mair);
|
|
||||||
__dsb_local();
|
|
||||||
__isb();
|
|
||||||
|
|
||||||
// TLB invalidation
|
|
||||||
// Whether this does anything before MMU is enabled is impldef, apparently
|
|
||||||
__tlb_invalidate_el2_local();
|
|
||||||
__dsb_local();
|
|
||||||
__isb();
|
|
||||||
|
|
||||||
// Enable MMU & enable caching. We will crash.
|
|
||||||
u64 sctlr = GET_SYSREG(sctlr_el2);
|
|
||||||
sctlr |= SCTLR_ELx_I | SCTLR_ELx_C | SCTLR_ELx_M;
|
|
||||||
SET_SYSREG(sctlr_el2, sctlr);
|
|
||||||
__dsb_local();
|
|
||||||
__isb();
|
|
||||||
}
|
|
||||||
|
|
||||||
uintptr_t memoryMapGetStackTop(u32 coreId)
|
|
||||||
{
|
|
||||||
return MEMORY_MAP_VA_STACKS_TOP - 0x2000 * coreId;
|
|
||||||
}
|
|
||||||
|
|
||||||
uintptr_t memoryMapPlatformMmio(uintptr_t pa, size_t size)
|
|
||||||
{
|
|
||||||
uintptr_t va = g_currentPlatformMmioPage;
|
|
||||||
static const u64 deviceAttribs = MMU_PTE_BLOCK_XN | MMU_PTE_BLOCK_INNER_SHAREBLE | ATTRIB_MEMTYPE_DEVICE;
|
|
||||||
u64 *mmuTable = (u64 *)MEMORY_MAP_VA_TTBL;
|
|
||||||
|
|
||||||
size = (size + 0xFFF) & ~0xFFFul;
|
|
||||||
mmu_map_page_range(mmuTable, va, pa, size, deviceAttribs);
|
|
||||||
|
|
||||||
g_currentPlatformMmioPage += size;
|
|
||||||
|
|
||||||
return va;
|
|
||||||
}
|
|
|
@ -16,10 +16,10 @@
|
||||||
|
|
||||||
#include "hvisor_traps_smc.hpp"
|
#include "hvisor_traps_smc.hpp"
|
||||||
#include "../hvisor_core_context.hpp"
|
#include "../hvisor_core_context.hpp"
|
||||||
|
#include "../hvisor_memory_map.hpp"
|
||||||
#include "../cpu/hvisor_cpu_caches.hpp"
|
#include "../cpu/hvisor_cpu_caches.hpp"
|
||||||
|
|
||||||
#include "../debug_manager.h"
|
#include "../debug_manager.h"
|
||||||
#include "../memory_map.h"
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ namespace {
|
||||||
if (cpuId < MAX_CORE) {
|
if (cpuId < MAX_CORE) {
|
||||||
auto &ctx = ams::hvisor::CoreContext::GetInstanceFor(cpuId);
|
auto &ctx = ams::hvisor::CoreContext::GetInstanceFor(cpuId);
|
||||||
ctx.SetKernelEntrypoint(ep);
|
ctx.SetKernelEntrypoint(ep);
|
||||||
frame->WriteRegister(2, g_loadImageLayout.startPa + 4); //FIXME
|
frame->WriteRegister(2, ams::hvisor::MemoryMap::GetStartPa() + 4); //FIXME
|
||||||
}
|
}
|
||||||
ams::hvisor::cpu::dmb();
|
ams::hvisor::cpu::dmb();
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ namespace {
|
||||||
// We may trigger warmboot, depending on powerState (x1 or default value)
|
// We may trigger warmboot, depending on powerState (x1 or default value)
|
||||||
uintptr_t ep = frame->ReadRegister(epIdx);
|
uintptr_t ep = frame->ReadRegister(epIdx);
|
||||||
ams::hvisor::currentCoreCtx->SetKernelEntrypoint(ep, true);
|
ams::hvisor::currentCoreCtx->SetKernelEntrypoint(ep, true);
|
||||||
frame->WriteRegister(epIdx, g_loadImageLayout.startPa + 4); //FIXME
|
frame->WriteRegister(epIdx, ams::hvisor::MemoryMap::GetStartPa() + 4); //FIXME
|
||||||
|
|
||||||
ams::hvisor::cpu::dmb();
|
ams::hvisor::cpu::dmb();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue