mirror of
https://github.com/u-boot/u-boot.git
synced 2024-11-28 23:23:30 +08:00
bootstd: Add a simple bootmeth for ChromiumOS
It is possible to boot x86-based ChromeOS machines by parsing a table and locating the kernel and command line. Add a bootmeth for this. Signed-off-by: Simon Glass <sjg@chromium.org> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
This commit is contained in:
parent
d0dfbf548d
commit
c88d67d021
11
boot/Kconfig
11
boot/Kconfig
@ -463,6 +463,17 @@ config BOOTMETH_GLOBAL
|
||||
EFI bootmgr, since they take full control over which bootdevs are
|
||||
selected to boot.
|
||||
|
||||
config BOOTMETH_CROS
|
||||
bool "Bootdev support for Chromium OS"
|
||||
depends on X86 || SANDBOX
|
||||
default y
|
||||
help
|
||||
Enables support for booting Chromium OS using bootdevs. This uses the
|
||||
kernel A slot and obtains the kernel command line from the parameters
|
||||
provided there.
|
||||
|
||||
Note that only x86 devices are supported at present.
|
||||
|
||||
config BOOTMETH_EXTLINUX
|
||||
bool "Bootdev support for extlinux boot"
|
||||
select PXE_UTILS
|
||||
|
@ -27,6 +27,7 @@ obj-$(CONFIG_$(SPL_TPL_)BOOTSTD) += bootstd-uclass.o
|
||||
obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_EXTLINUX) += bootmeth_extlinux.o
|
||||
obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_EXTLINUX_PXE) += bootmeth_pxe.o
|
||||
obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_EFILOADER) += bootmeth_efi.o
|
||||
obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_CROS) += bootmeth_cros.o
|
||||
obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_SANDBOX) += bootmeth_sandbox.o
|
||||
obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_SCRIPT) += bootmeth_script.o
|
||||
ifdef CONFIG_$(SPL_TPL_)BOOTSTD_FULL
|
||||
|
212
boot/bootmeth_cros.c
Normal file
212
boot/bootmeth_cros.c
Normal file
@ -0,0 +1,212 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Bootmethod for ChromiumOS
|
||||
*
|
||||
* Copyright 2023 Google LLC
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*/
|
||||
|
||||
#define LOG_CATEGORY UCLASS_BOOTSTD
|
||||
|
||||
#include <common.h>
|
||||
#include <blk.h>
|
||||
#include <bootdev.h>
|
||||
#include <bootflow.h>
|
||||
#include <bootmeth.h>
|
||||
#include <dm.h>
|
||||
#include <malloc.h>
|
||||
#include <mapmem.h>
|
||||
#include <part.h>
|
||||
#ifdef CONFIG_X86
|
||||
#include <asm/zimage.h>
|
||||
#endif
|
||||
#include <linux/sizes.h>
|
||||
|
||||
enum {
|
||||
/* Offsets in the kernel-partition header */
|
||||
KERN_START = 0x4f0,
|
||||
KERN_SIZE = 0x518,
|
||||
|
||||
SETUP_OFFSET = 0x1000, /* bytes before base */
|
||||
CMDLINE_OFFSET = 0x2000, /* bytes before base */
|
||||
OFFSET_BASE = 0x100000, /* assumed kernel load-address */
|
||||
};
|
||||
|
||||
static int cros_check(struct udevice *dev, struct bootflow_iter *iter)
|
||||
{
|
||||
/* This only works on block and network devices */
|
||||
if (bootflow_iter_check_blk(iter))
|
||||
return log_msg_ret("blk", -ENOTSUPP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int copy_cmdline(const char *from, const char *uuid, char **bufp)
|
||||
{
|
||||
const int maxlen = 2048;
|
||||
char buf[maxlen];
|
||||
char *cmd, *to, *end;
|
||||
int len;
|
||||
|
||||
/* Allow space for cmdline + UUID */
|
||||
len = strnlen(from, sizeof(buf));
|
||||
if (len >= maxlen)
|
||||
return -E2BIG;
|
||||
|
||||
log_debug("uuid %d %s\n", uuid ? (int)strlen(uuid) : 0, uuid);
|
||||
for (to = buf, end = buf + maxlen - UUID_STR_LEN - 1; *from; from++) {
|
||||
if (to >= end)
|
||||
return -E2BIG;
|
||||
if (from[0] == '%' && from[1] == 'U' && uuid &&
|
||||
strlen(uuid) == UUID_STR_LEN) {
|
||||
strcpy(to, uuid);
|
||||
to += UUID_STR_LEN;
|
||||
from++;
|
||||
} else {
|
||||
*to++ = *from;
|
||||
}
|
||||
}
|
||||
*to = '\0';
|
||||
len = to - buf;
|
||||
cmd = strdup(buf);
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
free(*bufp);
|
||||
*bufp = cmd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cros_read_bootflow(struct udevice *dev, struct bootflow *bflow)
|
||||
{
|
||||
struct blk_desc *desc = dev_get_uclass_plat(bflow->blk);
|
||||
ulong base, start, size, setup, cmdline, num_blks, kern_base;
|
||||
struct disk_partition info;
|
||||
const char *uuid = NULL;
|
||||
void *buf, *hdr;
|
||||
int ret;
|
||||
|
||||
log_debug("starting, part=%d\n", bflow->part);
|
||||
|
||||
/* We consider the whole disk, not any one partition */
|
||||
if (bflow->part)
|
||||
return log_msg_ret("max", -ENOENT);
|
||||
|
||||
/* Check partition 2 */
|
||||
ret = part_get_info(desc, 2, &info);
|
||||
if (ret)
|
||||
return log_msg_ret("part", ret);
|
||||
|
||||
/* Make a buffer for the header information */
|
||||
num_blks = SZ_4K >> desc->log2blksz;
|
||||
log_debug("Reading header, blk=%s, start=%lx, blocks=%lx\n",
|
||||
bflow->blk->name, (ulong)info.start, num_blks);
|
||||
hdr = memalign(SZ_1K, SZ_4K);
|
||||
if (!hdr)
|
||||
return log_msg_ret("hdr", -ENOMEM);
|
||||
ret = blk_read(bflow->blk, info.start, num_blks, hdr);
|
||||
if (ret != num_blks)
|
||||
return log_msg_ret("inf", ret);
|
||||
|
||||
if (memcmp("CHROMEOS", hdr, 8))
|
||||
return -ENOENT;
|
||||
|
||||
log_info("Header at %lx\n", (ulong)map_to_sysmem(hdr));
|
||||
start = *(u32 *)(hdr + KERN_START);
|
||||
size = ALIGN(*(u32 *)(hdr + KERN_SIZE), desc->blksz);
|
||||
log_debug("Reading start %lx size %lx\n", start, size);
|
||||
bflow->size = size;
|
||||
|
||||
buf = memalign(SZ_1K, size);
|
||||
if (!buf)
|
||||
return log_msg_ret("buf", -ENOMEM);
|
||||
num_blks = size >> desc->log2blksz;
|
||||
log_debug("Reading data, blk=%s, start=%lx, blocks=%lx\n",
|
||||
bflow->blk->name, (ulong)info.start, num_blks);
|
||||
ret = blk_read(bflow->blk, (ulong)info.start + 0x80, num_blks, buf);
|
||||
if (ret != num_blks)
|
||||
return log_msg_ret("inf", ret);
|
||||
base = map_to_sysmem(buf);
|
||||
|
||||
setup = base + start - OFFSET_BASE - SETUP_OFFSET;
|
||||
cmdline = base + start - OFFSET_BASE - CMDLINE_OFFSET;
|
||||
kern_base = base + start - OFFSET_BASE + SZ_16K;
|
||||
log_debug("base %lx setup %lx, cmdline %lx, kern_base %lx\n", base,
|
||||
setup, cmdline, kern_base);
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
const char *version;
|
||||
|
||||
version = zimage_get_kernel_version(map_sysmem(setup, 0),
|
||||
map_sysmem(kern_base, 0));
|
||||
log_debug("version %s\n", version);
|
||||
if (version)
|
||||
bflow->name = strdup(version);
|
||||
#endif
|
||||
if (!bflow->name)
|
||||
bflow->name = strdup("ChromeOS");
|
||||
if (!bflow->name)
|
||||
return log_msg_ret("nam", -ENOMEM);
|
||||
bflow->os_name = strdup("ChromeOS");
|
||||
if (!bflow->os_name)
|
||||
return log_msg_ret("os", -ENOMEM);
|
||||
|
||||
#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
|
||||
uuid = info.uuid;
|
||||
#endif
|
||||
ret = copy_cmdline(map_sysmem(cmdline, 0), uuid, &bflow->cmdline);
|
||||
if (ret)
|
||||
return log_msg_ret("cmd", ret);
|
||||
|
||||
bflow->state = BOOTFLOWST_READY;
|
||||
bflow->buf = buf;
|
||||
bflow->x86_setup = map_sysmem(setup, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cros_read_file(struct udevice *dev, struct bootflow *bflow,
|
||||
const char *file_path, ulong addr, ulong *sizep)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static int cros_boot(struct udevice *dev, struct bootflow *bflow)
|
||||
{
|
||||
#ifdef CONFIG_X86
|
||||
zboot_start(map_to_sysmem(bflow->buf), bflow->size, 0, 0,
|
||||
map_to_sysmem(bflow->x86_setup),
|
||||
bflow->cmdline);
|
||||
#endif
|
||||
|
||||
return log_msg_ret("go", -EFAULT);
|
||||
}
|
||||
|
||||
static int cros_bootmeth_bind(struct udevice *dev)
|
||||
{
|
||||
struct bootmeth_uc_plat *plat = dev_get_uclass_plat(dev);
|
||||
|
||||
plat->desc = "ChromiumOS boot";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct bootmeth_ops cros_bootmeth_ops = {
|
||||
.check = cros_check,
|
||||
.read_bootflow = cros_read_bootflow,
|
||||
.read_file = cros_read_file,
|
||||
.boot = cros_boot,
|
||||
};
|
||||
|
||||
static const struct udevice_id cros_bootmeth_ids[] = {
|
||||
{ .compatible = "u-boot,cros" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(bootmeth_cros) = {
|
||||
.name = "bootmeth_cros",
|
||||
.id = UCLASS_BOOTMETH,
|
||||
.of_match = cros_bootmeth_ids,
|
||||
.ops = &cros_bootmeth_ops,
|
||||
.bind = cros_bootmeth_bind,
|
||||
};
|
@ -10,6 +10,7 @@ CONFIG_FIT=y
|
||||
CONFIG_TIMESTAMP=y
|
||||
CONFIG_FIT_SIGNATURE=y
|
||||
# CONFIG_BOOTSTD_FULL is not set
|
||||
# CONFIG_BOOTMETH_CROS is not set
|
||||
# CONFIG_BOOTMETH_VBE is not set
|
||||
CONFIG_USE_BOOTCOMMAND=y
|
||||
CONFIG_BOOTCOMMAND="run distro_bootcmd"
|
||||
|
Loading…
Reference in New Issue
Block a user