All of lore.kernel.org
 help / color / mirror / Atom feed
From: Simon Glass <sjg@chromium.org>
To: U-Boot Mailing List <u-boot@lists.denx.de>
Cc: Tom Rini <trini@konsulko.com>, Simon Glass <sjg@chromium.org>,
	Heinrich Schuchardt <xypron.glpk@gmx.de>,
	Julien Masson <jmasson@baylibre.com>,
	Marek Vasut <marek.vasut+renesas@mailbox.org>,
	Mattijs Korpershoek <mkorpershoek@baylibre.com>
Subject: [PATCH 01/15] vbe: Split out some VBE code into a common file
Date: Thu,  9 Jan 2025 05:29:56 -0700	[thread overview]
Message-ID: <20250109123010.4005298-2-sjg@chromium.org> (raw)
In-Reply-To: <20250109123010.4005298-1-sjg@chromium.org>

Loading a FIT is useful for other VBE methods, such as ABrec, so start
a new common file. Add functions for reading the version and nvdata.
Also add a function to get the block device.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 boot/Makefile     |   2 +-
 boot/vbe_common.c |  93 ++++++++++++++++++++++++++++++
 boot/vbe_common.h | 143 ++++++++++++++++++++++++++++++++++++++++++++++
 boot/vbe_simple.c |  99 +++++++-------------------------
 boot/vbe_simple.h |  15 +----
 5 files changed, 258 insertions(+), 94 deletions(-)
 create mode 100644 boot/vbe_common.c
 create mode 100644 boot/vbe_common.h

diff --git a/boot/Makefile b/boot/Makefile
index 9446c6b82a9..30529bac367 100644
--- a/boot/Makefile
+++ b/boot/Makefile
@@ -66,7 +66,7 @@ endif
 
 obj-$(CONFIG_$(PHASE_)BOOTMETH_VBE) += vbe.o
 obj-$(CONFIG_$(PHASE_)BOOTMETH_VBE_REQUEST) += vbe_request.o
-obj-$(CONFIG_$(PHASE_)BOOTMETH_VBE_SIMPLE) += vbe_simple.o
+obj-$(CONFIG_$(PHASE_)BOOTMETH_VBE_SIMPLE) += vbe_simple.o vbe_common.o
 obj-$(CONFIG_$(PHASE_)BOOTMETH_VBE_SIMPLE_FW) += vbe_simple_fw.o
 obj-$(CONFIG_$(PHASE_)BOOTMETH_VBE_SIMPLE_OS) += vbe_simple_os.o
 
diff --git a/boot/vbe_common.c b/boot/vbe_common.c
new file mode 100644
index 00000000000..5f31cde0288
--- /dev/null
+++ b/boot/vbe_common.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Verified Boot for Embedded (VBE) common functions
+ *
+ * Copyright 2024 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <blk.h>
+#include <bootstage.h>
+#include <display_options.h>
+#include <dm.h>
+#include <image.h>
+#include <spl.h>
+#include <mapmem.h>
+#include <memalign.h>
+#include <linux/types.h>
+#include <u-boot/crc.h>
+#include "vbe_common.h"
+
+int vbe_read_version(struct udevice *blk, ulong offset, char *version,
+		     int max_size)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(u8, buf, MMC_MAX_BLOCK_LEN);
+
+	if (max_size > MMC_MAX_BLOCK_LEN)
+		return log_msg_ret("ver", -E2BIG);
+
+	if (offset & (MMC_MAX_BLOCK_LEN - 1))
+		return log_msg_ret("get", -EBADF);
+	offset /= MMC_MAX_BLOCK_LEN;
+
+	if (blk_read(blk, offset, 1, buf) != 1)
+		return log_msg_ret("read", -EIO);
+	strlcpy(version, buf, max_size);
+
+	return 0;
+}
+
+int vbe_read_nvdata(struct udevice *blk, ulong offset, ulong size, u8 *buf)
+{
+	uint hdr_ver, hdr_size, data_size, crc;
+	const struct vbe_nvdata *nvd;
+
+	if (size > MMC_MAX_BLOCK_LEN)
+		return log_msg_ret("state", -E2BIG);
+
+	if (offset & (MMC_MAX_BLOCK_LEN - 1))
+		return log_msg_ret("get", -EBADF);
+	offset /= MMC_MAX_BLOCK_LEN;
+
+	if (blk_read(blk, offset, 1, buf) != 1)
+		return log_msg_ret("read", -EIO);
+	nvd = (struct vbe_nvdata *)buf;
+	hdr_ver = (nvd->hdr & NVD_HDR_VER_MASK) >> NVD_HDR_VER_SHIFT;
+	hdr_size = (nvd->hdr & NVD_HDR_SIZE_MASK) >> NVD_HDR_SIZE_SHIFT;
+	if (hdr_ver != NVD_HDR_VER_CUR)
+		return log_msg_ret("hdr", -EPERM);
+	data_size = 1 << hdr_size;
+	if (data_size > sizeof(*nvd))
+		return log_msg_ret("sz", -EPERM);
+
+	crc = crc8(0, buf + 1, data_size - 1);
+	if (crc != nvd->crc8)
+		return log_msg_ret("crc", -EPERM);
+
+	return 0;
+}
+
+int vbe_get_blk(const char *storage, struct udevice **blkp)
+{
+	struct blk_desc *desc;
+	char devname[16];
+	const char *end;
+	int devnum;
+
+	/* First figure out the block device */
+	log_debug("storage=%s\n", storage);
+	devnum = trailing_strtoln_end(storage, NULL, &end);
+	if (devnum == -1)
+		return log_msg_ret("num", -ENODEV);
+	if (end - storage >= sizeof(devname))
+		return log_msg_ret("end", -E2BIG);
+	strlcpy(devname, storage, end - storage + 1);
+	log_debug("dev=%s, %x\n", devname, devnum);
+
+	desc = blk_get_dev(devname, devnum);
+	if (!desc)
+		return log_msg_ret("get", -ENXIO);
+	*blkp = desc->bdev;
+
+	return 0;
+}
diff --git a/boot/vbe_common.h b/boot/vbe_common.h
new file mode 100644
index 00000000000..df133fbf05f
--- /dev/null
+++ b/boot/vbe_common.h
@@ -0,0 +1,143 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Verified Boot for Embedded (VBE) common functions
+ *
+ * Copyright 2024 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#ifndef __VBE_COMMON_H
+#define __VBE_COMMON_H
+
+#include <linux/types.h>
+
+struct udevice;
+
+/*
+ * Controls whether we use a full bootmeth driver with VBE in this phase, or
+ * just access the information directly.
+ *
+ * For now VBE-simple uses the full bootmeth, but VBE-abrec does not, to reduce
+ * code size
+ */
+#define USE_BOOTMETH	CONFIG_IS_ENABLED(BOOTMETH_VBE_SIMPLE)
+
+struct spl_image_info;
+struct spl_load_info;
+
+enum {
+	MAX_VERSION_LEN		= 256,
+
+	NVD_HDR_VER_SHIFT	= 0,
+	NVD_HDR_VER_MASK	= 0xf,
+	NVD_HDR_SIZE_SHIFT	= 4,
+	NVD_HDR_SIZE_MASK	= 0xf << NVD_HDR_SIZE_SHIFT,
+
+	/* Firmware key-version is in the top 16 bits of fw_ver */
+	FWVER_KEY_SHIFT		= 16,
+	FWVER_FW_MASK		= 0xffff,
+
+	NVD_HDR_VER_CUR		= 1,	/* current version */
+};
+
+/**
+ * enum vbe_try_result - result of trying a firmware pick
+ *
+ * @VBETR_UNKNOWN: Unknown / invalid result
+ * @VBETR_TRYING: Firmware pick is being tried
+ * @VBETR_OK: Firmware pick is OK and can be used from now on
+ * @VBETR_BAD: Firmware pick is bad and should be removed
+ */
+enum vbe_try_result {
+	VBETR_UNKNOWN,
+	VBETR_TRYING,
+	VBETR_OK,
+	VBETR_BAD,
+};
+
+/**
+ * enum vbe_flags - flags controlling operation
+ *
+ * @VBEF_TRY_COUNT_MASK: mask for the 'try count' value
+ * @VBEF_TRY_B: Try the B slot
+ * @VBEF_RECOVERY: Use recovery slot
+ */
+enum vbe_flags {
+	VBEF_TRY_COUNT_MASK	= 0x3,
+	VBEF_TRY_B	= BIT(2),
+	VBEF_RECOVERY	= BIT(3),
+
+	VBEF_RESULT_SHIFT	= 4,
+	VBEF_RESULT_MASK	= 3 << VBEF_RESULT_SHIFT,
+
+	VBEF_PICK_SHIFT		= 6,
+	VBEF_PICK_MASK		= 3 << VBEF_PICK_SHIFT,
+};
+
+/**
+ * struct vbe_nvdata - basic storage format for non-volatile data
+ *
+ * This is used for all VBE methods
+ *
+ * @crc8: crc8 for the entire record except @crc8 field itself
+ * @hdr: header size and version (NVD_HDR_...)
+ * @spare1: unused, must be 0
+ * @fw_vernum: version and key version (FWVER_...)
+ * @flags: Flags controlling operation (enum vbe_flags)
+ */
+struct vbe_nvdata {
+	u8 crc8;
+	u8 hdr;
+	u16 spare1;
+	u32 fw_vernum;
+	u32 flags;
+	u8 spare2[0x34];
+};
+
+/**
+ * vbe_read_nvdata() - Read non-volatile data from a block device
+ *
+ * Reads the VBE nvdata from a device. This function reads a single block from
+ * the device, so the nvdata cannot be larger than that.
+ *
+ * @blk: Device to read from
+ * @offset: Offset to read, in bytes
+ * @size: Number of bytes to read
+ * @buf: Buffer to hold the data
+ * Return: 0 if OK, -E2BIG if @size > block size, -EBADF if the offset is not
+ * block-aligned, -EIO if an I/O error occurred, -EPERM if the header version is
+ * incorrect, the header size is invalid or the data fails its CRC check
+ */
+int vbe_read_nvdata(struct udevice *blk, ulong offset, ulong size, u8 *buf);
+
+/**
+ * vbe_read_version() - Read version-string from a block device
+ *
+ * Reads the VBE version-string from a device. This function reads a single
+ * block from the device, so the string cannot be larger than that. It uses a
+ * temporary buffer for the read, then copies in up to @size bytes
+ *
+ * @blk: Device to read from
+ * @offset: Offset to read, in bytes
+ * @version: Place to put the string
+ * @max_size: Maximum size of @version
+ * Return: 0 if OK, -E2BIG if @max_size > block size, -EBADF if the offset is
+ * not block-aligned, -EIO if an I/O error occurred
+ */
+int vbe_read_version(struct udevice *blk, ulong offset, char *version,
+		     int max_size);
+
+/**
+ * vbe_get_blk() - Obtain the block device to use for VBE
+ *
+ * Decodes the string to produce a block device
+ *
+ * @storage: String indicating the device to use, e.g. "mmc1"
+ * @blkp: Returns associated block device, on success
+ * Return 0 if OK, -ENODEV if @storage does not end with a number, -E2BIG if
+ * the device name is more than 15 characters, -ENXIO if the block device could
+ * not be found
+ */
+int vbe_get_blk(const char *storage, struct udevice **blkp);
+
+#endif /* __VBE_ABREC_H */
diff --git a/boot/vbe_simple.c b/boot/vbe_simple.c
index ed7b9598e38..792750f7ef6 100644
--- a/boot/vbe_simple.c
+++ b/boot/vbe_simple.c
@@ -18,70 +18,23 @@
 #include <vbe.h>
 #include <dm/device-internal.h>
 #include <dm/ofnode.h>
-#include <u-boot/crc.h>
+#include "vbe_common.h"
 #include "vbe_simple.h"
 
-/** struct simple_nvdata - storage format for non-volatile data */
-struct simple_nvdata {
-	u8 crc8;
-	u8 hdr;
-	u16 spare1;
-	u32 fw_vernum;
-	u8 spare2[0x38];
-};
-
-static int simple_read_version(struct udevice *dev, struct blk_desc *desc,
-			       u8 *buf, struct simple_state *state)
+static int simple_read_nvdata(struct udevice *dev, struct udevice *blk,
+			      struct simple_state *state)
 {
+	ALLOC_CACHE_ALIGN_BUFFER(u8, buf, MMC_MAX_BLOCK_LEN);
 	struct simple_priv *priv = dev_get_priv(dev);
-	int start;
-
-	if (priv->version_size > MMC_MAX_BLOCK_LEN)
-		return log_msg_ret("ver", -E2BIG);
-
-	start = priv->area_start + priv->version_offset;
-	if (start & (MMC_MAX_BLOCK_LEN - 1))
-		return log_msg_ret("get", -EBADF);
-	start /= MMC_MAX_BLOCK_LEN;
-
-	if (blk_dread(desc, start, 1, buf) != 1)
-		return log_msg_ret("read", -EIO);
-	strlcpy(state->fw_version, buf, MAX_VERSION_LEN);
-	log_debug("version=%s\n", state->fw_version);
+	const struct vbe_nvdata *nvd;
+	int ret;
 
-	return 0;
-}
+	ret = vbe_read_nvdata(blk, priv->area_start + priv->state_offset,
+			      priv->state_size, buf);
+	if (ret)
+		return log_msg_ret("nv", ret);
 
-static int simple_read_nvdata(struct udevice *dev, struct blk_desc *desc,
-			      u8 *buf, struct simple_state *state)
-{
-	struct simple_priv *priv = dev_get_priv(dev);
-	uint hdr_ver, hdr_size, size, crc;
-	const struct simple_nvdata *nvd;
-	int start;
-
-	if (priv->state_size > MMC_MAX_BLOCK_LEN)
-		return log_msg_ret("state", -E2BIG);
-
-	start = priv->area_start + priv->state_offset;
-	if (start & (MMC_MAX_BLOCK_LEN - 1))
-		return log_msg_ret("get", -EBADF);
-	start /= MMC_MAX_BLOCK_LEN;
-
-	if (blk_dread(desc, start, 1, buf) != 1)
-		return log_msg_ret("read", -EIO);
-	nvd = (struct simple_nvdata *)buf;
-	hdr_ver = (nvd->hdr & NVD_HDR_VER_MASK) >> NVD_HDR_VER_SHIFT;
-	hdr_size = (nvd->hdr & NVD_HDR_SIZE_MASK) >> NVD_HDR_SIZE_SHIFT;
-	if (hdr_ver != NVD_HDR_VER_CUR)
-		return log_msg_ret("hdr", -EPERM);
-	size = 1 << hdr_size;
-	if (size > sizeof(*nvd))
-		return log_msg_ret("sz", -ENOEXEC);
-
-	crc = crc8(0, buf + 1, size - 1);
-	if (crc != nvd->crc8)
-		return log_msg_ret("crc", -EPERM);
+	nvd = (struct vbe_nvdata *)buf;
 	state->fw_vernum = nvd->fw_vernum;
 
 	log_debug("version=%s\n", state->fw_version);
@@ -91,33 +44,21 @@ static int simple_read_nvdata(struct udevice *dev, struct blk_desc *desc,
 
 int vbe_simple_read_state(struct udevice *dev, struct simple_state *state)
 {
-	ALLOC_CACHE_ALIGN_BUFFER(u8, buf, MMC_MAX_BLOCK_LEN);
 	struct simple_priv *priv = dev_get_priv(dev);
-	struct blk_desc *desc;
-	char devname[16];
-	const char *end;
-	int devnum;
+	struct udevice *blk;
 	int ret;
 
-	/* First figure out the block device */
-	log_debug("storage=%s\n", priv->storage);
-	devnum = trailing_strtoln_end(priv->storage, NULL, &end);
-	if (devnum == -1)
-		return log_msg_ret("num", -ENODEV);
-	if (end - priv->storage >= sizeof(devname))
-		return log_msg_ret("end", -E2BIG);
-	strlcpy(devname, priv->storage, end - priv->storage + 1);
-	log_debug("dev=%s, %x\n", devname, devnum);
-
-	desc = blk_get_dev(devname, devnum);
-	if (!desc)
-		return log_msg_ret("get", -ENXIO);
-
-	ret = simple_read_version(dev, desc, buf, state);
+	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);
+	log_debug("version=%s\n", state->fw_version);
 
-	ret = simple_read_nvdata(dev, desc, buf, state);
+	ret = simple_read_nvdata(dev, blk, state);
 	if (ret)
 		return log_msg_ret("nvd", ret);
 
diff --git a/boot/vbe_simple.h b/boot/vbe_simple.h
index 56d319206f2..8eb3ddb61ba 100644
--- a/boot/vbe_simple.h
+++ b/boot/vbe_simple.h
@@ -9,20 +9,7 @@
 #ifndef __VBE_SIMPLE_H
 #define __VBE_SIMPLE_H
 
-enum {
-	MAX_VERSION_LEN		= 256,
-
-	NVD_HDR_VER_SHIFT	= 0,
-	NVD_HDR_VER_MASK	= 0xf,
-	NVD_HDR_SIZE_SHIFT	= 4,
-	NVD_HDR_SIZE_MASK	= 0xf << NVD_HDR_SIZE_SHIFT,
-
-	/* Firmware key-version is in the top 16 bits of fw_ver */
-	FWVER_KEY_SHIFT		= 16,
-	FWVER_FW_MASK		= 0xffff,
-
-	NVD_HDR_VER_CUR		= 1,	/* current version */
-};
+#include "vbe_common.h"
 
 /** struct simple_priv - information read from the device tree */
 struct simple_priv {
-- 
2.34.1


  reply	other threads:[~2025-01-09 12:30 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-01-09 12:29 [PATCH 00/15] vbe: Series part F Simon Glass
2025-01-09 12:29 ` Simon Glass [this message]
2025-01-14  1:22   ` [PATCH 01/15] vbe: Split out some VBE code into a common file Tom Rini
2025-01-14 12:58     ` Simon Glass
2025-01-14 13:26       ` Simon Glass
2025-01-14 16:58       ` Tom Rini
2025-01-14 17:33         ` Tom Rini
2025-01-15  1:18           ` Simon Glass
2025-01-15  1:41             ` Tom Rini
2025-01-15  2:48               ` Simon Glass
2025-01-15 14:10                 ` Simon Glass
2025-01-09 12:29 ` [PATCH 02/15] vbe: Split out reading a FIT " Simon Glass
2025-01-11 22:54   ` Tom Rini
2025-01-13 20:03     ` Simon Glass
2025-01-13 20:44       ` Tom Rini
2025-01-14  0:13         ` Simon Glass
2025-01-14  1:22           ` Tom Rini
2025-01-15 14:43             ` Tom Rini
2025-01-15 23:21               ` Simon Glass
2025-01-09 12:29 ` [PATCH 03/15] vbe: Allocate space for the FIT header Simon Glass
2025-01-09 12:29 ` [PATCH 04/15] vbe: Allow VBE to load FITs on any architecture Simon Glass
2025-01-09 12:30 ` [PATCH 05/15] vbe: Tidy up error checking with blk_read() Simon Glass
2025-01-09 12:30 ` [PATCH 06/15] vbe: Handle loading from an unaligned offset Simon Glass
2025-01-09 12:30 ` [PATCH 07/15] vbe: Allow loading loadables if there is no firmware Simon Glass
2025-01-09 12:30 ` [PATCH 08/15] vbe: Support loading an FDT from the FIT Simon Glass
2025-01-09 12:30 ` [PATCH 09/15] spl: Add fields for VBE Simon Glass
2025-01-09 12:30 ` [PATCH 10/15] spl: Add a type for the jumper function Simon Glass
2025-01-09 12:30 ` [PATCH 11/15] spl: Add support for a relocating jump to the next phase Simon Glass
2025-01-09 12:30 ` [PATCH 12/15] spl: Plumb in the relocating loader Simon Glass
2025-01-09 12:30 ` [PATCH 13/15] vbe: Support loading an FDT with " Simon Glass
2025-01-09 12:30 ` [PATCH 14/15] vbe: Support loading SPL images Simon Glass
2025-01-09 12:30 ` [PATCH 15/15] vbe: Update simple-fw to support using the SPL loader Simon Glass

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250109123010.4005298-2-sjg@chromium.org \
    --to=sjg@chromium.org \
    --cc=jmasson@baylibre.com \
    --cc=marek.vasut+renesas@mailbox.org \
    --cc=mkorpershoek@baylibre.com \
    --cc=trini@konsulko.com \
    --cc=u-boot@lists.denx.de \
    --cc=xypron.glpk@gmx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.