[coreboot-gerrit] New patch to review 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
Sat Nov 12 19:26:17 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 a43a0817a01c56ffb42aecf7cbdded17b3764302
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