arch/riscv: Enable FIT support
Tested on qemu-riscv. Depends on OpenSBI integration and proper memory detection in qemu. Boots into Linux until initrd should be loaded. Tested on SiFive/unleashed: Boots into Linux until earlycon terminates. Change-Id: I5ebc6cc2cc9e328f36d70fba13555386bb8c29d6 Signed-off-by: Jonathan Neuschäfer <j.neuschaefer@gmx.net> Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/30292 Reviewed-by: Philipp Deppenwiese <zaolin.daisuki@gmail.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
parent
2a20d13c39
commit
3a4511eb6c
|
@ -6,6 +6,7 @@
|
||||||
## Supported architectures
|
## Supported architectures
|
||||||
|
|
||||||
* aarch64
|
* aarch64
|
||||||
|
* riscv
|
||||||
|
|
||||||
## Supported FIT sections
|
## Supported FIT sections
|
||||||
|
|
||||||
|
@ -24,6 +25,7 @@ The section must be named in order to be found by the FIT parser:
|
||||||
## Architecture specifics
|
## Architecture specifics
|
||||||
|
|
||||||
The FIT parser needs architecure support.
|
The FIT parser needs architecure support.
|
||||||
|
|
||||||
### aarch64
|
### aarch64
|
||||||
The source code can be found in `src/arch/arm64/fit_payload.c`.
|
The source code can be found in `src/arch/arm64/fit_payload.c`.
|
||||||
|
|
||||||
|
@ -31,6 +33,13 @@ On aarch64 the kernel (a section named 'kernel') must be in **Image**
|
||||||
format and it needs a devicetree (a section named 'fdt') to boot.
|
format and it needs a devicetree (a section named 'fdt') to boot.
|
||||||
The kernel will be placed close to "*DRAMSTART*".
|
The kernel will be placed close to "*DRAMSTART*".
|
||||||
|
|
||||||
|
### RISC-V
|
||||||
|
The source code can be found in `src/arch/riscv/fit_payload.c`.
|
||||||
|
|
||||||
|
On RISC-V the kernel (a section named 'kernel') must be in **Image**
|
||||||
|
format and it needs a devicetree (a section named 'fdt') to boot.
|
||||||
|
The kernel will be placed close to "*DRAMSTART*".
|
||||||
|
|
||||||
### Other
|
### Other
|
||||||
Other architectures aren't supported.
|
Other architectures aren't supported.
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ config PAYLOAD_ELF
|
||||||
|
|
||||||
config PAYLOAD_FIT
|
config PAYLOAD_FIT
|
||||||
bool "A FIT payload"
|
bool "A FIT payload"
|
||||||
depends on ARCH_ARM64
|
depends on ARCH_ARM64 || ARCH_RISCV
|
||||||
select PAYLOAD_FIT_SUPPORT
|
select PAYLOAD_FIT_SUPPORT
|
||||||
help
|
help
|
||||||
Select this option if you have a payload image (a FIT file) which
|
Select this option if you have a payload image (a FIT file) which
|
||||||
|
@ -99,8 +99,8 @@ config PAYLOAD_IS_FLAT_BINARY
|
||||||
config PAYLOAD_FIT_SUPPORT
|
config PAYLOAD_FIT_SUPPORT
|
||||||
bool "FIT support"
|
bool "FIT support"
|
||||||
default n
|
default n
|
||||||
default y if PAYLOAD_LINUX && (ARCH_ARM || ARCH_ARM64)
|
default y if PAYLOAD_LINUX && (ARCH_ARM || ARCH_ARM64 || ARCH_RISCV)
|
||||||
depends on ARCH_ARM64
|
depends on ARCH_ARM64 || ARCH_RISCV
|
||||||
select FLATTENED_DEVICE_TREE
|
select FLATTENED_DEVICE_TREE
|
||||||
help
|
help
|
||||||
Select this option if your payload is of type FIT.
|
Select this option if your payload is of type FIT.
|
||||||
|
|
|
@ -39,6 +39,13 @@ config LINUXBOOT_ARM64
|
||||||
help
|
help
|
||||||
AARCH64 kernel and initramfs
|
AARCH64 kernel and initramfs
|
||||||
|
|
||||||
|
config LINUXBOOT_RISCV
|
||||||
|
bool "RISC-V"
|
||||||
|
depends on ARCH_RISCV
|
||||||
|
select PAYLOAD_FIT_SUPPORT
|
||||||
|
help
|
||||||
|
RISC-V kernel and initramfs
|
||||||
|
|
||||||
endchoice
|
endchoice
|
||||||
|
|
||||||
comment "Linux kernel"
|
comment "Linux kernel"
|
||||||
|
@ -126,7 +133,7 @@ config LINUXBOOT_KERNEL_CONFIGFILE
|
||||||
choice
|
choice
|
||||||
prompt "Kernel binary format"
|
prompt "Kernel binary format"
|
||||||
default LINUXBOOT_KERNEL_BZIMAGE if LINUXBOOT_X86 || LINUXBOOT_X86_64
|
default LINUXBOOT_KERNEL_BZIMAGE if LINUXBOOT_X86 || LINUXBOOT_X86_64
|
||||||
default LINUXBOOT_KERNEL_UIMAGE if LINUXBOOT_ARM64
|
default LINUXBOOT_KERNEL_UIMAGE if LINUXBOOT_ARM64 || LINUXBOOT_RISCV
|
||||||
|
|
||||||
config LINUXBOOT_KERNEL_BZIMAGE
|
config LINUXBOOT_KERNEL_BZIMAGE
|
||||||
bool "bzImage"
|
bool "bzImage"
|
||||||
|
@ -134,14 +141,14 @@ config LINUXBOOT_KERNEL_BZIMAGE
|
||||||
|
|
||||||
config LINUXBOOT_KERNEL_UIMAGE
|
config LINUXBOOT_KERNEL_UIMAGE
|
||||||
bool "uImage"
|
bool "uImage"
|
||||||
depends on LINUXBOOT_ARM64
|
depends on LINUXBOOT_ARM64 || LINUXBOOT_RISCV
|
||||||
|
|
||||||
endchoice
|
endchoice
|
||||||
|
|
||||||
|
|
||||||
config LINUXBOOT_DTB_FILE
|
config LINUXBOOT_DTB_FILE
|
||||||
string "Compiled devicetree file"
|
string "Compiled devicetree file"
|
||||||
depends on LINUXBOOT_ARM64
|
depends on LINUXBOOT_ARM64 || LINUXBOOT_RISCV
|
||||||
default ""
|
default ""
|
||||||
|
|
||||||
endif #LINUXBOOT_COMPILE_KERNEL
|
endif #LINUXBOOT_COMPILE_KERNEL
|
||||||
|
@ -154,7 +161,7 @@ config LINUX_COMMAND_LINE
|
||||||
|
|
||||||
config PAYLOAD_FILE
|
config PAYLOAD_FILE
|
||||||
default "payloads/external/LinuxBoot/linuxboot/bzImage" if LINUXBOOT_COMPILE_KERNEL && ( LINUXBOOT_X86 || LINUXBOOT_X86_64 )
|
default "payloads/external/LinuxBoot/linuxboot/bzImage" if LINUXBOOT_COMPILE_KERNEL && ( LINUXBOOT_X86 || LINUXBOOT_X86_64 )
|
||||||
default "payloads/external/LinuxBoot/linuxboot/uImage" if LINUXBOOT_COMPILE_KERNEL && LINUXBOOT_ARM64
|
default "payloads/external/LinuxBoot/linuxboot/uImage" if LINUXBOOT_COMPILE_KERNEL && (LINUXBOOT_ARM64 || LINUXBOOT_RISCV)
|
||||||
default LINUXBOOT_KERNEL_PATH if !LINUXBOOT_COMPILE_KERNEL
|
default LINUXBOOT_KERNEL_PATH if !LINUXBOOT_COMPILE_KERNEL
|
||||||
|
|
||||||
comment "Linux initramfs"
|
comment "Linux initramfs"
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
config PAYLOAD_LINUXBOOT
|
config PAYLOAD_LINUXBOOT
|
||||||
bool "LinuxBoot"
|
bool "LinuxBoot"
|
||||||
depends on ARCH_X86 || ARCH_ARM64
|
depends on ARCH_X86 || ARCH_ARM64 || ARCH_RISCV
|
||||||
help
|
help
|
||||||
Select this option if you want to build a coreboot image
|
Select this option if you want to build a coreboot image
|
||||||
with a LinuxBoot payload. If you don't know what this is
|
with a LinuxBoot payload. If you don't know what this is
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
config PAYLOAD_LINUX
|
config PAYLOAD_LINUX
|
||||||
bool "A Linux payload"
|
bool "A Linux payload"
|
||||||
depends on ARCH_X86 || ARCH_ARM
|
depends on ARCH_X86 || ARCH_ARM || ARCH_RISCV
|
||||||
help
|
help
|
||||||
Select this option if you have a Linux bzImage which coreboot
|
Select this option if you have a Linux bzImage which coreboot
|
||||||
should run as soon as the basic hardware initialization
|
should run as soon as the basic hardware initialization
|
||||||
|
|
|
@ -147,6 +147,7 @@ ramstage-y += boot.c
|
||||||
ramstage-y += tables.c
|
ramstage-y += tables.c
|
||||||
ramstage-y += payload.c
|
ramstage-y += payload.c
|
||||||
ramstage-$(ARCH_RISCV_PMP) += pmp.c
|
ramstage-$(ARCH_RISCV_PMP) += pmp.c
|
||||||
|
ramstage-y += fit_payload.c
|
||||||
ramstage-y += \
|
ramstage-y += \
|
||||||
$(top)/src/lib/memchr.c \
|
$(top)/src/lib/memchr.c \
|
||||||
$(top)/src/lib/memcmp.c \
|
$(top)/src/lib/memcmp.c \
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Google Inc.
|
||||||
|
* Copyright 2018 Facebook, Inc.
|
||||||
|
* Copyright 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; either version 2 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* 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 <console/console.h>
|
||||||
|
#include <bootmem.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <program_loading.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <commonlib/compression.h>
|
||||||
|
#include <commonlib/cbfs_serialized.h>
|
||||||
|
#include <lib.h>
|
||||||
|
#include <fit.h>
|
||||||
|
#include <endian.h>
|
||||||
|
|
||||||
|
/* Implements a Berkley Boot Loader (BBL) compatible payload loading */
|
||||||
|
|
||||||
|
#define MAX_KERNEL_SIZE (64*MiB)
|
||||||
|
|
||||||
|
#if CONFIG(ARCH_RISCV_RV32)
|
||||||
|
#define SECTION_ALIGN (4 * MiB)
|
||||||
|
#endif
|
||||||
|
#if CONFIG(ARCH_RISCV_RV64)
|
||||||
|
#define SECTION_ALIGN (2 * MiB)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static size_t get_kernel_size(const struct fit_image_node *node)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Since we don't have a way to determine the uncompressed size of the
|
||||||
|
* kernel, we have to keep as much memory as possible free for use by
|
||||||
|
* the kernel immediately after the end of the kernel image. The amount
|
||||||
|
* of space required will vary depending on selected features, and is
|
||||||
|
* effectively unbound.
|
||||||
|
*/
|
||||||
|
|
||||||
|
printk(BIOS_INFO,
|
||||||
|
"FIT: Leaving additional %u MiB of free space after kernel.\n",
|
||||||
|
MAX_KERNEL_SIZE >> 20);
|
||||||
|
|
||||||
|
return node->size + MAX_KERNEL_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Place the region in free memory range.
|
||||||
|
*
|
||||||
|
* The caller has to set region->offset to the minimum allowed address.
|
||||||
|
*/
|
||||||
|
static bool fit_place_mem(const struct range_entry *r, void *arg)
|
||||||
|
{
|
||||||
|
struct region *region = arg;
|
||||||
|
resource_t start;
|
||||||
|
|
||||||
|
if (range_entry_tag(r) != BM_MEM_RAM)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* Section must be aligned at page boundary */
|
||||||
|
start = ALIGN_UP(MAX(region->offset, range_entry_base(r)), SECTION_ALIGN);
|
||||||
|
|
||||||
|
if (start + region->size < range_entry_end(r)) {
|
||||||
|
region->offset = (size_t)start;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fit_payload_arch(struct prog *payload, struct fit_config_node *config,
|
||||||
|
struct region *kernel,
|
||||||
|
struct region *fdt,
|
||||||
|
struct region *initrd)
|
||||||
|
{
|
||||||
|
void *arg = NULL;
|
||||||
|
|
||||||
|
if (!config->fdt || !fdt) {
|
||||||
|
printk(BIOS_CRIT, "CRIT: Providing a valid FDT is mandatory to "
|
||||||
|
"boot a RISC-V kernel!\n");
|
||||||
|
return false;
|
||||||
|
/* TODO: Fall back to the ROM FDT? */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update kernel size from image header, if possible */
|
||||||
|
kernel->size = get_kernel_size(config->kernel);
|
||||||
|
printk(BIOS_DEBUG, "FIT: Using kernel size of 0x%zx bytes\n",
|
||||||
|
kernel->size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The code assumes that bootmem_walk provides a sorted list of memory
|
||||||
|
* regions, starting from the lowest address.
|
||||||
|
* The order of the calls here doesn't matter, as the placement is
|
||||||
|
* enforced in the called functions.
|
||||||
|
* For details check code on top.
|
||||||
|
*/
|
||||||
|
kernel->offset = 0;
|
||||||
|
if (!bootmem_walk(fit_place_mem, kernel))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Mark as reserved for future allocations. */
|
||||||
|
bootmem_add_range(kernel->offset, kernel->size, BM_MEM_PAYLOAD);
|
||||||
|
|
||||||
|
/* Place FDT and INITRD after kernel. */
|
||||||
|
|
||||||
|
/* Place INITRD */
|
||||||
|
if (config->ramdisk) {
|
||||||
|
initrd->offset = kernel->offset + kernel->size;
|
||||||
|
|
||||||
|
if (!bootmem_walk(fit_place_mem, initrd))
|
||||||
|
return false;
|
||||||
|
/* Mark as reserved for future allocations. */
|
||||||
|
bootmem_add_range(initrd->offset, initrd->size, BM_MEM_PAYLOAD);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Place FDT */
|
||||||
|
fdt->offset = kernel->offset + kernel->size;
|
||||||
|
|
||||||
|
if (!bootmem_walk(fit_place_mem, fdt))
|
||||||
|
return false;
|
||||||
|
/* Mark as reserved for future allocations. */
|
||||||
|
bootmem_add_range(fdt->offset, fdt->size, BM_MEM_PAYLOAD);
|
||||||
|
|
||||||
|
/* Kernel expects FDT as argument */
|
||||||
|
arg = (void *)fdt->offset;
|
||||||
|
|
||||||
|
prog_set_entry(payload, (void *)kernel->offset, arg);
|
||||||
|
|
||||||
|
bootmem_dump_ranges();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
Loading…
Reference in New Issue