summaryrefslogtreecommitdiff
path: root/v/vm.c
diff options
context:
space:
mode:
authorAndrew Waterman <waterman@cs.berkeley.edu>2015-05-19 02:27:00 -0700
committerAndrew Waterman <waterman@cs.berkeley.edu>2015-05-19 02:27:00 -0700
commitdac4ddd40078f31f4c2e766368c237eba84ef68c (patch)
tree49951629b42a1765dde2af0fa3bd3475eeaa38ad /v/vm.c
parentbb05f5bc5c509e763108f954e23233ba946542ea (diff)
downloadenv-dac4ddd40078f31f4c2e766368c237eba84ef68c.zip
env-dac4ddd40078f31f4c2e766368c237eba84ef68c.tar.gz
env-dac4ddd40078f31f4c2e766368c237eba84ef68c.tar.bz2
Improve coverage of VM tests
The supervisor code now runs in supervisor mode with negative virtual addresses. This further stresses VM and tests some RV64 corner cases.
Diffstat (limited to 'v/vm.c')
-rw-r--r--v/vm.c64
1 files changed, 40 insertions, 24 deletions
diff --git a/v/vm.c b/v/vm.c
index 5d0baa7..1b9845b 100644
--- a/v/vm.c
+++ b/v/vm.c
@@ -8,22 +8,24 @@
void trap_entry();
void pop_tf(trapframe_t*);
+void do_tohost(long tohost_value);
+
+#define pa2kva(pa) ((void*)(pa) - MEGAPAGE_SIZE)
static void cputchar(int x)
{
- while (swap_csr(mtohost, 0x0101000000000000 | (unsigned char)x));
- while (swap_csr(mfromhost, 0) == 0);
+ do_tohost(0x0101000000000000 | (unsigned char)x);
}
static void cputstring(const char* s)
{
- while(*s)
+ while (*s)
cputchar(*s++);
}
static void terminate(int code)
{
- while (swap_csr(mtohost, code));
+ do_tohost(code);
while (1);
}
@@ -38,8 +40,10 @@ static void terminate(int code)
typedef struct { pte_t addr; void* next; } freelist_t;
pte_t l1pt[PTES_PER_PT] __attribute__((aligned(PGSIZE)));
-pte_t l2pt[PTES_PER_PT] __attribute__((aligned(PGSIZE)));
-pte_t l3pt[PTES_PER_PT] __attribute__((aligned(PGSIZE)));
+pte_t user_l2pt[PTES_PER_PT] __attribute__((aligned(PGSIZE)));
+pte_t user_l3pt[PTES_PER_PT] __attribute__((aligned(PGSIZE)));
+pte_t kernel_l2pt[PTES_PER_PT] __attribute__((aligned(PGSIZE)));
+pte_t kernel_l3pt[PTES_PER_PT] __attribute__((aligned(PGSIZE)));
freelist_t user_mapping[MAX_TEST_PAGES];
freelist_t freelist_nodes[MAX_TEST_PAGES];
freelist_t *freelist_head, *freelist_tail;
@@ -66,10 +70,10 @@ void evict(unsigned long addr)
if (node->addr)
{
// check referenced and dirty bits
- assert(l3pt[addr/PGSIZE] & PTE_R);
- if (memcmp((void*)addr, (void*)node->addr, PGSIZE)) {
- assert(l3pt[addr/PGSIZE] & PTE_D);
- memcpy((void*)addr, (void*)node->addr, PGSIZE);
+ assert(user_l3pt[addr/PGSIZE] & PTE_R);
+ if (memcmp((void*)addr, pa2kva(addr), PGSIZE)) {
+ assert(user_l3pt[addr/PGSIZE] & PTE_D);
+ memcpy((void*)addr, pa2kva(addr), PGSIZE);
}
user_mapping[addr/PGSIZE].addr = 0;
@@ -95,12 +99,12 @@ void handle_fault(unsigned long addr)
if (freelist_head == freelist_tail)
freelist_tail = 0;
- l3pt[addr/PGSIZE] = (node->addr >> PGSHIFT << PTE_PPN_SHIFT) | PTE_V | PTE_TYPE_URWX_SRW;
+ user_l3pt[addr/PGSIZE] = (node->addr >> PGSHIFT << PTE_PPN_SHIFT) | PTE_V | PTE_TYPE_URWX_SRW;
asm volatile ("sfence.vm");
assert(user_mapping[addr/PGSIZE].addr == 0);
user_mapping[addr/PGSIZE] = *node;
- memcpy((void*)node->addr, (void*)addr, PGSIZE);
+ memcpy((void*)addr, pa2kva(addr), PGSIZE);
__builtin___clear_cache(0,0);
}
@@ -202,7 +206,7 @@ void handle_trap(trapframe_t* tf)
assert(!"unexpected exception");
out:
- if (!(tf->sr & MSTATUS_PRV1) && (tf->sr & MSTATUS_XS))
+ if (!(tf->sr & SSTATUS_PS) && (tf->sr & SSTATUS_XS))
restore_vector(tf);
pop_tf(tf);
}
@@ -213,31 +217,43 @@ void vm_boot(long test_addr, long seed)
assert(SIZEOF_TRAPFRAME_T == sizeof(trapframe_t));
- l1pt[0] = ((pte_t)l2pt >> PGSHIFT << PTE_PPN_SHIFT) | PTE_V | PTE_TYPE_TABLE;
- l2pt[0] = ((pte_t)l3pt >> PGSHIFT << PTE_PPN_SHIFT) | PTE_V | PTE_TYPE_TABLE;
+#if MAX_TEST_PAGES > PTES_PER_PT
+# error
+#endif
+ // map kernel to uppermost megapage
+ l1pt[PTES_PER_PT-1] = ((pte_t)kernel_l2pt >> PGSHIFT << PTE_PPN_SHIFT) | PTE_V | PTE_TYPE_TABLE;
+ kernel_l2pt[PTES_PER_PT-1] = ((pte_t)kernel_l3pt >> PGSHIFT << PTE_PPN_SHIFT) | PTE_V | PTE_TYPE_TABLE;
+
+ // map user to lowermost megapage
+ l1pt[0] = ((pte_t)user_l2pt >> PGSHIFT << PTE_PPN_SHIFT) | PTE_V | PTE_TYPE_TABLE;
+ user_l2pt[0] = ((pte_t)user_l3pt >> PGSHIFT << PTE_PPN_SHIFT) | PTE_V | PTE_TYPE_TABLE;
write_csr(sptbr, l1pt);
+
+ // set up supervisor trap handling
+ write_csr(stvec, pa2kva(trap_entry));
+ write_csr(sscratch, pa2kva(read_csr(mscratch)));
+ // interrupts on; FPU on; accelerator on
set_csr(mstatus, MSTATUS_IE1 | MSTATUS_FS | MSTATUS_XS);
+ // virtual memory off; set user mode upon eret
clear_csr(mstatus, MSTATUS_VM | MSTATUS_PRV1);
+ // virtual memory to Sv39
set_csr(mstatus, (long)VM_SV39 << __builtin_ctzl(MSTATUS_VM));
seed = 1 + (seed % MAX_TEST_PAGES);
- freelist_head = &freelist_nodes[0];
- freelist_tail = &freelist_nodes[MAX_TEST_PAGES-1];
+ freelist_head = pa2kva((void*)&freelist_nodes[0]);
+ freelist_tail = pa2kva(&freelist_nodes[MAX_TEST_PAGES-1]);
for (long i = 0; i < MAX_TEST_PAGES; i++)
{
freelist_nodes[i].addr = (MAX_TEST_PAGES + seed)*PGSIZE;
- freelist_nodes[i].next = &freelist_nodes[i+1];
+ freelist_nodes[i].next = pa2kva(&freelist_nodes[i+1]);
seed = LFSR_NEXT(seed);
+
+ kernel_l3pt[i] = (i << PTE_PPN_SHIFT) | PTE_V | PTE_TYPE_SRWX;
}
freelist_nodes[MAX_TEST_PAGES-1].next = 0;
trapframe_t tf;
memset(&tf, 0, sizeof(tf));
- tf.epc = test_addr;
+ write_csr(mepc, test_addr);
pop_tf(&tf);
}
-
-void double_fault()
-{
- assert(!"double fault!");
-}