RISC-V port mostly links now
authorAndrew Waterman <waterman@s141.Millennium.Berkeley.EDU>
Fri, 27 May 2011 09:57:58 +0000 (02:57 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:36:02 +0000 (17:36 -0700)
25 files changed:
kern/arch/riscv/Makefrag
kern/arch/riscv/atomic.c
kern/arch/riscv/atomic.h
kern/arch/riscv/boot.S [new file with mode: 0644]
kern/arch/riscv/boot/Makefrag
kern/arch/riscv/boot/boot [deleted symlink]
kern/arch/riscv/boot/boot.S [deleted file]
kern/arch/riscv/boot/main.c [deleted file]
kern/arch/riscv/cboot.c [new file with mode: 0644]
kern/arch/riscv/colored_caches.c [new file with mode: 0644]
kern/arch/riscv/entry.S
kern/arch/riscv/env.c [new file with mode: 0644]
kern/arch/riscv/i686 [deleted symlink]
kern/arch/riscv/init.c [new file with mode: 0644]
kern/arch/riscv/mmu.h
kern/arch/riscv/page_alloc.c [new file with mode: 0644]
kern/arch/riscv/pcr.h
kern/arch/riscv/pmap.c [new file with mode: 0644]
kern/arch/riscv/process.c [new file with mode: 0644]
kern/arch/riscv/riscv.h
kern/arch/riscv/ros/mmu.h
kern/arch/riscv/smp.c [new file with mode: 0644]
kern/arch/riscv/smp.h
kern/arch/riscv/timer.c
kern/arch/riscv/trap.c [new file with mode: 0644]

index 9b636a9..54ec04d 100644 (file)
@@ -11,6 +11,18 @@ OBJDIRS += $(KERN_ARCH_SRC_DIR)
 #
 # We also snatch the use of a couple handy source files
 # from the lib directory, to avoid gratuitous code duplication.
-KERN_ARCH_SRCFILES := $(KERN_ARCH_SRC_DIR)/entry.S \
+KERN_ARCH_SRCFILES := $(KERN_ARCH_SRC_DIR)/boot.S \
+                      $(KERN_ARCH_SRC_DIR)/entry.S \
+                      $(KERN_ARCH_SRC_DIR)/cboot.c \
+                      $(KERN_ARCH_SRC_DIR)/trap.c \
                       $(KERN_ARCH_SRC_DIR)/cpuinfo.c \
                       $(KERN_ARCH_SRC_DIR)/console.c \
+                      $(KERN_ARCH_SRC_DIR)/pmap.c \
+                      $(KERN_ARCH_SRC_DIR)/timer.c \
+                      $(KERN_ARCH_SRC_DIR)/atomic.c \
+                      $(KERN_ARCH_SRC_DIR)/smp.c \
+                      $(KERN_ARCH_SRC_DIR)/colored_caches.c \
+                      $(KERN_ARCH_SRC_DIR)/page_alloc.c \
+                      $(KERN_ARCH_SRC_DIR)/process.c \
+                      $(KERN_ARCH_SRC_DIR)/env.c \
+                      $(KERN_ARCH_SRC_DIR)/init.c \
index 66a5fd6..8c54229 100644 (file)
@@ -12,13 +12,14 @@ bool atomic_comp_swap(uintptr_t *addr, uintptr_t exp_val, uintptr_t new_val)
        static spinlock_t cas_locks[K*HW_CACHE_ALIGN/sizeof(spinlock_t)];
 
   uintptr_t bucket = (uintptr_t)addr / sizeof(uintptr_t) % K;
-       spinlock_t* lock = &cas_lock[bucket*HW_CACHE_ALIGN/sizeof(spinlock_t)];
+       spinlock_t* lock = &cas_locks[bucket*HW_CACHE_ALIGN/sizeof(spinlock_t)];
        
-       spin_lock_irqsave(&lock);
+       bool retval = 0;
+       spin_lock_irqsave(lock);
        if (*addr == exp_val) {
                atomic_swap(addr, new_val);
                retval = 1;
        }
-       spin_unlock_irqsave(&lock);
+       spin_unlock_irqsave(lock);
        return retval;
 }
index bbfee4b..4cf6fe5 100644 (file)
@@ -102,15 +102,15 @@ static inline uint32_t spin_locked(spinlock_t* lock)
        return lock->rlock;
 }
 
-static inline void __spin_lock(volatile uint32_t* rlock)
+static inline uint32_t spin_trylock(spinlock_t* lock)
 {
-       while(__sync_fetch_and_or(rlock, 1))
-               while(*rlock);
+       return __sync_fetch_and_or(&lock->rlock, 1);
 }
 
 static inline void spin_lock(spinlock_t *lock)
 {
-       __spin_lock(&lock->rlock);
+       while(spin_trylock(lock))
+               while(lock->rlock);
 }
 
 static inline void spin_unlock(spinlock_t *lock)
diff --git a/kern/arch/riscv/boot.S b/kern/arch/riscv/boot.S
new file mode 100644 (file)
index 0000000..2408b7d
--- /dev/null
@@ -0,0 +1,64 @@
+/* See COPYRIGHT for copyright information. */
+
+#include <arch/pcr.h>
+#include <ros/arch/arch.h>
+#include <ros/memlayout.h>
+
+///////////////////////////////////////////////////////////////////
+// The kernel (this code) is linked at address (KERNBASE + 0x00000000),
+// 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
+
+.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
+  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
+
+  // 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)
+
+.end    _start
+
+///////////////////////////////////////////////////////////////////
+// boot stack and regular stacks.
+// (boot stack cannot be in .bss, as .bss is later zereoed by the kernel.)
+///////////////////////////////////////////////////////////////////
+
+.data
+  .align  PGSHIFT
+  .space  KSTKSIZE
+  .global bootstacktop
+bootstacktop:
+
+.bss
+  .align  PGSHIFT
+  .global percore_stacks
+percore_stacks:
+  .space  KSTKSIZE*MAX_NUM_CPUS
index 648bb7a..3caa20a 100644 (file)
@@ -4,28 +4,3 @@
 # you must run GNU make in the top-level directory\r
 # where the GNUmakefile is located.\r
 #\r
-\r
-KERN_BOOT_DIR := $(KERN_DIR)/boot\r
-OBJDIRS += $(KERN_BOOT_DIR)\r
-\r
-KERN_BOOT_CFLAGS  += $(KERN_CFLAGS) -Os\r
-KERN_BOOT_LDFLAGS := $(KERN_LDFLAGS)\r
-KERN_BOOT_OBJS    := $(OBJDIR)/$(KERN_BOOT_DIR)/boot.o \\r
-                     $(OBJDIR)/$(KERN_BOOT_DIR)/main.o\r
-\r
-$(OBJDIR)/$(KERN_BOOT_DIR)/%.o: $(KERN_BOOT_DIR)/%.c\r
-       @echo + cc [BOOT] $<\r
-       @mkdir -p $(@D)\r
-       $(V)$(CC) $(KERN_BOOT_CFLAGS) -c -o $@ $<\r
-\r
-$(OBJDIR)/$(KERN_BOOT_DIR)/%.o: $(KERN_BOOT_DIR)/%.S\r
-       @echo + as [BOOT] $<\r
-       @mkdir -p $(@D)\r
-       $(V)$(CC) $(KERN_BOOT_CFLAGS) -c -o $@ $<\r
-\r
-$(OBJDIR)/$(KERN_DIR)/boot: $(KERN_BOOT_OBJS)\r
-       @echo + ld [BOOT] $<\r
-       $(V)$(LD) $(KERN_BOOT_LDFLAGS) -o $@.out $^\r
-       $(V)$(OBJDUMP) -S $@.out >$@.asm\r
-       $(V)$(OBJCOPY) -S -O binary $@.out $@\r
-       $(V)perl $(KERN_BOOT_DIR)/sign.pl $(OBJDIR)/$(KERN_DIR)/boot\r
diff --git a/kern/arch/riscv/boot/boot b/kern/arch/riscv/boot/boot
deleted file mode 120000 (symlink)
index cf41078..0000000
+++ /dev/null
@@ -1 +0,0 @@
-arch/i686/boot
\ No newline at end of file
diff --git a/kern/arch/riscv/boot/boot.S b/kern/arch/riscv/boot/boot.S
deleted file mode 100644 (file)
index 04200f6..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/* See COPYRIGHT for copyright information. */
-
-#include <arch/arch.h>
-#include <ros/memlayout.h>
-
-///////////////////////////////////////////////////////////////////
-// The kernel (this code) is linked at address (KERNBASE + 0x00000000),
-// but we tell the bootloader to load it at physical address 
-// 0x00000000, which is the start of extended memory.
-// (See kernel.ld)
-///////////////////////////////////////////////////////////////////
-
-
-///////////////////////////////////////////////////////////////////
-// RELOC(x) maps a symbol x from its link address to its actual
-// location in physical memory (its load address).
-///////////////////////////////////////////////////////////////////
-#define RELOC(x) ((x) - KERNBASE)
-
-///////////////////////////////////////////////////////////////////
-// entry point
-///////////////////////////////////////////////////////////////////
-
-.text
-
-.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, RELOC(bootstacktop)
-
-  // set up trap entry point
-  la     $t0, RELOC(trap_entry)
-  mtpcr  $t0, ASM_CR(PCR_EVEC)
-
-  // enable traps
-  li     $t0, SR_S | SR_ET | SR_SX
-  mtpcr  $t0, ASM_CR(PCR_SR)
-
-       // turn on paging (no RELOC() since jal is pc-relative)
-       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)
-
-.end    _start
-
-///////////////////////////////////////////////////////////////////
-// boot stack and regular stacks.
-// (boot stack cannot be in .bss, as .bss is later zereoed by the kernel.)
-///////////////////////////////////////////////////////////////////
-
-.data
-  .align  PGSIZE
-  .space  KSTKSIZE
-  .global bootstacktop
-bootstacktop:
-
-.bss
-  .align  PGSIZE
-  .global percore_stacks
-percore_stacks:
-  .space  KSTKSIZE*MAX_NUM_CPUS
diff --git a/kern/arch/riscv/boot/main.c b/kern/arch/riscv/boot/main.c
deleted file mode 100644 (file)
index ab47b20..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-#include <multiboot.h>
-#include <ros/memlayout.h>
-
-static void
-build_multiboot_info(multiboot_info_t* mbi)
-{
-       long memsize_kb = mfpcr(PCR_MEMSIZE)*(PGSIZE/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;
-}
-
-#ifdef __riscv64
-#define NL3PT ((KERNSIZE+L2PGSIZE-1)/L2PGSIZE)
-static pte_t l1pt[NL1ENTRIES], l2pt[NL2ENTRIES], l3pts[NL3PT][NL3ENTRIES]
-      __attribute__((section("data"))) __attribute__((aligned(PGSIZE)));
-#else
-static pte_t l1pt[NL1ENTRIES];
-#endif
-
-void
-mmu_init()
-{
-       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);
-
-       #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
-       static_assert(KERNSIZE <= L1PGSIZE);
-       static_assert(KERNBASE % L3PGSIZE == 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.
-  uintptr_t start = 0xFFFFFFFF80000000;
-       static_assert(start % L2PGSIZE == 0);
-       for(uintptr_t i = 0; i < ((uintptr_t)-start)/L2PGSIZE; i++)
-         l2pt[i+start/L2PGSIZE] = PTE(LA2PPN(i*L2PGSIZE), PTE_KERN_RW|PTE_E);
-       #else
-       // for rv32, just create the L1 page table.
-       static_assert(KERNBASE % L1PGSIZE == 0);
-
-       // KERNBASE mapping
-       for(uintptr_t i = 0; i < KERNSIZE/L1PGSIZE; i++)
-               l1pt_phys[i+KERNBASE/L1PGSIZE] = PTE(LA2PPN(i*L1PGSIZE), PTE_KERN_RW|PTE_E);
-       #endif
-
-       lcr3(l1pt_phys);
-       mtpcr(PCR_SR, mfpcr(PCR_SR) | SR_VM);
-}
-
-static void
-mmu_init_cleanup()
-{
-       // after relocation, we no longer rely on the identity mapping
-       for(uintptr_t i = 0; i < (KERNSIZE+L1PGSIZE-1)/L1PGSIZE; i++)
-               l1pt_phys[i] = 0;
-       tlbflush();
-}
-
-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));
-}
diff --git a/kern/arch/riscv/cboot.c b/kern/arch/riscv/cboot.c
new file mode 100644 (file)
index 0000000..f921663
--- /dev/null
@@ -0,0 +1,111 @@
+#include <multiboot.h>
+#include <ros/memlayout.h>
+#include <arch/arch.h>
+#include <arch/mmu.h>
+#include <string.h>
+#include <assert.h>
+
+static void
+build_multiboot_info(multiboot_info_t* mbi)
+{
+       long memsize_kb = mfpcr(PCR_MEMSIZE)*(PGSIZE/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;
+}
+
+#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[NPTENTRIES]
+      __attribute__((section("data"))) __attribute__((aligned(PGSIZE)));
+#endif
+
+void
+mmu_init()
+{
+       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);
+
+       #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
+       static_assert(KERNSIZE <= L1PGSIZE);
+       static_assert(KERNBASE % L3PGSIZE == 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);
+       #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);
+       #endif
+
+       lcr3((uintptr_t)l1pt_phys);
+       mtpcr(PCR_SR, mfpcr(PCR_SR) | SR_VM);
+}
+
+static void
+mmu_init_cleanup()
+{
+       // 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();
+}
+
+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));
+}
diff --git a/kern/arch/riscv/colored_caches.c b/kern/arch/riscv/colored_caches.c
new file mode 100644 (file)
index 0000000..e2143ac
--- /dev/null
@@ -0,0 +1,42 @@
+/* Copyright (c) 2009 The Regents of the University  of California. 
+ * See the COPYRIGHT files at the top of this source tree for full 
+ * license information.
+ * 
+ * Kevin Klues <klueska@cs.berkeley.edu>    
+ */
+
+#include <colored_caches.h>
+#include <stdio.h>
+
+#ifdef __SHARC__
+#pragma nosharc
+#endif
+
+// Global variables
+static cache_t l1,l2,l3;
+cache_t* llc_cache;
+available_caches_t available_caches;
+
+/************** Cache Related Functions  *****************/
+void cache_init() 
+{
+       // Initialize the caches available on this system.
+       // TODO: Should call out to something reading the acpi tables from 
+       // memory, or something similar.  For now, just initialize them inline
+       available_caches.l1 = SINIT(&l1);
+       available_caches.l2 = SINIT(&l2);
+       available_caches.l3 = SINIT(&l3);
+       llc_cache = &l3;
+       init_cache_properties(&l1,   32,  8, 64);
+       init_cache_properties(&l2,  256,  8, 64);
+       init_cache_properties(&l3, 8192, 16, 64);
+       printk("Cache init successful\n");
+}
+
+void cache_color_alloc_init()
+{
+       init_free_cache_colors_map(&l1);
+       init_free_cache_colors_map(&l2);
+       init_free_cache_colors_map(&l3);
+}
+
index 844cded..0c68ce5 100644 (file)
@@ -35,6 +35,30 @@ save_kernel_tf_asm:
 
   .end  save_kernel_tf_asm
 
+  .text
+  .ent    pop_kernel_tf
+  .global pop_kernel_tf
+pop_kernel_tf:
+  LOAD  $t0,32*REGBYTES($a0)
+  LOAD  $ra,33*REGBYTES($x2)
+
+  LOAD  $s0,20*REGBYTES($a0)
+  LOAD  $s1,21*REGBYTES($a0)
+  LOAD  $s2,22*REGBYTES($a0)
+  LOAD  $s3,23*REGBYTES($a0)
+  LOAD  $s4,24*REGBYTES($a0)
+  LOAD  $s5,25*REGBYTES($a0)
+  LOAD  $s6,26*REGBYTES($a0)
+  LOAD  $s7,27*REGBYTES($a0)
+  LOAD  $s8,28*REGBYTES($a0)
+  LOAD  $s9,29*REGBYTES($a0)
+  LOAD  $sp,30*REGBYTES($a0)
+
+  mtpcr  $t0,ASM_CR(PCR_SR)
+       ret
+
+  .end  pop_kernel_tf
+
   .ent  save_tf
 save_tf:  # write the trap frame onto the stack
 
@@ -97,9 +121,9 @@ save_tf:  # write the trap frame onto the stack
   ret
   .end  save_tf
 
-  .globl  pop_tf
-  .ent  pop_tf
-pop_tf:  # write the trap frame onto the stack
+  .globl  env_pop_tf
+  .ent  env_pop_tf
+env_pop_tf:  # write the trap frame onto the stack
   # restore gprs
   LOAD  $t0,32*REGBYTES($a0)  # restore sr (should disable interrupts)
   mtpcr  $t0,ASM_CR(PCR_SR)
@@ -145,7 +169,7 @@ pop_tf:  # write the trap frame onto the stack
   mfpcr $x1,ASM_CR(PCR_K0)
   mfpcr $x2,ASM_CR(PCR_K1)
   eret
-  .end  pop_tf
+  .end  env_pop_tf
 
   .global  trap_entry
   .ent  trap_entry
diff --git a/kern/arch/riscv/env.c b/kern/arch/riscv/env.c
new file mode 100644 (file)
index 0000000..953d4eb
--- /dev/null
@@ -0,0 +1,165 @@
+#include <arch/trap.h>
+#include <env.h>
+#include <assert.h>
+#include <arch/arch.h>
+#include <pmap.h>
+
+void
+env_push_ancillary_state(env_t* e)
+{
+       if(e->env_tf.sr & SR_EF)
+               save_fp_state(&e->env_ancillary_state);
+}
+
+void
+save_fp_state(ancillary_state_t* silly)
+{
+       uintptr_t sr = mfpcr(PCR_SR);
+       mtpcr(PCR_SR, sr | SR_EF);
+
+       asm("mffsr %0" : "=r"(silly->fsr));
+
+       asm("fsd $f0,%0" : "=m"(silly->fpr[0]));
+       asm("fsd $f1,%0" : "=m"(silly->fpr[1]));
+       asm("fsd $f2,%0" : "=m"(silly->fpr[2]));
+       asm("fsd $f3,%0" : "=m"(silly->fpr[3]));
+       asm("fsd $f4,%0" : "=m"(silly->fpr[4]));
+       asm("fsd $f5,%0" : "=m"(silly->fpr[5]));
+       asm("fsd $f6,%0" : "=m"(silly->fpr[6]));
+       asm("fsd $f7,%0" : "=m"(silly->fpr[7]));
+       asm("fsd $f8,%0" : "=m"(silly->fpr[8]));
+       asm("fsd $f9,%0" : "=m"(silly->fpr[9]));
+       asm("fsd $f10,%0" : "=m"(silly->fpr[10]));
+       asm("fsd $f11,%0" : "=m"(silly->fpr[11]));
+       asm("fsd $f12,%0" : "=m"(silly->fpr[12]));
+       asm("fsd $f13,%0" : "=m"(silly->fpr[13]));
+       asm("fsd $f14,%0" : "=m"(silly->fpr[14]));
+       asm("fsd $f15,%0" : "=m"(silly->fpr[15]));
+       asm("fsd $f16,%0" : "=m"(silly->fpr[16]));
+       asm("fsd $f17,%0" : "=m"(silly->fpr[17]));
+       asm("fsd $f18,%0" : "=m"(silly->fpr[18]));
+       asm("fsd $f19,%0" : "=m"(silly->fpr[19]));
+       asm("fsd $f20,%0" : "=m"(silly->fpr[20]));
+       asm("fsd $f21,%0" : "=m"(silly->fpr[21]));
+       asm("fsd $f22,%0" : "=m"(silly->fpr[22]));
+       asm("fsd $f23,%0" : "=m"(silly->fpr[23]));
+       asm("fsd $f24,%0" : "=m"(silly->fpr[24]));
+       asm("fsd $f25,%0" : "=m"(silly->fpr[25]));
+       asm("fsd $f26,%0" : "=m"(silly->fpr[26]));
+       asm("fsd $f27,%0" : "=m"(silly->fpr[27]));
+       asm("fsd $f28,%0" : "=m"(silly->fpr[28]));
+       asm("fsd $f29,%0" : "=m"(silly->fpr[29]));
+       asm("fsd $f30,%0" : "=m"(silly->fpr[30]));
+       asm("fsd $f31,%0" : "=m"(silly->fpr[31]));
+
+       mtpcr(PCR_SR, sr);
+}
+
+void
+env_pop_ancillary_state(env_t* e)
+{ 
+       if(e->env_tf.sr & SR_EF)
+               restore_fp_state(&e->env_ancillary_state);
+}
+
+void
+restore_fp_state(ancillary_state_t* silly)
+{
+       uintptr_t sr = mfpcr(PCR_SR);
+       mtpcr(PCR_SR, sr | SR_EF);
+
+       asm("mtfsr %0" : : "r"(silly->fsr));
+
+       asm("fld $f0,%0" : : "m"(silly->fpr[0]));
+       asm("fld $f1,%0" : : "m"(silly->fpr[1]));
+       asm("fld $f2,%0" : : "m"(silly->fpr[2]));
+       asm("fld $f3,%0" : : "m"(silly->fpr[3]));
+       asm("fld $f4,%0" : : "m"(silly->fpr[4]));
+       asm("fld $f5,%0" : : "m"(silly->fpr[5]));
+       asm("fld $f6,%0" : : "m"(silly->fpr[6]));
+       asm("fld $f7,%0" : : "m"(silly->fpr[7]));
+       asm("fld $f8,%0" : : "m"(silly->fpr[8]));
+       asm("fld $f9,%0" : : "m"(silly->fpr[9]));
+       asm("fld $f10,%0" : : "m"(silly->fpr[10]));
+       asm("fld $f11,%0" : : "m"(silly->fpr[11]));
+       asm("fld $f12,%0" : : "m"(silly->fpr[12]));
+       asm("fld $f13,%0" : : "m"(silly->fpr[13]));
+       asm("fld $f14,%0" : : "m"(silly->fpr[14]));
+       asm("fld $f15,%0" : : "m"(silly->fpr[15]));
+       asm("fld $f16,%0" : : "m"(silly->fpr[16]));
+       asm("fld $f17,%0" : : "m"(silly->fpr[17]));
+       asm("fld $f18,%0" : : "m"(silly->fpr[18]));
+       asm("fld $f19,%0" : : "m"(silly->fpr[19]));
+       asm("fld $f20,%0" : : "m"(silly->fpr[20]));
+       asm("fld $f21,%0" : : "m"(silly->fpr[21]));
+       asm("fld $f22,%0" : : "m"(silly->fpr[22]));
+       asm("fld $f23,%0" : : "m"(silly->fpr[23]));
+       asm("fld $f24,%0" : : "m"(silly->fpr[24]));
+       asm("fld $f25,%0" : : "m"(silly->fpr[25]));
+       asm("fld $f26,%0" : : "m"(silly->fpr[26]));
+       asm("fld $f27,%0" : : "m"(silly->fpr[27]));
+       asm("fld $f28,%0" : : "m"(silly->fpr[28]));
+       asm("fld $f29,%0" : : "m"(silly->fpr[29]));
+       asm("fld $f30,%0" : : "m"(silly->fpr[30]));
+       asm("fld $f31,%0" : : "m"(silly->fpr[31]));
+
+       mtpcr(PCR_SR, sr);
+}
+
+static int
+user_mem_walk_recursive(env_t* e, uintptr_t start, size_t len,
+                        mem_walk_callback_t callback, void* arg,
+                        mem_walk_callback_t pt_callback, void* pt_arg,
+                                                                                               pte_t* pt, int level)
+{
+  int pgshift = L1PGSHIFT - level*(L1PGSHIFT-L2PGSHIFT);
+       uintptr_t pgsize = 1UL << pgshift;
+
+       uintptr_t start_idx = (start >> pgshift) & (NPTENTRIES-1);
+       uintptr_t end_idx = (ROUNDUP(start+len, pgsize) >> pgshift) & (NPTENTRIES-1);
+
+       for(uintptr_t idx = start_idx; idx < end_idx; idx++)
+       {
+               int ret;
+               uintptr_t pgaddr = ROUNDDOWN(start, pgsize) + idx*pgsize;
+               pte_t* pte = &pt[idx];
+
+               if(*pte & PTE_T)
+               {
+                       assert(level < NPTLEVELS-1);
+                       if((ret = user_mem_walk_recursive(e, pgaddr, MIN(pgsize, start+len),
+                                                         callback, arg,
+                                                                                                                                                               pt_callback, pt_arg,
+                                                                                                                                                               KADDR(PTD_ADDR(*pte)), level+1)))
+                               return ret;
+                       if(pt_callback != NULL && (ret = pt_callback(e, pte, (void*)pgaddr, arg)))
+                               return ret;
+               }
+               else if(callback != NULL && !PAGE_UNMAPPED(*pte))
+                       if((ret = callback(e, pte, (void*)pgaddr, arg)))
+                               return ret;
+       }
+
+       return 0;
+}
+
+int
+env_user_mem_walk(env_t* e, void* start, size_t len,
+                  mem_walk_callback_t callback, void* arg)
+{
+       return user_mem_walk_recursive(e, (uintptr_t)start, len, callback, arg,
+                                      NULL, NULL, e->env_pgdir, 0);
+}
+
+void
+env_pagetable_free(env_t* e)
+{
+       int pt_free(env_t* e, pte_t* pte, void* va, void* arg)
+       {
+               page_decref(pa2page(PTD_ADDR(*pte)));
+               return 0;
+       }
+
+       assert(user_mem_walk_recursive(e, 0, KERNBASE, NULL, NULL,
+                                      pt_free, NULL, e->env_pgdir, 0) == 0);
+}
diff --git a/kern/arch/riscv/i686 b/kern/arch/riscv/i686
deleted file mode 120000 (symlink)
index 7f061e5..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../arch/i686
\ No newline at end of file
diff --git a/kern/arch/riscv/init.c b/kern/arch/riscv/init.c
new file mode 100644 (file)
index 0000000..cade583
--- /dev/null
@@ -0,0 +1,10 @@
+/* See COPYRIGHT for copyright information. */
+
+#include <smp.h>
+#include <arch/init.h>
+
+void arch_init()
+{              
+       smp_boot();
+       proc_init();
+}
index bc58e22..15d77ab 100644 (file)
 #define L4X(la)                ((((uintptr_t) (la)) >> L4PGSHIFT) & (NPTENTRIES-1))
 
 // construct linear address from indexes and offset
-#define PGADDR(l1, l2, l3, l4, o) ((void*) ((l1) << L1PGSHIFT | (l2) << L2PGSHIFT | (l3) << L3PGSHIFT | (l4) << L4PGSHIFT | (o)))
+#define PGADDR(l1, l2, l3, l4, o) ((uintptr_t) ((l1) << L1PGSHIFT | (l2) << L2PGSHIFT | (l3) << L3PGSHIFT | (l4) << L4PGSHIFT | (o)))
 #else
 // construct linear address from indexes and offset
-#define PGADDR(l1, l2, o) ((void*) ((l1) << L1PGSHIFT | (l2) << L2PGSHIFT | (o)))
+#define PGADDR(l1, l2, o) ((uintptr_t) ((l1) << L1PGSHIFT | (l2) << L2PGSHIFT | (o)))
 #endif
 
 // offset in page
diff --git a/kern/arch/riscv/page_alloc.c b/kern/arch/riscv/page_alloc.c
new file mode 100644 (file)
index 0000000..d109a4a
--- /dev/null
@@ -0,0 +1,83 @@
+/* Copyright (c) 2009 The Regents of the University  of California. 
+ * See the COPYRIGHT files at the top of this source tree for full 
+ * license information.
+ * 
+ * Kevin Klues <klueska@cs.berkeley.edu>    
+ */
+#ifdef __SHARC__
+#pragma nosharc
+#endif
+
+#ifdef __DEPUTY__
+#pragma nodeputy
+#endif
+
+#include <sys/queue.h>
+#include <page_alloc.h>
+#include <pmap.h>
+#include <kmalloc.h>
+#include <multiboot.h>
+#include <colored_caches.h>
+
+page_list_t *COUNT(llc_cache->num_colors) colored_page_free_list = NULL;
+spinlock_t colored_page_free_list_lock;
+
+void page_alloc_bootstrap() {
+       // Allocate space for the array required to manage the free lists
+       size_t list_size = llc_cache->num_colors*sizeof(page_list_t);
+       colored_page_free_list = (page_list_t*) boot_alloc(list_size, PGSIZE);
+}
+
+/*
+ * Initialize the memory free lists.
+ * After this point, ONLY use the functions below
+ * to allocate and deallocate physical memory via the 
+ * page_free_lists. 
+ */
+void page_alloc_init() 
+{
+       // First Bootstrap the page alloc process
+       static bool bootstrapped = FALSE;
+       if(!bootstrapped) {
+               bootstrapped = TRUE;
+               page_alloc_bootstrap();
+       }
+
+       // Then, initialize the array required to manage the 
+               // colored page free list
+       for(int i=0; i<llc_cache->num_colors; i++) {
+               LIST_INIT(&(colored_page_free_list[i]));
+       }
+       
+       //  Finally, mark the pages already in use by the kernel. 
+       //  1) Mark page 0 as in use.
+       //     This way we preserve the real-mode IDT and BIOS structures
+       //     in case we ever need them.  (Currently we don't, but...)
+       //  2) Mark the rest of base memory as free.
+       //  3) Then comes the IO hole [IOPHYSMEM, EXTPHYSMEM).
+       //     Mark it as in use so that it can never be allocated.      
+       //  4) Then extended memory [EXTPHYSMEM, ...).
+       //     Some of it is in use, some is free.
+       uintptr_t i;
+       physaddr_t physaddr_after_kernel = PADDR(ROUNDUP(boot_freemem, PGSIZE));
+
+       // mark [0, physaddr_after_kernel) as in-use
+       for(i = 0; i < LA2PPN(physaddr_after_kernel); i++)
+               page_setref(&pages[i], 1);
+
+       // mark [physaddr_after_kernel, maxaddrpa) as free
+       for(i = LA2PPN(physaddr_after_kernel); i < LA2PPN(maxaddrpa); i++)
+       {
+               page_setref(&pages[i], 0);
+               LIST_INSERT_HEAD(
+                  &(colored_page_free_list[get_page_color(i,llc_cache)]),
+                  &pages[i],
+                  pg_link
+               );
+       }
+
+       // mark [maxaddrpa, ...) as in-use (as they are invalid)
+       for(i = LA2PPN(maxaddrpa); i < npages; i++)
+               page_setref(&pages[i], 1);
+}
index a4defef..5eb5b43 100644 (file)
@@ -10,7 +10,9 @@
 #define SR_UX    0x0000000000000040
 #define SR_SX    0x0000000000000080
 #define SR_IM    0x000000000000FF00
-#define SR_IM7   0x0000000000008000
+#define SR_VM    0x0000000000010000
+
+#define SR_IM_SHIFT 8
 
 #define PCR_SR       0
 #define PCR_EPC      1
@@ -19,6 +21,7 @@
 #define PCR_COUNT    4
 #define PCR_COMPARE  5
 #define PCR_CAUSE    6
+#define PCR_IPI      7
 #define PCR_MEMSIZE  8
 #define PCR_PTBR     9
 #define PCR_TOHOST   16
 #define MEMSIZE_SHIFT 12
 
 #define TIMER_PERIOD 0x1000
+
+#define IPI_IRQ   5
 #define TIMER_IRQ 7
+#define NIRQ 8
 
 #define CAUSE_EXCCODE 0x000000FF
 #define CAUSE_IP      0x0000FF00
diff --git a/kern/arch/riscv/pmap.c b/kern/arch/riscv/pmap.c
new file mode 100644 (file)
index 0000000..54c80af
--- /dev/null
@@ -0,0 +1,104 @@
+/* See COPYRIGHT for copyright information. */
+#include <arch/arch.h>
+#include <arch/mmu.h>
+
+#include <error.h>
+#include <sys/queue.h>
+
+#include <atomic.h>
+#include <string.h>
+#include <assert.h>
+#include <pmap.h>
+#include <kclock.h>
+#include <env.h>
+#include <stdio.h>
+#include <kmalloc.h>
+#include <page_alloc.h>
+
+pde_t* boot_pgdir;             // Virtual address of boot time page directory
+physaddr_t boot_cr3;           // Physical address of boot time page directory
+page_t* pages = NULL;          // Virtual address of physical page array
+
+// --------------------------------------------------------------
+// Set up initial memory mappings and turn on MMU.
+// --------------------------------------------------------------
+
+void
+vm_init(void)
+{
+       // we already set up our page tables before jumping
+       // into the kernel, so there's not much going on here
+
+       extern pte_t l1pt[NPTENTRIES];
+       boot_pgdir = l1pt;
+       boot_cr3 = PADDR(boot_pgdir);
+}
+
+// Given 'pgdir', a pointer to a page directory, pgdir_walk returns
+// a pointer to the page table entry (PTE) for linear address 'va'.
+// This requires walking the two-level page table structure.
+//
+// If the relevant page table doesn't exist in the page directory, then:
+//    - If create == 0, pgdir_walk returns NULL.
+//    - Otherwise, pgdir_walk tries to allocate a new page table
+//     with page_alloc.  If this fails, pgdir_walk returns NULL.
+//    - Otherwise, pgdir_walk returns a pointer into the new page table.
+//
+// This is boot_pgdir_walk, but using page_alloc() instead of boot_alloc().
+// Unlike boot_pgdir_walk, pgdir_walk can fail.
+pte_t*
+pgdir_walk(pde_t *pgdir, const void *SNT va, int create)
+{
+  pte_t* ppte[NPTLEVELS];
+       pte_t* pt[NPTLEVELS];
+
+       pt[0] = pgdir;
+       for(int i = 0; i < NPTLEVELS-1; i++)
+       {
+         // this code relies upon the fact that all page tables are the same size
+         uintptr_t idx = (uintptr_t)va >> (L1PGSHIFT - i*(L1PGSHIFT-L2PGSHIFT));
+               idx = idx & (NPTENTRIES-1);
+
+               ppte[i] = &pt[i][idx];
+
+               if(*ppte[i] & PTE_E)
+                       return ppte[i];
+
+       if(!(*ppte[i] & PTE_T))
+               {
+                       if(!create)
+                               return NULL;
+
+                       page_t *new_table;
+                       if(kpage_alloc(&new_table))
+                               return NULL;
+                       memset(page2kva(new_table), 0, PGSIZE);
+
+                       *ppte[i] = PTD(page2pa(new_table));
+               }
+
+               pt[i+1] = (pte_t*)KADDR(PTD_ADDR(*ppte[i]));
+       }
+
+       uintptr_t idx = (uintptr_t)va >> (L1PGSHIFT - (NPTLEVELS-1)*(L1PGSHIFT-L2PGSHIFT));
+       idx = idx & (NPTENTRIES-1);
+  return &pt[NPTLEVELS-1][idx];
+}
+
+/* Returns the effective permissions for PTE_U, PTE_W, and PTE_P on a given
+ * virtual address. */
+int get_va_perms(pde_t *pgdir, const void *SNT va)
+{
+       pte_t* pte = pgdir_walk(pgdir, va, 0);
+       return pte == NULL ? 0 : (*pte & (PTE_PERM | PTE_E));
+}
+
+void
+page_check(void)
+{
+}
+
+void* mmio_alloc(physaddr_t pa, size_t size)
+{
+       return NULL;
+}
diff --git a/kern/arch/riscv/process.c b/kern/arch/riscv/process.c
new file mode 100644 (file)
index 0000000..93209bb
--- /dev/null
@@ -0,0 +1,42 @@
+#include <arch/arch.h>
+#include <arch/trap.h>
+#include <process.h>
+#include <pmap.h>
+#include <smp.h>
+
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+
+void proc_init_trapframe(trapframe_t *tf, uint32_t vcoreid,
+                         uintptr_t entryp, uintptr_t stack_top)
+{
+       memset(tf, 0, sizeof(*tf));
+
+       tf->gpr[30] = stack_top-64;
+       tf->sr = SR_S | SR_IM;
+
+       tf->epc = entryp;
+
+       /* Coupled closely with user's entry.S.  id is the vcoreid, which entry.S
+        * uses to determine what to do.  vcoreid == 0 is the main core/context. */
+       tf->gpr[4] = vcoreid;
+}
+
+void proc_secure_trapframe(struct trapframe *tf)
+{
+  tf->sr = SR_S | SR_IM;
+}
+
+/* Called when we are currently running an address space on our core and want to
+ * abandon it.  We need a known good pgdir before releasing the old one.  We
+ * decref, since current no longer tracks the proc (and current no longer
+ * protects the cr3).  We also need to clear out the TLS registers (before
+ * unmapping the address space!) */
+void __abandon_core(void)
+{
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       lcr3(boot_cr3);
+       proc_decref(pcpui->cur_proc);
+       pcpui->cur_proc = 0;
+}
index 7f8e7d4..a4964c2 100644 (file)
@@ -23,4 +23,10 @@ read_pc(void)
   return pc;
 }
 
+static __inline void
+send_ipi(uint32_t who)
+{
+  mtpcr(PCR_IPI, who);
+}
+
 #endif
index 7360c57..7690649 100644 (file)
@@ -1,23 +1,23 @@
-#ifndef _ROS_ARCH_MMU_H
-#define _ROS_ARCH_MMU_H
+#ifndef ROS_INC_MMU_H
+#define ROS_INC_MMU_H
 
 // All physical memory mapped at this address
 #ifdef __riscv64
 # define KERNBASE  0xFFFFFF8000000000
-# define NLEVELS                    4
+# define NPTLEVELS                  4
 # define L1PGSHIFT         (12+9+9+9)
-# define L1PGSIZE    (1 << L1PGSHIFT)
+# define L1PGSIZE   (1L << L1PGSHIFT)
 # define L2PGSHIFT           (12+9+9)
-# define L2PGSIZE    (1 << L2PGSHIFT)
+# define L2PGSIZE   (1L << L2PGSHIFT)
 # define L3PGSHIFT             (12+9)
-# define L3PGSIZE    (1 << L3PGSHIFT)
+# define L3PGSIZE   (1L << L3PGSHIFT)
 # define L4PGSHIFT               (12)
-# define L4PGSIZE    (1 << L4PGSHIFT)
+# define L4PGSIZE   (1L << L4PGSHIFT)
 # define PGSHIFT            L4PGSHIFT
 # define KPGSHIFT           L3PGSHIFT
 #else
 # define KERNBASE          0x80000000
-# define NLEVELS                    2
+# define NPTLEVELS                  2
 # define L1PGSHIFT            (12+10)
 # define L1PGSIZE    (1 << L1PGSHIFT)
 # define L2PGSHIFT                 12
diff --git a/kern/arch/riscv/smp.c b/kern/arch/riscv/smp.c
new file mode 100644 (file)
index 0000000..c8769e0
--- /dev/null
@@ -0,0 +1,147 @@
+#include <smp.h>
+#include <arch/arch.h>
+#include <arch/smp.h>
+#include <stdio.h>
+#include <string.h>
+#include <error.h>
+#include <assert.h>
+#include <atomic.h>
+
+volatile uint32_t num_cpus;
+
+void
+smp_boot(void)
+{
+       num_cpus = 1;
+       printd("Cores, report in!\n");
+
+       smp_percpu_init();
+
+       //while(*(volatile uint32_t*)&num_cpus < num_cores());
+
+       printd("%d cores reporting!\n",num_cpus);
+}
+
+void
+smp_init(void)
+{
+       static spinlock_t report_in_lock = SPINLOCK_INITIALIZER;
+
+       smp_percpu_init();
+       spin_lock(&report_in_lock);
+       num_cpus++;
+       spin_unlock(&report_in_lock);
+
+       printd("Good morning, Vietnam! (core id = %d)\n",core_id());
+
+       smp_idle();
+}
+
+handler_wrapper_t*
+smp_make_wrapper()
+{
+       static handler_wrapper_t
+       wrapper_pool[MAX_NUM_CPUS*8] = {{{0},SPINLOCK_INITIALIZER}};
+
+       size_t i;
+       for(i = 0; i < sizeof(wrapper_pool)/sizeof(wrapper_pool[0]); i++)
+               if(spin_trylock(&wrapper_pool[i].lock) == 0)
+                       return &wrapper_pool[i];
+       return NULL;
+}
+
+void
+smp_call_wrapper(trapframe_t* tf, uint32_t src, isr_t handler,
+                 handler_wrapper_t* wrapper,void* data)
+{
+       if(wrapper)
+               wrapper->wait_list[core_id()] = 0;
+       handler(tf,data);
+}
+
+int smp_call_function_self(isr_t handler, void* data,
+                           handler_wrapper_t** wait_wrapper)
+{
+       return smp_call_function_single(core_id(),handler,data,wait_wrapper);
+}
+
+int smp_call_function_all(isr_t handler, void* data,
+                          handler_wrapper_t** wait_wrapper)
+{
+       int8_t state = 0;
+       int i;
+       handler_wrapper_t* wrapper = 0;
+       if(wait_wrapper)
+       {
+               wrapper = *wait_wrapper = smp_make_wrapper();
+               if(!wrapper)
+                       return -ENOMEM;
+
+               for(i = 0; i < num_cpus; i++)
+                       wrapper->wait_list[i] = 1;
+       }
+
+       enable_irqsave(&state);
+
+       // send to others
+       for(i = 0; i < num_cpus; i++)
+       {
+               if(i == core_id())
+                       continue;
+
+               send_kernel_message(i,(amr_t)smp_call_wrapper,
+                                         handler, wrapper, data, KMSG_IMMEDIATE);
+       }
+
+       // send to me
+       send_kernel_message(core_id(),(amr_t)smp_call_wrapper,
+                                 handler,wrapper,data, KMSG_IMMEDIATE);
+
+       cpu_relax(); // wait to get the interrupt
+
+       disable_irqsave(&state);
+
+       return 0;
+}
+
+int smp_call_function_single(uint32_t dest, isr_t handler, void* data,
+                             handler_wrapper_t** wait_wrapper)
+{
+       int8_t state = 0;
+       handler_wrapper_t* wrapper = 0;
+       if(wait_wrapper)
+       {
+               wrapper = *wait_wrapper = smp_make_wrapper();
+               if(!wrapper)
+                       return -ENOMEM;
+               wrapper->wait_list[dest] = 1;
+       }
+
+       enable_irqsave(&state);
+
+       send_kernel_message(dest,(amr_t)smp_call_wrapper,
+                                 handler,wrapper,data, KMSG_IMMEDIATE);
+
+       cpu_relax(); // wait to get the interrupt, if it's to this core
+
+       disable_irqsave(&state);
+
+       return 0;
+}
+
+int smp_call_wait(handler_wrapper_t* wrapper)
+{
+       int i;
+       for(i = 0; i < num_cpus; i++)
+               while(wrapper->wait_list[i]);
+
+       spin_unlock(&wrapper->lock);
+       return 0;
+}
+
+/* Perform any initialization needed by per_cpu_info.  Right now, this just
+ * inits the amsg list (which sparc will probably also want).  Make sure every
+ * core calls this at some point in the smp_boot process. */
+void __arch_pcpu_init(uint32_t coreid)
+{
+}
index 62da4eb..b71f0de 100644 (file)
@@ -1,22 +1,16 @@
-/*
- * Copyright (c) 2009 The Regents of the University of California
- * Barret Rhoden <brho@cs.berkeley.edu>
- * See LICENSE for details.
- */
-
 #ifndef ROS_ARCH_SMP_H
 #define ROS_ARCH_SMP_H
 
+#include <ros/common.h>
+#include <arch/arch.h>
 #include <atomic.h>
 
-// be careful changing this, esp if you go over 16
-#define NUM_HANDLER_WRAPPERS           5
-
-struct HandlerWrapper {
-       checklist_t* cpu_list;
-       uint8_t vector;
-};
+typedef volatile uint8_t wait_list_t[MAX_NUM_CPUS];
 
-typedef struct HandlerWrapper LCKD(&cpu_list->lock) handler_wrapper_t;
+typedef struct
+{
+       wait_list_t wait_list;
+       spinlock_t lock;
+} handler_wrapper_t;
 
 #endif /* !ROS_ARCH_SMP_H */
index 0e26ea5..6cbb4cd 100644 (file)
@@ -12,7 +12,7 @@ timer_init(void)
 {      
   mtpcr(PCR_COUNT, 0);
   mtpcr(PCR_COMPARE, 0);
-       mtpcr(PCR_SR, mfpcr(PCR_SR) | SR_IM7);
+       mtpcr(PCR_SR, mfpcr(PCR_SR) | (SR_IM & (1 << (TIMER_IRQ+SR_IM_SHIFT))));
 
        system_timing.tsc_freq = TSC_HZ;
        cprintf("TSC Frequency: %llu\n", system_timing.tsc_freq);
@@ -26,7 +26,7 @@ set_core_timer(uint32_t usec, bool periodic)
 {
        uint32_t clocks =  (uint64_t)usec*TSC_HZ/1000000;
 
-  uint8_t irq_state = 0;
+  int8_t irq_state = 0;
        disable_irqsave(&irq_state);
 
   mtpcr(PCR_COMPARE, mfpcr(PCR_COUNT) + clocks);
diff --git a/kern/arch/riscv/trap.c b/kern/arch/riscv/trap.c
new file mode 100644 (file)
index 0000000..8519e5a
--- /dev/null
@@ -0,0 +1,437 @@
+#include <arch/arch.h>
+#include <assert.h>
+#include <arch/trap.h>
+#include <string.h>
+#include <process.h>
+#include <syscall.h>
+#include <monitor.h>
+#include <manager.h>
+#include <stdio.h>
+#include <smp.h>
+#include <slab.h>
+#include <mm.h>
+#include <ros/mman.h>
+#include <umem.h>
+#include <pmap.h>
+
+/* These are the stacks the kernel will load when it receives a trap from user
+ * space.  The deal is that they get set right away in entry.S, and can always
+ * be used for finding the top of the stack (from which you should subtract the
+ * sizeof the trapframe.  Note, we need to have a junk value in the array so
+ * that this is NOT part of the BSS.  If it is in the BSS, it will get 0'd in
+ * kernel_init(), which is after these values get set.
+ *
+ * TODO: if these end up becoming contended cache lines, move this to
+ * per_cpu_info. */
+uintptr_t core_stacktops[MAX_NUM_CPUS] = {0xcafebabe, 0};
+
+struct kmem_cache *kernel_msg_cache;
+void kernel_msg_init(void)
+{
+       kernel_msg_cache = kmem_cache_create("kernel_msgs",
+                          sizeof(struct kernel_message), HW_CACHE_ALIGN, 0, 0, 0);
+}
+
+spinlock_t kernel_message_buf_busy[MAX_NUM_CPUS] = {SPINLOCK_INITIALIZER};
+kernel_message_t kernel_message_buf[MAX_NUM_CPUS];
+
+/* This is mostly identical to x86's, minus the different send_ipi call. */
+uint32_t send_kernel_message(uint32_t dst, amr_t pc,
+                             TV(a0t) arg0, TV(a1t) arg1, TV(a2t) arg2, int type)
+{
+       kernel_message_t *k_msg;
+       assert(pc);
+       // note this will be freed on the destination core
+       k_msg = (kernel_message_t *CT(1))TC(kmem_cache_alloc(kernel_msg_cache, 0));
+       k_msg->srcid = core_id();
+       k_msg->pc = pc;
+       k_msg->arg0 = arg0;
+       k_msg->arg1 = arg1;
+       k_msg->arg2 = arg2;
+       switch (type) {
+               case KMSG_IMMEDIATE:
+                       spin_lock_irqsave(&per_cpu_info[dst].immed_amsg_lock);
+                       STAILQ_INSERT_TAIL(&per_cpu_info[dst].immed_amsgs, k_msg, link);
+                       spin_unlock_irqsave(&per_cpu_info[dst].immed_amsg_lock);
+                       break;
+               case KMSG_ROUTINE:
+                       spin_lock_irqsave(&per_cpu_info[dst].routine_amsg_lock);
+                       STAILQ_INSERT_TAIL(&per_cpu_info[dst].routine_amsgs, k_msg, link);
+                       spin_unlock_irqsave(&per_cpu_info[dst].routine_amsg_lock);
+                       break;
+               default:
+                       panic("Unknown type of kernel message!");
+       }
+       /* if we're sending a routine message locally, we don't want/need an IPI */
+       if ((dst != k_msg->srcid) || (type == KMSG_IMMEDIATE))
+               send_ipi(dst);
+       return 0;
+}
+
+void
+advance_pc(trapframe_t* state)
+{
+       state->epc += 4;
+}
+
+/* Set stacktop for the current core to be the stack the kernel will start on
+ * when trapping/interrupting from userspace */
+void set_stack_top(uintptr_t stacktop)
+{
+       core_stacktops[core_id()] = stacktop;
+}
+
+/* Note the assertion assumes we are in the top page of the stack. */
+uintptr_t get_stack_top(void)
+{
+       uintptr_t sp, stacktop;
+       stacktop = core_stacktops[core_id()];
+       asm volatile("move %0,$sp" : "=r"(sp));
+       assert(ROUNDUP(sp, PGSIZE) == stacktop);
+       return stacktop;
+}
+
+void
+idt_init(void)
+{
+}
+
+void
+sysenter_init(void)
+{
+}
+
+/* Helper.  For now, this copies out the TF to pcpui, and sets the tf to use it.
+ * Eventually, we ought to do this in trap_entry.S.  Honestly, do whatever you
+ * want with this.  The **tf is for convenience in x86. */
+static void set_current_tf(struct per_cpu_info *pcpui, struct trapframe **tf)
+{
+       pcpui->actual_tf = **tf;
+       pcpui->cur_tf = &pcpui->actual_tf;
+       *tf = &pcpui->actual_tf;
+}
+
+static int
+format_trapframe(trapframe_t *tf, char* buf, int bufsz)
+{
+       // slightly hackish way to read out the instruction that faulted.
+       // not guaranteed to be right 100% of the time
+       uint32_t insn;
+       if(!(current && !memcpy_from_user(current,&insn,(void*)tf->epc,4)))
+               insn = -1;
+
+       int len = snprintf(buf,bufsz,"TRAP frame at %p on core %d\n",
+                          tf, core_id());
+       static const char* regnames[] = {
+         "z ", "ra", "v0", "v1", "a0", "a1", "a2", "a3",
+         "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
+         "t4", "t5", "t6", "t7", "s0", "s1", "s2", "s3",
+         "s4", "s5", "s6", "s7", "s8", "fp", "sp", "tp"
+       };
+       
+       tf->gpr[0] = 0;
+       
+       for(int i = 0; i < 32; i+=4)
+       {
+               for(int j = 0; j < 4; j++)
+                       len += snprintf(buf+len, bufsz-len,
+                                       "%s %016lx%c", regnames[i+j], tf->gpr[i+j], 
+                                       j < 3 ? ' ' : '\n');
+       }
+       len += snprintf(buf+len, bufsz-len,
+                       "sr %lx pc %lx va %lx insn       %x\n", tf->sr, tf->epc,
+                       tf->badvaddr, (uint32_t)tf->insn);
+
+       return len;
+}
+
+void
+print_trapframe(trapframe_t* tf)
+{
+       char buf[1024];
+       int len = format_trapframe(tf,buf,sizeof(buf));
+       cputbuf(buf,len);
+}
+
+/* Helper function.  Returns 0 if the list was empty. */
+static kernel_message_t *get_next_amsg(struct kernel_msg_list *list_head,
+                                       spinlock_t *list_lock)
+{
+       kernel_message_t *k_msg;
+       spin_lock_irqsave(list_lock);
+       k_msg = STAILQ_FIRST(list_head);
+       if (k_msg)
+               STAILQ_REMOVE_HEAD(list_head, link);
+       spin_unlock_irqsave(list_lock);
+       return k_msg;
+}
+
+/* Mostly the same as x86's implementation.  Keep them in sync.  This assumes
+ * you can send yourself an IPI, and that IPIs can get squashed like on x86. */
+static void
+handle_ipi(trapframe_t* tf)
+{
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       if (!in_kernel(tf))
+               set_current_tf(pcpui, &tf);
+       else if((void*)tf->epc == &cpu_halt) // break out of the cpu_halt loop
+               advance_pc(tf);
+
+       per_cpu_info_t *myinfo = &per_cpu_info[core_id()];
+       kernel_message_t msg_cp, *k_msg;
+
+       while (1) { // will break out when there are no more messages
+               /* Try to get an immediate message.  Exec and free it. */
+               k_msg = get_next_amsg(&myinfo->immed_amsgs, &myinfo->immed_amsg_lock);
+               if (k_msg) {
+                       assert(k_msg->pc);
+                       k_msg->pc(tf, k_msg->srcid, k_msg->arg0, k_msg->arg1, k_msg->arg2);
+                       kmem_cache_free(kernel_msg_cache, (void*)k_msg);
+               } else { // no immediate, might be a routine
+                       if (in_kernel(tf))
+                               return; // don't execute routine msgs if we were in the kernel
+                       k_msg = get_next_amsg(&myinfo->routine_amsgs,
+                                             &myinfo->routine_amsg_lock);
+                       if (!k_msg) // no routines either
+                               return;
+                       /* copy in, and then free, in case we don't return */
+                       msg_cp = *k_msg;
+                       kmem_cache_free(kernel_msg_cache, (void*)k_msg);
+                       /* make sure an IPI is pending if we have more work */
+                       /* techincally, we don't need to lock when checking */
+                       if (!STAILQ_EMPTY(&myinfo->routine_amsgs))
+                               send_ipi(core_id());
+                       /* Execute the kernel message */
+                       assert(msg_cp.pc);
+                       msg_cp.pc(tf, msg_cp.srcid, msg_cp.arg0, msg_cp.arg1, msg_cp.arg2);
+               }
+       }
+}
+
+/* Same as in x86.  Might be diff in the future if there is no way to check for
+ * immediate messages or there is the ability to selectively mask IPI vectors.*/
+void process_routine_kmsg(struct trapframe *tf)
+{
+       per_cpu_info_t *myinfo = &per_cpu_info[core_id()];
+       kernel_message_t msg_cp, *k_msg;
+       int8_t irq_state = 0;
+
+       disable_irqsave(&irq_state);
+       /* If we were told what our TF was, use that.  o/w, go with current_tf. */
+       tf = tf ? tf : current_tf;
+       while (1) {
+               /* normally, we want ints disabled, so we don't have an empty self-ipi
+                * for every routine message. (imagine a long list of routines).  But we
+                * do want immediates to run ahead of routines.  This enabling should
+                * work (might not in some shitty VMs).  Also note we can receive an
+                * extra self-ipi for routine messages before we turn off irqs again.
+                * Not a big deal, since we will process it right away. */
+               if (!STAILQ_EMPTY(&myinfo->immed_amsgs)) {
+                       enable_irq();
+                       cpu_relax();
+                       disable_irq();
+               }
+               k_msg = get_next_amsg(&myinfo->routine_amsgs,
+                                     &myinfo->routine_amsg_lock);
+               if (!k_msg) {
+                       enable_irqsave(&irq_state);
+                       return;
+               }
+               /* copy in, and then free, in case we don't return */
+               msg_cp = *k_msg;
+               kmem_cache_free(kernel_msg_cache, (void*)k_msg);
+               /* make sure an IPI is pending if we have more work */
+               if (!STAILQ_EMPTY(&myinfo->routine_amsgs))
+                       send_ipi(core_id());
+               /* Execute the kernel message */
+               assert(msg_cp.pc);
+               msg_cp.pc(tf, msg_cp.srcid, msg_cp.arg0, msg_cp.arg1, msg_cp.arg2);
+       }
+}
+
+static void
+unhandled_trap(trapframe_t* state, const char* name)
+{
+       static spinlock_t screwup_lock = SPINLOCK_INITIALIZER;
+       spin_lock(&screwup_lock);
+
+       if(in_kernel(state))
+       {
+               print_trapframe(state);
+               panic("Unhandled trap in kernel!\nTrap type: %s", name);
+       }
+       else
+       {
+               char tf_buf[1024];
+               int tf_len = format_trapframe(state, tf_buf, sizeof(tf_buf));
+
+               warn("Unhandled trap in user!\nTrap type: %s\n%s", name, tf_buf);
+               backtrace();
+               spin_unlock(&screwup_lock);
+
+               assert(current);
+               proc_incref(current, 1);
+               proc_destroy(current);
+
+               panic("I shouldn't have gotten here!");
+       }
+}
+
+static void
+handle_timer_interrupt(trapframe_t* state)
+{
+       timer_interrupt(state, NULL);
+}
+
+static void
+handle_interrupt(trapframe_t* state)
+{
+       typedef void (*trap_handler)(trapframe_t*);
+       
+       const static trap_handler trap_handlers[NIRQ] = {
+         [TIMER_IRQ] = handle_timer_interrupt,
+         [IPI_IRQ] = handle_ipi,
+       };
+
+       int interrupts = (state->cause & CAUSE_IP) >> CAUSE_IP_SHIFT;
+
+       for(int i = 0; interrupts; interrupts >>= 1, i++)
+       {
+               if(interrupts & 1)
+               {
+                       if(trap_handlers[i])
+                               trap_handlers[i](state);
+                       else
+                       {
+                               char name[32];
+                               snprintf(name, sizeof(name), "Bad Interrupt %d", i);
+                               unhandled_trap(state, name);
+                       }
+               }
+       }
+}
+
+static void
+handle_misaligned_fetch(trapframe_t* state)
+{
+       unhandled_trap(state, "Misaligned Fetch");
+}
+
+static void
+handle_misaligned_load(trapframe_t* state)
+{
+       unhandled_trap(state, "Misaligned Load");
+}
+
+static void
+handle_misaligned_store(trapframe_t* state)
+{
+       unhandled_trap(state, "Misaligned Store");
+}
+
+static void
+handle_fault_fetch(trapframe_t* state)
+{
+       if(in_kernel(state))
+       {
+               print_trapframe(state);
+               panic("Load Page Fault in the Kernel at 0x%08x!", state->badvaddr);
+       }
+       
+       if(handle_page_fault(current, state->badvaddr, PROT_READ))
+               unhandled_trap(state, "Load Page Fault");
+}
+
+static void
+handle_fault_load(trapframe_t* state)
+{
+       if(in_kernel(state))
+       {
+               print_trapframe(state);
+               panic("Load Page Fault in the Kernel at 0x%08x!", state->badvaddr);
+       }
+       
+       if(handle_page_fault(current, state->badvaddr, PROT_READ))
+               unhandled_trap(state, "Load Page Fault");
+}
+
+static void
+handle_fault_store(trapframe_t* state)
+{
+       if(in_kernel(state))
+       {
+               print_trapframe(state);
+               panic("Store Page Fault in the Kernel at 0x%08x!", state->badvaddr);
+       }
+       
+       if(handle_page_fault(current, state->badvaddr, PROT_WRITE))
+               unhandled_trap(state, "Store Page Fault");
+}
+
+static void
+handle_illegal_instruction(trapframe_t* state)
+{
+       unhandled_trap(state, "Illegal Instruction");
+}
+
+static void
+handle_fp_disabled(trapframe_t* state)
+{
+       if(in_kernel(state))
+               panic("kernel executed an FP instruction!");
+
+       state->sr |= SR_EF;
+}
+
+static void
+handle_syscall(trapframe_t* state)
+{
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       uintptr_t a0 = state->gpr[4];
+       uintptr_t a1 = state->gpr[5];
+
+       advance_pc(state);
+       enable_irq();
+       struct per_cpu_info* coreinfo = &per_cpu_info[core_id()];
+
+       set_current_tf(pcpui, &state);
+
+       prep_syscalls(current, (struct syscall*)a0, a1);
+
+       proc_restartcore();
+}
+
+static void
+handle_breakpoint(trapframe_t* state)
+{
+       advance_pc(state);
+       monitor(state);
+}
+
+void
+handle_trap(trapframe_t* tf)
+{
+       typedef void (*trap_handler)(trapframe_t*);
+       
+       const static trap_handler trap_handlers[NUM_CAUSES] = {
+         [CAUSE_MISALIGNED_FETCH] = handle_misaligned_fetch,
+         [CAUSE_FAULT_FETCH] = handle_fault_fetch,
+         [CAUSE_ILLEGAL_INSTRUCTION] = handle_illegal_instruction,
+         [CAUSE_PRIVILEGED_INSTRUCTION] = handle_illegal_instruction,
+         [CAUSE_FP_DISABLED] = handle_fp_disabled,
+         [CAUSE_INTERRUPT] = handle_interrupt,
+         [CAUSE_SYSCALL] = handle_syscall,
+         [CAUSE_BREAKPOINT] = handle_breakpoint,
+         [CAUSE_MISALIGNED_LOAD] = handle_misaligned_load,
+         [CAUSE_MISALIGNED_STORE] = handle_misaligned_store,
+         [CAUSE_FAULT_LOAD] = handle_fault_load,
+         [CAUSE_FAULT_STORE] = handle_fault_store,
+       };
+       
+       int exccode = (tf->cause & CAUSE_EXCCODE) >> CAUSE_EXCCODE_SHIFT;
+       assert(exccode < NUM_CAUSES && trap_handlers[exccode]);
+       
+       trap_handlers[exccode](tf);
+       
+       env_pop_tf(tf);
+}