Simon Glass | 15d320d | 2025-01-15 18:27:07 -0700 | [diff] [blame] | 1 | // 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 Glass | 9846e5f | 2025-01-15 18:27:08 -0700 | [diff] [blame] | 9 | #include <blk.h> |
| 10 | #include <memalign.h> |
| 11 | #include <spl.h> |
Simon Glass | 72424b8 | 2025-01-15 18:27:09 -0700 | [diff] [blame^] | 12 | #include <u-boot/crc.h> |
Simon Glass | 15d320d | 2025-01-15 18:27:07 -0700 | [diff] [blame] | 13 | #include "vbe_common.h" |
| 14 | |
| 15 | int 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 Glass | 9846e5f | 2025-01-15 18:27:08 -0700 | [diff] [blame] | 39 | |
| 40 | int 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 Glass | 72424b8 | 2025-01-15 18:27:09 -0700 | [diff] [blame^] | 63 | |
| 64 | int 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 | } |