blob: 672878fe6fe94d09215a393efe63f186e6733c9c [file] [log] [blame]
Simon Glass15d320d2025-01-15 18:27:07 -07001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Verified Boot for Embedded (VBE) common functions
4 *
5 * Copyright 2024 Google LLC
6 * Written by Simon Glass <sjg@chromium.org>
7 */
8
Simon Glass9846e5f2025-01-15 18:27:08 -07009#include <blk.h>
10#include <memalign.h>
11#include <spl.h>
Simon Glass72424b82025-01-15 18:27:09 -070012#include <u-boot/crc.h>
Simon Glass15d320d2025-01-15 18:27:07 -070013#include "vbe_common.h"
14
15int vbe_get_blk(const char *storage, struct udevice **blkp)
16{
17 struct blk_desc *desc;
18 char devname[16];
19 const char *end;
20 int devnum;
21
22 /* First figure out the block device */
23 log_debug("storage=%s\n", storage);
24 devnum = trailing_strtoln_end(storage, NULL, &end);
25 if (devnum == -1)
26 return log_msg_ret("num", -ENODEV);
27 if (end - storage >= sizeof(devname))
28 return log_msg_ret("end", -E2BIG);
29 strlcpy(devname, storage, end - storage + 1);
30 log_debug("dev=%s, %x\n", devname, devnum);
31
32 desc = blk_get_dev(devname, devnum);
33 if (!desc)
34 return log_msg_ret("get", -ENXIO);
35 *blkp = desc->bdev;
36
37 return 0;
38}
Simon Glass9846e5f2025-01-15 18:27:08 -070039
40int vbe_read_version(struct udevice *blk, ulong offset, char *version,
41 int max_size)
42{
43 ALLOC_CACHE_ALIGN_BUFFER(u8, buf, MMC_MAX_BLOCK_LEN);
44
45 /* we can use an assert() here since we already read only one block */
46 assert(max_size <= MMC_MAX_BLOCK_LEN);
47
48 /*
49 * we can use an assert() here since reading the wrong block will just
50 * cause an invalid version-string to be (safely) read
51 */
52 assert(!(offset & (MMC_MAX_BLOCK_LEN - 1)));
53
54 offset /= MMC_MAX_BLOCK_LEN;
55
56 if (blk_read(blk, offset, 1, buf) != 1)
57 return log_msg_ret("read", -EIO);
58 strlcpy(version, buf, max_size);
59 log_debug("version=%s\n", version);
60
61 return 0;
62}
Simon Glass72424b82025-01-15 18:27:09 -070063
64int vbe_read_nvdata(struct udevice *blk, ulong offset, ulong size, u8 *buf)
65{
66 uint hdr_ver, hdr_size, data_size, crc;
67 const struct vbe_nvdata *nvd;
68
69 /* we can use an assert() here since we already read only one block */
70 assert(size <= MMC_MAX_BLOCK_LEN);
71
72 /*
73 * We can use an assert() here since reading the wrong block will just
74 * cause invalid state to be (safely) read. If the crc passes, then we
75 * obtain invalid state and it will likely cause booting to fail.
76 *
77 * VBE relies on valid values being in U-Boot's devicetree, so this
78 * should not every be wrong on a production device.
79 */
80 assert(!(offset & (MMC_MAX_BLOCK_LEN - 1)));
81
82 if (offset & (MMC_MAX_BLOCK_LEN - 1))
83 return log_msg_ret("get", -EBADF);
84 offset /= MMC_MAX_BLOCK_LEN;
85
86 if (blk_read(blk, offset, 1, buf) != 1)
87 return log_msg_ret("read", -EIO);
88 nvd = (struct vbe_nvdata *)buf;
89 hdr_ver = (nvd->hdr & NVD_HDR_VER_MASK) >> NVD_HDR_VER_SHIFT;
90 hdr_size = (nvd->hdr & NVD_HDR_SIZE_MASK) >> NVD_HDR_SIZE_SHIFT;
91 if (hdr_ver != NVD_HDR_VER_CUR)
92 return log_msg_ret("hdr", -EPERM);
93 data_size = 1 << hdr_size;
94 if (!data_size || data_size > sizeof(*nvd))
95 return log_msg_ret("sz", -EPERM);
96
97 crc = crc8(0, buf + 1, data_size - 1);
98 if (crc != nvd->crc8)
99 return log_msg_ret("crc", -EPERM);
100
101 return 0;
102}