diff options
-rw-r--r-- | src/arch/riscv/Kconfig | 24 | ||||
-rw-r--r-- | src/arch/riscv/Makefile.inc | 41 | ||||
-rw-r--r-- | src/arch/riscv/boot.c | 46 | ||||
-rw-r--r-- | src/arch/riscv/include/arch/boot.h | 9 | ||||
-rw-r--r-- | src/arch/riscv/opensbi.c | 41 | ||||
-rw-r--r-- | src/arch/riscv/payload.c | 26 | ||||
-rw-r--r-- | src/arch/riscv/tables.c | 6 |
7 files changed, 182 insertions, 11 deletions
diff --git a/src/arch/riscv/Kconfig b/src/arch/riscv/Kconfig index a4f1788497..f2ca571c97 100644 --- a/src/arch/riscv/Kconfig +++ b/src/arch/riscv/Kconfig @@ -41,6 +41,30 @@ config ARCH_RISCV_S bool default n +config RISCV_HAS_OPENSBI + def_bool n + +config RISCV_OPENSBI + bool "Use OpenSBI to hand over control to payload" + depends on ARCH_RISCV_M && ARCH_RISCV_S + depends on RISCV_HAS_OPENSBI + default n + help + Load OpenSBI after payload has been loaded and use it to + provide the SBI and to handover control to payload. + +config OPENSBI_PLATFORM + string + depends on RISCV_HAS_OPENSBI + help + The OpenSBI platform to build for. + +config OPENSBI_TEXT_START + hex + depends on RISCV_HAS_OPENSBI + help + The linking address used to build opensbi. + config ARCH_RISCV_U # U (user) mode is for programs. bool diff --git a/src/arch/riscv/Makefile.inc b/src/arch/riscv/Makefile.inc index d5f62954eb..01168593f1 100644 --- a/src/arch/riscv/Makefile.inc +++ b/src/arch/riscv/Makefile.inc @@ -174,4 +174,45 @@ LDFLAGS_ramstage += -m elf32lriscv endif #CONFIG_ARCH_RISCV_RV32 endif #CONFIG_ARCH_RAMSTAGE_RISCV + +ifeq ($(CONFIG_RISCV_OPENSBI),y) + +OPENSBI_SOURCE := $(top)/3rdparty/opensbi +OPENSBI_BUILD := $(abspath $(obj)/3rdparty/opensbi) +OPENSBI_TARGET := $(OPENSBI_BUILD)/platform/$(CONFIG_OPENSBI_PLATFORM)/firmware/fw_dynamic.elf +OPENSBI := $(obj)/opensbi.elf + +$(OPENSBI_TARGET): $(obj)/config.h | $(OPENSBI_SOURCE) + printf " MAKE $(subst $(obj)/,,$(@))\n" + mkdir -p $(OPENSBI_BUILD) + $(MAKE) \ + -C "$(OPENSBI_SOURCE)" \ + CC="$(CC_ramstage)" \ + LD="$(LD_ramstage)" \ + OBJCOPY="$(OBJCOPY_ramstage)" \ + AR="$(AR_ramstage)" \ + PLATFORM=$(CONFIG_OPENSBI_PLATFORM) \ + O="$(OPENSBI_BUILD)" \ + FW_JUMP=y \ + FW_DYNAMIC=y \ + FW_PAYLOAD=n \ + FW_PAYLOAD_OFFSET=0 \ + FW_TEXT_START=$(CONFIG_OPENSBI_TEXT_START) + +$(OPENSBI): $(OPENSBI_TARGET) + cp $< $@ + +OPENSBI_CBFS := $(CONFIG_CBFS_PREFIX)/opensbi +$(OPENSBI_CBFS)-file := $(OPENSBI) +$(OPENSBI_CBFS)-type := payload +$(OPENSBI_CBFS)-compression := $(CBFS_COMPRESS_FLAG) +cbfs-files-y += $(OPENSBI_CBFS) + +check-ramstage-overlap-files += $(OPENSBI_CBFS) + +CPPFLAGS_common += -I$(OPENSBI_SOURCE)/include +ramstage-y += opensbi.c + +endif #CONFIG_RISCV_OPENSBI + endif #CONFIG_ARCH_RISCV diff --git a/src/arch/riscv/boot.c b/src/arch/riscv/boot.c index 8e4bb36af5..6a23b8a696 100644 --- a/src/arch/riscv/boot.c +++ b/src/arch/riscv/boot.c @@ -20,6 +20,12 @@ #include <arch/smp/smp.h> #include <mcall.h> #include <commonlib/cbfs_serialized.h> +#include <console/console.h> + +struct arch_prog_run_args { + struct prog *prog; + struct prog *opensbi; +}; /* * A pointer to the Flattened Device Tree passed to coreboot by the boot ROM. @@ -28,10 +34,10 @@ * This pointer is only used in ramstage! */ -static void do_arch_prog_run(struct prog *prog) +static void do_arch_prog_run(struct arch_prog_run_args *args) { - void (*doit)(int hart_id, void *fdt); int hart_id; + struct prog *prog = args->prog; void *fdt = prog_entry_arg(prog); /* @@ -48,17 +54,39 @@ static void do_arch_prog_run(struct prog *prog) fdt = HLS()->fdt; if (ENV_RAMSTAGE && prog_type(prog) == PROG_PAYLOAD) { - run_payload(prog, fdt, RISCV_PAYLOAD_MODE_S); - return; - } + if (CONFIG(RISCV_OPENSBI)) + run_payload_opensbi(prog, fdt, args->opensbi, RISCV_PAYLOAD_MODE_S); + else + run_payload(prog, fdt, RISCV_PAYLOAD_MODE_S); + } else { + void (*doit)(int hart_id, void *fdt) = prog_entry(prog); + + hart_id = HLS()->hart_id; - doit = prog_entry(prog); - hart_id = HLS()->hart_id; + doit(hart_id, fdt); + } - doit(hart_id, fdt); + die("Failed to run stage"); } void arch_prog_run(struct prog *prog) { - smp_resume((void (*)(void *))do_arch_prog_run, prog); + struct arch_prog_run_args args = {}; + + args.prog = prog; + + /* In case of OpenSBI we have to load it before resuming all HARTs */ + if (ENV_RAMSTAGE && CONFIG(RISCV_OPENSBI)) { + struct prog sbi = PROG_INIT(PROG_OPENSBI, CONFIG_CBFS_PREFIX"/opensbi"); + + if (prog_locate(&sbi)) + die("OpenSBI not found"); + + if (!selfload_check(&sbi, BM_MEM_OPENSBI)) + die("OpenSBI load failed"); + + args.opensbi = &sbi; + } + + smp_resume((void (*)(void *))do_arch_prog_run, &args); } diff --git a/src/arch/riscv/include/arch/boot.h b/src/arch/riscv/include/arch/boot.h index 34a507edec..c05c669f00 100644 --- a/src/arch/riscv/include/arch/boot.h +++ b/src/arch/riscv/include/arch/boot.h @@ -16,12 +16,17 @@ #ifndef ARCH_RISCV_INCLUDE_ARCH_BOOT_H #define ARCH_RISCV_INCLUDE_ARCH_BOOT_H -#include <program_loading.h> - #define RISCV_PAYLOAD_MODE_U 0 #define RISCV_PAYLOAD_MODE_S 1 #define RISCV_PAYLOAD_MODE_M 3 +struct prog; void run_payload(struct prog *prog, void *fdt, int payload_mode); +void run_payload_opensbi(struct prog *prog, void *fdt, struct prog *opensbi, int payload_mode); +void run_opensbi(const int hart_id, + const void *opensbi, + const void *fdt, + const void *payload, + const int payload_mode); #endif diff --git a/src/arch/riscv/opensbi.c b/src/arch/riscv/opensbi.c new file mode 100644 index 0000000000..695c24f756 --- /dev/null +++ b/src/arch/riscv/opensbi.c @@ -0,0 +1,41 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2019 9elements Agency GmbH <patrick.rudolph@9elements.com> + * + * 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 <sbi/fw_dynamic.h> +#include <arch/boot.h> +/* DO NOT INLCUDE COREBOOT HEADERS HERE */ + +void run_opensbi(const int hart_id, + const void *fdt, + const void *opensbi, + const void *payload, + const int payload_mode) +{ + struct fw_dynamic_info info = { + .magic = FW_DYNAMIC_INFO_MAGIC_VALUE, + .version = FW_DYNAMIC_INFO_VERSION_MAX, + .next_mode = payload_mode, + .next_addr = (uintptr_t)payload, + }; + + csr_write(mepc, opensbi); + asm volatile ( + "mv a0, %0\n\t" + "mv a1, %1\n\t" + "mv a2, %2\n\t" + "mret" : + : "r"(hart_id), "r"(fdt), "r"(&info) + : "a0", "a1", "a2"); +} diff --git a/src/arch/riscv/payload.c b/src/arch/riscv/payload.c index 903e8a6ab6..297d30d2a5 100644 --- a/src/arch/riscv/payload.c +++ b/src/arch/riscv/payload.c @@ -15,18 +15,44 @@ * GNU General Public License for more details. */ +#include <program_loading.h> #include <stdint.h> #include <arch/boot.h> #include <arch/encoding.h> +#include <arch/smp/atomic.h> #include <console/console.h> #include <vm.h> +/* Run OpenSBI and let OpenSBI hand over control to the payload */ +void run_payload_opensbi(struct prog *prog, void *fdt, struct prog *opensbi, int payload_mode) +{ + int hart_id = read_csr(mhartid); + uintptr_t status = read_csr(mstatus); + status = INSERT_FIELD(status, MSTATUS_MPIE, 0); + + /* + * In case of OpenSBI we always run it in M-Mode. + * OpenSBI will switch to payload_mode when done. + */ + + status = INSERT_FIELD(status, MSTATUS_MPP, PRV_M); + /* Trap vector base address point to the payload */ + write_csr(mtvec, prog_entry(opensbi)); + /* disable M-Mode interrupt */ + write_csr(mie, 0); + write_csr(mstatus, status); + + run_opensbi(hart_id, fdt, prog_entry(opensbi), prog_entry(prog), payload_mode); +} + +/* Runs the payload without OpenSBI integration */ void run_payload(struct prog *prog, void *fdt, int payload_mode) { void (*doit)(int hart_id, void *fdt) = prog_entry(prog); int hart_id = read_csr(mhartid); uintptr_t status = read_csr(mstatus); status = INSERT_FIELD(status, MSTATUS_MPIE, 0); + switch (payload_mode) { case RISCV_PAYLOAD_MODE_U: status = INSERT_FIELD(status, MSTATUS_MPP, PRV_U); diff --git a/src/arch/riscv/tables.c b/src/arch/riscv/tables.c index eef6bf2ffd..c5bcab0661 100644 --- a/src/arch/riscv/tables.c +++ b/src/arch/riscv/tables.c @@ -18,6 +18,9 @@ #include <bootmem.h> #include <boot/tables.h> #include <boot/coreboot_tables.h> +#include <symbols.h> + +DECLARE_OPTIONAL_REGION(opensbi); void arch_write_tables(uintptr_t coreboot_table) { @@ -25,6 +28,9 @@ void arch_write_tables(uintptr_t coreboot_table) void bootmem_arch_add_ranges(void) { + if (CONFIG(RISCV_OPENSBI) && REGION_SIZE(opensbi) > 0) + bootmem_add_range((uintptr_t)_opensbi, REGION_SIZE(opensbi), + BM_MEM_OPENSBI); } void lb_arch_add_records(struct lb_header *header) |