summaryrefslogtreecommitdiff
path: root/src/arch/riscv
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/riscv')
-rw-r--r--src/arch/riscv/Kconfig24
-rw-r--r--src/arch/riscv/Makefile.inc41
-rw-r--r--src/arch/riscv/boot.c46
-rw-r--r--src/arch/riscv/include/arch/boot.h9
-rw-r--r--src/arch/riscv/opensbi.c41
-rw-r--r--src/arch/riscv/payload.c26
-rw-r--r--src/arch/riscv/tables.c6
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)