mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-11 07:24:46 +00:00

Simon Glass <sjg@chromium.org> says: This includes various patches towards implementing the VBE abrec bootmeth in U-Boot. It mostly focuses on introducing a relocating SPL-loader so that VBE can run in the limited amount of SRAM available on many devices. Another minor new feature is support in VBE for specifying the image phase when loading from a FIT. This allows a single FIT to include images for several boot phases, thus simplifying image-creation. One lingering niggle in this series is that it has a different code path for sandbox, since it does not support the relocating jump. It should be possible to resolve this with additional work, but I have not attempted this so far. For v2, I have split the first patch into 5 pieces, to make it easier to see the code-size impact, plus added a few tweaks to reduce code size. Again, only MMC is supported so far. Looking ahead, series G will have some more plumbing and H some rk3399 pieces. That should be enough to complete these feature. Here is a run in my lab, with the VBE ABrec bootmeth. You can see that VPL runs before memory is set up. SPL sets up memory and can be upgraded in the field reliably. $ ub-int vbe Building U-Boot in sourcedir for rk3399-generic Bootstrapping U-Boot from dir /tmp/b/rk3399-generic Writing U-Boot using method rockchip U-Boot TPL 2025.01-rc3-00345-gdfbdbf1eb56c-dirty (Jan 08 2025 - 10:47:58) Trying to boot from vbe_abrec load: Firefly-RK3399 Board Using 'config-3' configuration Trying 'image-vpl' firmware subimage Using 'config-3' configuration Trying 'fdt-3' fdt subimage U-Boot VPL 2025.01-rc3-00345-gdfbdbf1eb56c-dirty (Jan 08 2025 - 10:47:58) Trying to boot from vbe_abrec load: Firefly-RK3399 Board Starting with empty state VBE: Firmware pick A at 800000 Using 'config-3' configuration Trying 'spl' firmware subimage Using 'config-3' configuration Trying 'fdt-3' fdt subimage Channel 0: DDR3, 800MHz BW=32 Col=10 Bk=8 CS0 Row=15 CS1 Row=15 CS=2 Die BW=16 Size=2048MB Channel 1: DDR3, 800MHz BW=32 Col=10 Bk=8 CS0 Row=15 CS1 Row=15 CS=2 Die BW=16 Size=2048MB 256B stride U-Boot SPL 2025.01-rc3-00345-gdfbdbf1eb56c-dirty (Jan 08 2025 - 10:47:58 -0700) Trying to boot from vbe_abrec load: Firefly-RK3399 Board VBE: Firmware pick A at 900000 load_simple_fit: Skip load 'atf-5': image size is 0! Relocating bloblist ff8eff00 to 100000: done ns16550_serial serial@ff1a0000: pinctrl_select_state_full: uclass_get_device_by_phandle_id: err=-19 U-Boot 2025.01-rc3-00345-gdfbdbf1eb56c-dirty (Jan 08 2025 - 10:47:58 -0700) SoC: Rockchip rk3399 Reset cause: POR Model: Firefly-RK3399 Board DRAM: 4 GiB (effective 3.9 GiB) Core: 314 devices, 33 uclasses, devicetree: separate MMC: mmc@fe310000: 3, mmc@fe320000: 1, mmc@fe330000: 0 Loading Environment from SPIFlash... Invalid bus 0 (err=-19) *** Warning - spi_flash_probe_bus_cs() failed, using default environment In: serial,usbkbd Out: serial,vidconsole Err: serial,vidconsole Model: Firefly-RK3399 Board Net: PMIC: RK808 eth0: ethernet@fe300000 starting USB... Bus usb@fe380000: USB EHCI 1.00 Bus usb@fe3a0000: USB OHCI 1.0 Bus usb@fe3c0000: USB EHCI 1.00 Bus usb@fe3e0000: USB OHCI 1.0 Bus usb@fe900000: Register 2000140 NbrPorts 2 Starting the controller USB XHCI 1.10 scanning bus usb@fe380000 for devices... 1 USB Device(s) found scanning bus usb@fe3a0000 for devices... 1 USB Device(s) found scanning bus usb@fe3c0000 for devices... 2 USB Device(s) found scanning bus usb@fe3e0000 for devices... 1 USB Device(s) found scanning bus usb@fe900000 for devices... 1 USB Device(s) found scanning usb for storage devices... 0 Storage Device(s) found Hit any key to stop autoboot: 0 Link: https://lore.kernel.org/r/20250116012723.2820301-1-sjg@chromium.org
170 lines
4.1 KiB
C
170 lines
4.1 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Verified Boot for Embedded (VBE) 'simple' method
|
|
*
|
|
* Copyright 2022 Google LLC
|
|
* Written by Simon Glass <sjg@chromium.org>
|
|
*/
|
|
|
|
#define LOG_CATEGORY LOGC_BOOT
|
|
|
|
#include <bootdev.h>
|
|
#include <bootflow.h>
|
|
#include <bootmeth.h>
|
|
#include <dm.h>
|
|
#include <log.h>
|
|
#include <memalign.h>
|
|
#include <mmc.h>
|
|
#include <vbe.h>
|
|
#include <dm/device-internal.h>
|
|
#include <dm/ofnode.h>
|
|
#include "vbe_simple.h"
|
|
|
|
static int simple_read_nvdata(const struct simple_priv *priv,
|
|
struct udevice *blk, struct simple_state *state)
|
|
{
|
|
ALLOC_CACHE_ALIGN_BUFFER(u8, buf, MMC_MAX_BLOCK_LEN);
|
|
const struct vbe_nvdata *nvd;
|
|
int ret;
|
|
|
|
ret = vbe_read_nvdata(blk, priv->area_start + priv->state_offset,
|
|
priv->state_size, buf);
|
|
if (ret)
|
|
return log_msg_ret("nv", ret);
|
|
|
|
nvd = (struct vbe_nvdata *)buf;
|
|
state->fw_vernum = nvd->fw_vernum;
|
|
|
|
log_debug("version=%s\n", state->fw_version);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int vbe_simple_read_state(struct udevice *dev, struct simple_state *state)
|
|
{
|
|
struct simple_priv *priv = dev_get_priv(dev);
|
|
struct udevice *blk;
|
|
int ret;
|
|
|
|
ret = vbe_get_blk(priv->storage, &blk);
|
|
if (ret)
|
|
return log_msg_ret("blk", ret);
|
|
|
|
ret = vbe_read_version(blk, priv->area_start + priv->version_offset,
|
|
state->fw_version, MAX_VERSION_LEN);
|
|
if (ret)
|
|
return log_msg_ret("ver", ret);
|
|
|
|
ret = simple_read_nvdata(priv, blk, state);
|
|
if (ret)
|
|
return log_msg_ret("nvd", ret);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int vbe_simple_get_state_desc(struct udevice *dev, char *buf,
|
|
int maxsize)
|
|
{
|
|
struct simple_state state;
|
|
int ret;
|
|
|
|
ret = vbe_simple_read_state(dev, &state);
|
|
if (ret)
|
|
return log_msg_ret("read", ret);
|
|
|
|
if (maxsize < 30)
|
|
return -ENOSPC;
|
|
snprintf(buf, maxsize, "Version: %s\nVernum: %x/%x", state.fw_version,
|
|
state.fw_vernum >> FWVER_KEY_SHIFT,
|
|
state.fw_vernum & FWVER_FW_MASK);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int vbe_simple_read_bootflow(struct udevice *dev, struct bootflow *bflow)
|
|
{
|
|
int ret;
|
|
|
|
if (CONFIG_IS_ENABLED(BOOTMETH_VBE_SIMPLE_FW)) {
|
|
if (vbe_phase() == VBE_PHASE_FIRMWARE) {
|
|
ret = vbe_simple_read_bootflow_fw(dev, bflow);
|
|
if (ret)
|
|
return log_msg_ret("fw", ret);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
static int vbe_simple_read_file(struct udevice *dev, struct bootflow *bflow,
|
|
const char *file_path, ulong addr,
|
|
enum bootflow_img_t type, ulong *sizep)
|
|
{
|
|
int ret;
|
|
|
|
if (vbe_phase() == VBE_PHASE_OS) {
|
|
ret = bootmeth_common_read_file(dev, bflow, file_path, addr,
|
|
type, sizep);
|
|
if (ret)
|
|
return log_msg_ret("os", ret);
|
|
}
|
|
|
|
/* To be implemented */
|
|
return -EINVAL;
|
|
}
|
|
|
|
static struct bootmeth_ops bootmeth_vbe_simple_ops = {
|
|
.get_state_desc = vbe_simple_get_state_desc,
|
|
.read_bootflow = vbe_simple_read_bootflow,
|
|
.read_file = vbe_simple_read_file,
|
|
};
|
|
|
|
static int bootmeth_vbe_simple_probe(struct udevice *dev)
|
|
{
|
|
struct simple_priv *priv = dev_get_priv(dev);
|
|
|
|
memset(priv, '\0', sizeof(*priv));
|
|
if (dev_read_u32(dev, "area-start", &priv->area_start) ||
|
|
dev_read_u32(dev, "area-size", &priv->area_size) ||
|
|
dev_read_u32(dev, "version-offset", &priv->version_offset) ||
|
|
dev_read_u32(dev, "version-size", &priv->version_size) ||
|
|
dev_read_u32(dev, "state-offset", &priv->state_offset) ||
|
|
dev_read_u32(dev, "state-size", &priv->state_size))
|
|
return log_msg_ret("read", -EINVAL);
|
|
dev_read_u32(dev, "skip-offset", &priv->skip_offset);
|
|
priv->storage = strdup(dev_read_string(dev, "storage"));
|
|
if (!priv->storage)
|
|
return log_msg_ret("str", -EINVAL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int bootmeth_vbe_simple_bind(struct udevice *dev)
|
|
{
|
|
struct bootmeth_uc_plat *plat = dev_get_uclass_plat(dev);
|
|
|
|
plat->desc = IS_ENABLED(CONFIG_BOOTSTD_FULL) ?
|
|
"VBE simple" : "vbe-simple";
|
|
plat->flags = BOOTMETHF_GLOBAL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if CONFIG_IS_ENABLED(OF_REAL)
|
|
static const struct udevice_id generic_simple_vbe_simple_ids[] = {
|
|
{ .compatible = "fwupd,vbe-simple" },
|
|
{ }
|
|
};
|
|
#endif
|
|
|
|
U_BOOT_DRIVER(vbe_simple) = {
|
|
.name = "vbe_simple",
|
|
.id = UCLASS_BOOTMETH,
|
|
.of_match = of_match_ptr(generic_simple_vbe_simple_ids),
|
|
.ops = &bootmeth_vbe_simple_ops,
|
|
.bind = bootmeth_vbe_simple_bind,
|
|
.probe = bootmeth_vbe_simple_probe,
|
|
.flags = DM_FLAG_PRE_RELOC,
|
|
.priv_auto = sizeof(struct simple_priv),
|
|
};
|