[coreboot-gerrit] Patch set updated for coreboot: riscv: map first 1GiB of physical memory at the top of virtual address space

Ronald G. Minnich (rminnich@gmail.com) gerrit at coreboot.org
Sun Nov 13 00:28:23 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 1ba7ca0312c62f51ca218ff0a69354402915e154
Author: Ronald G. Minnich <rminnich at gmail.com>
Date:   Fri Nov 4 11:27:25 2016 -0700

    riscv: map first 1GiB of physical memory at the top of virtual address space
    
    The first 4G of physical address space is now mapped at 1 << 38.
    The first 1G of ram is now mapped at the top of memory minus 1G.
    
    Change-Id: I77b151720001bddad5563b0f8e1279abcea056fa
---
 src/arch/riscv/virtual_memory.c | 90 +++++++++++++++++++++++++++++++++++++----
 1 file changed, 82 insertions(+), 8 deletions(-)

diff --git a/src/arch/riscv/virtual_memory.c b/src/arch/riscv/virtual_memory.c
index 999d73c..9ee4eba 100644
--- a/src/arch/riscv/virtual_memory.c
+++ b/src/arch/riscv/virtual_memory.c
@@ -125,6 +125,26 @@ 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 identify 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
+// RISCV map: map the first 2 GiB of DRAM, whereever it is,
+// to 0xffffffff_80000000
+//
+// Long term: Map IO space, and all of DRAM, to the *lowest* possible
+// negative address for this implementation.
+//
+// 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);
@@ -166,14 +186,63 @@ 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.
+#if 0
+	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);
+#endif
+
+	// IO space starting at 0xffffff8000000000
+	root_pt[0x100] = pte_create(0x00000000 >> RISCV_PGSHIFT,
+				PTE_R | PTE_W, 0);
+	root_pt[0x101] = pte_create(0x40000000 >> RISCV_PGSHIFT,
+				PTE_R | PTE_W, 0);
+	root_pt[0x102] = pte_create(0x80000000 >> RISCV_PGSHIFT,
+				PTE_R | PTE_W | PTE_X, 0);
+	root_pt[0x103] = pte_create(0xc0000000 >> RISCV_PGSHIFT,
+				PTE_R | PTE_W | PTE_X, 0);
 
 	// 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] = pte_create(0x00000000 >> RISCV_PGSHIFT,
+				PTE_R | PTE_W, 0);
+	root_pt[0x1fd] = pte_create(0x40000000 >> RISCV_PGSHIFT,
+				PTE_R | PTE_W, 0);
+	root_pt[0x1fe] = pte_create(0x80000000 >> RISCV_PGSHIFT,
+				PTE_R | PTE_W | PTE_X, 0);
+	root_pt[0x1ff] = pte_create(0xc0000000 >> RISCV_PGSHIFT,
+				PTE_R | PTE_W | PTE_X, 0);
 	mb();
 	root_page_table = root_pt;
 	uintptr_t ptbr = ((uintptr_t) root_pt) >> RISCV_PGSHIFT;
@@ -198,9 +267,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();



More information about the coreboot-gerrit mailing list