From 81ad66f25ce4c15180e558696961bd8eaf967fea Mon Sep 17 00:00:00 2001 From: Yunsup Lee Date: Mon, 22 Apr 2013 14:56:59 -0700 Subject: initial commit --- env/p/link.ld | 44 +++++++++ env/p/riscv_test.h | 76 +++++++++++++++ env/pm/link.ld | 44 +++++++++ env/pm/riscv_test.h | 75 +++++++++++++++ env/pt/link.ld | 44 +++++++++ env/pt/pcr.h | 93 +++++++++++++++++++ env/pt/riscv_test.h | 236 ++++++++++++++++++++++++++++++++++++++++++++++ env/v/entry.S | 171 ++++++++++++++++++++++++++++++++++ env/v/link.ld | 50 ++++++++++ env/v/pcr.h | 93 +++++++++++++++++++ env/v/riscv_test.h | 129 ++++++++++++++++++++++++++ env/v/vm.c | 263 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 12 files changed, 1318 insertions(+) create mode 100644 env/p/link.ld create mode 100644 env/p/riscv_test.h create mode 100644 env/pm/link.ld create mode 100644 env/pm/riscv_test.h create mode 100644 env/pt/link.ld create mode 100644 env/pt/pcr.h create mode 100644 env/pt/riscv_test.h create mode 100644 env/v/entry.S create mode 100644 env/v/link.ld create mode 100644 env/v/pcr.h create mode 100644 env/v/riscv_test.h create mode 100644 env/v/vm.c (limited to 'env') diff --git a/env/p/link.ld b/env/p/link.ld new file mode 100644 index 0000000..6b19389 --- /dev/null +++ b/env/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/env/p/riscv_test.h b/env/p/riscv_test.h new file mode 100644 index 0000000..a4f9668 --- /dev/null +++ b/env/p/riscv_test.h @@ -0,0 +1,76 @@ +#ifndef _ENV_PHYSICAL_SINGLE_CORE_H +#define _ENV_PHYSICAL_SINGLE_CORE_H + +//----------------------------------------------------------------------- +// Begin Macro +//----------------------------------------------------------------------- + +#define RVTEST_RV64U \ + +#define RVTEST_RV64S \ + +#define RVTEST_FP_ENABLE \ + setpcr cr0, 2; \ + mfpcr a0, cr0; \ + and a0, a0, 2; \ + beqz a0, 1f; \ + mtfsr x0; \ +1: + +#define RVTEST_PASS_NOFP \ + RVTEST_FP_ENABLE \ + bnez a0, 2f; \ + RVTEST_PASS \ +2: \ + +#define RVTEST_VEC_ENABLE \ + mfpcr a0, cr0; \ + ori a0, a0, 4; \ + mtpcr a0, cr0; \ + li a0, 0xff; \ + mtpcr a0, cr18; \ + +#define RVTEST_CODE_BEGIN \ + .text; \ + .align 4; \ + .global _start; \ +_start: \ + RVTEST_FP_ENABLE \ + RVTEST_VEC_ENABLE \ + mfpcr a0, cr10; 1: bnez a0, 1b; \ + +//----------------------------------------------------------------------- +// End Macro +//----------------------------------------------------------------------- + +#define RVTEST_CODE_END \ + +//----------------------------------------------------------------------- +// Pass/Fail Macro +//----------------------------------------------------------------------- + +#define RVTEST_PASS \ + fence; \ + li x1, 1; \ + mtpcr x1, cr30; \ +1: b 1b; \ + +#define RVTEST_FAIL \ + fence; \ + beqz x28, 1f; \ + sll x28, x28, 1; \ + or x28, x28, 1; \ + mtpcr x28, cr30; \ +1: b 1b; \ + +//----------------------------------------------------------------------- +// 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: + +#endif diff --git a/env/pm/link.ld b/env/pm/link.ld new file mode 100644 index 0000000..6b19389 --- /dev/null +++ b/env/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/env/pm/riscv_test.h b/env/pm/riscv_test.h new file mode 100644 index 0000000..102e6e0 --- /dev/null +++ b/env/pm/riscv_test.h @@ -0,0 +1,75 @@ +#ifndef _ENV_PHYSICAL_MULTI_CORE_H +#define _ENV_PHYSICAL_MULTI_CORE_H + +//----------------------------------------------------------------------- +// Begin Macro +//----------------------------------------------------------------------- + +#define RVTEST_RV64U \ + +#define RVTEST_RV64S \ + +#define RVTEST_FP_ENABLE \ + setpcr cr0, 2; \ + mfpcr a0, cr0; \ + and a0, a0, 2; \ + beqz a0, 1f; \ + mtfsr x0; \ +1: + +#define RVTEST_PASS_NOFP \ + RVTEST_FP_ENABLE \ + bnez a0, 2f; \ + RVTEST_PASS \ +2: \ + +#define RVTEST_VEC_ENABLE \ + mfpcr a0, cr0; \ + ori a0, a0, 4; \ + mtpcr a0, cr0; \ + li a0, 0xff; \ + mtpcr a0, cr18; \ + +#define RVTEST_CODE_BEGIN \ + .text; \ + .align 4; \ + .global _start; \ +_start: \ + RVTEST_FP_ENABLE \ + RVTEST_VEC_ENABLE \ + +//----------------------------------------------------------------------- +// End Macro +//----------------------------------------------------------------------- + +#define RVTEST_CODE_END \ + +//----------------------------------------------------------------------- +// Pass/Fail Macro +//----------------------------------------------------------------------- + +#define RVTEST_FAIL \ + fence; \ + beqz x28, 1f; \ + sll x28, x28, 1; \ + or x28, x28, 1; \ + mtpcr x28, cr30; \ +1: b 1b; \ + +#define RVTEST_PASS \ + fence; \ + li x1, 1; \ + mtpcr x1, cr30; \ +1: b 1b; \ + +//----------------------------------------------------------------------- +// 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: + +#endif diff --git a/env/pt/link.ld b/env/pt/link.ld new file mode 100644 index 0000000..6b19389 --- /dev/null +++ b/env/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/env/pt/pcr.h b/env/pt/pcr.h new file mode 100644 index 0000000..72043b7 --- /dev/null +++ b/env/pt/pcr.h @@ -0,0 +1,93 @@ +#ifndef _RISCV_PCR_H +#define _RISCV_PCR_H + +#define SR_ET 0x00000001 +#define SR_EF 0x00000002 +#define SR_EV 0x00000004 +#define SR_EC 0x00000008 +#define SR_PS 0x00000010 +#define SR_S 0x00000020 +#define SR_U64 0x00000040 +#define SR_S64 0x00000080 +#define SR_VM 0x00000100 +#define SR_IM 0x00FF0000 +#define SR_ZERO ~(SR_ET|SR_EF|SR_EV|SR_EC|SR_PS|SR_S|SR_U64|SR_S64|SR_VM|SR_IM) +#define SR_IM_SHIFT 16 + +#define PCR_SR 0 +#define PCR_EPC 1 +#define PCR_BADVADDR 2 +#define PCR_EVEC 3 +#define PCR_COUNT 4 +#define PCR_COMPARE 5 +#define PCR_CAUSE 6 +#define PCR_PTBR 7 +#define PCR_SEND_IPI 8 +#define PCR_CLR_IPI 9 +#define PCR_COREID 10 +#define PCR_IMPL 11 +#define PCR_K0 12 +#define PCR_K1 13 +#define PCR_VECBANK 18 +#define PCR_VECCFG 19 +#define PCR_RESET 29 +#define PCR_TOHOST 30 +#define PCR_FROMHOST 31 + +#define IMPL_ISASIM 1 +#define IMPL_ROCKET 2 + +#define IRQ_IPI 5 +#define IRQ_TIMER 7 + +#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_VECTOR_DISABLED 12 +#define CAUSE_VECTOR_BANK 13 + +#define CAUSE_VECTOR_MISALIGNED_FETCH 24 +#define CAUSE_VECTOR_FAULT_FETCH 25 +#define CAUSE_VECTOR_ILLEGAL_INSTRUCTION 26 +#define CAUSE_VECTOR_ILLEGAL_COMMAND 27 +#define CAUSE_VECTOR_MISALIGNED_LOAD 28 +#define CAUSE_VECTOR_MISALIGNED_STORE 29 +#define CAUSE_VECTOR_FAULT_LOAD 30 +#define CAUSE_VECTOR_FAULT_STORE 31 + +#ifdef __riscv + +#define ASM_CR(r) _ASM_CR(r) +#define _ASM_CR(r) cr##r + +#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; }) + +#endif + +#endif + +#endif diff --git a/env/pt/riscv_test.h b/env/pt/riscv_test.h new file mode 100644 index 0000000..4c42803 --- /dev/null +++ b/env/pt/riscv_test.h @@ -0,0 +1,236 @@ +#ifndef _ENV_PHYSICAL_SINGLE_CORE_TIMER_H +#define _ENV_PHYSICAL_SINGLE_CORE_TIMER_H + +#include "pcr.h" + +//----------------------------------------------------------------------- +// Begin Macro +//----------------------------------------------------------------------- + +#define RVTEST_RV64U \ + +#define RVTEST_FP_ENABLE \ + setpcr cr0, 2; \ + mfpcr a0, cr0; \ + and a0, a0, 2; \ + beqz a0, 1f; \ + mtfsr x0; \ +1: + +#define RVTEST_PASS_NOFP \ + RVTEST_FP_ENABLE \ + bnez a0, 2f; \ + RVTEST_PASS \ +2: \ + +#define RVTEST_VEC_ENABLE \ + mfpcr a0, cr0; \ + ori a0, a0, 4; \ + mtpcr a0, cr0; \ + li a0, 0xff; \ + mtpcr a0, cr18; \ + +#define RVTEST_CODE_BEGIN \ + .text; \ + .align 4; \ + .global _start; \ +_start: \ + RVTEST_FP_ENABLE \ + RVTEST_VEC_ENABLE \ + mfpcr a0, cr10; 1: bnez a0, 1b; \ + ENABLE_TIMER_INTERRUPT \ + +//----------------------------------------------------------------------- +// End Macro +//----------------------------------------------------------------------- + +#define RVTEST_CODE_END \ + XCPT_HANDLER \ + +//----------------------------------------------------------------------- +// Pass/Fail Macro +//----------------------------------------------------------------------- + +#define RVTEST_PASS \ + fence; \ + li x1, 1; \ + mtpcr x1, cr30; \ +1: b 1b; \ + +#define RVTEST_FAIL \ + fence; \ + beqz x28, 1f; \ + sll x28, x28, 1; \ + or x28, x28, 1; \ + mtpcr x28, cr30; \ +1: b 1b; \ + +//----------------------------------------------------------------------- +// Data Section Macro +//----------------------------------------------------------------------- + +#define RVTEST_DATA_BEGIN \ + .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: \ + .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; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + .dword 0xdeadbeefcafebabe; \ + +#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: + +//----------------------------------------------------------------------- +// Misc +//----------------------------------------------------------------------- + +#define ENABLE_TIMER_INTERRUPT \ + mtpcr x0,ASM_CR(PCR_CLR_IPI);\ + mfpcr a0,ASM_CR(PCR_SR); \ + li a1, SR_ET|SR_IM; \ + or a0,a0,a1; \ + mtpcr a0,ASM_CR(PCR_SR); \ + la a0,handler; \ + mtpcr a0,ASM_CR(PCR_EVEC); \ + mtpcr x0,ASM_CR(PCR_COUNT); \ + addi a0,x0,60; \ + mtpcr a0,ASM_CR(PCR_COMPARE);\ + +#define XCPT_HANDLER \ +handler: \ + mtpcr a0,ASM_CR(PCR_K0); \ + mtpcr a1,ASM_CR(PCR_K1); \ + 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); \ + mfpcr s1,ASM_CR(PCR_VECBANK);\ + mfpcr s0,ASM_CR(PCR_VECCFG); \ + la a0,evac; \ + vxcptevac a0; \ + mtpcr s1,ASM_CR(PCR_VECBANK);\ + srli a1,s0,12; \ + andi a1,a1,0x3f; \ + srli a2,s0,18; \ + andi a2,a2,0x3f; \ + vvcfg a1,a2; \ + li a2,0xfff; \ + and a1,s0,a2; \ + vsetvl a1,a1; \ + 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,ASM_CR(PCR_COUNT); \ + addi a0,a0,60; \ + mtpcr a0,ASM_CR(PCR_COMPARE);\ + mfpcr a0,ASM_CR(PCR_K0); \ + mfpcr a1,ASM_CR(PCR_K1); \ + eret; \ + +#endif diff --git a/env/v/entry.S b/env/v/entry.S new file mode 100644 index 0000000..35eaae3 --- /dev/null +++ b/env/v/entry.S @@ -0,0 +1,171 @@ +#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,ASM_CR(PCR_K0) + STORE x3,1*REGBYTES(x2) # x1 is in PCR_K0 + mfpcr x3,ASM_CR(PCR_K1) + STORE x3,2*REGBYTES(x2) # x2 is in PCR_K1 + + # get sr, epc, badvaddr, cause + mfpcr x3,ASM_CR(PCR_SR) # sr + STORE x3,32*REGBYTES(x2) + mfpcr x4,ASM_CR(PCR_EPC) # epc + STORE x4,33*REGBYTES(x2) + mfpcr x3,ASM_CR(PCR_BADVADDR) # badvaddr + STORE x3,34*REGBYTES(x2) + mfpcr x3,ASM_CR(PCR_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 x3,0(x4) + lh x4,2(x4) + sh x3, 36*REGBYTES(x2) + sh x4,2+36*REGBYTES(x2) +1: + + mfpcr x3,ASM_CR(PCR_VECBANK) # vecbank + STORE x3,37*REGBYTES(x2) + mfpcr x3,ASM_CR(PCR_VECCFG) # veccfg + STORE x3,38*REGBYTES(x2) + + 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,ASM_CR(PCR_SR) + + LOAD x1,1*REGBYTES(a0) + mtpcr x1,ASM_CR(PCR_K0) + LOAD x1,2*REGBYTES(a0) + mtpcr x1,ASM_CR(PCR_K1) + 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,ASM_CR(PCR_EPC) + mfpcr x1,ASM_CR(PCR_K0) + mfpcr x2,ASM_CR(PCR_K1) + eret + + .global trap_entry +trap_entry: + mtpcr ra,ASM_CR(PCR_K0) + mtpcr x2,ASM_CR(PCR_K1) + + # coming from kernel? + mfpcr ra,ASM_CR(PCR_SR) + 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 ASM_CR(PCR_SR), SR_ET + move a0,x2 + mfpcr ra,ASM_CR(PCR_SR) + and ra,ra,SR_EV + beqz ra, 2f + addi x2,x2,39*REGBYTES + vxcptsave x2 +2:jal handle_trap + + # when coming from kernel, continue below its stack +1:add x2, sp, -SIZEOF_TRAPFRAME_T + jal save_tf + move sp,x2 + setpcr ASM_CR(PCR_SR), SR_ET + move a0,x2 + jal handle_trap + + .bss + .global stack_bot + .global stack_top +stack_bot: + .skip 32768 +stack_top: diff --git a/env/v/link.ld b/env/v/link.ld new file mode 100644 index 0000000..4efeaaa --- /dev/null +++ b/env/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/env/v/pcr.h b/env/v/pcr.h new file mode 100644 index 0000000..72043b7 --- /dev/null +++ b/env/v/pcr.h @@ -0,0 +1,93 @@ +#ifndef _RISCV_PCR_H +#define _RISCV_PCR_H + +#define SR_ET 0x00000001 +#define SR_EF 0x00000002 +#define SR_EV 0x00000004 +#define SR_EC 0x00000008 +#define SR_PS 0x00000010 +#define SR_S 0x00000020 +#define SR_U64 0x00000040 +#define SR_S64 0x00000080 +#define SR_VM 0x00000100 +#define SR_IM 0x00FF0000 +#define SR_ZERO ~(SR_ET|SR_EF|SR_EV|SR_EC|SR_PS|SR_S|SR_U64|SR_S64|SR_VM|SR_IM) +#define SR_IM_SHIFT 16 + +#define PCR_SR 0 +#define PCR_EPC 1 +#define PCR_BADVADDR 2 +#define PCR_EVEC 3 +#define PCR_COUNT 4 +#define PCR_COMPARE 5 +#define PCR_CAUSE 6 +#define PCR_PTBR 7 +#define PCR_SEND_IPI 8 +#define PCR_CLR_IPI 9 +#define PCR_COREID 10 +#define PCR_IMPL 11 +#define PCR_K0 12 +#define PCR_K1 13 +#define PCR_VECBANK 18 +#define PCR_VECCFG 19 +#define PCR_RESET 29 +#define PCR_TOHOST 30 +#define PCR_FROMHOST 31 + +#define IMPL_ISASIM 1 +#define IMPL_ROCKET 2 + +#define IRQ_IPI 5 +#define IRQ_TIMER 7 + +#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_VECTOR_DISABLED 12 +#define CAUSE_VECTOR_BANK 13 + +#define CAUSE_VECTOR_MISALIGNED_FETCH 24 +#define CAUSE_VECTOR_FAULT_FETCH 25 +#define CAUSE_VECTOR_ILLEGAL_INSTRUCTION 26 +#define CAUSE_VECTOR_ILLEGAL_COMMAND 27 +#define CAUSE_VECTOR_MISALIGNED_LOAD 28 +#define CAUSE_VECTOR_MISALIGNED_STORE 29 +#define CAUSE_VECTOR_FAULT_LOAD 30 +#define CAUSE_VECTOR_FAULT_STORE 31 + +#ifdef __riscv + +#define ASM_CR(r) _ASM_CR(r) +#define _ASM_CR(r) cr##r + +#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; }) + +#endif + +#endif + +#endif diff --git a/env/v/riscv_test.h b/env/v/riscv_test.h new file mode 100644 index 0000000..4d9cceb --- /dev/null +++ b/env/v/riscv_test.h @@ -0,0 +1,129 @@ +#ifndef _ENV_VIRTUAL_SINGLE_CORE_H +#define _ENV_VIRTUAL_SINGLE_CORE_H + +//----------------------------------------------------------------------- +// Begin Macro +//----------------------------------------------------------------------- + +#define RVTEST_RV64U \ + +#define RVTEST_RV64S \ + +#define RVTEST_FP_ENABLE \ + mfpcr t0, cr0; \ + or t0, t0, 2; \ + mtpcr t0, cr0; \ + mtfsr x0; \ + +#define RVTEST_VEC_ENABLE \ + mfpcr t0, cr0; \ + ori t0, t0, 4; \ + mtpcr t0, cr0; \ + li t0, 0xff; \ + mtpcr t0, cr11; \ + +#define RVTEST_CODE_BEGIN \ + .text; \ + .align 13; \ + .global userstart; \ +userstart: \ + +//----------------------------------------------------------------------- +// 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; + +#define RVTEST_PASS_NOFP li a0, 1234; 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" + +#define vvcfg(nxregs, nfregs) ({ \ + asm volatile ("vvcfg %0,%1" : : "r"(nxregs), "r"(nfregs)); }) + +#define vsetvl(vl) ({ long __tmp; \ + asm volatile ("vsetvl %0,%1" : "=r"(__tmp) : "r"(vl)); }) + +#define vcfg(word) ({ vvcfg((word)>>12, (word)>>18); vsetvl((word)); }) + +#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 fencevl() ({ \ + asm volatile ("fence.v.l" ::: "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 1336 + +#ifndef __ASSEMBLER__ + + +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 vecbank; + long veccfg; + long evac[128]; +} trapframe_t; +#endif + +#endif diff --git a/env/v/vm.c b/env/v/vm.c new file mode 100644 index 0000000..37ef19e --- /dev/null +++ b/env/v/vm.c @@ -0,0 +1,263 @@ +#include +#include +#include + +#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)); +} + +#define stringify1(x) #x +#define stringify(x) stringify1(x) +#define assert(x) do { \ + if (x) break; \ + cputstring("Assertion failed: " stringify(x)); \ + terminate(3); \ + while(1); \ +} 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 | 0x3F2; + mtpcr(PCR_PTBR, l1pt); + + 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); +} + +void emulate_vxcptsave(trapframe_t* tf) +{ + long where = tf->gpr[(tf->insn >> 22) & 0x1F]; + + asm volatile ("vxcptevac %0" : : "r"(where)); + fencevl(); +} + +void do_vxcptrestore(long* where) +{ + vxcpthold(); + + int idx = 0; + 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); + } +} + +void emulate_vxcptrestore(trapframe_t* tf) +{ + long* where = (long*)tf->gpr[(tf->insn >> 22) & 0x1F]; + vxcptkill(); + vcfg(tf->veccfg); + do_vxcptrestore(where); +} + +void restore_vector(trapframe_t* tf) +{ + mtpcr(PCR_VECBANK, tf->vecbank); + vcfg(tf->veccfg); + + if (mfpcr(PCR_IMPL) == IMPL_ROCKET) + do_vxcptrestore(tf->evac); + else + asm volatile("vxcptrestore %0" : : "r"(tf->evac) : "memory"); +} + +void handle_trap(trapframe_t* tf) +{ + if (tf->cause == CAUSE_SYSCALL) + { + int n = tf->gpr[18]; + if (n == 1234) // TEST_PASS_NOFP + { + if (mfpcr(PCR_SR) & SR_EF) + { + tf->epc += 4; + goto out; + } + n = 1; + } + + for (long i = 1; i < MAX_TEST_PAGES; i++) + evict(i*PGSIZE); + + terminate(n); + while(1); + } + else if (tf->cause == CAUSE_FAULT_FETCH) + handle_fault(tf->epc); + else if (tf->cause == CAUSE_ILLEGAL_INSTRUCTION) + { + if ((tf->insn & 0xF83FFFFF) == 0x37B) + emulate_vxcptsave(tf); + else if ((tf->insn & 0xF83FFFFF) == 0x77B) + emulate_vxcptrestore(tf); + else + assert(0); + tf->epc += 4; + } + else if (tf->cause == CAUSE_FAULT_LOAD || tf->cause == CAUSE_FAULT_STORE || + tf->cause == CAUSE_VECTOR_FAULT_LOAD || tf->cause == CAUSE_VECTOR_FAULT_STORE || + tf->cause == CAUSE_VECTOR_FAULT_FETCH) + handle_fault(tf->badvaddr); + else + assert(0); + +out: + if (!(tf->sr & SR_PS) && (tf->sr & SR_EV)) + restore_vector(tf); + pop_tf(tf); +} + +void vm_boot(long test_addr, long seed) +{ + while (mfpcr(PCR_COREID) > 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 | 1; + l2pt[0] = (pte_t)l3pt | 1; + for (long i = 0; i < MAX_TEST_PAGES; i++) + l3pt[i] = l3pt[i+MAX_TEST_PAGES] = (i*PGSIZE) | 0x382; + + mtpcr(PCR_PTBR, l1pt); + mtpcr(PCR_SR, mfpcr(PCR_SR) | SR_VM | SR_EF); + + if (mfpcr(PCR_SR) & SR_EF) + asm volatile ("mtfsr x0"); + + // relocate + long adjustment = RELOC(0L), tmp; + mtpcr(PCR_EVEC, (char*)&trap_entry + adjustment); + asm volatile ("add sp, sp, %1; rdpc %0; addi %0, %0, 16; add %0, %0, %1; jr %0" : "=&r"(tmp) : "r"(adjustment)); + + memset(RELOC(&l3pt[0]), 0, MAX_TEST_PAGES*sizeof(pte_t)); + mtpcr(PCR_PTBR, l1pt); + + trapframe_t tf; + memset(&tf, 0, sizeof(tf)); + tf.sr = SR_EF | SR_EV | SR_S | SR_U64 | SR_S64 | SR_VM; + tf.epc = test_addr; + + pop_tf(&tf); +} -- cgit v1.1