aboutsummaryrefslogtreecommitdiff
path: root/boot
diff options
context:
space:
mode:
Diffstat (limited to 'boot')
-rw-r--r--boot/Kconfig4
-rw-r--r--boot/bootflow.c17
-rw-r--r--boot/bootm.c37
-rw-r--r--boot/bootmeth-uclass.c12
-rw-r--r--boot/bootmeth_cros.c367
-rw-r--r--boot/bootmeth_cros.h197
6 files changed, 575 insertions, 59 deletions
diff --git a/boot/Kconfig b/boot/Kconfig
index b00d7a8d11..5e2d4286ae 100644
--- a/boot/Kconfig
+++ b/boot/Kconfig
@@ -464,8 +464,8 @@ config BOOTMETH_GLOBAL
config BOOTMETH_CROS
bool "Bootdev support for Chromium OS"
- depends on X86 || SANDBOX
- default y
+ depends on X86 || ARM || SANDBOX
+ default y if !ARM
help
Enables support for booting Chromium OS using bootdevs. This uses the
kernel A slot and obtains the kernel command line from the parameters
diff --git a/boot/bootflow.c b/boot/bootflow.c
index 81b5829d5b..6ef62e1d18 100644
--- a/boot/bootflow.c
+++ b/boot/bootflow.c
@@ -432,6 +432,7 @@ void bootflow_free(struct bootflow *bflow)
free(bflow->buf);
free(bflow->os_name);
free(bflow->fdt_fname);
+ free(bflow->bootmeth_priv);
}
void bootflow_remove(struct bootflow *bflow)
@@ -444,6 +445,22 @@ void bootflow_remove(struct bootflow *bflow)
free(bflow);
}
+#if CONFIG_IS_ENABLED(BOOTSTD_FULL)
+int bootflow_read_all(struct bootflow *bflow)
+{
+ int ret;
+
+ if (bflow->state != BOOTFLOWST_READY)
+ return log_msg_ret("rd", -EPROTO);
+
+ ret = bootmeth_read_all(bflow->method, bflow);
+ if (ret)
+ return log_msg_ret("rd2", ret);
+
+ return 0;
+}
+#endif /* BOOTSTD_FULL */
+
int bootflow_boot(struct bootflow *bflow)
{
int ret;
diff --git a/boot/bootm.c b/boot/bootm.c
index 75f0b4a9af..b1c3afe0a3 100644
--- a/boot/bootm.c
+++ b/boot/bootm.c
@@ -823,6 +823,43 @@ err:
return ret;
}
+int bootm_boot_start(ulong addr, const char *cmdline)
+{
+ static struct cmd_tbl cmd = {"bootm"};
+ char addr_str[30];
+ char *argv[] = {addr_str, NULL};
+ int states;
+ int ret;
+
+ /*
+ * TODO(sjg@chromium.org): This uses the command-line interface, but
+ * should not. To clean this up, the various bootm states need to be
+ * passed an info structure instead of cmdline flags. Then this can
+ * set up the required info and move through the states without needing
+ * the command line.
+ */
+ states = BOOTM_STATE_START | BOOTM_STATE_FINDOS | BOOTM_STATE_PRE_LOAD |
+ BOOTM_STATE_FINDOTHER | BOOTM_STATE_LOADOS |
+ BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |
+ BOOTM_STATE_OS_GO;
+ if (IS_ENABLED(CONFIG_SYS_BOOT_RAMDISK_HIGH))
+ states |= BOOTM_STATE_RAMDISK;
+ if (IS_ENABLED(CONFIG_PPC) || IS_ENABLED(CONFIG_MIPS))
+ states |= BOOTM_STATE_OS_CMDLINE;
+ images.state |= states;
+
+ snprintf(addr_str, sizeof(addr_str), "%lx", addr);
+
+ ret = env_set("bootargs", cmdline);
+ if (ret) {
+ printf("Failed to set cmdline\n");
+ return ret;
+ }
+ ret = do_bootm_states(&cmd, 0, 1, argv, states, &images, 1);
+
+ return ret;
+}
+
#if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
/**
* image_get_kernel - verify legacy format kernel image
diff --git a/boot/bootmeth-uclass.c b/boot/bootmeth-uclass.c
index 175eb1de5e..1d157d54db 100644
--- a/boot/bootmeth-uclass.c
+++ b/boot/bootmeth-uclass.c
@@ -61,6 +61,18 @@ int bootmeth_set_bootflow(struct udevice *dev, struct bootflow *bflow,
return ops->set_bootflow(dev, bflow, buf, size);
}
+#if CONFIG_IS_ENABLED(BOOTSTD_FULL)
+int bootmeth_read_all(struct udevice *dev, struct bootflow *bflow)
+{
+ const struct bootmeth_ops *ops = bootmeth_get_ops(dev);
+
+ if (!ops->read_all)
+ return -ENOSYS;
+
+ return ops->read_all(dev, bflow);
+}
+#endif /* BOOTSTD_FULL */
+
int bootmeth_boot(struct udevice *dev, struct bootflow *bflow)
{
const struct bootmeth_ops *ops = bootmeth_get_ops(dev);
diff --git a/boot/bootmeth_cros.c b/boot/bootmeth_cros.c
index aa19ae097f..1776fb1838 100644
--- a/boot/bootmeth_cros.c
+++ b/boot/bootmeth_cros.c
@@ -12,24 +12,76 @@
#include <blk.h>
#include <bootdev.h>
#include <bootflow.h>
+#include <bootm.h>
#include <bootmeth.h>
+#include <display_options.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>
+#include "bootmeth_cros.h"
+
+/*
+ * Layout of the ChromeOS kernel
+ *
+ * Partitions 2 and 4 contain kernels
+ *
+ * Contents are:
+ *
+ * Offset Contents
+ * 0 struct vb2_keyblock
+ * m struct vb2_kernel_preamble
+ * m + n kernel buffer
+ *
+ * m is keyblock->keyblock_size
+ * n is preamble->preamble_size
+ *
+ * The kernel buffer itself consists of various parts:
+ *
+ * Offset Contents
+ * m + n kernel image (Flat vmlinux binary or FIT)
+ * b - 8KB Command line text
+ * b - 4KB X86 setup block (struct boot_params, extends for about 16KB)
+ * b X86 bootloader (continuation of setup block)
+ * b + 16KB X86 setup block (copy, used for hold data pointed to)
+ *
+ * b is m + n + preamble->bootloader_address - preamble->body_load_address
+ *
+ * Useful metadata extends from b - 8KB through to b + 32 KB
+ */
enum {
- /* Offsets in the kernel-partition header */
- KERN_START = 0x4f0,
- KERN_SIZE = 0x518,
+ PROBE_SIZE = SZ_4K, /* initial bytes read from partition */
- SETUP_OFFSET = 0x1000, /* bytes before base */
- CMDLINE_OFFSET = 0x2000, /* bytes before base */
- OFFSET_BASE = 0x100000, /* assumed kernel load-address */
+ X86_SETUP_OFFSET = -0x1000, /* setup offset relative to base */
+ CMDLINE_OFFSET = -0x2000, /* cmdline offset relative to base */
+ X86_KERNEL_OFFSET = 0x4000, /* kernel offset relative to base */
+};
+
+/**
+ * struct cros_priv - Private data
+ *
+ * This is read from the disk and recorded for use when the full kernel must
+ * be loaded and booted
+ *
+ * @body_offset: Offset of kernel body from start of partition (in bytes)
+ * @body_size: Size of kernel body in bytes
+ * @part_start: Block offset of selected partition from the start of the disk
+ * @body_load_address: Nominal load address for kernel body
+ * @bootloader_address: Address of bootloader, after body is loaded at
+ * body_load_address
+ * @bootloader_size: Size of bootloader in bytes
+ * @info_buf: Buffer containing ChromiumOS info
+ */
+struct cros_priv {
+ ulong body_offset;
+ ulong body_size;
+ lbaint_t part_start;
+ ulong body_load_address;
+ ulong bootloader_address;
+ ulong bootloader_size;
+ void *info_buf;
};
static int cros_check(struct udevice *dev, struct bootflow_iter *iter)
@@ -77,61 +129,83 @@ static int copy_cmdline(const char *from, const char *uuid, char **bufp)
return 0;
}
-static int cros_read_bootflow(struct udevice *dev, struct bootflow *bflow)
+/**
+ * scan_part() - Scan a kernel partition to see if has a ChromeOS header
+ *
+ * This reads the first PROBE_SIZE of a partition, loookng for
+ * VB2_KEYBLOCK_MAGIC
+ *
+ * @blk: Block device to scan
+ * @partnum: Partition number to scan
+ * @info: Please to put partition info
+ * @hdrp: Return allocated keyblock header on success
+ */
+static int scan_part(struct udevice *blk, int partnum,
+ struct disk_partition *info, struct vb2_keyblock **hdrp)
{
- 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;
+ struct blk_desc *desc = dev_get_uclass_plat(blk);
+ struct vb2_keyblock *hdr;
+ ulong num_blks;
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);
+ ret = part_get_info(desc, partnum, info);
if (ret)
return log_msg_ret("part", ret);
/* Make a buffer for the header information */
- num_blks = SZ_4K >> desc->log2blksz;
+ num_blks = PROBE_SIZE >> 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);
+ blk->name, (ulong)info->start, num_blks);
+ hdr = memalign(SZ_1K, PROBE_SIZE);
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);
+ ret = blk_read(blk, info->start, num_blks, hdr);
+ if (ret != num_blks) {
+ free(hdr);
+ return log_msg_ret("inf", -EIO);
+ }
- if (memcmp("CHROMEOS", hdr, 8))
+ if (memcmp(VB2_KEYBLOCK_MAGIC, hdr->magic, VB2_KEYBLOCK_MAGIC_SIZE)) {
+ free(hdr);
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;
+ *hdrp = hdr;
+
+ return 0;
+}
+
+/**
+ * cros_read_buf() - Read information into a buf and parse it
+ *
+ * @bflow: Bootflow to update
+ * @buf: Buffer to use
+ * @size: Size of buffer and number of bytes to read thereinto
+ * @start: Start offset to read from on disk
+ * @before_base: Number of bytes to read before the bootloader base
+ * @uuid: UUID string if supported, else NULL
+ * Return: 0 if OK, -ENOMEM if out of memory, -EIO on read failure
+ */
+static int cros_read_buf(struct bootflow *bflow, void *buf, ulong size,
+ loff_t start, ulong before_base, const char *uuid)
+{
+ struct blk_desc *desc = dev_get_uclass_plat(bflow->blk);
+ ulong base, setup, cmdline, kern_base;
+ ulong num_blks;
+ int ret;
- 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);
+ log_debug("Reading info to %lx, blk=%s, size=%lx, blocks=%lx\n",
+ (ulong)map_to_sysmem(buf), bflow->blk->name, size, num_blks);
+ ret = blk_read(bflow->blk, start, num_blks, buf);
if (ret != num_blks)
- return log_msg_ret("inf", ret);
- base = map_to_sysmem(buf);
+ return log_msg_ret("inf", -EIO);
+ base = map_to_sysmem(buf) + before_base;
- 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 = base + X86_SETUP_OFFSET;
+ cmdline = base + CMDLINE_OFFSET;
+ kern_base = base + X86_KERNEL_OFFSET;
+ log_debug("base %lx setup %lx cmdline %lx kern_base %lx\n", base,
setup, cmdline, kern_base);
#ifdef CONFIG_X86
@@ -151,35 +225,211 @@ static int cros_read_bootflow(struct udevice *dev, struct bootflow *bflow)
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->x86_setup = map_sysmem(setup, 0);
+
+ return 0;
+}
+
+/**
+ * cros_read_info() - Read information and fill out the bootflow
+ *
+ * @bflow: Bootflow to update
+ * @uuid: UUID string if supported, else NULL
+ * @preamble: Kernel preamble information
+ * Return: 0 if OK, -ENOMEM if out of memory, -EIO on read failure
+ */
+static int cros_read_info(struct bootflow *bflow, const char *uuid,
+ const struct vb2_kernel_preamble *preamble)
+{
+ struct cros_priv *priv = bflow->bootmeth_priv;
+ struct udevice *blk = bflow->blk;
+ struct blk_desc *desc = dev_get_uclass_plat(blk);
+ ulong offset, size, before_base;
+ void *buf;
+ int ret;
+
+ log_debug("Kernel preamble at %lx, version major %x, minor %x\n",
+ (ulong)map_to_sysmem(preamble),
+ preamble->header_version_major,
+ preamble->header_version_minor);
+
+ log_debug(" - load_address %lx, bl_addr %lx, bl_size %lx\n",
+ (ulong)preamble->body_load_address,
+ (ulong)preamble->bootloader_address,
+ (ulong)preamble->bootloader_size);
+
+ priv->body_size = preamble->body_signature.data_size;
+ priv->body_load_address = preamble->body_load_address;
+ priv->bootloader_address = preamble->bootloader_address;
+ priv->bootloader_size = preamble->bootloader_size;
+ log_debug("Kernel body at %lx size %lx\n", priv->body_offset,
+ priv->body_size);
+
+ /* Work out how many bytes to read before the bootloader base */
+ before_base = -CMDLINE_OFFSET;
+
+ /* Read the cmdline through to the end of the bootloader */
+ size = priv->bootloader_size + before_base;
+ offset = priv->body_offset +
+ (priv->bootloader_address - priv->body_load_address) +
+ CMDLINE_OFFSET;
+ buf = malloc(size);
+ if (!buf)
+ return log_msg_ret("buf", -ENOMEM);
+
+ ret = cros_read_buf(bflow, buf, size,
+ priv->part_start + (offset >> desc->log2blksz),
+ before_base, uuid);
+ if (ret) {
+ /* Clear this since the buffer is invalid */
+ bflow->x86_setup = NULL;
+ free(buf);
+ return log_msg_ret("pro", ret);
+ }
+ priv->info_buf = buf;
+
+ return 0;
+}
+
+static int cros_read_kernel(struct bootflow *bflow)
+{
+ struct blk_desc *desc = dev_get_uclass_plat(bflow->blk);
+ struct cros_priv *priv = bflow->bootmeth_priv;
+ ulong base, setup;
+ ulong num_blks;
+ void *buf;
+ int ret;
+
+ bflow->size = priv->body_size;
+
+ buf = memalign(SZ_1K, priv->body_size);
+ if (!buf)
+ return log_msg_ret("buf", -ENOMEM);
+
+ /* Check that the header is not smaller than permitted */
+ if (priv->body_offset < PROBE_SIZE)
+ return log_msg_ret("san", EFAULT);
+
+ /* Read kernel body */
+ num_blks = priv->body_size >> desc->log2blksz;
+ log_debug("Reading body to %lx, blk=%s, size=%lx, blocks=%lx\n",
+ (ulong)map_to_sysmem(buf), bflow->blk->name, priv->body_size,
+ num_blks);
+ ret = blk_read(bflow->blk,
+ priv->part_start + (priv->body_offset >> desc->log2blksz),
+ num_blks, buf);
+ if (ret != num_blks)
+ return log_msg_ret("inf", -EIO);
+ base = map_to_sysmem(buf) + priv->bootloader_address -
+ priv->body_load_address;
+ setup = base + X86_SETUP_OFFSET;
- bflow->state = BOOTFLOWST_READY;
bflow->buf = buf;
bflow->x86_setup = map_sysmem(setup, 0);
return 0;
}
+static int cros_read_bootflow(struct udevice *dev, struct bootflow *bflow)
+{
+ const struct vb2_kernel_preamble *preamble;
+ struct disk_partition info;
+ struct vb2_keyblock *hdr;
+ const char *uuid = NULL;
+ struct cros_priv *priv;
+ int part, 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 then 4 */
+ part = 2;
+ ret = scan_part(bflow->blk, part, &info, &hdr);
+ if (ret) {
+ part = 4;
+ ret = scan_part(bflow->blk, part, &info, &hdr);
+ if (ret)
+ return log_msg_ret("scan", ret);
+ }
+ bflow->part = part;
+
+ priv = malloc(sizeof(struct cros_priv));
+ if (!priv) {
+ free(hdr);
+ return log_msg_ret("buf", -ENOMEM);
+ }
+ bflow->bootmeth_priv = priv;
+
+ log_info("Selected partition %d, header at %lx\n", bflow->part,
+ (ulong)map_to_sysmem(hdr));
+
+ /* Grab a few things from the preamble */
+ preamble = (void *)hdr + hdr->keyblock_size;
+ priv->body_offset = hdr->keyblock_size + preamble->preamble_size;
+ priv->part_start = info.start;
+
+ /* Now read everything we can learn about kernel */
+#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
+ uuid = info.uuid;
+#endif
+ ret = cros_read_info(bflow, uuid, preamble);
+ preamble = NULL;
+ free(hdr);
+ if (ret)
+ return log_msg_ret("inf", ret);
+ bflow->size = priv->body_size;
+ bflow->state = BOOTFLOWST_READY;
+
+ return 0;
+}
+
static int cros_read_file(struct udevice *dev, struct bootflow *bflow,
const char *file_path, ulong addr, ulong *sizep)
{
return -ENOSYS;
}
+#if CONFIG_IS_ENABLED(BOOSTD_FULL)
+static int cros_read_all(struct udevice *dev, struct bootflow *bflow)
+{
+ int ret;
+
+ if (bflow->buf)
+ return log_msg_ret("ld", -EALREADY);
+ ret = cros_read_kernel(bflow);
+ if (ret)
+ return log_msg_ret("rd", ret);
+
+ return 0;
+}
+#endif /* BOOSTD_FULL */
+
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
+ int ret;
+
+ if (!bflow->buf) {
+ ret = cros_read_kernel(bflow);
+ if (ret)
+ return log_msg_ret("rd", ret);
+ }
+
+ if (IS_ENABLED(CONFIG_X86)) {
+ ret = zboot_start(map_to_sysmem(bflow->buf), bflow->size, 0, 0,
+ map_to_sysmem(bflow->x86_setup),
+ bflow->cmdline);
+ } else {
+ ret = bootm_boot_start(map_to_sysmem(bflow->buf),
+ bflow->cmdline);
+ }
- return log_msg_ret("go", -EFAULT);
+ return log_msg_ret("go", ret);
}
static int cros_bootmeth_bind(struct udevice *dev)
@@ -196,6 +446,9 @@ static struct bootmeth_ops cros_bootmeth_ops = {
.read_bootflow = cros_read_bootflow,
.read_file = cros_read_file,
.boot = cros_boot,
+#if CONFIG_IS_ENABLED(BOOSTD_FULL)
+ .read_all = cros_read_all,
+#endif /* BOOSTD_FULL */
};
static const struct udevice_id cros_bootmeth_ids[] = {
diff --git a/boot/bootmeth_cros.h b/boot/bootmeth_cros.h
new file mode 100644
index 0000000000..8e3038571d
--- /dev/null
+++ b/boot/bootmeth_cros.h
@@ -0,0 +1,197 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Structures used by the ChromiumOS bootmeth
+ *
+ * See docs at:
+ * https://www.chromium.org/chromium-os/chromiumos-design-docs/verified-boot-data-structures/
+ *
+ * Original code at:
+ * https://chromium.googlesource.com/chromiumos/platform/vboot_reference/+/refs/heads/main/firmware/2lib/include/2struct.h
+ *
+ * Code taken from vboot_reference commit 5b8596ce file 2struct.h
+ *
+ * Copyright 2023 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#ifndef __BOOTMETH_CROS_H
+#define __BOOTMETH_CROS_H
+
+/* Signature data (a secure hash, possibly signed) */
+struct vb2_signature {
+ /* Offset of signature data from start of this struct */
+ uint32_t sig_offset;
+ uint32_t reserved0;
+
+ /* Size of signature data in bytes */
+ uint32_t sig_size;
+ uint32_t reserved1;
+
+ /* Size of the data block which was signed in bytes */
+ uint32_t data_size;
+ uint32_t reserved2;
+} __attribute__((packed));
+
+#define EXPECTED_VB2_SIGNATURE_SIZE 24
+
+/* Packed public key data */
+struct vb2_packed_key {
+ /* Offset of key data from start of this struct */
+ uint32_t key_offset;
+ uint32_t reserved0;
+
+ /* Size of key data in bytes (NOT strength of key in bits) */
+ uint32_t key_size;
+ uint32_t reserved1;
+
+ /* Signature algorithm used by the key (enum vb2_crypto_algorithm) */
+ uint32_t algorithm;
+ uint32_t reserved2;
+
+ /* Key version */
+ uint32_t key_version;
+ uint32_t reserved3;
+
+ /* TODO: when redoing this struct, add a text description of the key */
+} __attribute__((packed));
+
+#define EXPECTED_VB2_PACKED_KEY_SIZE 32
+
+#define VB2_KEYBLOCK_MAGIC "CHROMEOS"
+#define VB2_KEYBLOCK_MAGIC_SIZE 8
+
+/*
+ * Keyblock, containing the public key used to sign some other chunk of data.
+ *
+ * This should be followed by:
+ * 1) The data_key key data, pointed to by data_key.key_offset.
+ * 2) The checksum data for (vb2_keyblock + data_key data), pointed to
+ * by keyblock_checksum.sig_offset.
+ * 3) The signature data for (vb2_keyblock + data_key data), pointed to
+ * by keyblock_signature.sig_offset.
+ */
+struct vb2_keyblock {
+ /* Magic number */
+ uint8_t magic[VB2_KEYBLOCK_MAGIC_SIZE];
+
+ /* Version of this header format */
+ uint32_t header_version_major;
+ uint32_t header_version_minor;
+
+ /*
+ * Length of this entire keyblock, including keys, signatures, and
+ * padding, in bytes
+ */
+ uint32_t keyblock_size;
+ uint32_t reserved0;
+
+ /*
+ * Signature for this keyblock (header + data pointed to by data_key)
+ * For use with signed data keys
+ */
+ struct vb2_signature keyblock_signature;
+
+ /*
+ * SHA-512 hash for this keyblock (header + data pointed to by
+ * data_key) For use with unsigned data keys.
+ *
+ * Only supported for kernel keyblocks, not firmware keyblocks.
+ */
+ struct vb2_signature keyblock_hash;
+
+ /* Flags for key (VB2_KEYBLOCK_FLAG_*) */
+ uint32_t keyblock_flags;
+ uint32_t reserved1;
+
+ /* Key to verify the chunk of data */
+ struct vb2_packed_key data_key;
+} __attribute__((packed));
+
+#define EXPECTED_VB2_KEYBLOCK_SIZE 112
+
+/*
+ * Preamble block for kernel, version 2.2
+ *
+ * This should be followed by:
+ * 1) The signature data for the kernel body, pointed to by
+ * body_signature.sig_offset.
+ * 2) The signature data for (vb2_kernel_preamble + body signature data),
+ * pointed to by preamble_signature.sig_offset.
+ * 3) The 16-bit vmlinuz header, which is used for reconstruction of
+ * vmlinuz image.
+ */
+struct vb2_kernel_preamble {
+ /*
+ * Size of this preamble, including keys, signatures, vmlinuz header,
+ * and padding, in bytes
+ */
+ uint32_t preamble_size;
+ uint32_t reserved0;
+
+ /* Signature for this preamble (header + body signature) */
+ struct vb2_signature preamble_signature;
+
+ /* Version of this header format */
+ uint32_t header_version_major;
+ uint32_t header_version_minor;
+
+ /* Kernel version */
+ uint32_t kernel_version;
+ uint32_t reserved1;
+
+ /* Load address for kernel body */
+ uint64_t body_load_address;
+ /* TODO (vboot 2.1): we never used that */
+
+ /* Address of bootloader, after body is loaded at body_load_address */
+ uint64_t bootloader_address;
+ /* TODO (vboot 2.1): should be a 32-bit offset */
+
+ /* Size of bootloader in bytes */
+ uint32_t bootloader_size;
+ uint32_t reserved2;
+
+ /* Signature for the kernel body */
+ struct vb2_signature body_signature;
+
+ /*
+ * TODO (vboot 2.1): fields for kernel offset and size. Right now the
+ * size is implicitly the same as the size of data signed by the body
+ * signature, and the offset is implicitly at the end of the preamble.
+ * But that forces us to pad the preamble to 64KB rather than just
+ * having a tiny preamble and an offset field.
+ */
+
+ /*
+ * Fields added in header version 2.1. You must verify the header
+ * version before reading these fields!
+ */
+
+ /*
+ * Address of 16-bit header for vmlinuz reassembly. Readers should
+ * return 0 for header version < 2.1.
+ */
+ uint64_t vmlinuz_header_address;
+
+ /* Size of 16-bit header for vmlinuz in bytes. Readers should return 0
+ for header version < 2.1 */
+ uint32_t vmlinuz_header_size;
+ uint32_t reserved3;
+
+ /*
+ * Fields added in header version 2.2. You must verify the header
+ * version before reading these fields!
+ */
+
+ /*
+ * Flags; see VB2_KERNEL_PREAMBLE_*. Readers should return 0 for
+ * header version < 2.2. Flags field is currently defined as:
+ * [31:2] - Reserved (for future use)
+ * [1:0] - Kernel image type (0b00 - CrOS,
+ * 0b01 - bootimg,
+ * 0b10 - multiboot)
+ */
+ uint32_t flags;
+} __attribute__((packed));
+
+#endif /* __BOOTMETH_CROS_H */