From 897aaf5b13f39ba2b9ca8ade3a58d1350eb42ad7 Mon Sep 17 00:00:00 2001 From: Siwei Zhuang Date: Tue, 2 Apr 2019 15:36:33 +1100 Subject: [PATCH] RISCV: Change 64 bit kernel window mapping to avoid PMP exception. The SBI memory was mapped outside the kernel window. This would trigger an instruction access fault on some hardware, when the bootloader has set up PMP to protect the SBI memory. Instead of protecting a particular memory region, the PMP locks the entire page table entry that covers the region. The PADDR_LOAD and kernel base are adjusted to have the SBI memory included in the kernel window. So that the SBI memory can be mapped as part of the kernel image to a separate page table entry. This also avoids the kernel to allocate untyped memory from the SBI region. --- include/arch/riscv/arch/model/statedata.h | 7 +++---- .../plat/64/plat_mode/machine/hardware.h | 2 +- include/plat/spike/plat/machine/hardware.h | 2 +- src/arch/riscv/kernel/vspace.c | 19 +++++++++++++------ src/arch/riscv/model/statedata.c | 3 ++- src/plat/spike/linker.lds | 4 ++-- 6 files changed, 22 insertions(+), 15 deletions(-) diff --git a/include/arch/riscv/arch/model/statedata.h b/include/arch/riscv/arch/model/statedata.h index 5559b2763..39652b159 100644 --- a/include/arch/riscv/arch/model/statedata.h +++ b/include/arch/riscv/arch/model/statedata.h @@ -40,10 +40,9 @@ extern asid_pool_t *riscvKSASIDTable[BIT(asidHighBits)]; /* Kernel Page Tables */ extern pte_t kernel_root_pageTable[BIT(PT_INDEX_BITS)] VISIBLE; -/* If our PADDR_LOAD is not 1GiB aligned then we need to introduce a level2 pagetable - * in order to map in our kernel image at KERNEL_BASE */ -#if CONFIG_PT_LEVELS == 3 && !IS_ALIGNED(PADDR_LOAD, RISCV_GET_LVL_PGSIZE_BITS(1)) -#define RISCV_KERNEL_WINDOW_LEVEL2_PT +/* We need to introduce a level2 pagetable in order to map the BBL to a separate + * page entry to avoid PMP exception. */ +#if __riscv_xlen != 32 extern pte_t kernel_image_level2_pt[BIT(PT_INDEX_BITS)]; #endif #endif diff --git a/include/plat/spike/plat/64/plat_mode/machine/hardware.h b/include/plat/spike/plat/64/plat_mode/machine/hardware.h index 5dabfa111..635b9c1bd 100644 --- a/include/plat/spike/plat/64/plat_mode/machine/hardware.h +++ b/include/plat/spike/plat/64/plat_mode/machine/hardware.h @@ -26,7 +26,7 @@ /* This is the base of the kernel window, which is directly mapped to PADDR_BASE */ #define PPTR_BASE 0xFFFFFFC000000000lu /* This is the mapping of the kernel (mapped above the kernel window currently) */ -#define KERNEL_BASE 0xFFFFFFFF80000000lu +#define KERNEL_BASE 0xFFFFFFFF84000000lu #else #error Only PT_LEVELS == 3 is supported #endif diff --git a/include/plat/spike/plat/machine/hardware.h b/include/plat/spike/plat/machine/hardware.h index b7c1930ac..f7ce26537 100644 --- a/include/plat/spike/plat/machine/hardware.h +++ b/include/plat/spike/plat/machine/hardware.h @@ -38,7 +38,7 @@ /* This represents the physical address that the kernel image will be linked to. This needs to * be on a 1gb boundary as we currently require being able to creating a mapping to this address * as the largest frame size */ -#define PADDR_LOAD 0xC0000000lu +#define PADDR_LOAD 0x84000000lu #endif /* The highest valid physical address that can be indexed in the kernel window */ diff --git a/src/arch/riscv/kernel/vspace.c b/src/arch/riscv/kernel/vspace.c index a9c1e2039..53fb99503 100644 --- a/src/arch/riscv/kernel/vspace.c +++ b/src/arch/riscv/kernel/vspace.c @@ -38,6 +38,7 @@ #include #include #include +#include struct resolve_ret { paddr_t frameBase; @@ -107,7 +108,7 @@ BOOT_CODE VISIBLE void map_kernel_window(void) /* first we map in memory from PADDR_BASE */ word_t paddr = PADDR_BASE; - while (pptr < KERNEL_BASE) { + while (pptr < ROUND_DOWN(KERNEL_BASE, RISCV_GET_LVL_PGSIZE_BITS(1))) { assert(IS_ALIGNED(pptr, RISCV_GET_LVL_PGSIZE_BITS(1))); assert(IS_ALIGNED(paddr, RISCV_GET_LVL_PGSIZE_BITS(1))); @@ -116,19 +117,25 @@ BOOT_CODE VISIBLE void map_kernel_window(void) pptr += RISCV_GET_LVL_PGSIZE(1); paddr += RISCV_GET_LVL_PGSIZE(1); } - /* now we should be mapping the 1GiB kernel base, starting again from PADDR_LOAD */ - assert(pptr == KERNEL_BASE); - paddr = PADDR_LOAD; + /* now we should be mapping the 1GiB kernel base */ + assert(pptr == ROUND_DOWN(KERNEL_BASE, RISCV_GET_LVL_PGSIZE_BITS(1))); + paddr = ROUND_DOWN(PADDR_LOAD, RISCV_GET_LVL_PGSIZE_BITS(1)); -#ifndef RISCV_KERNEL_WINDOW_LEVEL2_PT +#if __riscv_xlen == 32 kernel_root_pageTable[RISCV_GET_PT_INDEX(pptr, 1)] = pte_next(paddr, true); pptr += RISCV_GET_LVL_PGSIZE(1); paddr += RISCV_GET_LVL_PGSIZE(1); #else word_t index = 0; + /* The kernel image are mapped twice, locating the two indexes in the + * root page table, pointing them to the same second level page table. + */ + kernel_root_pageTable[RISCV_GET_PT_INDEX(PADDR_LOAD + BASE_OFFSET, 1)] = + pte_next(kpptr_to_paddr(kernel_image_level2_pt), false); kernel_root_pageTable[RISCV_GET_PT_INDEX(pptr, 1)] = pte_next(kpptr_to_paddr(kernel_image_level2_pt), false); - while (pptr < KERNEL_BASE + RISCV_GET_LVL_PGSIZE(1)) { + while (pptr < ROUND_DOWN(KERNEL_BASE, RISCV_GET_LVL_PGSIZE_BITS(1)) + + RISCV_GET_LVL_PGSIZE(1)) { kernel_image_level2_pt[index] = pte_next(paddr, true); index++; pptr += RISCV_GET_LVL_PGSIZE(2); diff --git a/src/arch/riscv/model/statedata.c b/src/arch/riscv/model/statedata.c index c68f44112..e9c6630dc 100644 --- a/src/arch/riscv/model/statedata.c +++ b/src/arch/riscv/model/statedata.c @@ -31,6 +31,7 @@ asid_pool_t *riscvKSASIDTable[BIT(asidHighBits)]; /* Kernel Page Tables */ pte_t kernel_root_pageTable[BIT(PT_INDEX_BITS)] ALIGN_BSS(BIT(seL4_PageTableBits)); -#ifdef RISCV_KERNEL_WINDOW_LEVEL2_PT + +#if __riscv_xlen != 32 pte_t kernel_image_level2_pt[BIT(PT_INDEX_BITS)] ALIGN_BSS(BIT(seL4_PageTableBits)); #endif diff --git a/src/plat/spike/linker.lds b/src/plat/spike/linker.lds index e88c33da6..ea6bc06e3 100644 --- a/src/plat/spike/linker.lds +++ b/src/plat/spike/linker.lds @@ -24,7 +24,7 @@ ENTRY(_start) #if CONFIG_PT_LEVELS == 2 KERNEL_BASE = 0xFF800000; #elif CONFIG_PT_LEVELS == 3 -KERNEL_BASE = 0xFFFFFFFF80000000; +KERNEL_BASE = 0xFFFFFFFF84000000; #elif CONFIG_PT_LEVELS == 4 #error PT_LEVELS == 4 is not supported yet #endif @@ -33,7 +33,7 @@ KERNEL_BASE = 0xFFFFFFFF80000000; #ifdef CONFIG_BUILD_ROCKET_CHIP_ZEDBOARD PADDR_LOAD = 0x0000000088000000; #else -PADDR_LOAD = 0x00000000C0000000; +PADDR_LOAD = 0x0000000084000000; #endif KERNEL_OFFSET = KERNEL_BASE - PADDR_LOAD;