aboutsummaryrefslogtreecommitdiff
path: root/pk/mtrap.c
diff options
context:
space:
mode:
Diffstat (limited to 'pk/mtrap.c')
-rw-r--r--pk/mtrap.c281
1 files changed, 0 insertions, 281 deletions
diff --git a/pk/mtrap.c b/pk/mtrap.c
deleted file mode 100644
index b64360e..0000000
--- a/pk/mtrap.c
+++ /dev/null
@@ -1,281 +0,0 @@
-#include "mtrap.h"
-#include "frontend.h"
-#include "mcall.h"
-#include "vm.h"
-#include <errno.h>
-#include <stdarg.h>
-#include <stdio.h>
-
-void __attribute__((noreturn)) bad_trap()
-{
- die("machine mode: unhandlable trap %d @ %p", read_csr(mcause), read_csr(mepc));
-}
-
-static uintptr_t mcall_hart_id()
-{
- return read_const_csr(mhartid);
-}
-
-static void request_htif_keyboard_interrupt()
-{
- uintptr_t old_tohost = swap_csr(mtohost, TOHOST_CMD(1, 0, 0));
- assert(old_tohost == 0);
-}
-
-void htif_interrupt()
-{
- uintptr_t fromhost = swap_csr(mfromhost, 0);
- // we should only be interrupted by keypresses
- if (!(FROMHOST_DEV(fromhost) == 1 && FROMHOST_CMD(fromhost) == 0))
- die("unexpected htif interrupt");
- HLS()->console_ibuf = 1 + (uint8_t)FROMHOST_DATA(fromhost);
- set_csr(mip, MIP_SSIP);
-}
-
-static void do_tohost_fromhost(uintptr_t dev, uintptr_t cmd, uintptr_t data)
-{
- while (swap_csr(mtohost, TOHOST_CMD(dev, cmd, data)) != 0)
- if (read_csr(mfromhost))
- htif_interrupt();
-
- while (1) {
- uintptr_t fromhost = read_csr(mfromhost);
- if (fromhost) {
- if (FROMHOST_DEV(fromhost) == dev && FROMHOST_CMD(fromhost) == cmd) {
- write_csr(mfromhost, 0);
- break;
- }
- htif_interrupt();
- }
- }
-}
-
-static uintptr_t mcall_console_putchar(uint8_t ch)
-{
- do_tohost_fromhost(1, 1, ch);
- return 0;
-}
-
-static uintptr_t mcall_htif_syscall(uintptr_t magic_mem)
-{
- do_tohost_fromhost(0, 0, magic_mem);
- return 0;
-}
-
-void poweroff()
-{
- while (1)
- write_csr(mtohost, 1);
-}
-
-void printm(const char* s, ...)
-{
- char buf[256];
- va_list vl;
-
- va_start(vl, s);
- vsnprintf(buf, sizeof buf, s, vl);
- va_end(vl);
-
- for (const char* p = buf; *p; p++)
- mcall_console_putchar(*p);
-}
-
-static void send_ipi(uintptr_t recipient, int event)
-{
- if ((atomic_or(&OTHER_HLS(recipient)->mipi_pending, event) & event) == 0) {
- mb();
- OTHER_HLS(recipient)->csrs[CSR_MIPI] = 1;
- }
-}
-
-static uintptr_t mcall_send_ipi(uintptr_t recipient)
-{
- if (recipient >= num_harts)
- return -1;
-
- send_ipi(recipient, IPI_SOFT);
- return 0;
-}
-
-static void reset_ssip()
-{
- clear_csr(mip, MIP_SSIP);
- mb();
-
- if (HLS()->sipi_pending || HLS()->console_ibuf > 0)
- set_csr(mip, MIP_SSIP);
-}
-
-static uintptr_t mcall_console_getchar()
-{
- int ch = atomic_swap(&HLS()->console_ibuf, -1);
- if (ch >= 0)
- request_htif_keyboard_interrupt();
- reset_ssip();
- return ch - 1;
-}
-
-static uintptr_t mcall_clear_ipi()
-{
- int ipi = atomic_swap(&HLS()->sipi_pending, 0);
- reset_ssip();
- return ipi;
-}
-
-static uintptr_t mcall_shutdown()
-{
- poweroff();
-}
-
-static uintptr_t mcall_set_timer(unsigned long long when)
-{
- // bbl/pk don't use the timer, so there's no need to virtualize it
- write_csr(mtimecmp, when);
-#ifndef __riscv64
- write_csr(mtimecmph, when >> 32);
-#endif
- clear_csr(mip, MIP_STIP);
- set_csr(mie, MIP_MTIP);
- return 0;
-}
-
-void software_interrupt()
-{
- clear_csr(mip, MIP_MSIP);
- mb();
- int ipi_pending = atomic_swap(&HLS()->mipi_pending, 0);
-
- if (ipi_pending & IPI_SOFT) {
- HLS()->sipi_pending = 1;
- set_csr(mip, MIP_SSIP);
- }
-
- if (ipi_pending & IPI_FENCE_I)
- asm volatile ("fence.i");
-
- if (ipi_pending & IPI_SFENCE_VM)
- asm volatile ("sfence.vm");
-}
-
-static void send_ipi_many(uintptr_t* pmask, int event)
-{
- _Static_assert(MAX_HARTS <= 8 * sizeof(*pmask), "# harts > uintptr_t bits");
- uintptr_t mask = -1;
- if (pmask)
- mask = *pmask;
-
- // send IPIs to everyone
- for (ssize_t i = num_harts-1; i >= 0; i--)
- if ((mask >> i) & 1)
- send_ipi(i, event);
-
- // wait until all events have been handled.
- // prevent deadlock while spinning by handling any IPIs from other harts.
- for (ssize_t i = num_harts-1; i >= 0; i--)
- if ((mask >> i) & 1)
- while (OTHER_HLS(i)->mipi_pending & event)
- software_interrupt();
-}
-
-static uintptr_t mcall_remote_sfence_vm(uintptr_t* hart_mask, uintptr_t asid)
-{
- // ignore the ASID and do a global flush.
- // this allows us to avoid queueing a message.
- send_ipi_many(hart_mask, IPI_SFENCE_VM);
- return 0;
-}
-
-static uintptr_t mcall_remote_fence_i(uintptr_t* hart_mask)
-{
- send_ipi_many(hart_mask, IPI_FENCE_I);
- return 0;
-}
-
-void mcall_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc)
-{
- uintptr_t n = regs[17], arg0 = regs[10], arg1 = regs[11], retval;
- switch (n)
- {
- case MCALL_HART_ID:
- retval = mcall_hart_id();
- break;
- case MCALL_CONSOLE_PUTCHAR:
- retval = mcall_console_putchar(arg0);
- break;
- case MCALL_CONSOLE_GETCHAR:
- retval = mcall_console_getchar();
- break;
- case MCALL_HTIF_SYSCALL:
- retval = mcall_htif_syscall(arg0);
- break;
- case MCALL_SEND_IPI:
- retval = mcall_send_ipi(arg0);
- break;
- case MCALL_CLEAR_IPI:
- retval = mcall_clear_ipi();
- break;
- case MCALL_SHUTDOWN:
- retval = mcall_shutdown();
- break;
- case MCALL_SET_TIMER:
- retval = mcall_set_timer(arg0);
- break;
- case MCALL_REMOTE_SFENCE_VM:
- retval = mcall_remote_sfence_vm((uintptr_t*)arg0, arg1);
- break;
- case MCALL_REMOTE_FENCE_I:
- retval = mcall_remote_fence_i((uintptr_t*)arg0);
- break;
- default:
- retval = -ENOSYS;
- break;
- }
- regs[10] = retval;
- write_csr(mepc, mepc + 4);
-}
-
-void redirect_trap(uintptr_t epc, uintptr_t mstatus)
-{
- write_csr(sepc, epc);
- write_csr(scause, read_csr(mcause));
- write_csr(mepc, read_csr(stvec));
-
- uintptr_t prev_priv = EXTRACT_FIELD(mstatus, MSTATUS_MPP);
- uintptr_t prev_ie = EXTRACT_FIELD(mstatus, MSTATUS_MPIE);
- mstatus = INSERT_FIELD(mstatus, MSTATUS_SPP, prev_priv);
- mstatus = INSERT_FIELD(mstatus, MSTATUS_SPIE, prev_ie);
- mstatus = INSERT_FIELD(mstatus, MSTATUS_MPP, PRV_S);
- mstatus = INSERT_FIELD(mstatus, MSTATUS_MPIE, 0);
- write_csr(mstatus, mstatus);
-
- extern void __redirect_trap();
- return __redirect_trap();
-}
-
-static void machine_page_fault(uintptr_t* regs, uintptr_t mepc)
-{
- // MPRV=1 iff this trap occurred while emulating an instruction on behalf
- // of a lower privilege level. In that case, a2=epc and a3=mstatus.
- if (read_csr(mstatus) & MSTATUS_MPRV) {
- write_csr(sbadaddr, read_csr(mbadaddr));
- return redirect_trap(regs[12], regs[13]);
- }
- bad_trap();
-}
-
-void trap_from_machine_mode(uintptr_t* regs, uintptr_t dummy, uintptr_t mepc)
-{
- uintptr_t mcause = read_csr(mcause);
-
- switch (mcause)
- {
- case CAUSE_FAULT_LOAD:
- case CAUSE_FAULT_STORE:
- return machine_page_fault(regs, mepc);
- case CAUSE_MACHINE_ECALL:
- return mcall_trap(regs, mcause, mepc);
- default:
- bad_trap();
- }
-}