diff options
-rw-r--r-- | hwacha_xcpt.h | 17 | ||||
-rw-r--r-- | p/link.ld | 44 | ||||
-rw-r--r-- | p/riscv_test.h | 117 | ||||
-rw-r--r-- | pcr.h | 114 | ||||
-rw-r--r-- | pm/link.ld | 44 | ||||
-rw-r--r-- | pm/riscv_test.h | 9 | ||||
-rw-r--r-- | pt/link.ld | 44 | ||||
-rw-r--r-- | pt/riscv_test.h | 159 | ||||
-rw-r--r-- | v/entry.S | 172 | ||||
-rw-r--r-- | v/link.ld | 50 | ||||
-rw-r--r-- | v/riscv_test.h | 155 | ||||
-rw-r--r-- | v/vm.c | 275 |
12 files changed, 1200 insertions, 0 deletions
diff --git a/hwacha_xcpt.h b/hwacha_xcpt.h new file mode 100644 index 0000000..5c4dacc --- /dev/null +++ b/hwacha_xcpt.h @@ -0,0 +1,17 @@ +#ifndef _HWACHA_XCPT_H +#define _HWACHA_XCPT_H + +#define HWACHA_CAUSE_ILLEGAL_CFG 0 // AUX: 0=illegal nxpr, 1=illegal nfpr +#define HWACHA_CAUSE_ILLEGAL_INSTRUCTION 1 // AUX: instruction +#define HWACHA_CAUSE_PRIVILEGED_INSTRUCTION 2 // AUX: instruction +#define HWACHA_CAUSE_TVEC_ILLEGAL_REGID 3 // AUX: instruction +#define HWACHA_CAUSE_VF_MISALIGNED_FETCH 4 // AUX: pc +#define HWACHA_CAUSE_VF_FAULT_FETCH 5 // AUX: pc +#define HWACHA_CAUSE_VF_ILLEGAL_INSTRUCTION 6 // AUX: pc +#define HWACHA_CAUSE_VF_ILLEGAL_REGID 7 // AUX: pc +#define HWACHA_CAUSE_MISALIGNED_LOAD 8 // AUX: badvaddr +#define HWACHA_CAUSE_MISALIGNED_STORE 9 // AUX: badvaddr +#define HWACHA_CAUSE_FAULT_LOAD 10 // AUX: badvaddr +#define HWACHA_CAUSE_FAULT_STORE 11 // AUX: badvaddr + +#endif diff --git a/p/link.ld b/p/link.ld new file mode 100644 index 0000000..6b19389 --- /dev/null +++ b/p/link.ld @@ -0,0 +1,44 @@ +/*======================================================================*/ +/* Proxy kernel linker script */ +/*======================================================================*/ +/* This is the linker script used when building the proxy kernel. */ + +/*----------------------------------------------------------------------*/ +/* Setup */ +/*----------------------------------------------------------------------*/ + +/* The OUTPUT_ARCH command specifies the machine architecture where the + argument is one of the names used in the BFD library. More + specifically one of the entires in bfd/cpu-mips.c */ + +OUTPUT_ARCH( "riscv" ) + +/* The ENTRY command specifies the entry point (ie. first instruction + to execute). The symbol _start should be defined in each test. */ + +ENTRY( _start ) + +/*----------------------------------------------------------------------*/ +/* Sections */ +/*----------------------------------------------------------------------*/ + +SECTIONS +{ + + /* text: test code section */ + . = 0x00002000; + .text : + { + *(.text) + } + + /* data: Initialized data segment */ + .data : + { + *(.data) + } + + /* End of uninitalized data segement */ + _end = .; +} + diff --git a/p/riscv_test.h b/p/riscv_test.h new file mode 100644 index 0000000..4253ef5 --- /dev/null +++ b/p/riscv_test.h @@ -0,0 +1,117 @@ +#ifndef _ENV_PHYSICAL_SINGLE_CORE_H +#define _ENV_PHYSICAL_SINGLE_CORE_H + +#include "../pcr.h" +#include "../hwacha_xcpt.h" + +//----------------------------------------------------------------------- +// Begin Macro +//----------------------------------------------------------------------- + +#define RVTEST_RV64U \ + .macro init; \ + .endm + +#define RVTEST_RV64UF \ + .macro init; \ + RVTEST_FP_ENABLE; \ + .endm + +#define RVTEST_RV64UV \ + .macro init; \ + RVTEST_FP_ENABLE; \ + RVTEST_VEC_ENABLE; \ + .endm + +#define RVTEST_RV32U \ + .macro init; \ + RVTEST_32_ENABLE; \ + .endm + +#define RVTEST_RV32UF \ + .macro init; \ + RVTEST_32_ENABLE; \ + RVTEST_FP_ENABLE; \ + .endm + +#define RVTEST_RV32UV \ + .macro init; \ + RVTEST_32_ENABLE; \ + RVTEST_FP_ENABLE; \ + RVTEST_VEC_ENABLE; \ + .endm + +#define RVTEST_RV64S \ + .macro init; \ + .endm + +#define RVTEST_32_ENABLE \ + clearpcr status, SR_S64 \ + +#define RVTEST_FP_ENABLE \ + setpcr status, SR_EF; \ + mfpcr a0, status; \ + and a0, a0, SR_EF; \ + bnez a0, 2f; \ + RVTEST_PASS; \ +2:fssr x0; \ + +#define RVTEST_VEC_ENABLE \ + setpcr status, SR_EA; \ + mfpcr a0, status; \ + and a0, a0, SR_EA; \ + bnez a0, 2f; \ + RVTEST_PASS; \ +2: \ + +#define RISCV_MULTICORE_DISABLE \ + mfpcr a0, hartid; 1: bnez a0, 1b; \ + +#define EXTRA_INIT + +#define RVTEST_CODE_BEGIN \ + .text; \ + .align 4; \ + .global _start; \ +_start: \ + RISCV_MULTICORE_DISABLE; \ + init; \ + EXTRA_INIT; \ + +//----------------------------------------------------------------------- +// End Macro +//----------------------------------------------------------------------- + +#define RVTEST_CODE_END \ + +//----------------------------------------------------------------------- +// Pass/Fail Macro +//----------------------------------------------------------------------- + +#define RVTEST_PASS \ + fence; \ + li x1, 1; \ + mtpcr x1, tohost; \ +1: b 1b; \ + +#define RVTEST_FAIL \ + fence; \ + beqz x28, 1f; \ + sll x28, x28, 1; \ + or x28, x28, 1; \ + mtpcr x28, tohost; \ +1: b 1b; \ + +//----------------------------------------------------------------------- +// Data Section Macro +//----------------------------------------------------------------------- + +//#define RVTEST_DATA_BEGIN EXTRA_DATA +//#define RVTEST_DATA_END + +#define EXTRA_DATA + +#define RVTEST_DATA_BEGIN EXTRA_DATA .align 4; .global begin_signature; begin_signature: +#define RVTEST_DATA_END .align 4; .global end_signature; end_signature: + +#endif @@ -0,0 +1,114 @@ +// See LICENSE for license details. + +#ifndef _RISCV_PCR_H +#define _RISCV_PCR_H + +#define SR_S 0x00000001 +#define SR_PS 0x00000002 +#define SR_EI 0x00000004 +#define SR_PEI 0x00000008 +#define SR_EF 0x00000010 +#define SR_U64 0x00000020 +#define SR_S64 0x00000040 +#define SR_VM 0x00000080 +#define SR_EA 0x00000100 +#define SR_IM 0x00FF0000 +#define SR_IP 0xFF000000 +#define SR_ZERO ~(SR_S|SR_PS|SR_EI|SR_PEI|SR_EF|SR_U64|SR_S64|SR_VM|SR_EA|SR_IM|SR_IP) +#define SR_IM_SHIFT 16 +#define SR_IP_SHIFT 24 + +#define PCR_SUP0 0 +#define PCR_SUP1 1 +#define PCR_EPC 2 +#define PCR_BADVADDR 3 +#define PCR_PTBR 4 +#define PCR_ASID 5 +#define PCR_COUNT 6 +#define PCR_COMPARE 7 +#define PCR_EVEC 8 +#define PCR_CAUSE 9 +#define PCR_SR 10 +#define PCR_HARTID 11 +#define PCR_IMPL 12 +#define PCR_FATC 13 +#define PCR_SEND_IPI 14 +#define PCR_CLR_IPI 15 +#define PCR_VECBANK 18 +#define PCR_VECCFG 19 +#define PCR_RESET 29 +#define PCR_TOHOST 30 +#define PCR_FROMHOST 31 + +#define IRQ_COP 2 +#define IRQ_IPI 5 +#define IRQ_HOST 6 +#define IRQ_TIMER 7 + +#define IMPL_SPIKE 1 +#define IMPL_ROCKET 2 + +#define CAUSE_MISALIGNED_FETCH 0 +#define CAUSE_FAULT_FETCH 1 +#define CAUSE_ILLEGAL_INSTRUCTION 2 +#define CAUSE_PRIVILEGED_INSTRUCTION 3 +#define CAUSE_FP_DISABLED 4 +#define CAUSE_SYSCALL 6 +#define CAUSE_BREAKPOINT 7 +#define CAUSE_MISALIGNED_LOAD 8 +#define CAUSE_MISALIGNED_STORE 9 +#define CAUSE_FAULT_LOAD 10 +#define CAUSE_FAULT_STORE 11 +#define CAUSE_ACCELERATOR_DISABLED 12 + +// page table entry (PTE) fields +#define PTE_V 0x001 // Entry is a page Table descriptor +#define PTE_T 0x002 // Entry is a page Table, not a terminal node +#define PTE_G 0x004 // Global +#define PTE_UR 0x008 // User Write permission +#define PTE_UW 0x010 // User Read permission +#define PTE_UX 0x020 // User eXecute permission +#define PTE_SR 0x040 // Supervisor Read permission +#define PTE_SW 0x080 // Supervisor Write permission +#define PTE_SX 0x100 // Supervisor eXecute permission +#define PTE_PERM (PTE_SR | PTE_SW | PTE_SX | PTE_UR | PTE_UW | PTE_UX) + +#ifdef __riscv + +#ifdef __riscv64 +# define RISCV_PGLEVELS 3 +# define RISCV_PGSHIFT 13 +#else +# define RISCV_PGLEVELS 2 +# define RISCV_PGSHIFT 12 +#endif +#define RISCV_PGLEVEL_BITS 10 +#define RISCV_PGSIZE (1 << RISCV_PGSHIFT) + +#ifndef __ASSEMBLER__ + +#define mtpcr(reg,val) ({ long __tmp = (long)(val), __tmp2; \ + asm volatile ("mtpcr %0,%1,cr%2" : "=r"(__tmp2) : "r"(__tmp),"i"(reg)); \ + __tmp2; }) + +#define mfpcr(reg) ({ long __tmp; \ + asm volatile ("mfpcr %0,cr%1" : "=r"(__tmp) : "i"(reg)); \ + __tmp; }) + +#define setpcr(reg,val) ({ long __tmp; \ + asm volatile ("setpcr %0,cr%2,%1" : "=r"(__tmp) : "i"(val), "i"(reg)); \ + __tmp; }) + +#define clearpcr(reg,val) ({ long __tmp; \ + asm volatile ("clearpcr %0,cr%2,%1" : "=r"(__tmp) : "i"(val), "i"(reg)); \ + __tmp; }) + +#define rdcycle() ({ unsigned long __tmp; \ + asm volatile ("rdcycle %0" : "=r"(__tmp)); \ + __tmp; }) + +#endif + +#endif + +#endif diff --git a/pm/link.ld b/pm/link.ld new file mode 100644 index 0000000..6b19389 --- /dev/null +++ b/pm/link.ld @@ -0,0 +1,44 @@ +/*======================================================================*/ +/* Proxy kernel linker script */ +/*======================================================================*/ +/* This is the linker script used when building the proxy kernel. */ + +/*----------------------------------------------------------------------*/ +/* Setup */ +/*----------------------------------------------------------------------*/ + +/* The OUTPUT_ARCH command specifies the machine architecture where the + argument is one of the names used in the BFD library. More + specifically one of the entires in bfd/cpu-mips.c */ + +OUTPUT_ARCH( "riscv" ) + +/* The ENTRY command specifies the entry point (ie. first instruction + to execute). The symbol _start should be defined in each test. */ + +ENTRY( _start ) + +/*----------------------------------------------------------------------*/ +/* Sections */ +/*----------------------------------------------------------------------*/ + +SECTIONS +{ + + /* text: test code section */ + . = 0x00002000; + .text : + { + *(.text) + } + + /* data: Initialized data segment */ + .data : + { + *(.data) + } + + /* End of uninitalized data segement */ + _end = .; +} + diff --git a/pm/riscv_test.h b/pm/riscv_test.h new file mode 100644 index 0000000..4bd1637 --- /dev/null +++ b/pm/riscv_test.h @@ -0,0 +1,9 @@ +#ifndef _ENV_PHYSICAL_MULTI_CORE_H +#define _ENV_PHYSICAL_MULTI_CORE_HA + +#include "../p/riscv_test.h" + +#undef RISCV_MULTICORE_DISABLE +#define RISCV_MULTICORE_DISABLE + +#endif diff --git a/pt/link.ld b/pt/link.ld new file mode 100644 index 0000000..6b19389 --- /dev/null +++ b/pt/link.ld @@ -0,0 +1,44 @@ +/*======================================================================*/ +/* Proxy kernel linker script */ +/*======================================================================*/ +/* This is the linker script used when building the proxy kernel. */ + +/*----------------------------------------------------------------------*/ +/* Setup */ +/*----------------------------------------------------------------------*/ + +/* The OUTPUT_ARCH command specifies the machine architecture where the + argument is one of the names used in the BFD library. More + specifically one of the entires in bfd/cpu-mips.c */ + +OUTPUT_ARCH( "riscv" ) + +/* The ENTRY command specifies the entry point (ie. first instruction + to execute). The symbol _start should be defined in each test. */ + +ENTRY( _start ) + +/*----------------------------------------------------------------------*/ +/* Sections */ +/*----------------------------------------------------------------------*/ + +SECTIONS +{ + + /* text: test code section */ + . = 0x00002000; + .text : + { + *(.text) + } + + /* data: Initialized data segment */ + .data : + { + *(.data) + } + + /* End of uninitalized data segement */ + _end = .; +} + diff --git a/pt/riscv_test.h b/pt/riscv_test.h new file mode 100644 index 0000000..66eb59c --- /dev/null +++ b/pt/riscv_test.h @@ -0,0 +1,159 @@ +#ifndef _ENV_PHYSICAL_SINGLE_CORE_TIMER_H +#define _ENV_PHYSICAL_SINGLE_CORE_TIMER_H + +#include "../p/riscv_test.h" + +#undef EXTRA_INIT +#define EXTRA_INIT \ + ENABLE_TIMER_INTERRUPT; \ + b 6f; \ + XCPT_HANDLER; \ +6: + +//----------------------------------------------------------------------- +// Data Section Macro +//----------------------------------------------------------------------- + +#undef EXTRA_DATA +#define EXTRA_DATA \ + .align 3; \ +regspill: \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ +evac: \ + .skip 32768; \ + +//----------------------------------------------------------------------- +// Misc +//----------------------------------------------------------------------- + +#define ENABLE_TIMER_INTERRUPT \ + mtpcr x0,clear_ipi; \ + mfpcr a0,status; \ + li a1,SR_IM; \ + or a0,a0,a1; \ + mtpcr a0,status; \ + setpcr status,SR_EI; \ + la a0,_handler; \ + mtpcr a0,evec; \ + mtpcr x0,count; \ + addi a0,x0,60; \ + mtpcr a0,compare; \ + +#define XCPT_HANDLER \ +_handler: \ + mtpcr a0,sup0; \ + mtpcr a1,sup1; \ + vxcptcause x0; \ + la a0,evac; \ + vxcptsave a0; \ + vxcptrestore a0; \ + setpcr status,SR_PEI; \ + mfpcr a0,count; \ + addi a0,a0,60; \ + mtpcr a0,compare; \ + mfpcr a0,sup0; \ + mfpcr a1,sup1; \ + eret; \ + +#if 0 +#define XCPT_HANDLER \ +_handler: \ + mtpcr a0,sup0; \ + mtpcr a1,sup1; \ + la a0,regspill; \ + sd a2,0(a0); \ + sd a3,8(a0); \ + sd a4,16(a0); \ + sd a5,24(a0); \ + sd s0,32(a0); \ + sd s1,40(a0); \ + vgetcfg s0; \ + vgetvl s1; \ + la a0,evac; \ + vxcptevac a0; \ + vsetcfg s0; \ + vsetvl s1,s1; \ + vxcpthold; \ + li a5,0; \ +_handler_loop: \ + ld a1,0(a0); \ + addi a0,a0,8; \ + blt a1,x0,_done; \ + srli a2,a1,32; \ + andi a2,a2,0x1; \ + beq a2,x0,_vcnt; \ +_vcmd: \ + beq a5,x0,_vcmd_skip; \ + venqcmd a4,a3; \ +_vcmd_skip: \ + li a5,1; \ + move a4,a1; \ + srli a3,a4,36; \ + andi a3,a3,0x1; \ +_vimm1: \ + srli a2,a4,35; \ + andi a2,a2,0x1; \ + beq a2,x0,_vimm2; \ + ld a1,0(a0); \ + addi a0,a0,8; \ + venqimm1 a1,a3; \ +_vimm2: \ + srli a2,a4,34; \ + andi a2,a2,0x1; \ + beq a2,x0,_end; \ + ld a1,0(a0); \ + addi a0,a0,8; \ + venqimm2 a1,a3; \ + j _end; \ +_vcnt: \ + ld a2,0(a0); \ + srli a2,a2,31; \ + andi a2,a2,0x2; \ + or a3,a3,a2; \ + venqcnt a1,a3; \ +_end: \ + j _handler_loop; \ +_done: \ + beq a5,x0,_done_skip; \ + venqcmd a4,a3; \ +_done_skip: \ + la a0,regspill; \ + ld a2,0(a0); \ + ld a3,8(a0); \ + ld a4,16(a0); \ + ld a5,24(a0); \ + ld s0,32(a0); \ + ld s1,40(a0); \ + mfpcr a0,count; \ + addi a0,a0,60; \ + mtpcr a0,compare; \ + mfpcr a0,sup0; \ + mfpcr a1,sup1; \ + eret; \ + +#endif + +#endif diff --git a/v/entry.S b/v/entry.S new file mode 100644 index 0000000..541abae --- /dev/null +++ b/v/entry.S @@ -0,0 +1,172 @@ +#include "riscv_test.h" + +#ifdef __riscv64 +# define STORE sd +# define LOAD ld +# define REGBYTES 8 +#else +# define STORE sw +# define LOAD lw +# define REGBYTES 4 +#endif + + .text + .global _start +_start: + la sp, stack_top + li a1, 1337 + la a0, userstart + j vm_boot + +save_tf: # write the trap frame onto the stack + + # save gprs + STORE x3,3*REGBYTES(x2) + STORE x4,4*REGBYTES(x2) + STORE x5,5*REGBYTES(x2) + STORE x6,6*REGBYTES(x2) + STORE x7,7*REGBYTES(x2) + STORE x8,8*REGBYTES(x2) + STORE x9,9*REGBYTES(x2) + STORE x10,10*REGBYTES(x2) + STORE x11,11*REGBYTES(x2) + STORE x12,12*REGBYTES(x2) + STORE x13,13*REGBYTES(x2) + STORE x14,14*REGBYTES(x2) + STORE x15,15*REGBYTES(x2) + STORE x16,16*REGBYTES(x2) + STORE x17,17*REGBYTES(x2) + STORE x18,18*REGBYTES(x2) + STORE x19,19*REGBYTES(x2) + STORE x20,20*REGBYTES(x2) + STORE x21,21*REGBYTES(x2) + STORE x22,22*REGBYTES(x2) + STORE x23,23*REGBYTES(x2) + STORE x24,24*REGBYTES(x2) + STORE x25,25*REGBYTES(x2) + STORE x26,26*REGBYTES(x2) + STORE x27,27*REGBYTES(x2) + STORE x28,28*REGBYTES(x2) + STORE x29,29*REGBYTES(x2) + STORE x30,30*REGBYTES(x2) + STORE x31,31*REGBYTES(x2) + + mfpcr x3,sup0 + STORE x3,1*REGBYTES(x2) # x1 is in PCR_K0 + mfpcr x3,sup1 + STORE x3,2*REGBYTES(x2) # x2 is in PCR_K1 + + # get sr, epc, badvaddr, cause + mfpcr x3,status # sr + STORE x3,32*REGBYTES(x2) + mfpcr x4,epc # epc + STORE x4,33*REGBYTES(x2) + mfpcr x3,badvaddr # badvaddr + STORE x3,34*REGBYTES(x2) + mfpcr x3,cause # cause + STORE x3,35*REGBYTES(x2) + + # get faulting insn, if it wasn't a fetch-related trap + li x5, CAUSE_MISALIGNED_FETCH + li x6, CAUSE_FAULT_FETCH + beq x3, x5, 1f + beq x3, x6, 1f + lh x5,0(x4) + lh x6,2(x4) + sh x5, 36*REGBYTES(x2) + sh x6,2+36*REGBYTES(x2) +1: + + bge x3, x0, 1f + vxcptcause x3 + STORE x3,37*REGBYTES(x2) +1: + + ret + + .globl pop_tf +pop_tf: # write the trap frame onto the stack + # restore gprs + LOAD a1,32*REGBYTES(a0) # restore sr (should disable interrupts) + mtpcr a1,status + + LOAD x1,1*REGBYTES(a0) + mtpcr x1,sup0 + LOAD x1,2*REGBYTES(a0) + mtpcr x1,sup1 + move x1,a0 + LOAD x3,3*REGBYTES(x1) + LOAD x4,4*REGBYTES(x1) + LOAD x5,5*REGBYTES(x1) + LOAD x6,6*REGBYTES(x1) + LOAD x7,7*REGBYTES(x1) + LOAD x8,8*REGBYTES(x1) + LOAD x9,9*REGBYTES(x1) + LOAD x10,10*REGBYTES(x1) + LOAD x11,11*REGBYTES(x1) + LOAD x12,12*REGBYTES(x1) + LOAD x13,13*REGBYTES(x1) + LOAD x14,14*REGBYTES(x1) + LOAD x15,15*REGBYTES(x1) + LOAD x16,16*REGBYTES(x1) + LOAD x17,17*REGBYTES(x1) + LOAD x18,18*REGBYTES(x1) + LOAD x19,19*REGBYTES(x1) + LOAD x20,20*REGBYTES(x1) + LOAD x21,21*REGBYTES(x1) + LOAD x22,22*REGBYTES(x1) + LOAD x23,23*REGBYTES(x1) + LOAD x24,24*REGBYTES(x1) + LOAD x25,25*REGBYTES(x1) + LOAD x26,26*REGBYTES(x1) + LOAD x27,27*REGBYTES(x1) + LOAD x28,28*REGBYTES(x1) + LOAD x29,29*REGBYTES(x1) + LOAD x30,30*REGBYTES(x1) + LOAD x31,31*REGBYTES(x1) + + # gtfo! + LOAD x2,33*REGBYTES(x1) + mtpcr x2,epc + mfpcr x1,sup0 + mfpcr x2,sup1 + eret + + .global trap_entry +trap_entry: + mtpcr ra,sup0 + mtpcr x2,sup1 + + # coming from kernel? + mfpcr ra,status + and ra,ra,SR_PS + bnez ra, 1f + + # no, so start at the top of the stack + la x2,stack_top+MAX_TEST_PAGES*PGSIZE-SIZEOF_TRAPFRAME_T + jal save_tf + move sp,x2 + setpcr status, SR_EI + move a0,x2 + mfpcr ra,status + and ra,ra,SR_EA + beqz ra, 2f + addi x2,x2,38*REGBYTES + vxcptsave x2 +2:jal handle_trap + + # when coming from kernel, continue below its stack +1:li x2,17712 + sub x2, sp, x2 + jal save_tf + move sp,x2 + setpcr status, SR_EI + move a0,x2 + jal handle_trap + + .bss + .global stack_bot + .global stack_top +stack_bot: + .skip 32768 +stack_top: diff --git a/v/link.ld b/v/link.ld new file mode 100644 index 0000000..4efeaaa --- /dev/null +++ b/v/link.ld @@ -0,0 +1,50 @@ +/*======================================================================*/ +/* Proxy kernel linker script */ +/*======================================================================*/ +/* This is the linker script used when building the proxy kernel. */ + +/*----------------------------------------------------------------------*/ +/* Setup */ +/*----------------------------------------------------------------------*/ + +/* The OUTPUT_ARCH command specifies the machine architecture where the + argument is one of the names used in the BFD library. More + specifically one of the entires in bfd/cpu-mips.c */ + +OUTPUT_ARCH( "riscv" ) + +/* The ENTRY command specifies the entry point (ie. first instruction + to execute). The symbol _start should be defined in each test. */ + +ENTRY( _start ) + +/*----------------------------------------------------------------------*/ +/* Sections */ +/*----------------------------------------------------------------------*/ + +SECTIONS +{ + + /* text: test code section */ + . = 0x00002000; + .text : + { + *(.text) + } + + /* data: Initialized data segment */ + .data ALIGN(0x2000): + { + *(.data) + } + + /* bss: Initialized bss segment */ + .bss ALIGN(0x2000): + { + *(.bss) + } + + /* End of uninitalized bss segement */ + _end = .; +} + diff --git a/v/riscv_test.h b/v/riscv_test.h new file mode 100644 index 0000000..20d0690 --- /dev/null +++ b/v/riscv_test.h @@ -0,0 +1,155 @@ +#ifndef _ENV_VIRTUAL_SINGLE_CORE_H +#define _ENV_VIRTUAL_SINGLE_CORE_H + +//----------------------------------------------------------------------- +// Begin Macro +//----------------------------------------------------------------------- + +#define RVTEST_RV64U \ + .macro init; \ + .endm + +#define RVTEST_RV64UF \ + .macro init; \ + fssr x0; \ + .endm + +#define RVTEST_RV64UV \ + RVTEST_RV64UF + +#define RVTEST_CODE_BEGIN \ + .text; \ + .align 13; \ + .global userstart; \ +userstart: \ + init + +//----------------------------------------------------------------------- +// End Macro +//----------------------------------------------------------------------- + +#define RVTEST_CODE_END \ + +//----------------------------------------------------------------------- +// Pass/Fail Macro +//----------------------------------------------------------------------- + +#define RVTEST_PASS li a0, 1; syscall; +#define RVTEST_FAIL sll a0, x28, 1; 1:beqz a0, 1b; or a0, a0, 1; syscall; + +//----------------------------------------------------------------------- +// Data Section Macro +//----------------------------------------------------------------------- + +#define RVTEST_DATA_BEGIN +#define RVTEST_DATA_END + +//#define RVTEST_DATA_BEGIN .align 4; .global begin_signature; begin_signature: +//#define RVTEST_DATA_END .align 4; .global end_signature; end_signature: + +//----------------------------------------------------------------------- +// Supervisor mode definitions and macros +//----------------------------------------------------------------------- + +#include "../pcr.h" +#include "../hwacha_xcpt.h" + +#define dword_bit_cmd(dw) ((dw >> 32) & 0x1) +#define dword_bit_cnt(dw) (!dword_bit_cmd(dw)) +#define dword_bit_imm1(dw) ((dw >> 35) & 0x1) +#define dword_bit_imm2(dw) ((dw >> 34) & 0x1) +#define dword_bit_pf(dw) ((dw >> 36) & 0x1) + +#define fence() ({ \ + asm volatile ("fence" ::: "memory"); }) + +#define vxcptkill() ({ \ + asm volatile ("vxcptkill"); }) + +#define vxcpthold() ({ \ + asm volatile ("vxcpthold"); }) + +#define venqcmd(bits, pf) ({ \ + asm volatile ("venqcmd %0,%1" : : "r"(bits), "r"(pf)); }) + +#define venqimm1(bits, pf) ({ \ + asm volatile ("venqimm1 %0,%1" : : "r"(bits), "r"(pf)); }) + +#define venqimm2(bits, pf) ({ \ + asm volatile ("venqimm2 %0,%1" : : "r"(bits), "r"(pf)); }) + +#define venqcnt(bits, pf) ({ \ + asm volatile ("venqcnt %0,%1" :: "r"(bits), "r"(pf)); }) + +#define MAX_TEST_PAGES 63 // this must be the period of the LFSR below +#define LFSR_NEXT(x) (((((x)^((x)>>1)) & 1) << 5) | ((x) >> 1)) + +#define PGSHIFT 13 +#define PGSIZE (1 << PGSHIFT) + +#define SIZEOF_TRAPFRAME_T 20784 + +#ifndef __ASSEMBLER__ + +static inline void vsetcfg(long cfg) +{ + asm volatile ("vsetcfg %0" : : "r"(cfg)); +} + +static inline void vsetvl(long vl) +{ + long __tmp; + asm volatile ("vsetvl %0,%1" : "=r"(__tmp) : "r"(vl)); +} + +static inline long vgetcfg() +{ + int cfg; + asm volatile ("vgetcfg %0" : "=r"(cfg) :); + return cfg; +} + +static inline long vgetvl() +{ + int vl; + asm volatile ("vgetvl %0" : "=r"(vl) :); +} + +static inline long vxcptaux() +{ + int aux; + asm volatile ("vxcptaux %0" : "=r"(aux) :); + return aux; +} + +static inline void vxcptrestore(long* mem) +{ + asm volatile("vxcptrestore %0" : : "r"(mem) : "memory"); +} + +static inline void vxcptevac(long* mem) +{ + asm volatile ("vxcptevac %0" : : "r"(mem)); +} + +typedef unsigned long pte_t; +#define LEVELS (sizeof(pte_t) == sizeof(uint64_t) ? 3 : 2) +#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)) + +typedef struct +{ + long gpr[32]; + long sr; + long epc; + long badvaddr; + long cause; + long insn; + long hwacha_cause; + long evac[2560]; +} trapframe_t; +#endif + +#endif @@ -0,0 +1,275 @@ +#include <stdint.h> +#include <string.h> +#include <stdio.h> + +#include "riscv_test.h" + +void trap_entry(); +void pop_tf(trapframe_t*); + +static void cputchar(int x) +{ + while (mtpcr(PCR_TOHOST, 0x0101000000000000 | (unsigned char)x)); +} + +static void cputstring(const char* s) +{ + while(*s) + cputchar(*s++); + cputchar('\n'); +} + +static void terminate(int code) +{ + while (mtpcr(PCR_TOHOST, code)); + while (1); +} + +#define stringify1(x) #x +#define stringify(x) stringify1(x) +#define assert(x) do { \ + if (x) break; \ + cputstring("Assertion failed: " stringify(x)); \ + terminate(3); \ +} while(0) + +#define RELOC(x) ((typeof(x))((char*)(x) + (PGSIZE*MAX_TEST_PAGES))) + +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))); +freelist_t user_mapping[MAX_TEST_PAGES]; +freelist_t freelist_nodes[MAX_TEST_PAGES]; +freelist_t *freelist_head, *freelist_tail; + +void printhex(uint64_t x) +{ + char str[17]; + for (int i = 0; i < 16; i++) + { + str[15-i] = (x & 0xF) + ((x & 0xF) < 10 ? '0' : 'a'-10); + x >>= 4; + } + str[16] = 0; + + cputstring(str); +} + +void evict(unsigned long addr) +{ + assert(addr >= PGSIZE && addr < RELOC(0L)); + addr = addr/PGSIZE*PGSIZE; + + freelist_t* node = RELOC(&user_mapping[addr/PGSIZE]); + if (node->addr) + { + memcpy((void*)RELOC(addr), (void*)addr, PGSIZE); + RELOC(&user_mapping[addr/PGSIZE])->addr = 0; + + if (*RELOC(&freelist_tail) == 0) + *RELOC(&freelist_head) = *RELOC(&freelist_tail) = node; + else + { + (*RELOC(&freelist_tail))->next = node; + *RELOC(&freelist_tail) = node; + } + } +} + +void handle_fault(unsigned long addr) +{ + assert(addr >= PGSIZE && addr < RELOC(0L)); + addr = addr/PGSIZE*PGSIZE; + + freelist_t* node = *RELOC(&freelist_head); + assert(node); + *RELOC(&freelist_head) = node->next; + if (*RELOC(&freelist_head) == *RELOC(&freelist_tail)) + *RELOC(&freelist_tail) = 0; + + *RELOC(&l3pt[addr/PGSIZE]) = node->addr | PTE_UW | PTE_UR | PTE_UX | PTE_SW | PTE_SR | PTE_SX | PTE_V; + mtpcr(PCR_FATC, 0); + + assert(RELOC(&user_mapping[addr/PGSIZE])->addr == 0); + *RELOC(&user_mapping[addr/PGSIZE]) = *node; + memcpy((void*)addr, (void*)RELOC(addr), PGSIZE); + + __builtin___clear_cache(0,0); +} + +static void emulate_vxcptsave(trapframe_t* tf) +{ + long* where = (long*)tf->gpr[(tf->insn >> 15) & 0x1F]; + + where[0] = vgetcfg(); + where[1] = vgetvl(); + vxcptevac(&where[2]); + fence(); +} + +static void do_vxcptrestore(long* where) +{ + vsetcfg(where[0]); + vsetvl(where[1]); + + vxcpthold(); + + int idx = 2; + long dword, cmd, pf; + int first = 1; + + while (1) + { + dword = where[idx++]; + + if (dword < 0) break; + + if (dword_bit_cnt(dword)) + { + venqcnt(dword, pf | (dword_bit_cmd(where[idx]) << 1)); + } + else + { + if (!first) + { + venqcmd(cmd, pf); + } + + first = 0; + cmd = dword; + pf = dword_bit_pf(cmd); + + if (dword_bit_imm1(cmd)) + { + venqimm1(where[idx++], pf); + } + if (dword_bit_imm2(cmd)) + { + venqimm2(where[idx++], pf); + } + } + } + if (!first) + { + venqcmd(cmd, pf); + } +} + +static void emulate_vxcptrestore(trapframe_t* tf) +{ + long* where = (long*)tf->gpr[(tf->insn >> 15) & 0x1F]; + vxcptkill(); + do_vxcptrestore(where); +} + +static void restore_vector(trapframe_t* tf) +{ + if (mfpcr(PCR_IMPL) == IMPL_ROCKET) + do_vxcptrestore(tf->evac); + else + vxcptrestore(tf->evac); +} + +void handle_trap(trapframe_t* tf) +{ + if (tf->cause == CAUSE_SYSCALL) + { + int n = tf->gpr[18]; + + for (long i = 1; i < MAX_TEST_PAGES; i++) + evict(i*PGSIZE); + + terminate(n); + } + else if (tf->cause == CAUSE_FAULT_FETCH) + handle_fault(tf->epc); + else if (tf->cause == CAUSE_ILLEGAL_INSTRUCTION) + { + int fssr; + asm ("la %0, 1f; lw %0, 0(%0); b 2f; 1: fssr x0; 2:" : "=r"(fssr)); + + if (tf->insn == fssr) + terminate(1); // FP test on non-FP hardware. "succeed." +#if 0 + else if ((tf->insn & 0xF83FFFFF) == 0x37B) + emulate_vxcptsave(tf); + else if ((tf->insn & 0xF83FFFFF) == 0x77B) + emulate_vxcptrestore(tf); +#endif + else + assert(0); + tf->epc += 4; + } + else if (tf->cause == CAUSE_FAULT_LOAD || tf->cause == CAUSE_FAULT_STORE) + handle_fault(tf->badvaddr); + else if ((tf->cause << 1) == (IRQ_COP << 1)) + { + if (tf->hwacha_cause == HWACHA_CAUSE_VF_FAULT_FETCH || + tf->hwacha_cause == HWACHA_CAUSE_FAULT_LOAD || + tf->hwacha_cause == HWACHA_CAUSE_FAULT_STORE) + { + long badvaddr = vxcptaux(); + handle_fault(badvaddr); + } + else + assert(0); + } + else + assert(0); + +out: + if (!(tf->sr & SR_PS) && (tf->sr & SR_EA)) { + restore_vector(tf); + tf->sr |= SR_PEI; + } + pop_tf(tf); +} + +void vm_boot(long test_addr, long seed) +{ + while (mfpcr(PCR_HARTID) > 0); // only core 0 proceeds + + assert(SIZEOF_TRAPFRAME_T == sizeof(trapframe_t)); + + seed = 1 + (seed % MAX_TEST_PAGES); + freelist_head = RELOC(&freelist_nodes[0]); + freelist_tail = RELOC(&freelist_nodes[MAX_TEST_PAGES-1]); + for (long i = 0; i < MAX_TEST_PAGES; i++) + { + freelist_nodes[i].addr = (MAX_TEST_PAGES+i)*PGSIZE; + freelist_nodes[i].next = RELOC(&freelist_nodes[i+1]); + seed = LFSR_NEXT(seed); + } + freelist_nodes[MAX_TEST_PAGES-1].next = 0; + + assert(MAX_TEST_PAGES*2 < PTES_PER_PT); + l1pt[0] = (pte_t)l2pt | PTE_V | PTE_T; + l2pt[0] = (pte_t)l3pt | PTE_V | PTE_T; + for (long i = 0; i < MAX_TEST_PAGES; i++) + l3pt[i] = l3pt[i+MAX_TEST_PAGES] = (i*PGSIZE) | PTE_SW | PTE_SR | PTE_SX | PTE_V; + + mtpcr(PCR_PTBR, l1pt); + mtpcr(PCR_SR, mfpcr(PCR_SR) | SR_VM | SR_EF); + + // relocate + long adjustment = RELOC(0L), tmp; + mtpcr(PCR_EVEC, (char*)&trap_entry + adjustment); + asm volatile ("add sp, sp, %1\n" + "jal %0, 1f\n" + "1: add %0, %0, %1\n" + "jr %0, 8" + : "=&r"(tmp) + : "r"(adjustment)); + + memset(RELOC(&l3pt[0]), 0, MAX_TEST_PAGES*sizeof(pte_t)); + mtpcr(PCR_FATC, 0); + + trapframe_t tf; + memset(&tf, 0, sizeof(tf)); + tf.sr = SR_PEI | ((1 << IRQ_COP) << SR_IM_SHIFT) | SR_EF | SR_EA | SR_S | SR_U64 | SR_S64 | SR_VM; + tf.epc = test_addr; + + pop_tf(&tf); +} |