summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYunsup Lee <yunsup@cs.berkeley.edu>2013-11-13 18:03:30 -0800
committerYunsup Lee <yunsup@cs.berkeley.edu>2013-11-13 18:03:30 -0800
commitf3545105d54ab746efac58b96e998a252cafd16b (patch)
treeda4932d63a025a7f12cac970c588e9eb5465847e
downloadenv-f3545105d54ab746efac58b96e998a252cafd16b.zip
env-f3545105d54ab746efac58b96e998a252cafd16b.tar.gz
env-f3545105d54ab746efac58b96e998a252cafd16b.tar.bz2
split out envs from riscv-tests
-rw-r--r--hwacha_xcpt.h17
-rw-r--r--p/link.ld44
-rw-r--r--p/riscv_test.h117
-rw-r--r--pcr.h114
-rw-r--r--pm/link.ld44
-rw-r--r--pm/riscv_test.h9
-rw-r--r--pt/link.ld44
-rw-r--r--pt/riscv_test.h159
-rw-r--r--v/entry.S172
-rw-r--r--v/link.ld50
-rw-r--r--v/riscv_test.h155
-rw-r--r--v/vm.c275
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
diff --git a/pcr.h b/pcr.h
new file mode 100644
index 0000000..6c6d986
--- /dev/null
+++ b/pcr.h
@@ -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
diff --git a/v/vm.c b/v/vm.c
new file mode 100644
index 0000000..6b61c02
--- /dev/null
+++ b/v/vm.c
@@ -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);
+}