Updated RISC-V boot sequence; use 8KB pages
authorAndrew Waterman <waterman@s144.Millennium.Berkeley.EDU>
Thu, 27 Oct 2011 10:07:43 +0000 (03:07 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 01:28:05 +0000 (18:28 -0700)
kern/arch/riscv/boot.S
kern/arch/riscv/cboot.c
kern/arch/riscv/ros/mmu.h

index 5230375..41f76b8 100644 (file)
@@ -16,6 +16,7 @@
 // entry point
 ///////////////////////////////////////////////////////////////////
 
+#define PCR0 (SR_S | SR_ET | SR_SX)
 .text
 
 .global _start
@@ -29,7 +30,7 @@ _start:
   mtpcr  t0, ASM_CR(PCR_EVEC)
 
   // enable traps
-  li     t0, SR_S | SR_ET | SR_SX
+  li     t0, PCR0
   mtpcr  t0, ASM_CR(PCR_SR)
 
   // core 0?
@@ -47,22 +48,16 @@ _start:
   la     a1, l1pt_boot
   sub    a1, a1, t1
 #ifdef __riscv64
-  la     a2, l2pt_kernbase
-  sub    a2, a2, t1
-  la     a3, l2pt_load
-  sub    a3, a3, t1
+  la     a2, l2pt
+  sub    a2, a1, t1
 #endif
   jal    pagetable_init
-
-  // turn on MMU
-  la     a0, l1pt_boot
-  sub    a0, a0, t1
-  jal    mmu_init
+  jal    enable_mmu
 
   // relocate stack and call into C code using absolute jump, not pc-relative
   la     sp, bootstacktop
-  lui    t0, %hi(cmain)
-  jalr.j t0, %lo(cmain)
+  la     t0, cmain
+  jr     t0
 
 notcore0:
   // set up stack: sp = percoore_stacks+(core_id()+1)*KSTKSIZE
@@ -73,18 +68,27 @@ notcore0:
   li     t1, KERN_LOAD_ADDR
   sub    sp, sp, t1
   
-  // turn on MMU
-  la     a0, l1pt_boot
-  sub    a0, a0, t1
-  jal    mmu_init
+  jal    enable_mmu
 
   // relocate stack and call into C code
   li     t1, KERN_LOAD_ADDR
   add    sp, sp, t1
-  lui    t0, %hi(smp_init)
-  jalr.j t0, %lo(smp_init)
+  la     t0, smp_init
+  jr     t0
 
 .end _start
+
+.ent enable_mmu
+enable_mmu:
+  la     t0, l1pt_boot
+  li     t1, KERN_LOAD_ADDR
+  sub    t0, t0, t1
+  mtpcr  t0, ASM_CR(PCR_PTBR)
+  li     t0, PCR0 | SR_VM
+  mtpcr  t0, ASM_CR(PCR_SR)
+  ret
+.end enable_mmu
+
 ///////////////////////////////////////////////////////////////////
 // boot stack and regular stacks.
 // (boot stack cannot be in .bss, as .bss is later zereoed by the kernel.)
@@ -92,6 +96,14 @@ notcore0:
 
 .data
   .align  PGSHIFT
+l1pt_boot:
+  .space  PGSIZE
+.global l1pt
+l1pt:
+  .space  PGSIZE
+l2pt:
+  .space  PGSIZE
+
   .space  KSTKSIZE
   .global bootstacktop
 bootstacktop:
index 4bcd18a..54d46f4 100644 (file)
 #include <stdio.h>
 #include <pmap.h>
 
-#ifdef __riscv64
-# define MAX_KERNBASE_SIZE L1PGSIZE
-#else
-# define MAX_KERNBASE_SIZE ((uintptr_t)(-KERNBASE))
-#endif
+#define MAX_KERNBASE_SIZE (KERN_VMAP_TOP - KERNBASE)
 
-static void
-build_multiboot_info(multiboot_info_t* mbi)
+static uint64_t
+mem_size(void)
 {
-       long memsize = mfpcr(PCR_MEMSIZE)*PGSIZE;
-       // the current memory mapping requires the kernel be mapped by a single
-       // L2 page table.
-       memsize = MIN(memsize, L1PGSIZE);
-       memsize = ROUNDDOWN(memsize, L2PGSIZE);
-
-       long memsize_kb = memsize/1024;
-       long basemem_kb = EXTPHYSMEM/1024;
-
-       memset(mbi, 0, sizeof(mbi));
-
-       mbi->flags = 0x00000001;
-       mbi->mem_lower = basemem_kb;
-       mbi->mem_upper = memsize_kb - basemem_kb;
-}
-
-pte_t l1pt_boot[NPTENTRIES]
-      __attribute__((section(".data"))) __attribute__((aligned(PGSIZE)));
-pte_t l1pt[NPTENTRIES]
-      __attribute__((section(".data"))) __attribute__((aligned(PGSIZE)));
-#ifdef __riscv64
-pte_t l2pt_kernbase[NPTENTRIES]
-      __attribute__((section(".data"))) __attribute__((aligned(PGSIZE)));
-pte_t l2pt_load[NPTENTRIES]
-      __attribute__((section(".data"))) __attribute__((aligned(PGSIZE)));
+       uint64_t sz = MIN(mfpcr(PCR_MEMSIZE)*PGSIZE, MAX_KERNBASE_SIZE);
+#ifndef __riscv64
+       // limit memory size for RV32
+       sz = MIN(sz, L1PGSIZE*NPTENTRIES);
 #endif
+       return sz;
+}
 
-#ifdef __riscv64
-void pagetable_init(pte_t* l1pt_phys, pte_t* l1pt_boot_phys,
-                    pte_t* l2pt_kernbase_phys, pte_t* l2pt_load_phys)
-#else
-void pagetable_init(pte_t* l1pt_phys, pte_t* l1pt_boot_phys)
-#endif
+void pagetable_init(pte_t* l1pt, pte_t* l1pt_boot, pte_t* l2pt)
 {
-       pte_t perm = PTE_KERN_RW | PTE_E;
-
-       // The boot L1 PT retains the identity mapping [0,MAX_KERNBASE_SIZE-1],
-       // whereas the post-boot L1 PT does not.  This is not a "safe" mapping,
-       // since there may be fewer than MAX_KERNBASE_SIZE bytes of physical memory,
-       // so we'll only use this mapping briefly.
-       for(uintptr_t va = 0; va < MAX_KERNBASE_SIZE+L1PGSIZE-1; va += L1PGSIZE)
-               l1pt_boot_phys[L1X(va)] = PTE(LA2PPN(va), perm);
-
-       #ifdef __riscv64
-       // kernel can be mapped by a single L2 PT.
-       static_assert(L1X(KERNBASE) == L1X(KERNBASE+MAX_KERNBASE_SIZE-1));
-       static_assert(MAX_KERNBASE_SIZE % L2PGSIZE == 0);
-       static_assert(KERNBASE % L2PGSIZE == 0);
-
-       // KERNBASE mapping uses one L1 PTD -> L2 PT
-       l1pt_phys[L1X(KERNBASE)]      = PTD(l2pt_kernbase_phys);
-       l1pt_boot_phys[L1X(KERNBASE)] = PTD(l2pt_kernbase_phys);
+       static_assert(KERNBASE % L1PGSIZE == 0);
+       // The boot L1 PT retains the identity mapping [0,memsize-1],
+       // whereas the post-boot L1 PT does not.
+       uint64_t memsize = mem_size();
+       for(uint64_t pa = 0; pa < memsize+L1PGSIZE-1; pa += L1PGSIZE)
+       {
+               pte_t pte = PTE(LA2PPN(pa), PTE_KERN_RW | PTE_E);
 
-       // don't actually map all the way up to MAX_KERNBASE_SIZE, just to phys. mem size
-       uintptr_t memsize = ROUNDDOWN(mfpcr(PCR_MEMSIZE)*PGSIZE, L2PGSIZE);
-       for(uintptr_t va = KERNBASE; va < KERNBASE+memsize; va += L2PGSIZE)
-               l2pt_kernbase_phys[L2X(va)] = PTE(LA2PPN(va-KERNBASE), perm);
+               l1pt_boot[L1X(pa)] = pte; // identity mapping
+               l1pt_boot[L1X(KERNBASE+pa)] = pte; // KERNBASE mapping
+               l1pt[L1X(KERNBASE+pa)] = pte; // KERNBASE mapping
+       }
 
+#ifdef __riscv64
        // The kernel code and static data actually are usually not accessed
        // via the KERNBASE mapping, but rather by an aliased "load" mapping in
        // the upper 2GB (0xFFFFFFFF80000000 and up).
        // This simplifies the linking model by making all static addresses
        // representable in 32 bits.
-       // In RISC-V, this allows static addresses to be loaded with a two
-       // instruction sequence, rather than 8 instructions worst-case.
        static_assert(L1X(KERN_LOAD_ADDR) > L1X(KERNBASE));
        static_assert(KERN_LOAD_ADDR % L2PGSIZE == 0);
        static_assert((uintptr_t)(-KERN_LOAD_ADDR) <= L1PGSIZE);
 
-       l1pt_phys[L1X(KERN_LOAD_ADDR)]      = PTD(l2pt_load_phys);
-       l1pt_boot_phys[L1X(KERN_LOAD_ADDR)] = PTD(l2pt_load_phys);
-
-       for(uintptr_t va = KERN_LOAD_ADDR; va != 0; va += L2PGSIZE)
-               l2pt_load_phys[L2X(va)] = PTE(LA2PPN(va-KERN_LOAD_ADDR), perm);
-       #else
-       // for rv32, just create the L1 page table.
-       static_assert(KERNBASE % L1PGSIZE == 0);
+       l1pt[L1X(KERN_LOAD_ADDR)] = PTD(l2pt);
+       l1pt_boot[L1X(KERN_LOAD_ADDR)] = PTD(l2pt);
 
-       // KERNBASE mapping
-       for(uintptr_t pa = 0; pa < MAX_KERNBASE_SIZE; pa += L1PGSIZE)
-       {
-               pte_t pte = PTE(LA2PPN(pa), perm);
-               l1pt_phys[L1X(KERNBASE+pa)] = pte;
-               l1pt_boot_phys[L1X(KERNBASE+pa)] = pte;
-       }
-       #endif
-}
-
-void
-mmu_init(pte_t* l1pt_boot_phys)
-{
-       // load in the boot page table
-       lcr3((uintptr_t)l1pt_boot_phys);
-       mtpcr(PCR_SR, mfpcr(PCR_SR) | SR_VM);
+       for (uintptr_t pa = 0; pa < (uintptr_t)(-KERN_LOAD_ADDR); pa += L2PGSIZE)
+               l2pt[L2X(KERN_LOAD_ADDR+pa)] = PTE(LA2PPN(pa), PTE_KERN_RW | PTE_E);
+#else
+       (void) l2pt; // don't need this for rv32
+#endif
 }
 
 void
 cmain()
 {
        multiboot_info_t mbi;
-       build_multiboot_info(&mbi);
+       memset(&mbi, 0, sizeof(mbi));
+       mbi.flags = 0x00000001;
+       mbi.mem_lower = (unsigned long)(mem_size() / 1024);
 
        extern void kernel_init(multiboot_info_t *mboot_info);
        // kernel_init expects a pre-relocation mbi address
index 932ecc8..a962cd1 100644 (file)
@@ -9,20 +9,18 @@
 
 // All physical memory mapped at this address
 #ifdef __riscv64
-# define KERNBASE       0xFFFFFF0000000000
-# define ULIM           0x0000010000000000
+# define KERNBASE       0xFFFFFC0000000000
+# define ULIM           0x0000040000000000
 # define KERN_LOAD_ADDR 0xFFFFFFFF80000000
 # define KERN_VMAP_TOP         KERN_LOAD_ADDR // upper 2GB reserved (see mmu_init)
-# define NPTLEVELS                       4
-# define L1PGSHIFT              (12+9+9+9)
+# define NPTLEVELS                       3
+# define L1PGSHIFT              (13+10+10)
 # define L1PGSIZE        (1L << L1PGSHIFT)
-# define L2PGSHIFT                (12+9+9)
+# define L2PGSHIFT                 (13+10)
 # define L2PGSIZE        (1L << L2PGSHIFT)
-# define L3PGSHIFT                  (12+9)
+# define L3PGSHIFT                    (13)
 # define L3PGSIZE        (1L << L3PGSHIFT)
-# define L4PGSHIFT                    (12)
-# define L4PGSIZE        (1L << L4PGSHIFT)
-# define PGSHIFT                 L4PGSHIFT
+# define PGSHIFT                 L3PGSHIFT
 # define PTSIZE                   L2PGSIZE
 #else
 # define KERNBASE               0x80000000
@@ -30,9 +28,9 @@
 # define KERN_LOAD_ADDR           KERNBASE
 # define KERN_VMAP_TOP                 0xfec00000 /* using sparc's upper limit */
 # define NPTLEVELS                       2
-# define L1PGSHIFT                 (12+10)
+# define L1PGSHIFT                 (13+11)
 # define L1PGSIZE         (1 << L1PGSHIFT)
-# define L2PGSHIFT                      12
+# define L2PGSHIFT                      13
 # define L2PGSIZE         (1 << L2PGSHIFT)
 # define PGSHIFT                 L2PGSHIFT
 # define PTSIZE                   L1PGSIZE
@@ -91,7 +89,7 @@
 #define PTE(ppn, flags) ((ppn) << PTE_PPN_SHIFT | (flags))
 
 // construct PTD from physical address
-#define PTD(pa) ((uintptr_t)(pa) | PTE_T)
+#define PTD(pa) (((uintptr_t)(pa) >> PGSHIFT << PTE_PPN_SHIFT) | PTE_T)
 
 // Page directory and page table constants
 #define NPTENTRIES (PGSIZE/sizeof(pte_t))
 #define PTE_SW   0x100 // Supervisor Read permission
 #define PTE_SR   0x200 // Supervisor Write permission
 #define PTE_PERM (PTE_SR | PTE_SW | PTE_SX | PTE_UR | PTE_UW | PTE_UX)
-#define PTE_PPN_SHIFT 12
+#define PTE_PPN_SHIFT 13
 
 // commly used access modes
 #define PTE_KERN_RW    (PTE_SR | PTE_SW | PTE_SX)