From 22e0c560bb565642d52e4e0f8bab000c8d06f0b8 Mon Sep 17 00:00:00 2001 From: Xiang Wang Date: Wed, 15 Aug 2018 16:27:05 +0800 Subject: 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 Reviewed-on: https://review.coreboot.org/28096 Tested-by: build bot (Jenkins) Reviewed-by: Ronald G. Minnich --- src/arch/riscv/Makefile.inc | 2 + src/arch/riscv/include/sbi.h | 37 +++++++++++++ src/arch/riscv/include/vm.h | 8 +++ src/arch/riscv/sbi.c | 121 ++++++++++++++++++++++++++++++++++++++++++ src/arch/riscv/trap_handler.c | 20 ++++++- 5 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 src/arch/riscv/include/sbi.h create mode 100644 src/arch/riscv/sbi.c 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 +#include +#include +#include +#include +#include +#include +#include +#include + +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 #include #include +#include +#include static const char *const exception_names[] = { "Instruction address misaligned", @@ -91,6 +93,20 @@ static void interrupt_handler(trapframe *tf) clear_csr(mie, MIP_MTIP); 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"); @@ -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); -- cgit v1.2.3