From 4e793ec358d2d2babf61e968e0836296ad2a9d71 Mon Sep 17 00:00:00 2001 From: "Ronald G. Minnich" Date: Fri, 4 Nov 2016 11:27:25 -0700 Subject: riscv: map first 4GiB of physical address space MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit o The first 4G of physical address space is now mapped at 0. o The first 4G of physical address space is now mapped at 1 << 38. o The first 2G of DRAM (2 - 4 GiB of physical address space) is now mapped at the top of memory save for the last 4K i.e. at 0xffffffff80000000, with SBI page at the very top. Of these, we hope to remove the *most* of the last one once the gcc toolchain can handle linking programs that can run at "top 33 bits of address not all ones (but bit 63 set)". The 4K mapping of the top of the 64 bit address space will always remain, however, for SBI calls. Change-Id: I77b151720001bddad5563b0f8e1279abcea056fa Reviewed-on: https://review.coreboot.org/17403 Tested-by: build bot (Jenkins) Reviewed-by: Jonathan Neuschäfer --- src/arch/riscv/virtual_memory.c | 88 +++++++++++++++++++++++++++++++++++------ 1 file changed, 76 insertions(+), 12 deletions(-) (limited to 'src/arch/riscv') diff --git a/src/arch/riscv/virtual_memory.c b/src/arch/riscv/virtual_memory.c index 6d93bd0def..26a0169335 100644 --- a/src/arch/riscv/virtual_memory.c +++ b/src/arch/riscv/virtual_memory.c @@ -38,6 +38,7 @@ static int delegate = 0 | (1 << CAUSE_FAULT_STORE) | (1 << CAUSE_USER_ECALL) ; + pte_t* root_page_table; /* Indent the following text by 2*level spaces */ @@ -140,11 +141,58 @@ pte_t pte_create(uintptr_t ppn, int prot, int user) return pte; } +// The current RISCV *physical* address space is this: +// * 0 - 2 GiB: miscellaneous IO devices +// * 2 GiB - 4 GiB DRAM +// * top 2048 bytes of memory: SBI (which we round out to a 4K page) +// We have determined, also, that if code references a physical address +// not backed by a device, we'll take a fault. In other words, we don't +// need to finely map the memory-mapped devices as we would on an x86. +// We can use GiB mappings for the IO space and we will take a trap +// if we reference hardware that does not exist. +// +// The intent of the RISCV designers is that pages be set up in M mode +// for lower privilege software. They have also told me that they +// expect, unlike other platforms, that next level software use these +// page tables. Some kernels (Linux) prefer the old fashioned model, +// where kernel starts with an identity (ID) map and sets up page tables as +// it sees fit. Other kernels (harvey) are fine with using whatever +// firmware sets up. We need to accommodate both. So, we set up the +// identity map for Linux, but also set up the map for kernels that +// are more willing to conform to the RISCV model. The map is as +// follows: +// +// ID map: map IO space and all of DRAM 1:1 using 1 GiB PTEs +// I.e. we use 1 GiB PTEs for 4 GiB. +// Linux/BSD uses this mapping just enough to replace it. +// +// The SBI page is the last page in the 64 bit address space. +// map that using the middle_pts shown below. +// +// Top 2G map, including SBI page: map the 2 Gib - 4 GiB of physical +// address space to 0xffffffff_80000000. This will be needed until the +// GNU toolchain can compile code to run at 0xffffffc000000000, +// i.e. the start of Sv39. +// +// Only Harvey/Plan 9 uses this Mapping, and temporarily. It can +// never be full removed as we need the 4KiB mapping for the SBI page. +// +// standard RISCV map long term: Map IO space, and all of DRAM, to the *lowest* +// possible negative address for this implementation, +// e.g. 0xffffffc000000000 for Sv39 CPUs. For now we can use GiB PTEs. +// +// RISCV map for now: map IO space, and all of DRAM, starting at +// 0xffff_ffc0_0000_0000, i.e. just as for Sv39. +// +// It is our intent on Harvey (and eventually Akaros) that we use +// this map, once the toolchain can correctly support it. +// We have tested this arrangement and it lets us boot harvey to user mode. void init_vm(uintptr_t virtMemStart, uintptr_t physMemStart, pte_t *sbi_pt) { memset(sbi_pt, 0, RISCV_PGSIZE); // need to leave room for sbi page - uintptr_t memorySize = 0x7F000000; // 0xFFF... - 0xFFFFFFFF81000000 - RISCV_PGSIZE + // 0xFFF... - 0xFFFFFFFF81000000 - RISCV_PGSIZE + intptr_t memorySize = 0x7F000000; // middle page table pte_t* middle_pt = (void*)sbi_pt + RISCV_PGSIZE; @@ -181,14 +229,22 @@ void init_vm(uintptr_t virtMemStart, uintptr_t physMemStart, pte_t *sbi_pt) pte_t* sbi_pte = middle_pt + ((num_middle_pts << RISCV_PGLEVEL_BITS)-1); *sbi_pte = ptd_create((uintptr_t)sbi_pt >> RISCV_PGSHIFT); - // IO space. - root_pt[0] = pte_create(0, PTE_W|PTE_R, 0); - root_pt[1] = pte_create(0x40000000>>RISCV_PGSHIFT, - PTE_W|PTE_R, 0); + // IO space. Identity mapped. + root_pt[0x000] = pte_create(0x00000000 >> RISCV_PGSHIFT, + PTE_R | PTE_W, 0); + root_pt[0x001] = pte_create(0x40000000 >> RISCV_PGSHIFT, + PTE_R | PTE_W, 0); + root_pt[0x002] = pte_create(0x80000000 >> RISCV_PGSHIFT, + PTE_R | PTE_W | PTE_X, 0); + root_pt[0x003] = pte_create(0xc0000000 >> RISCV_PGSHIFT, + PTE_R | PTE_W | PTE_X, 0); + + // Negative address space map at 0xffffffc000000000 + root_pt[0x100] = root_pt[0]; + root_pt[0x101] = root_pt[1]; + root_pt[0x102] = root_pt[2]; + root_pt[0x103] = root_pt[3]; - // Start of RAM - root_pt[2] = pte_create(0x80000000>>RISCV_PGSHIFT, - PTE_W|PTE_R, 0); mb(); root_page_table = root_pt; uintptr_t ptbr = ((uintptr_t) root_pt) >> RISCV_PGSHIFT; @@ -213,9 +269,14 @@ void initVirtualMemory(void) { } // TODO: Figure out how to grab this from cbfs + // N.B. We used to map physical from 0x81000000, + // but since kernels need to be able to see the page tables + // created by firmware, we're going to map from start of RAM. + // All this is subject to change as we learn more. Much + // about RISCV is still in flux. printk(BIOS_DEBUG, "Initializing virtual memory...\n"); - uintptr_t physicalStart = 0x81000000; - uintptr_t virtualStart = 0xffffffff81000000; + uintptr_t physicalStart = 0x80000000; + uintptr_t virtualStart = 0xffffffff80000000; init_vm(virtualStart, physicalStart, (pte_t *)_pagetables); mb(); flush_tlb(); @@ -245,6 +306,9 @@ void mstatus_init(void) * 1.9. Right now there's no agreement on the values for these * architectural registers. */ - //write_csr(mscounteren, 0b111); - //write_csr(mucounteren, 0b111); + // write_csr(mscounteren, 0b111); + // write_csr(mucounteren, 0b111); + + // for SPIKE: + // write_csr(/*mscounteren*/0x321, 0b111); } -- cgit v1.2.3