RISC-V SMP boot works
authorAndrew Waterman <waterman@s141.Millennium.Berkeley.EDU>
Sat, 28 May 2011 06:33:53 +0000 (23:33 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:36:02 +0000 (17:36 -0700)
this commit won't compile because i'm not committing a change to the mainline
that changes the memory layout without further consultation

kern/arch/riscv/arch.h
kern/arch/riscv/boot.S
kern/arch/riscv/cboot.c
kern/arch/riscv/console.c
kern/arch/riscv/kernel.ld
kern/arch/riscv/pcr.h
kern/arch/riscv/riscv.h
kern/arch/riscv/ros/mmu.h
kern/arch/riscv/smp.c
kern/arch/riscv/trap.c

index 3f0f721..8941a47 100644 (file)
@@ -2,6 +2,7 @@
 #define ROS_INC_ARCH_H
 
 #include <ros/arch/arch.h>
+#include <arch/mmu.h>
 #include <ros/common.h>
 #include <ros/arch/membar.h>
 #include <arch/riscv.h>
@@ -10,7 +11,7 @@
 
 /* Arch Constants */
 #define HW_CACHE_ALIGN 64
-#define IOAPIC_BASE    0xFFFFFFFF80000000 // upper 2GB reserved (see mmu_init)
+#define IOAPIC_BASE    LOAD_ADDR // upper 2GB reserved (see mmu_init)
 
 void print_cpuinfo(void);
 void show_mapping(uintptr_t start, size_t size);
@@ -133,7 +134,7 @@ get_hw_coreid(int coreid)
 static __inline int
 hw_core_id(void)
 {
-  return 0;
+  return mfpcr(PCR_COREID);
 }
 
 /* hw_coreid -> os_coreid */
index 2408b7d..6947dbe 100644 (file)
@@ -3,9 +3,10 @@
 #include <arch/pcr.h>
 #include <ros/arch/arch.h>
 #include <ros/memlayout.h>
+#incldue <arch/mmu.h>
 
 ///////////////////////////////////////////////////////////////////
-// The kernel (this code) is linked at address (KERNBASE + 0x00000000),
+// The kernel (this code) is linked at address 0xFFFFFFFF80000000,
 // but we tell the bootloader to load it at physical address 
 // 0x00000000, which is the start of extended memory.
 // (See kernel.ld)
 // entry point
 ///////////////////////////////////////////////////////////////////
 
-.text
+.section ".boottext"
 
 .global _start
-.ent    _start
 _start:
   // This is the first kernel code that executes; it is run only by core 0.
 
-  // set up stack and terminate frame pointer for backtracing
-  li     $fp, 0
-  la     $sp, bootstacktop
-       li     $t1, KERNBASE
-       sub    $sp, $sp, $t1
-
-  // set up trap entry point
+  // set up trap entry point.  this is not a relocated address, as we
+  // do not support trapping before the MMU is set up.
   la     $t0, trap_entry
-       sub    $t0, $t0, $t1
   mtpcr  $t0, ASM_CR(PCR_EVEC)
 
   // enable traps
   li     $t0, SR_S | SR_ET | SR_SX
   mtpcr  $t0, ASM_CR(PCR_SR)
 
-       jal    mmu_init
+  // core 0?
+  mfpcr  $t0, ASM_CR(PCR_COREID)
+  bnez   $t0, notcore0
+
+  // set up stack and terminate frame pointer for backtracing
+  li     $fp, 0
+  la     $sp, bootstacktop
+  li     $t1, LOAD_ADDR
+  sub    $sp, $sp, $t1
+
+  // set up initial page mappings
+  la     $a0, l1pt
+  sub    $a0, $a0, $t1
+  la     $a1, l1pt_boot
+  sub    $a1, $a1, $t1
+#ifdef __riscv64
+  la     $a2, l2pt
+  sub    $a2, $a2, $t1
+#endif
+  jal    pagetable_init
+
+  // turn on MMU
+  la     $a0, l1pt_boot
+  sub    $a0, $a0, $t1
+  jal    mmu_init
 
   // 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)
+  lui    $t0, %hi(cmain)
+  jalr.j $t0, %lo(cmain)
+
+notcore0:
+  // set up stack and terminate frame pointer for backtracing
+  // sp = percoore_stacks+(core_id()+1)*KSTKSIZE
+  li     $fp, 0
+  la     $sp, percore_stacks
+  add    $t0, $t0, 1
+  sll    $t0, $t0, KSTKSHIFT
+  add    $sp, $sp, $t0
+  li     $t1, LOAD_ADDR
+  sub    $sp, $sp, $t1
+  
+  // turn on MMU
+  la     $a0, l1pt_boot
+  sub    $a0, $a0, $t1
+  jal    mmu_init
 
-.end    _start
+  // relocate stack and call into C code
+  li     $t1, LOAD_ADDR
+  add    $sp, $sp, $t1
+  lui    $t0, %hi(smp_init)
+  jalr.j $t0, %lo(smp_init)
 
 ///////////////////////////////////////////////////////////////////
 // boot stack and regular stacks.
index f921663..fce5190 100644 (file)
@@ -4,6 +4,8 @@
 #include <arch/mmu.h>
 #include <string.h>
 #include <assert.h>
+#include <stdio.h>
+#include <pmap.h>
 
 static void
 build_multiboot_info(multiboot_info_t* mbi)
@@ -19,93 +21,80 @@ build_multiboot_info(multiboot_info_t* mbi)
 }
 
 #define KERNSIZE ((uintptr_t)(-KERNBASE))
-#ifdef __riscv64
-#define NL3PT ((KERNSIZE+L2PGSIZE-1)/L2PGSIZE)
-pte_t l1pt[NPTENTRIES], l2pt[NPTENTRIES], l3pts[NL3PT][NPTENTRIES]
-      __attribute__((section("data"))) __attribute__((aligned(PGSIZE)));
-#else
+
+pte_t l1pt_boot[NPTENTRIES]
+      __attribute__((section(".data"))) __attribute__((aligned(PGSIZE)));
 pte_t l1pt[NPTENTRIES]
-      __attribute__((section("data"))) __attribute__((aligned(PGSIZE)));
+      __attribute__((section(".data"))) __attribute__((aligned(PGSIZE)));
+#ifdef __riscv64
+pte_t l2pt[NPTENTRIES]
+      __attribute__((section(".data"))) __attribute__((aligned(PGSIZE)));
 #endif
 
-void
-mmu_init()
+#ifdef __riscv64
+void pagetable_init(pte_t* l1pt_phys, pte_t* l1pt_boot_phys, pte_t* l2pt_phys)
+#else
+void pagetable_init(pte_t* l1pt_phys, pte_t* l1pt_boot_phys)
+#endif
 {
-       pte_t* l1pt_phys = (pte_t*)((uint8_t*)l1pt - KERNBASE);
-       pte_t* l2pt_phys = (pte_t*)((uint8_t*)l2pt - KERNBASE);
-
-       // Retain the identity mapping [0,KERNSIZE]
-       for(uintptr_t i = 0; i < (KERNSIZE+L1PGSIZE-1)/L1PGSIZE; i++)
-               l1pt_phys[i] = PTE(LA2PPN(i*L1PGSIZE), PTE_KERN_RW|PTE_E);
+       // The boot L1 PT retains the identity mapping [0,KERNSIZE-1],
+       // whereas the post-boot L1 PT does not.
+       for(uintptr_t va = 0; va < KERNSIZE+L1PGSIZE-1; va += L1PGSIZE)
+               l1pt_boot_phys[L1X(va)] = PTE(LA2PPN(va), PTE_KERN_RW | PTE_E);
 
        #ifdef __riscv64
-       // for rv64, we need to create an L1 and an L2 PT, and many L3 PTs.
-
-       // kernel can be mapped by a single L1 page
+       // for rv64, we need to create an L1 and an L2 PT.
+       
+       // kernel can be mapped by a single L1 page and several L2 pages
        static_assert(KERNSIZE <= L1PGSIZE);
-       static_assert(KERNBASE % L3PGSIZE == 0);
+       static_assert(KERNBASE % L2PGSIZE == 0);
 
        // highest L1 page contains KERNBASE mapping
-       uintptr_t l1x = L1X(KERNBASE);
-       l1pt_phys[l1x] = PTD(l2pt);
-
-       for(uintptr_t i = 0; i < NL3PT; i++)
-       {
-               uintptr_t l2x = L2X(KERNBASE + i*L2PGSIZE);
-               l2pt_phys[l2x] = PTD(l3pts[l2x]);
-               for(uintptr_t l3x = 0; l3x < NPTENTRIES; l3x++)
-               {
-                       uintptr_t addr = PGADDR(l1x, l2x, l3x, 0, 0);
-                       if(addr >= KERNBASE)
-                               l3pts[l2x][l3x] = PTE(LA2PPN(addr), PTE_KERN_RW | PTE_E);
-               }
-       }
-
-       // KERNBASE mapping
-       l1pt_phys[NPTENTRIES-1] = PTD(l2pt_phys);
-       for(uintptr_t i = 0; i < (KERNSIZE+L2PGSIZE-1)/L2PGSIZE; i++)
-               l2pt_phys[i] = PTD(l1pt_phys + i*NPTENTRIES);
-       
-  // Map the upper 2GB (0xFFFFFFFF80000000 and up) to alias the KERNBASE
-       // mapping.  We'll use this region to reference static/global variables
-       // more efficiently with a LUI/ADD pair, which can only reach addresses
-       // 0x00000000->0x7FFFF7FF and 0xFFFFFFFF80000000->0xFFFFFFFFFFFFF7FF.
-       // The alternative requires an 8-instruction sequence in the general case.
-  const uintptr_t start = 0xFFFFFFFF80000000;
-       static_assert(start % L2PGSIZE == 0);
-       for(uintptr_t va = start; va != 0; va += L2PGSIZE)
-         l2pt[L2X(va)] = PTE(LA2PPN(va-start), PTE_KERN_RW|PTE_E);
+       l1pt_phys[L1X(KERNBASE)] = l1pt_boot_phys[L1X(KERNBASE)] = PTD(l2pt_phys);
+
+       // KERNBASE mapping with 1GB pages
+       for(uintptr_t va = KERNBASE; va < LOAD_ADDR; va += L2PGSIZE)
+               l2pt_phys[L2X(va)] = PTE(LA2PPN(va-KERNBASE), PTE_KERN_RW | PTE_E);
+
+       // The kernel code and static data actually are usually not accessed
+       // via the KERNBASE mapping, but rather by an aliased 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(LOAD_ADDR % L2PGSIZE == 0);
+       for(uintptr_t va = LOAD_ADDR; va != 0; va += L2PGSIZE)
+               l2pt_phys[L2X(va)] = PTE(LA2PPN(va-LOAD_ADDR), PTE_KERN_RW|PTE_E);
        #else
        // for rv32, just create the L1 page table.
        static_assert(KERNBASE % L1PGSIZE == 0);
 
        // KERNBASE mapping
        for(uintptr_t pa = 0; pa < KERNSIZE; pa += L1PGSIZE)
-               l1pt_phys[L1X(KERNBASE+pa)] = PTE(LA2PPN(pa), PTE_KERN_RW|PTE_E);
+       {
+               pte_t pte = PTE(LA2PPN(pa), PTE_KERN_RW|PTE_E);
+               l1pt_phys[L1X(KERNBASE+pa)] = pte;
+               l1pt_boot_phys[L1X(KERNBASE+pa)] = pte;
+       }
        #endif
-
-       lcr3((uintptr_t)l1pt_phys);
-       mtpcr(PCR_SR, mfpcr(PCR_SR) | SR_VM);
 }
 
-static void
-mmu_init_cleanup()
+void
+mmu_init(pte_t* l1pt_boot_phys)
 {
-       // after relocation, we no longer rely on the identity mapping
-       for(uintptr_t va = 0; va < KERNSIZE+L1PGSIZE-1; va += L1PGSIZE)
-               l1pt[L1X(va)] = 0;
-       tlbflush();
+       // load in the boot page table
+       lcr3((uintptr_t)l1pt_boot_phys);
+       mtpcr(PCR_SR, mfpcr(PCR_SR) | SR_VM);
 }
 
 void
 cmain()
 {
-       mmu_init_cleanup();
-
        multiboot_info_t mbi;
        build_multiboot_info(&mbi);
 
        extern void kernel_init(multiboot_info_t *mboot_info);
        // kernel_init expects a pre-relocation mbi address
-       kernel_init((multiboot_info_t*)((uint8_t*)&mbi - KERNBASE));
+       kernel_init((multiboot_info_t*)((uint8_t*)&mbi - LOAD_ADDR));
 }
index 4dfc2cb..8cba973 100644 (file)
@@ -18,7 +18,7 @@ fesvr_syscall(long n, long a0, long a1, long a2, long a3)
 
   asm volatile ("cflush; fence");
 
-  mtpcr(PCR_TOHOST, magic_mem);
+  mtpcr(PCR_TOHOST, PADDR(magic_mem));
   while(mfpcr(PCR_FROMHOST) == 0);
 
   long ret = magic_mem[0];
index dce3cf4..32a10fa 100644 (file)
@@ -8,7 +8,8 @@ SECTIONS
 {
        /* Link the kernel for 0xC01000C0, but load it at 0x001000C0) */
 
-       .text 0xFFFFFF8000000000 : AT(0) {
+       .text 0xFFFFFFFF80000000 : AT(0) {
+         *(.boottext)
                *(.text .stub .text.* .gnu.linkonce.t.*)
        }
 
@@ -45,12 +46,14 @@ SECTIONS
        /* The data segment */
        .data : {
                *(.data)
+               *(.sdata)
        }
 
        PROVIDE(edata = .);
 
        .bss : {
                *(.bss)
+               *(.sbss)
        }
 
        PROVIDE(end = .);
index 5eb5b43..368e765 100644 (file)
@@ -24,6 +24,8 @@
 #define PCR_IPI      7
 #define PCR_MEMSIZE  8
 #define PCR_PTBR     9
+#define PCR_COREID   10
+#define PCR_NUMCORES 12
 #define PCR_TOHOST   16
 #define PCR_FROMHOST 17
 #define PCR_CONSOLE  18
index a4964c2..703bbe3 100644 (file)
@@ -23,6 +23,12 @@ read_pc(void)
   return pc;
 }
 
+static __inline uintptr_t
+num_cores(void)
+{
+       return mfpcr(PCR_NUMCORES);
+}
+
 static __inline void
 send_ipi(uint32_t who)
 {
index 7690649..2737d1e 100644 (file)
@@ -4,6 +4,7 @@
 // All physical memory mapped at this address
 #ifdef __riscv64
 # define KERNBASE  0xFFFFFF8000000000
+# define LOAD_ADDR 0xFFFFFFFF80000000
 # define NPTLEVELS                  4
 # define L1PGSHIFT         (12+9+9+9)
 # define L1PGSIZE   (1L << L1PGSHIFT)
@@ -17,6 +18,7 @@
 # define KPGSHIFT           L3PGSHIFT
 #else
 # define KERNBASE          0x80000000
+# define LOAD_ADDR         0x80000000
 # define NPTLEVELS                  2
 # define L1PGSHIFT            (12+10)
 # define L1PGSIZE    (1 << L1PGSHIFT)
index c8769e0..bce487f 100644 (file)
@@ -6,18 +6,22 @@
 #include <error.h>
 #include <assert.h>
 #include <atomic.h>
+#include <pmap.h>
 
 volatile uint32_t num_cpus;
 
 void
 smp_boot(void)
 {
+       smp_percpu_init();
+
        num_cpus = 1;
        printd("Cores, report in!\n");
 
-       smp_percpu_init();
-
-       //while(*(volatile uint32_t*)&num_cpus < num_cores());
+       for(uintptr_t i = 1, ncores = num_cores(); i < ncores; i++)
+               send_ipi(i);
+       
+       while(*(volatile uint32_t*)&num_cpus < num_cores());
 
        printd("%d cores reporting!\n",num_cpus);
 }
@@ -144,4 +148,8 @@ int smp_call_wait(handler_wrapper_t* wrapper)
  * core calls this at some point in the smp_boot process. */
 void __arch_pcpu_init(uint32_t coreid)
 {
+       // Switch to the real L1 page table, rather than the boot page table which
+       // has the [0,KERNSIZE-1] identity mapping.
+       extern pte_t l1pt[NPTENTRIES];
+       lcr3(PADDR(l1pt));
 }
index 8519e5a..84584ea 100644 (file)
@@ -139,7 +139,7 @@ format_trapframe(trapframe_t *tf, char* buf, int bufsz)
                                        j < 3 ? ' ' : '\n');
        }
        len += snprintf(buf+len, bufsz-len,
-                       "sr %lx pc %lx va %lx insn       %x\n", tf->sr, tf->epc,
+                       "sr %016lx pc %016lx va %016lx insn       %008x\n", tf->sr, tf->epc,
                        tf->badvaddr, (uint32_t)tf->insn);
 
        return len;