From dac4ddd40078f31f4c2e766368c237eba84ef68c Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Tue, 19 May 2015 02:27:00 -0700 Subject: 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. --- p/riscv_test.h | 2 -- v/entry.S | 64 +++++++++++++++++++++++++++++++++++++++++----------------- v/riscv_test.h | 5 +++-- v/vm.c | 64 ++++++++++++++++++++++++++++++++++++---------------------- 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!"); -} -- cgit v1.1