scripts: Fix to not skip some option parameters for rpi4 fusing script
[platform/kernel/u-boot.git] / boot / vbe_simple.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Verified Boot for Embedded (VBE) 'simple' method
4  *
5  * Copyright 2022 Google LLC
6  * Written by Simon Glass <sjg@chromium.org>
7  */
8
9 #include <common.h>
10 #include <log.h>
11 #include <memalign.h>
12 #include <part.h>
13 #include <bootflow.h>
14 #include <bootmeth.h>
15 #include <dm.h>
16 #include <mmc.h>
17 #include <vbe.h>
18 #include <version_string.h>
19 #include <dm/device-internal.h>
20 #include <dm/ofnode.h>
21 #include <u-boot/crc.h>
22
23 enum {
24         MAX_VERSION_LEN         = 256,
25
26         NVD_HDR_VER_SHIFT       = 0,
27         NVD_HDR_VER_MASK        = 0xf,
28         NVD_HDR_SIZE_SHIFT      = 4,
29         NVD_HDR_SIZE_MASK       = 0xf << NVD_HDR_SIZE_SHIFT,
30
31         /* Firmware key-version is in the top 16 bits of fw_ver */
32         FWVER_KEY_SHIFT         = 16,
33         FWVER_FW_MASK           = 0xffff,
34
35         NVD_HDR_VER_CUR         = 1,    /* current version */
36 };
37
38 /** struct simple_priv - information read from the device tree */
39 struct simple_priv {
40         u32 area_start;
41         u32 area_size;
42         u32 skip_offset;
43         u32 state_offset;
44         u32 state_size;
45         u32 version_offset;
46         u32 version_size;
47         const char *storage;
48 };
49
50 /** struct simple_state - state information read from media
51  *
52  * @fw_version: Firmware version string
53  * @fw_vernum: Firmware version number
54  */
55 struct simple_state {
56         char fw_version[MAX_VERSION_LEN];
57         u32 fw_vernum;
58 };
59
60 /** struct simple_nvdata - storage format for non-volatile data */
61 struct simple_nvdata {
62         u8 crc8;
63         u8 hdr;
64         u16 spare1;
65         u32 fw_vernum;
66         u8 spare2[0x38];
67 };
68
69 static int simple_read_version(struct udevice *dev, struct blk_desc *desc,
70                                u8 *buf, struct simple_state *state)
71 {
72         struct simple_priv *priv = dev_get_priv(dev);
73         int start;
74
75         if (priv->version_size > MMC_MAX_BLOCK_LEN)
76                 return log_msg_ret("ver", -E2BIG);
77
78         start = priv->area_start + priv->version_offset;
79         if (start & (MMC_MAX_BLOCK_LEN - 1))
80                 return log_msg_ret("get", -EBADF);
81         start /= MMC_MAX_BLOCK_LEN;
82
83         if (blk_dread(desc, start, 1, buf) != 1)
84                 return log_msg_ret("read", -EIO);
85         strlcpy(state->fw_version, buf, MAX_VERSION_LEN);
86         log_debug("version=%s\n", state->fw_version);
87
88         return 0;
89 }
90
91 static int simple_read_nvdata(struct udevice *dev, struct blk_desc *desc,
92                               u8 *buf, struct simple_state *state)
93 {
94         struct simple_priv *priv = dev_get_priv(dev);
95         uint hdr_ver, hdr_size, size, crc;
96         const struct simple_nvdata *nvd;
97         int start;
98
99         if (priv->state_size > MMC_MAX_BLOCK_LEN)
100                 return log_msg_ret("state", -E2BIG);
101
102         start = priv->area_start + priv->state_offset;
103         if (start & (MMC_MAX_BLOCK_LEN - 1))
104                 return log_msg_ret("get", -EBADF);
105         start /= MMC_MAX_BLOCK_LEN;
106
107         if (blk_dread(desc, start, 1, buf) != 1)
108                 return log_msg_ret("read", -EIO);
109         nvd = (struct simple_nvdata *)buf;
110         hdr_ver = (nvd->hdr & NVD_HDR_VER_MASK) >> NVD_HDR_VER_SHIFT;
111         hdr_size = (nvd->hdr & NVD_HDR_SIZE_MASK) >> NVD_HDR_SIZE_SHIFT;
112         if (hdr_ver != NVD_HDR_VER_CUR)
113                 return log_msg_ret("hdr", -EPERM);
114         size = 1 << hdr_size;
115         if (size > sizeof(*nvd))
116                 return log_msg_ret("sz", -ENOEXEC);
117
118         crc = crc8(0, buf + 1, size - 1);
119         if (crc != nvd->crc8)
120                 return log_msg_ret("crc", -EPERM);
121         state->fw_vernum = nvd->fw_vernum;
122
123         log_debug("version=%s\n", state->fw_version);
124
125         return 0;
126 }
127
128 static int simple_read_state(struct udevice *dev, struct simple_state *state)
129 {
130         ALLOC_CACHE_ALIGN_BUFFER(u8, buf, MMC_MAX_BLOCK_LEN);
131         struct simple_priv *priv = dev_get_priv(dev);
132         struct blk_desc *desc;
133         char devname[16];
134         const char *end;
135         int devnum;
136         int ret;
137
138         /* First figure out the block device */
139         log_debug("storage=%s\n", priv->storage);
140         devnum = trailing_strtoln_end(priv->storage, NULL, &end);
141         if (devnum == -1)
142                 return log_msg_ret("num", -ENODEV);
143         if (end - priv->storage >= sizeof(devname))
144                 return log_msg_ret("end", -E2BIG);
145         strlcpy(devname, priv->storage, end - priv->storage + 1);
146         log_debug("dev=%s, %x\n", devname, devnum);
147
148         desc = blk_get_dev(devname, devnum);
149         if (!desc)
150                 return log_msg_ret("get", -ENXIO);
151
152         ret = simple_read_version(dev, desc, buf, state);
153         if (ret)
154                 return log_msg_ret("ver", ret);
155
156         ret = simple_read_nvdata(dev, desc, buf, state);
157         if (ret)
158                 return log_msg_ret("nvd", ret);
159
160         return 0;
161 }
162
163 static int vbe_simple_get_state_desc(struct udevice *dev, char *buf,
164                                      int maxsize)
165 {
166         struct simple_state state;
167         int ret;
168
169         ret = simple_read_state(dev, &state);
170         if (ret)
171                 return log_msg_ret("read", ret);
172
173         if (maxsize < 30)
174                 return -ENOSPC;
175         snprintf(buf, maxsize, "Version: %s\nVernum: %x/%x", state.fw_version,
176                  state.fw_vernum >> FWVER_KEY_SHIFT,
177                  state.fw_vernum & FWVER_FW_MASK);
178
179         return 0;
180 }
181
182 static int vbe_simple_read_bootflow(struct udevice *dev, struct bootflow *bflow)
183 {
184         /* To be implemented */
185
186         return -EINVAL;
187 }
188
189 static struct bootmeth_ops bootmeth_vbe_simple_ops = {
190         .get_state_desc = vbe_simple_get_state_desc,
191         .read_bootflow  = vbe_simple_read_bootflow,
192         .read_file      = bootmeth_common_read_file,
193 };
194
195 int vbe_simple_fixup_node(ofnode node, struct simple_state *state)
196 {
197         char *version;
198         int ret;
199
200         version = strdup(state->fw_version);
201         if (!version)
202                 return log_msg_ret("ver", -ENOMEM);
203
204         ret = ofnode_write_string(node, "cur-version", version);
205         if (ret)
206                 return log_msg_ret("ver", ret);
207         ret = ofnode_write_u32(node, "cur-vernum", state->fw_vernum);
208         if (ret)
209                 return log_msg_ret("ver", ret);
210         ret = ofnode_write_string(node, "bootloader-version", version_string);
211         if (ret)
212                 return log_msg_ret("fix", ret);
213
214         return 0;
215 }
216
217 /**
218  * bootmeth_vbe_simple_ft_fixup() - Write out all VBE simple data to the DT
219  *
220  * @ctx: Context for event
221  * @event: Event to process
222  * @return 0 if OK, -ve on error
223  */
224 static int bootmeth_vbe_simple_ft_fixup(void *ctx, struct event *event)
225 {
226         oftree tree = event->data.ft_fixup.tree;
227         struct udevice *dev;
228
229         /*
230          * Ideally we would have driver model support for fixups, but that does
231          * not exist yet. It is a step too far to try to do this before VBE is
232          * in place.
233          */
234         for (vbe_find_first_device(&dev); dev; vbe_find_next_device(&dev)) {
235                 struct simple_state state;
236                 ofnode node;
237                 int ret;
238
239                 if (strcmp("vbe_simple", dev->driver->name))
240                         continue;
241
242                 /* Check if there is a node to fix up */
243                 node = ofnode_path_root(tree, "/chosen/fwupd");
244                 if (!ofnode_valid(node))
245                         continue;
246                 node = ofnode_find_subnode(node, dev->name);
247                 if (!ofnode_valid(node))
248                         continue;
249
250                 log_debug("Fixing up: %s\n", dev->name);
251                 ret = device_probe(dev);
252                 if (ret)
253                         return log_msg_ret("probe", ret);
254                 ret = simple_read_state(dev, &state);
255                 if (ret)
256                         return log_msg_ret("read", ret);
257
258                 ret = vbe_simple_fixup_node(node, &state);
259                 if (ret)
260                         return log_msg_ret("fix", ret);
261         }
262
263         return 0;
264 }
265 EVENT_SPY(EVT_FT_FIXUP, bootmeth_vbe_simple_ft_fixup);
266
267 static int bootmeth_vbe_simple_probe(struct udevice *dev)
268 {
269         struct simple_priv *priv = dev_get_priv(dev);
270
271         memset(priv, '\0', sizeof(*priv));
272         if (dev_read_u32(dev, "area-start", &priv->area_start) ||
273             dev_read_u32(dev, "area-size", &priv->area_size) ||
274             dev_read_u32(dev, "version-offset", &priv->version_offset) ||
275             dev_read_u32(dev, "version-size", &priv->version_size) ||
276             dev_read_u32(dev, "state-offset", &priv->state_offset) ||
277             dev_read_u32(dev, "state-size", &priv->state_size))
278                 return log_msg_ret("read", -EINVAL);
279         dev_read_u32(dev, "skip-offset", &priv->skip_offset);
280         priv->storage = strdup(dev_read_string(dev, "storage"));
281         if (!priv->storage)
282                 return log_msg_ret("str", -EINVAL);
283
284         return 0;
285 }
286
287 static int bootmeth_vbe_simple_bind(struct udevice *dev)
288 {
289         struct bootmeth_uc_plat *plat = dev_get_uclass_plat(dev);
290
291         plat->desc = IS_ENABLED(CONFIG_BOOTSTD_FULL) ?
292                 "VBE simple" : "vbe-simple";
293         plat->flags = BOOTMETHF_GLOBAL;
294
295         return 0;
296 }
297
298 #if CONFIG_IS_ENABLED(OF_REAL)
299 static const struct udevice_id generic_simple_vbe_simple_ids[] = {
300         { .compatible = "fwupd,vbe-simple" },
301         { }
302 };
303 #endif
304
305 U_BOOT_DRIVER(vbe_simple) = {
306         .name   = "vbe_simple",
307         .id     = UCLASS_BOOTMETH,
308         .of_match = of_match_ptr(generic_simple_vbe_simple_ids),
309         .ops    = &bootmeth_vbe_simple_ops,
310         .bind   = bootmeth_vbe_simple_bind,
311         .probe  = bootmeth_vbe_simple_probe,
312         .flags  = DM_FLAG_PRE_RELOC,
313         .priv_auto      = sizeof(struct simple_priv),
314 };