aboutsummaryrefslogtreecommitdiff
path: root/src/arch/riscv/sbi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/riscv/sbi.c')
-rw-r--r--src/arch/riscv/sbi.c121
1 files changed, 121 insertions, 0 deletions
diff --git a/src/arch/riscv/sbi.c b/src/arch/riscv/sbi.c
new file mode 100644
index 0000000000..832d4d3d97
--- /dev/null
+++ b/src/arch/riscv/sbi.c
@@ -0,0 +1,121 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2018 HardenedLinux
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <mcall.h>
+#include <stdint.h>
+#include <commonlib/compiler.h>
+#include <arch/exception.h>
+#include <sbi.h>
+#include <vm.h>
+#include <console/uart.h>
+#include <console/console.h>
+#include <commonlib/helpers.h>
+
+static uintptr_t send_ipi(uintptr_t *pmask, intptr_t type)
+{
+ uintptr_t mask = mprv_read_uintptr_t(pmask);
+ for (int i = 0; mask; i++) {
+ if (mask & 1) {
+ OTHER_HLS(i)->ipi_pending |= type;
+ /* send soft interrupt to target hart */
+ set_msip(i, 1);
+ }
+ mask = mask >> 1;
+ }
+ return 0;
+}
+
+static uintptr_t sbi_set_timer(uint64_t when)
+{
+ clear_csr(mip, MIP_STIP);
+ set_csr(mie, MIP_MTIP);
+ *(HLS()->timecmp) = when;
+ return 0;
+}
+
+#if IS_ENABLED(CONFIG_CONSOLE_SERIAL)
+static uintptr_t sbi_console_putchar(uint8_t ch)
+{
+ uart_tx_byte(CONFIG_UART_FOR_CONSOLE, ch);
+ return 0;
+}
+
+static uintptr_t sbi_console_getchar(void)
+{
+ return uart_rx_byte(CONFIG_UART_FOR_CONSOLE);
+}
+#endif
+
+static uintptr_t sbi_clear_ipi(void)
+{
+ clear_csr(mip, MIP_SSIP);
+ return 0;
+}
+
+
+/*
+ * sbi is triggered by the s-mode ecall
+ * parameter : register a0 a1 a2
+ * function : register a7
+ * return : register a0
+ */
+void handle_sbi(trapframe *tf)
+{
+ uintptr_t ret = 0;
+ uintptr_t arg0 = tf->gpr[10];
+ __unused uintptr_t arg1 = tf->gpr[11];
+ uintptr_t which = tf->gpr[17];
+
+ switch (which) {
+ case SBI_SET_TIMER:
+#if __riscv_xlen == 32
+ ret = sbi_set_timer(arg0 + ((uint64_t)arg1 << 32));
+#else
+ ret = sbi_set_timer(arg0);
+#endif
+ break;
+#if IS_ENABLED(CONFIG_CONSOLE_SERIAL)
+ case SBI_CONSOLE_PUTCHAR:
+ ret = sbi_console_putchar(arg0);
+ break;
+ case SBI_CONSOLE_GETCHAR:
+ ret = sbi_console_getchar();
+ break;
+#endif
+ case SBI_CLEAR_IPI:
+ ret = sbi_clear_ipi();
+ break;
+ case SBI_SEND_IPI:
+ ret = send_ipi((uintptr_t *)arg0, IPI_SOFT);
+ break;
+ case SBI_REMOTE_FENCE_I:
+ ret = send_ipi((uintptr_t *)arg0, IPI_FENCE_I);
+ break;
+ case SBI_REMOTE_SFENCE_VMA:
+ ret = send_ipi((uintptr_t *)arg0, IPI_SFENCE_VMA);
+ break;
+ case SBI_REMOTE_SFENCE_VMA_ASID:
+ ret = send_ipi((uintptr_t *)arg0, IPI_SFENCE_VMA_ASID);
+ break;
+ case SBI_SHUTDOWN:
+ ret = send_ipi((uintptr_t *)arg0, IPI_SHUTDOWN);
+ break;
+ default:
+ ret = -38;
+ break;
+ }
+ tf->gpr[10] = ret;
+ write_csr(mepc, read_csr(mepc) + 4);
+}