summaryrefslogtreecommitdiff
path: root/v
diff options
context:
space:
mode:
authorAndrew Waterman <andrew@sifive.com>2017-03-09 12:42:07 -0800
committerAndrew Waterman <andrew@sifive.com>2017-03-09 12:42:07 -0800
commit00d8922398c202c13d6eb5da07e92be6364309a1 (patch)
tree72d518fd759b9b3184bb5aba5b6c5d91619c5f17 /v
parentb3e14827904c2b1247171f4f1522be397349e7ea (diff)
downloadenv-00d8922398c202c13d6eb5da07e92be6364309a1.zip
env-00d8922398c202c13d6eb5da07e92be6364309a1.tar.gz
env-00d8922398c202c13d6eb5da07e92be6364309a1.tar.bz2
WIP on priv-1.10
Diffstat (limited to 'v')
-rw-r--r--v/vm.c65
1 files changed, 40 insertions, 25 deletions
diff --git a/v/vm.c b/v/vm.c
index 1aa068a..2e057fb 100644
--- a/v/vm.c
+++ b/v/vm.c
@@ -9,20 +9,21 @@
void trap_entry();
void pop_tf(trapframe_t*);
-volatile uint64_t tohost __attribute__((aligned(64)));
-volatile uint64_t fromhost __attribute__((aligned(64)));
+volatile uint64_t tohost;
+volatile uint64_t fromhost;
static void do_tohost(uint64_t tohost_value)
{
+ while (tohost)
+ fromhost = 0;
tohost = tohost_value;
- while (fromhost == 0)
- ;
- fromhost = 0;
}
#define pa2kva(pa) ((void*)(pa) - DRAM_BASE - MEGAPAGE_SIZE)
#define uva2kva(pa) ((void*)(pa) - MEGAPAGE_SIZE)
+#define flush_page(addr) asm volatile ("sfence.vma %0" : : "r" (addr))
+
static uint64_t lfsr63(uint64_t x)
{
uint64_t bit = (x ^ (x >> 1)) & 1;
@@ -61,15 +62,13 @@ void wtf()
#define l1pt pt[0]
#define user_l2pt pt[1]
-#define kernel_l2pt pt[2]
#if __riscv_xlen == 64
-# define NPT 5
+# define NPT 4
+#define kernel_l2pt pt[2]
# define user_l3pt pt[3]
-# define kernel_l3pt pt[4]
#else
-# define NPT 3
+# define NPT 2
# define user_l3pt user_l2pt
-# define kernel_l3pt kernel_l2pt
#endif
pte_t pt[NPT][PTES_PER_PT] __attribute__((aligned(PGSIZE)));
@@ -119,24 +118,39 @@ static void evict(unsigned long addr)
}
}
-void handle_fault(unsigned long addr)
+void handle_fault(uintptr_t addr, uintptr_t cause)
{
assert(addr >= PGSIZE && addr < MAX_TEST_PAGES * PGSIZE);
addr = addr/PGSIZE*PGSIZE;
+ if (user_l3pt[addr/PGSIZE]) {
+ if (!(user_l3pt[addr/PGSIZE] & PTE_A)) {
+ user_l3pt[addr/PGSIZE] |= PTE_A;
+ } else {
+ assert(!(user_l3pt[addr/PGSIZE] & PTE_D) && cause == CAUSE_FAULT_STORE);
+ user_l3pt[addr/PGSIZE] |= PTE_D;
+ }
+ flush_page(addr);
+ return;
+ }
+
freelist_t* node = freelist_head;
assert(node);
freelist_head = node->next;
if (freelist_head == freelist_tail)
freelist_tail = 0;
- user_l3pt[addr/PGSIZE] = (node->addr >> PGSHIFT << PTE_PPN_SHIFT) | PTE_V | PTE_U | PTE_R | PTE_W | PTE_X;
- asm volatile ("sfence.vm");
+ uintptr_t new_pte = (node->addr >> PGSHIFT << PTE_PPN_SHIFT) | PTE_V | PTE_U | PTE_R | PTE_W | PTE_X;
+ user_l3pt[addr/PGSIZE] = new_pte | PTE_A | PTE_D;
+ flush_page(addr);
assert(user_mapping[addr/PGSIZE].addr == 0);
user_mapping[addr/PGSIZE] = *node;
memcpy((void*)addr, uva2kva(addr), PGSIZE);
+ user_l3pt[addr/PGSIZE] = new_pte;
+ flush_page(addr);
+
__builtin___clear_cache(0,0);
}
@@ -165,7 +179,7 @@ void handle_trap(trapframe_t* tf)
tf->epc += 4;
}
else if (tf->cause == CAUSE_FAULT_FETCH || tf->cause == CAUSE_FAULT_LOAD || tf->cause == CAUSE_FAULT_STORE)
- handle_fault(tf->badvaddr);
+ handle_fault(tf->badvaddr, tf->cause);
else
assert(!"unexpected exception");
@@ -196,18 +210,23 @@ void vm_boot(uintptr_t test_addr)
_Static_assert(SIZEOF_TRAPFRAME_T == sizeof(trapframe_t), "???");
-#if MAX_TEST_PAGES > PTES_PER_PT
+#if (MAX_TEST_PAGES > PTES_PER_PT) || (DRAM_BASE % MEGAPAGE_SIZE) != 0
# error
#endif
- write_csr(sptbr, (uintptr_t)l1pt >> PGSHIFT);
- // map kernel to uppermost megapage
- l1pt[PTES_PER_PT-1] = ((pte_t)kernel_l2pt >> PGSHIFT << PTE_PPN_SHIFT) | PTE_V;
// map user to lowermost megapage
l1pt[0] = ((pte_t)user_l2pt >> PGSHIFT << PTE_PPN_SHIFT) | PTE_V;
+ // map kernel to uppermost megapage
#if __riscv_xlen == 64
- kernel_l2pt[PTES_PER_PT-1] = ((pte_t)kernel_l3pt >> PGSHIFT << PTE_PPN_SHIFT) | PTE_V;
+ l1pt[PTES_PER_PT-1] = ((pte_t)kernel_l2pt >> PGSHIFT << PTE_PPN_SHIFT) | PTE_V;
+ kernel_l2pt[PTES_PER_PT-1] = (DRAM_BASE/RISCV_PGSIZE << PTE_PPN_SHIFT) | PTE_V | PTE_R | PTE_W | PTE_X | PTE_A | PTE_D;
user_l2pt[0] = ((pte_t)user_l3pt >> PGSHIFT << PTE_PPN_SHIFT) | PTE_V;
+ uintptr_t vm_choice = SPTBR_MODE_SV39;
+#else
+ l1pt[PTES_PER_PT-1] = (DRAM_BASE/RISCV_PGSIZE << PTE_PPN_SHIFT) | PTE_V | PTE_R | PTE_W | PTE_X | PTE_A | PTE_D;
+ uintptr_t vm_choice = SPTBR_MODE_SV32;
#endif
+ write_csr(sptbr, ((uintptr_t)l1pt >> PGSHIFT) |
+ (vm_choice * (SPTBR_MODE & ~(SPTBR_MODE<<1))));
// set up supervisor trap handling
write_csr(stvec, pa2kva(trap_entry));
@@ -217,10 +236,8 @@ void vm_boot(uintptr_t test_addr)
(1 << CAUSE_FAULT_FETCH) |
(1 << CAUSE_FAULT_LOAD) |
(1 << CAUSE_FAULT_STORE));
- // on ERET, user mode; FPU on; accelerator on; VM on
- int vm_choice = sizeof(long) == 8 ? VM_SV39 : VM_SV32;
- write_csr(mstatus, MSTATUS_FS | MSTATUS_XS |
- (vm_choice * (MSTATUS_VM & ~(MSTATUS_VM<<1))));
+ // FPU on; accelerator on
+ write_csr(mstatus, MSTATUS_FS | MSTATUS_XS);
write_csr(mie, 0);
random = 1 + (random % MAX_TEST_PAGES);
@@ -231,8 +248,6 @@ void vm_boot(uintptr_t test_addr)
freelist_nodes[i].addr = DRAM_BASE + (MAX_TEST_PAGES + random)*PGSIZE;
freelist_nodes[i].next = pa2kva(&freelist_nodes[i+1]);
random = LFSR_NEXT(random);
-
- kernel_l3pt[i] = ((i + DRAM_BASE/RISCV_PGSIZE) << PTE_PPN_SHIFT) | PTE_V | PTE_R | PTE_W | PTE_X;
}
freelist_nodes[MAX_TEST_PAGES-1].next = 0;