summaryrefslogtreecommitdiff
path: root/v
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
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')
-rw-r--r--v/entry.S64
-rw-r--r--v/riscv_test.h5
-rw-r--r--v/vm.c64
3 files changed, 89 insertions, 44 deletions
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!");
-}