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 
9 #ifndef __VBE_COMMON_H
10 #define __VBE_COMMON_H
11 
12 #include <dm/ofnode_decl.h>
13 #include <linux/bitops.h>
14 #include <linux/types.h>
15 
16 struct spl_image_info;
17 struct udevice;
18 
19 /*
20  * Controls whether we use a full bootmeth driver with VBE in this phase, or
21  * just access the information directly.
22  *
23  * For now VBE-simple uses the full bootmeth, but VBE-abrec does not, to reduce
24  * code size
25  */
26 #define USE_BOOTMETH	CONFIG_IS_ENABLED(BOOTMETH_VBE_SIMPLE)
27 
28 enum {
29 	MAX_VERSION_LEN		= 256,
30 
31 	NVD_HDR_VER_SHIFT	= 0,
32 	NVD_HDR_VER_MASK	= 0xf,
33 	NVD_HDR_SIZE_SHIFT	= 4,
34 	NVD_HDR_SIZE_MASK	= 0xf << NVD_HDR_SIZE_SHIFT,
35 
36 	/* Firmware key-version is in the top 16 bits of fw_ver */
37 	FWVER_KEY_SHIFT		= 16,
38 	FWVER_FW_MASK		= 0xffff,
39 
40 	NVD_HDR_VER_CUR		= 1,	/* current version */
41 };
42 
43 /**
44  * enum vbe_try_result - result of trying a firmware pick
45  *
46  * @VBETR_UNKNOWN: Unknown / invalid result
47  * @VBETR_TRYING: Firmware pick is being tried
48  * @VBETR_OK: Firmware pick is OK and can be used from now on
49  * @VBETR_BAD: Firmware pick is bad and should be removed
50  */
51 enum vbe_try_result {
52 	VBETR_UNKNOWN,
53 	VBETR_TRYING,
54 	VBETR_OK,
55 	VBETR_BAD,
56 };
57 
58 /**
59  * enum vbe_flags - flags controlling operation
60  *
61  * @VBEF_TRY_COUNT_MASK: mask for the 'try count' value
62  * @VBEF_TRY_B: Try the B slot
63  * @VBEF_RECOVERY: Use recovery slot
64  */
65 enum vbe_flags {
66 	VBEF_TRY_COUNT_MASK	= 0x3,
67 	VBEF_TRY_B		= BIT(2),
68 	VBEF_RECOVERY		= BIT(3),
69 
70 	VBEF_RESULT_SHIFT	= 4,
71 	VBEF_RESULT_MASK	= 3 << VBEF_RESULT_SHIFT,
72 
73 	VBEF_PICK_SHIFT		= 6,
74 	VBEF_PICK_MASK		= 3 << VBEF_PICK_SHIFT,
75 };
76 
77 /**
78  * struct vbe_nvdata - basic storage format for non-volatile data
79  *
80  * This is used for all VBE methods
81  *
82  * @crc8: crc8 for the entire record except @crc8 field itself
83  * @hdr: header size and version (NVD_HDR_...)
84  * @spare1: unused, must be 0
85  * @fw_vernum: version and key version (FWVER_...)
86  * @flags: Flags controlling operation (enum vbe_flags)
87  */
88 struct vbe_nvdata {
89 	u8 crc8;
90 	u8 hdr;
91 	u16 spare1;
92 	u32 fw_vernum;
93 	u32 flags;
94 	u8 spare2[0x34];
95 };
96 
97 /**
98  * vbe_get_blk() - Obtain the block device to use for VBE
99  *
100  * Decodes the string to produce a block device
101  *
102  * @storage: String indicating the device to use, e.g. "mmc1"
103  * @blkp: Returns associated block device, on success
104  * Return 0 if OK, -ENODEV if @storage does not end with a number, -E2BIG if
105  * the device name is more than 15 characters, -ENXIO if the block device could
106  * not be found
107  */
108 int vbe_get_blk(const char *storage, struct udevice **blkp);
109 
110 /**
111  * vbe_read_version() - Read version-string from a block device
112  *
113  * Reads the VBE version-string from a device. This function reads a single
114  * block from the device, so the string cannot be larger than that. It uses a
115  * temporary buffer for the read, then copies in up to @size bytes
116  *
117  * @blk: Device to read from
118  * @offset: Offset to read, in bytes
119  * @version: Place to put the string
120  * @max_size: Maximum size of @version
121  * Return: 0 if OK, -E2BIG if @max_size > block size, -EBADF if the offset is
122  * not block-aligned, -EIO if an I/O error occurred
123  */
124 int vbe_read_version(struct udevice *blk, ulong offset, char *version,
125 		     int max_size);
126 
127 /**
128  * vbe_read_nvdata() - Read non-volatile data from a block device
129  *
130  * Reads the VBE nvdata from a device. This function reads a single block from
131  * the device, so the nvdata cannot be larger than that.
132  *
133  * @blk: Device to read from
134  * @offset: Offset to read, in bytes
135  * @size: Number of bytes to read
136  * @buf: Buffer to hold the data
137  * Return: 0 if OK, -E2BIG if @size > block size, -EBADF if the offset is not
138  * block-aligned, -EIO if an I/O error occurred, -EPERM if the header version is
139  * incorrect, the header size is invalid or the data fails its CRC check
140  */
141 int vbe_read_nvdata(struct udevice *blk, ulong offset, ulong size, u8 *buf);
142 
143 /**
144  * vbe_read_fit() - Read an image from a FIT
145  *
146  * This handles most of the VBE logic for reading from a FIT. It reads the FIT
147  * metadata, decides which image to load and loads it to a suitable address,
148  * ready for jumping to the next phase of VBE.
149  *
150  * This supports transition from VPL to SPL as well as SPL to U-Boot proper. For
151  * now, TPL->VPL is not supported.
152  *
153  * Both embedded and external data are supported for the FIT
154  *
155  * @blk: Block device containing FIT
156  * @area_offset: Byte offset of the VBE area in @blk containing the FIT
157  * @area_size: Size of the VBE area
158  * @image: SPL image to fill in with details of the loaded image, or NULL
159  * @load_addrp: If non-null, returns the address where the image was loaded
160  * @lenp: If non-null, returns the size of the image loaded, in bytes
161  * @namep: If non-null, returns the name of the FIT-image node that was loaded
162  *	(allocated by this function)
163  * Return: 0 if OK, -EINVAL if the area does not contain an FDT (the underlying
164  * format for FIT), -E2BIG if the FIT extends past @area_size, -ENOMEM if there
165  * was not space to allocate the image-node name, other error if a read error
166  * occurred (see blk_read()), or something went wrong with the actually
167  * FIT-parsing (see fit_image_load()).
168  */
169 int vbe_read_fit(struct udevice *blk, ulong area_offset, ulong area_size,
170 		 struct spl_image_info *image, ulong *load_addrp, ulong *lenp,
171 		 char **namep);
172 
173 /**
174  * vbe_get_node() - Get the node containing the VBE settings
175  *
176  * Return: VBE node (typically "/bootstd/firmware0")
177  */
178 ofnode vbe_get_node(void);
179 
180 #endif /* __VBE_ABREC_H */
181