diff options
author | Andrew Waterman <waterman@cs.berkeley.edu> | 2015-05-19 02:27:00 -0700 |
---|---|---|
committer | Andrew Waterman <waterman@cs.berkeley.edu> | 2015-05-19 02:27:00 -0700 |
commit | dac4ddd40078f31f4c2e766368c237eba84ef68c (patch) | |
tree | 49951629b42a1765dde2af0fa3bd3475eeaa38ad /v | |
parent | bb05f5bc5c509e763108f954e23233ba946542ea (diff) | |
download | env-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.S | 64 | ||||
-rw-r--r-- | v/riscv_test.h | 5 | ||||
-rw-r--r-- | v/vm.c | 64 |
3 files changed, 89 insertions, 44 deletions
@@ -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 { @@ -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!"); -} |