summaryrefslogtreecommitdiff
path: root/v/vm.c
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 /v/vm.c
downloadenv-f3545105d54ab746efac58b96e998a252cafd16b.zip
env-f3545105d54ab746efac58b96e998a252cafd16b.tar.gz
env-f3545105d54ab746efac58b96e998a252cafd16b.tar.bz2
split out envs from riscv-tests
Diffstat (limited to 'v/vm.c')
-rw-r--r--v/vm.c275
1 files changed, 275 insertions, 0 deletions
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);
+}