
All VBE methods read non-volatile data, so move this function into a common file.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Split patch into several pieces
boot/vbe_common.c | 41 +++++++++++++++++++++++++++++++++++++++++ boot/vbe_common.h | 16 ++++++++++++++++ boot/vbe_simple.c | 44 ++++++++------------------------------------ 3 files changed, 65 insertions(+), 36 deletions(-)
diff --git a/boot/vbe_common.c b/boot/vbe_common.c index 8bbcc37e67e..672878fe6fe 100644 --- a/boot/vbe_common.c +++ b/boot/vbe_common.c @@ -9,6 +9,7 @@ #include <blk.h> #include <memalign.h> #include <spl.h> +#include <u-boot/crc.h> #include "vbe_common.h"
int vbe_get_blk(const char *storage, struct udevice **blkp) @@ -59,3 +60,43 @@ int vbe_read_version(struct udevice *blk, ulong offset, char *version,
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; + + /* we can use an assert() here since we already read only one block */ + assert(size <= MMC_MAX_BLOCK_LEN); + + /* + * We can use an assert() here since reading the wrong block will just + * cause invalid state to be (safely) read. If the crc passes, then we + * obtain invalid state and it will likely cause booting to fail. + * + * VBE relies on valid values being in U-Boot's devicetree, so this + * should not every be wrong on a production device. + */ + assert(!(offset & (MMC_MAX_BLOCK_LEN - 1))); + + 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 || 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; +} diff --git a/boot/vbe_common.h b/boot/vbe_common.h index a122bead93e..37a81330325 100644 --- a/boot/vbe_common.h +++ b/boot/vbe_common.h @@ -78,4 +78,20 @@ int vbe_get_blk(const char *storage, struct udevice **blkp); int vbe_read_version(struct udevice *blk, ulong offset, char *version, int max_size);
+/** + * 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); + #endif /* __VBE_ABREC_H */ diff --git a/boot/vbe_simple.c b/boot/vbe_simple.c index ce385065321..c6766c532f2 100644 --- a/boot/vbe_simple.c +++ b/boot/vbe_simple.c @@ -18,48 +18,21 @@ #include <vbe.h> #include <dm/device-internal.h> #include <dm/ofnode.h> -#include <u-boot/crc.h> #include "vbe_simple.h"
static int simple_read_nvdata(const struct simple_priv *priv, - struct udevice *blk, u8 *buf, - struct simple_state *state) + struct udevice *blk, struct simple_state *state) { - uint hdr_ver, hdr_size, size, crc; + ALLOC_CACHE_ALIGN_BUFFER(u8, buf, MMC_MAX_BLOCK_LEN); const struct vbe_nvdata *nvd; - int start; - - /* we can use an assert() here since we already read only one block */ - assert(priv->state_size <= MMC_MAX_BLOCK_LEN); - - start = priv->area_start + priv->state_offset; - - /* - * We can use an assert() here since reading the wrong block will just - * cause invalid state to be (safely) read. If the crc passes, then we - * obtain invalid state and it will likely cause booting to fail. - * - * VBE relies on valid values being in U-Boot's devicetree, so this - * should not every be wrong on a production device. - */ - assert(!(start & (MMC_MAX_BLOCK_LEN - 1))); + int ret;
- start /= MMC_MAX_BLOCK_LEN; + ret = vbe_read_nvdata(blk, priv->area_start + priv->state_offset, + priv->state_size, buf); + if (ret) + return log_msg_ret("nv", ret);
- if (blk_read(blk, start, 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); - size = 1 << hdr_size; - if (!size || 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); state->fw_vernum = nvd->fw_vernum;
log_debug("version=%s\n", state->fw_version); @@ -69,7 +42,6 @@ static int simple_read_nvdata(const struct simple_priv *priv,
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 udevice *blk; int ret; @@ -83,7 +55,7 @@ int vbe_simple_read_state(struct udevice *dev, struct simple_state *state) if (ret) return log_msg_ret("ver", ret);
- ret = simple_read_nvdata(priv, blk, buf, state); + ret = simple_read_nvdata(priv, blk, state); if (ret) return log_msg_ret("nvd", ret);