[coreboot-gerrit] Patch set updated for coreboot: riscv: map first 4GiB of physical address space

Ronald G. Minnich (rminnich@gmail.com) gerrit at coreboot.org
Thu Nov 17 05:29:24 CET 2016


Ronald G. Minnich (rminnich at gmail.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/17403

-gerrit

commit 72e539d69228357adc2fb7d475a4e3962d90faac
Author: Ronald G. Minnich <rminnich at gmail.com>
Date:   Fri Nov 4 11:27:25 2016 -0700

    riscv: map first 4GiB of physical address space
    
    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 4G of physical address space is now mapped at
      the top of memory minus 4G.
    
    Of these, we hope to remove 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)".
    
    Change-Id: I77b151720001bddad5563b0f8e1279abcea056fa
---
 src/arch/riscv/virtual_memory.c | 97 ++++++++++++++++++++++++++++++++++++-----
 1 file changed, 87 insertions(+), 10 deletions(-)

diff --git a/src/arch/riscv/virtual_memory.c b/src/arch/riscv/virtual_memory.c
index 6d93bd0..d0c353a 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,6 +141,31 @@ pte_t pte_create(uintptr_t ppn, int prot, int user)
 	return pte;
 }
 
+// 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
+// Linux/BSD uses this mapping long enough to replace it.
+//
+// RISCV map: map the first 2 GiB of DRAM, whereever it is,
+// to 0xffffffff_80000000. This will be needed until the GNU
+// toolchain can compile code to run at 0xffffffc000000000.
+// Only Harvey/Plan 9 uses this Mapping.
+//
+// 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.
+//
+// RISCV map for now: map IO space, and all of DRAM, starting at
+// 0xffff_ff80_0000_0000.
 void init_vm(uintptr_t virtMemStart, uintptr_t physMemStart, pte_t *sbi_pt)
 {
 	memset(sbi_pt, 0, RISCV_PGSIZE);
@@ -181,14 +207,57 @@ 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] = ptd_create((uintptr_t)middle_pt >> RISCV_PGSHIFT);
+
+	// 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);
+	//
+	// A RISCV goal is that Machine or Hypervisor modes be able
+	// start a Supervisor (kernel) at the C entry point.  The
+	// intent is that firmware creates the virtual memory maps for
+	// the kernel to use.
+	//
+	// Question: what is the virtual address of physical memory
+	// for a kernel? Hey, glad you asked! In most kernels out
+	// there, physical memory is mapped at the top of the virtual
+	// address space.  The express intent of the RISCV designers
+	// (I asked them) is that we be able to enter a kernel at
+	// main() in C, with no assembly needed.
+	//
+	// This is a neat idea that may not quite work out. For
+	// example: where's the stack go?  Once you start in
+	// Supervisor mode, you are using virtual addresses set up by
+	// coreboot. So you can't use the coreboot stack, it's mapped
+	// to low physical addresses. You *should* not use the
+	// coreboot stack, your kernel may need it in a different
+	// place. So the kernel needs to change the stack, in ...  a
+	// bit of startup assembly code, what else? Oh well. Map
+	// physical to high virtual. It's the most common way to
+	// go. Kernels that want to put kernel virtual addresses based
+	// at 0 will need to fi xup page tables in ... a bit of startup
+	// assembly code :-)
+	//
+	// TODO: use a constant for the number of PTEs per page, when
+	// (hopefully) newer RISCV toolchains define that constant.
+	// Start of negative address space.
+	// top 2 GiB of negative address space.
+	root_pt[0x1fc] = root_pt[0];
+	root_pt[0x1fd] = root_pt[1];
+	root_pt[0x1fe] = root_pt[2];
+	root_pt[0x1ff] = root_pt[3];
+
 	mb();
 	root_page_table = root_pt;
 	uintptr_t ptbr = ((uintptr_t) root_pt) >> RISCV_PGSHIFT;
@@ -213,9 +282,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 +319,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);
 }



More information about the coreboot-gerrit mailing list