From ab3d8c44cbb32295f1ab96ee95ebd50eec747cb6 Mon Sep 17 00:00:00 2001 From: Curtis Millar Date: Thu, 19 Nov 2020 17:16:41 +1100 Subject: [PATCH] riscv: Map devices with large pages on 32 & 64-bit For 64-bit, this adds a 2nd-level page table for mapping devices using 2MiB frames instead of 1GiB frames. The boot mapping and hardware header generator have also been fixed to correctly report the number of large frames needed for devices rather than only reporting the first. The frame size is also specified correctly (rather than assuming mapping with 4KiB frames). This likely fixes an issue whereby only the first 4KiB frame of a device was reserved but the remaining region of that kernel device could be mapped at user level. Signed-off-by: Curtis Millar --- include/arch/riscv/arch/model/statedata.h | 1 + include/drivers/irq/riscv_plic0.h | 2 +- src/arch/riscv/kernel/vspace.c | 17 +++++++++++++++++ src/arch/riscv/machine/hardware.c | 4 ++-- src/arch/riscv/model/statedata.c | 1 + tools/hardware.yml | 1 + tools/hardware/config.py | 13 +++++++++++++ tools/hardware/utils/rule.py | 4 ++-- 8 files changed, 38 insertions(+), 5 deletions(-) diff --git a/include/arch/riscv/arch/model/statedata.h b/include/arch/riscv/arch/model/statedata.h index 82f754aba..d350435d1 100644 --- a/include/arch/riscv/arch/model/statedata.h +++ b/include/arch/riscv/arch/model/statedata.h @@ -31,5 +31,6 @@ extern pte_t kernel_root_pageTable[BIT(PT_INDEX_BITS)] VISIBLE; * page entry to avoid PMP exception. */ #if __riscv_xlen != 32 extern pte_t kernel_image_level2_pt[BIT(PT_INDEX_BITS)]; +extern pte_t kernel_image_level2_dev_pt[BIT(PT_INDEX_BITS)]; #endif diff --git a/include/drivers/irq/riscv_plic0.h b/include/drivers/irq/riscv_plic0.h index 00811b38c..9d5f37aef 100644 --- a/include/drivers/irq/riscv_plic0.h +++ b/include/drivers/irq/riscv_plic0.h @@ -16,7 +16,7 @@ * https://static.dev.sifive.com/U54-MC-RVCoreIP.pdf */ -#define PLIC_PPTR_BASE (PLIC_PPTR + 0x0C000000) +#define PLIC_PPTR_BASE PLIC_PPTR #define PLIC_HART_ID (CONFIG_FIRST_HART_ID) diff --git a/src/arch/riscv/kernel/vspace.c b/src/arch/riscv/kernel/vspace.c index d852c44d6..64de4dff4 100644 --- a/src/arch/riscv/kernel/vspace.c +++ b/src/arch/riscv/kernel/vspace.c @@ -85,9 +85,22 @@ static pte_t pte_next(word_t phys_addr, bool_t is_leaf) BOOT_CODE void map_kernel_frame(paddr_t paddr, pptr_t vaddr, vm_rights_t vm_rights) { +#if __riscv_xlen == 32 paddr = ROUND_DOWN(paddr, RISCV_GET_LVL_PGSIZE_BITS(0)); assert((paddr % RISCV_GET_LVL_PGSIZE(0)) == 0); kernel_root_pageTable[RISCV_GET_PT_INDEX(vaddr, 0)] = pte_next(paddr, true); +#else + if (vaddr >= KDEV_BASE) { + /* Map devices in 2nd-level page table */ + paddr = ROUND_DOWN(paddr, RISCV_GET_LVL_PGSIZE_BITS(1)); + assert((paddr % RISCV_GET_LVL_PGSIZE(1)) == 0); + kernel_image_level2_dev_pt[RISCV_GET_PT_INDEX(vaddr, 1)] = pte_next(paddr, true); + } else { + paddr = ROUND_DOWN(paddr, RISCV_GET_LVL_PGSIZE_BITS(0)); + assert((paddr % RISCV_GET_LVL_PGSIZE(0)) == 0); + kernel_root_pageTable[RISCV_GET_PT_INDEX(vaddr, 0)] = pte_next(paddr, true); + } +#endif } BOOT_CODE VISIBLE void map_kernel_window(void) @@ -133,6 +146,10 @@ BOOT_CODE VISIBLE void map_kernel_window(void) pptr += RISCV_GET_LVL_PGSIZE(1); paddr += RISCV_GET_LVL_PGSIZE(1); } + + /* Map kernel device page table */ + kernel_root_pageTable[RISCV_GET_PT_INDEX(KDEV_BASE, 0)] = + pte_next(kpptr_to_paddr(kernel_image_level2_dev_pt), false); #endif /* There should be 1GiB free where we put device mapping */ diff --git a/src/arch/riscv/machine/hardware.c b/src/arch/riscv/machine/hardware.c index 06a66d883..1357ce07b 100644 --- a/src/arch/riscv/machine/hardware.c +++ b/src/arch/riscv/machine/hardware.c @@ -55,12 +55,12 @@ BOOT_CODE void map_kernel_devices(void) } for (int i = 0; i < (sizeof(kernel_devices) / sizeof(kernel_frame_t)); i++) { - map_kernel_frame(kernel_devices[i].paddr, KDEV_BASE, + map_kernel_frame(kernel_devices[i].paddr, kernel_devices[i].pptr, VMKernelOnly); if (!kernel_devices[i].userAvailable) { p_region_t reg = { .start = kernel_devices[i].paddr, - .end = kernel_devices[i].paddr + (1 << PAGE_BITS), + .end = kernel_devices[i].paddr + (1 << seL4_LargePageBits), }; reserve_region(reg); } diff --git a/src/arch/riscv/model/statedata.c b/src/arch/riscv/model/statedata.c index 2352797a6..66534c711 100644 --- a/src/arch/riscv/model/statedata.c +++ b/src/arch/riscv/model/statedata.c @@ -22,6 +22,7 @@ pte_t kernel_root_pageTable[BIT(PT_INDEX_BITS)] ALIGN_BSS(BIT(seL4_PageTableBits #if __riscv_xlen != 32 pte_t kernel_image_level2_pt[BIT(PT_INDEX_BITS)] ALIGN_BSS(BIT(seL4_PageTableBits)); +pte_t kernel_image_level2_dev_pt[BIT(PT_INDEX_BITS)] ALIGN_BSS(BIT(seL4_PageTableBits)); #endif SMP_STATE_DEFINE(core_map_t, coreMap); diff --git a/tools/hardware.yml b/tools/hardware.yml index fcfdc831f..9092950d3 100644 --- a/tools/hardware.yml +++ b/tools/hardware.yml @@ -245,6 +245,7 @@ devices: regions: - index: 0 kernel: PLIC_PPTR + kernel_size: 0x04000000 # elfloader rules - compatible: diff --git a/tools/hardware/config.py b/tools/hardware/config.py index bec1802f5..c2bc5cf22 100644 --- a/tools/hardware/config.py +++ b/tools/hardware/config.py @@ -25,6 +25,10 @@ class Config: ''' Get page size in bits for this arch ''' return 12 # 4096-byte pages + def get_device_page_bits(self) -> int: + ''' Get page size in bits for mapping devices for this arch ''' + return self.get_page_bits() + class ARMConfig(Config): ''' Config class for ARM ''' @@ -46,6 +50,15 @@ class RISCVConfig(Config): of physical memory. Mark it as unavailable. ''' return self.MEGA_PAGE_SIZE + def get_device_page_bits(self) -> int: + ''' Get page size in bits for mapping devices for this arch ''' + if self.addrspace_max > (1 << 32): + # rv39 and rv48 use 2MiB device pages + return 21 + else: + # rv32 uses 4MiB device pages + return 22 + def get_arch_config(arch: str, addrspace_max: int) -> Config: ''' Return an appropriate Config object for the given architecture ''' diff --git a/tools/hardware/utils/rule.py b/tools/hardware/utils/rule.py index ef86e2719..9fa857acc 100644 --- a/tools/hardware/utils/rule.py +++ b/tools/hardware/utils/rule.py @@ -168,14 +168,14 @@ class DeviceRule: kernel_name = rule['kernel'] user = rule.get('user', False) macro = rule.get('macro', None) - max_size = 1 << self.config.get_page_bits() + max_size = 1 << self.config.get_device_page_bits() if 'kernel_size' in rule: max_size = rule['kernel_size'] elif max_size < reg.size: logging.warning( "Only mapping {}/{} bytes from node {}, region {}. Set kernel_size in YAML to silence.".format(max_size, reg.size, node.path, i)) ret.append(KernelRegionGroup(reg, kernel_name, - self.config.get_page_bits(), max_size, macro, user)) + self.config.get_device_page_bits(), max_size, macro, user)) return ret