summaryrefslogtreecommitdiff
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
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.
-rw-r--r--p/riscv_test.h2
-rw-r--r--v/entry.S64
-rw-r--r--v/riscv_test.h5
-rw-r--r--v/vm.c64
4 files changed, 89 insertions, 46 deletions
diff --git a/p/riscv_test.h b/p/riscv_test.h
index a94a404..b82b108 100644
--- a/p/riscv_test.h
+++ b/p/riscv_test.h
@@ -168,9 +168,7 @@ _start: \
RISCV_MULTICORE_DISABLE; \
CHECK_XLEN; \
la t0, stvec_handler; \
- beqz t0, skip_set_stvec; \
csrw stvec, t0; \
- skip_set_stvec: \
li t0, MSTATUS_PRV1 | MSTATUS_PRV2 | MSTATUS_IE1 | MSTATUS_IE2; \
csrc mstatus, t0; \
init; \
diff --git a/v/entry.S b/v/entry.S
index 0f0ee14..8fa19f7 100644
--- a/v/entry.S
+++ b/v/entry.S
@@ -12,22 +12,28 @@
#define STACK_TOP (_end + 131072)
- .section ".text.init"
+ .section ".text.init","ax",@progbits
.align 6
entry_from_user:
- j trap_entry
+ mrts
.align 6
entry_from_supervisor:
- j double_fault
+ csrr t0, mcause
+ addi t0, t0, -CAUSE_SUPERVISOR_ECALL
+ beqz t0, handle_tohost
+ j wtf
.align 6
entry_from_hypervisor:
- j double_fault
+ j wtf
.align 6
entry_from_machine:
- j double_fault
+ csrr t0, mcause
+ addi t0, t0, -CAUSE_MACHINE_ECALL
+ beqz t0, handle_tohost
+ j wtf
.align 6
power_on_reset:
@@ -39,9 +45,9 @@ power_on_reset:
.globl pop_tf
pop_tf:
- csrc mstatus, MSTATUS_IE
+ csrc sstatus, SSTATUS_IE
LOAD t0,33*REGBYTES(a0)
- csrw mepc,t0
+ csrw sepc,t0
LOAD x1,1*REGBYTES(a0)
LOAD x2,2*REGBYTES(a0)
LOAD x3,3*REGBYTES(a0)
@@ -77,7 +83,7 @@ pop_tf:
.global trap_entry
trap_entry:
- csrrw sp, mscratch, sp
+ csrrw sp, sscratch, sp
# save gprs
STORE x1,1*REGBYTES(sp)
@@ -111,17 +117,17 @@ trap_entry:
STORE x30,30*REGBYTES(sp)
STORE x31,31*REGBYTES(sp)
- csrrw t0,mscratch,sp
+ csrrw t0,sscratch,sp
STORE t0,2*REGBYTES(sp)
# get sr, epc, badvaddr, cause
- csrr t0,mstatus
+ csrr t0,sstatus
STORE t0,32*REGBYTES(sp)
- csrr t0,mepc
+ csrr t0,sepc
STORE t0,33*REGBYTES(sp)
- csrr t0,mbadaddr
+ csrr t0,sbadaddr
STORE t0,34*REGBYTES(sp)
- csrr t0,mcause
+ csrr t0,scause
STORE t0,35*REGBYTES(sp)
# get hwacha cause if IRQ_COP
@@ -136,11 +142,11 @@ trap_entry:
STORE t0,36*REGBYTES(sp)
1:
- move a0,sp
- csrr t0,mstatus
- li t1, MSTATUS_XS
- and t0,t0,t1
- beqz t0,2f
+ move a0, sp
+ csrr t0, sstatus
+ li t1, SSTATUS_XS
+ and t0, t0, t1
+ beqz t0, 2f
# disable saving vector state for now
addi t0,sp,SIZEOF_TRAPFRAME_T_SCALAR
@@ -152,3 +158,25 @@ trap_entry:
addi t0,t0,2*REGBYTES
vxcptevac t0
2:j handle_trap
+
+ .global do_tohost
+do_tohost:
+ ecall
+ ret
+
+handle_tohost:
+1:csrrw t0, mtohost, a0
+ bnez t0, 1b
+
+1:csrrw t0, mfromhost, x0
+ bnez t0, 1b
+
+ csrr t0, mepc
+ addi t0, t0, 4
+ csrw mepc, t0
+ eret
+
+wtf:
+ li a0, 841
+1:csrw mtohost, a0
+ j 1b
diff --git a/v/riscv_test.h b/v/riscv_test.h
index c690a32..1b38b5a 100644
--- a/v/riscv_test.h
+++ b/v/riscv_test.h
@@ -79,7 +79,7 @@ userstart: \
#define LFSR_NEXT(x) (((((x)^((x)>>1)) & 1) << 5) | ((x) >> 1))
#define PGSHIFT 12
-#define PGSIZE (1 << PGSHIFT)
+#define PGSIZE (1UL << PGSHIFT)
#define SIZEOF_TRAPFRAME_T 20776
#define SIZEOF_TRAPFRAME_T_SCALAR 296
@@ -139,7 +139,8 @@ typedef unsigned long pte_t;
#define PTIDXBITS (PGSHIFT - (sizeof(pte_t) == 8 ? 3 : 2))
#define VPN_BITS (PTIDXBITS * LEVELS)
#define VA_BITS (VPN_BITS + PGSHIFT)
-#define PTES_PER_PT (PGSIZE/sizeof(pte_t))
+#define PTES_PER_PT (1UL << RISCV_PGLEVEL_BITS)
+#define MEGAPAGE_SIZE (PTES_PER_PT * PGSIZE)
typedef struct
{
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!");
-}