riscv: add support for OpenSBI
Call OpenSBI in M-Mode and use it to set up SBI and to lockdown the platform. It will also jump to the specified payload when done. This behaviour is similar to BL31 on aarch31. The payload is 41KiB in size on qemu. Tested on qemu-riscv: Required to boot a kernel as OpenSBI's instruction emulation feature is required on that virtual machine. Tested on SiFive/unleashed: The earlycon is working. No console after regular serial driver should take over, which might be related to kernel config. Change-Id: I2a178595bd2aa2e1f114cbc69e8eadd46955b54d Signed-off-by: Xiang Wang <merle@hardenedlinux.org> Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/32394 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Philipp Deppenwiese <zaolin.daisuki@gmail.com>
This commit is contained in:
parent
c989e0bd56
commit
a6f9eab44a
|
@ -41,6 +41,30 @@ config ARCH_RISCV_S
|
||||||
bool
|
bool
|
||||||
default n
|
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
|
config ARCH_RISCV_U
|
||||||
# U (user) mode is for programs.
|
# U (user) mode is for programs.
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -174,4 +174,45 @@ LDFLAGS_ramstage += -m elf32lriscv
|
||||||
endif #CONFIG_ARCH_RISCV_RV32
|
endif #CONFIG_ARCH_RISCV_RV32
|
||||||
|
|
||||||
endif #CONFIG_ARCH_RAMSTAGE_RISCV
|
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
|
endif #CONFIG_ARCH_RISCV
|
||||||
|
|
|
@ -20,6 +20,12 @@
|
||||||
#include <arch/smp/smp.h>
|
#include <arch/smp/smp.h>
|
||||||
#include <mcall.h>
|
#include <mcall.h>
|
||||||
#include <commonlib/cbfs_serialized.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.
|
* 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!
|
* 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;
|
int hart_id;
|
||||||
|
struct prog *prog = args->prog;
|
||||||
void *fdt = prog_entry_arg(prog);
|
void *fdt = prog_entry_arg(prog);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -48,17 +54,39 @@ static void do_arch_prog_run(struct prog *prog)
|
||||||
fdt = HLS()->fdt;
|
fdt = HLS()->fdt;
|
||||||
|
|
||||||
if (ENV_RAMSTAGE && prog_type(prog) == PROG_PAYLOAD) {
|
if (ENV_RAMSTAGE && prog_type(prog) == PROG_PAYLOAD) {
|
||||||
|
if (CONFIG(RISCV_OPENSBI))
|
||||||
|
run_payload_opensbi(prog, fdt, args->opensbi, RISCV_PAYLOAD_MODE_S);
|
||||||
|
else
|
||||||
run_payload(prog, fdt, RISCV_PAYLOAD_MODE_S);
|
run_payload(prog, fdt, RISCV_PAYLOAD_MODE_S);
|
||||||
return;
|
} else {
|
||||||
}
|
void (*doit)(int hart_id, void *fdt) = prog_entry(prog);
|
||||||
|
|
||||||
doit = prog_entry(prog);
|
|
||||||
hart_id = HLS()->hart_id;
|
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)
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,12 +16,17 @@
|
||||||
#ifndef ARCH_RISCV_INCLUDE_ARCH_BOOT_H
|
#ifndef ARCH_RISCV_INCLUDE_ARCH_BOOT_H
|
||||||
#define 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_U 0
|
||||||
#define RISCV_PAYLOAD_MODE_S 1
|
#define RISCV_PAYLOAD_MODE_S 1
|
||||||
#define RISCV_PAYLOAD_MODE_M 3
|
#define RISCV_PAYLOAD_MODE_M 3
|
||||||
|
|
||||||
|
struct prog;
|
||||||
void run_payload(struct prog *prog, void *fdt, int payload_mode);
|
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
|
#endif
|
||||||
|
|
|
@ -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");
|
||||||
|
}
|
|
@ -15,18 +15,44 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <program_loading.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <arch/boot.h>
|
#include <arch/boot.h>
|
||||||
#include <arch/encoding.h>
|
#include <arch/encoding.h>
|
||||||
|
#include <arch/smp/atomic.h>
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
#include <vm.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 run_payload(struct prog *prog, void *fdt, int payload_mode)
|
||||||
{
|
{
|
||||||
void (*doit)(int hart_id, void *fdt) = prog_entry(prog);
|
void (*doit)(int hart_id, void *fdt) = prog_entry(prog);
|
||||||
int hart_id = read_csr(mhartid);
|
int hart_id = read_csr(mhartid);
|
||||||
uintptr_t status = read_csr(mstatus);
|
uintptr_t status = read_csr(mstatus);
|
||||||
status = INSERT_FIELD(status, MSTATUS_MPIE, 0);
|
status = INSERT_FIELD(status, MSTATUS_MPIE, 0);
|
||||||
|
|
||||||
switch (payload_mode) {
|
switch (payload_mode) {
|
||||||
case RISCV_PAYLOAD_MODE_U:
|
case RISCV_PAYLOAD_MODE_U:
|
||||||
status = INSERT_FIELD(status, MSTATUS_MPP, PRV_U);
|
status = INSERT_FIELD(status, MSTATUS_MPP, PRV_U);
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
#include <bootmem.h>
|
#include <bootmem.h>
|
||||||
#include <boot/tables.h>
|
#include <boot/tables.h>
|
||||||
#include <boot/coreboot_tables.h>
|
#include <boot/coreboot_tables.h>
|
||||||
|
#include <symbols.h>
|
||||||
|
|
||||||
|
DECLARE_OPTIONAL_REGION(opensbi);
|
||||||
|
|
||||||
void arch_write_tables(uintptr_t coreboot_table)
|
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)
|
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)
|
void lb_arch_add_records(struct lb_header *header)
|
||||||
|
|
Loading…
Reference in New Issue