diff options
author | Xiang Wang <wxjstz@126.com> | 2018-08-15 16:27:05 +0800 |
---|---|---|
committer | Patrick Georgi <pgeorgi@google.com> | 2018-11-05 09:04:01 +0000 |
commit | 22e0c560bb565642d52e4e0f8bab000c8d06f0b8 (patch) | |
tree | a960e9bc01d3d4d9ddb65ba828b64d39a64baade /src/arch/riscv/sbi.c | |
parent | 26f725efc235b282e20aa678f8e683a014920b71 (diff) | |
download | coreboot-22e0c560bb565642d52e4e0f8bab000c8d06f0b8.tar.xz |
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>
Diffstat (limited to 'src/arch/riscv/sbi.c')
-rw-r--r-- | src/arch/riscv/sbi.c | 121 |
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); +} |