summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXiang Wang <wxjstz@126.com>2018-08-15 16:27:05 +0800
committerPatrick Georgi <pgeorgi@google.com>2018-11-05 09:04:01 +0000
commit22e0c560bb565642d52e4e0f8bab000c8d06f0b8 (patch)
treea960e9bc01d3d4d9ddb65ba828b64d39a64baade
parent26f725efc235b282e20aa678f8e683a014920b71 (diff)
riscv: add support for supervisor binary interface (SBI)
SBI is runtime service for OS. For an introduction, please refer to https://github.com/riscv/riscv-sbi-doc/blob/master/riscv-sbi.md Change-Id: Ib6c1f21d2f085f02208305dc4e3a0f970d400c27 Signed-off-by: Xiang Wang <wxjstz@126.com> Reviewed-on: https://review.coreboot.org/28096 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
-rw-r--r--src/arch/riscv/Makefile.inc2
-rw-r--r--src/arch/riscv/include/sbi.h37
-rw-r--r--src/arch/riscv/include/vm.h8
-rw-r--r--src/arch/riscv/sbi.c121
-rw-r--r--src/arch/riscv/trap_handler.c20
5 files changed, 187 insertions, 1 deletions
diff --git a/src/arch/riscv/Makefile.inc b/src/arch/riscv/Makefile.inc
index eacf32acfd..aee4b3b167 100644
--- a/src/arch/riscv/Makefile.inc
+++ b/src/arch/riscv/Makefile.inc
@@ -50,6 +50,7 @@ bootblock-y += trap_util.S
bootblock-y += trap_handler.c
bootblock-y += fp_asm.S
bootblock-y += misaligned.c
+bootblock-y += sbi.c
bootblock-y += mcall.c
bootblock-y += virtual_memory.c
bootblock-y += boot.c
@@ -118,6 +119,7 @@ ramstage-y += trap_util.S
ramstage-y += trap_handler.c
ramstage-y += fp_asm.S
ramstage-y += misaligned.c
+ramstage-y += sbi.c
ramstage-y += virtual_memory.c
ramstage-y += stages.c
ramstage-y += misc.c
diff --git a/src/arch/riscv/include/sbi.h b/src/arch/riscv/include/sbi.h
new file mode 100644
index 0000000000..e9301f630c
--- /dev/null
+++ b/src/arch/riscv/include/sbi.h
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#ifndef RISCV_SBI_H
+#define RISCV_SBI_H
+
+#define SBI_SET_TIMER 0
+#define SBI_CONSOLE_PUTCHAR 1
+#define SBI_CONSOLE_GETCHAR 2
+#define SBI_CLEAR_IPI 3
+#define SBI_SEND_IPI 4
+#define SBI_REMOTE_FENCE_I 5
+#define SBI_REMOTE_SFENCE_VMA 6
+#define SBI_REMOTE_SFENCE_VMA_ASID 7
+#define SBI_SHUTDOWN 8
+
+#define IPI_SOFT 1
+#define IPI_FENCE_I 2
+#define IPI_SFENCE_VMA 4
+#define IPI_SFENCE_VMA_ASID 8
+#define IPI_SHUTDOWN 16
+
+void handle_sbi(trapframe *tf);
+
+#endif /* RISCV_SBI_H */
diff --git a/src/arch/riscv/include/vm.h b/src/arch/riscv/include/vm.h
index 749c9c86bf..9f6236ea75 100644
--- a/src/arch/riscv/include/vm.h
+++ b/src/arch/riscv/include/vm.h
@@ -102,6 +102,14 @@ DEFINE_MPRV_WRITE(mprv_write_u64, uint64_t, sd)
DEFINE_MPRV_WRITE(mprv_write_long, long, sd)
DEFINE_MPRV_WRITE(mprv_write_ulong, unsigned long, sd)
+#if __riscv_xlen == 32
+ DEFINE_MPRV_READ(mprv_read_uintptr_t, uintptr_t, lw)
+ DEFINE_MPRV_READ(mprv_write_uintptr_t, uintptr_t, sw)
+#elif __riscv_xlen == 64
+ DEFINE_MPRV_READ(mprv_read_uintptr_t, uintptr_t, ld)
+ DEFINE_MPRV_READ(mprv_write_uintptr_t, uintptr_t, sd)
+#endif
+
#undef DEFINE_MPRV_READ_FLAGS
#undef DEFINE_MPRV_READ
#undef DEFINE_MPRV_READ_MXR
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);
+}
diff --git a/src/arch/riscv/trap_handler.c b/src/arch/riscv/trap_handler.c
index 8029218fb2..73c52787ae 100644
--- a/src/arch/riscv/trap_handler.c
+++ b/src/arch/riscv/trap_handler.c
@@ -19,6 +19,8 @@
#include <console/console.h>
#include <string.h>
#include <vm.h>
+#include <mcall.h>
+#include <sbi.h>
static const char *const exception_names[] = {
"Instruction address misaligned",
@@ -92,6 +94,20 @@ static void interrupt_handler(trapframe *tf)
set_csr(mip, MIP_STIP);
break;
+ case IRQ_M_SOFT:
+ if (HLS()->ipi_pending & IPI_SOFT) {
+ set_csr(mip, MIP_SSIP);
+ } else if (HLS()->ipi_pending & IPI_FENCE_I) {
+ asm volatile("fence.i");
+ } else if (HLS()->ipi_pending & IPI_SFENCE_VMA) {
+ asm volatile("sfence.vma");
+ } else if (HLS()->ipi_pending & IPI_SFENCE_VMA_ASID) {
+ asm volatile("sfence.vma");
+ } else if (HLS()->ipi_pending & IPI_SHUTDOWN) {
+ while (HLS()->ipi_pending & IPI_SHUTDOWN)
+ asm volatile("wfi");
+ }
+ break;
default:
printk(BIOS_EMERG, "======================================\n");
printk(BIOS_EMERG, "coreboot: Unknown machine interrupt: 0x%llx\n",
@@ -117,11 +133,13 @@ void trap_handler(trapframe *tf)
case CAUSE_LOAD_ACCESS:
case CAUSE_STORE_ACCESS:
case CAUSE_USER_ECALL:
- case CAUSE_SUPERVISOR_ECALL:
case CAUSE_HYPERVISOR_ECALL:
case CAUSE_MACHINE_ECALL:
print_trap_information(tf);
break;
+ case CAUSE_SUPERVISOR_ECALL:
+ handle_sbi(tf);
+ return;
case CAUSE_MISALIGNED_LOAD:
case CAUSE_MISALIGNED_STORE:
print_trap_information(tf);