1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Verified Boot for Embedded (VBE) loading firmware phases
4 *
5 * Copyright 2022 Google LLC
6 * Written by Simon Glass <sjg@chromium.org>
7 */
8
9 #define LOG_CATEGORY LOGC_BOOT
10
11 #include <binman_sym.h>
12 #include <bloblist.h>
13 #include <bootdev.h>
14 #include <bootflow.h>
15 #include <bootmeth.h>
16 #include <bootstage.h>
17 #include <dm.h>
18 #include <image.h>
19 #include <log.h>
20 #include <mapmem.h>
21 #include <mmc.h>
22 #include <spl.h>
23 #include <vbe.h>
24 #include <dm/device-internal.h>
25 #include "vbe_common.h"
26 #include "vbe_simple.h"
27
28 #ifdef CONFIG_BOOTMETH_VBE_SIMPLE
29 binman_sym_extern(ulong, vbe_a, image_pos);
30 binman_sym_extern(ulong, vbe_a, size);
31 #else
32 binman_sym_declare(ulong, vbe_a, image_pos);
33 binman_sym_declare(ulong, vbe_a, size);
34 #endif
35
36 binman_sym_declare(ulong, vpl, image_pos);
37 binman_sym_declare(ulong, vpl, size);
38
39 /**
40 * vbe_simple_read_bootflow_fw() - Create a bootflow for firmware
41 *
42 * Locates and loads the firmware image (FIT) needed for the next phase. The FIT
43 * should ideally use external data, to reduce the amount of it that needs to be
44 * read.
45 *
46 * @bdev: bootdev device containing the firmwre
47 * @meth: VBE simple bootmeth
48 * @blow: Place to put the created bootflow, on success
49 * @return 0 if OK, -ve on error
50 */
vbe_simple_read_bootflow_fw(struct udevice * dev,struct bootflow * bflow)51 int vbe_simple_read_bootflow_fw(struct udevice *dev, struct bootflow *bflow)
52 {
53 struct udevice *media = dev_get_parent(bflow->dev);
54 struct udevice *meth = bflow->method;
55 struct simple_priv *priv = dev_get_priv(meth);
56 ulong len, load_addr;
57 struct udevice *blk;
58 int ret;
59
60 log_debug("media=%s\n", media->name);
61 ret = blk_get_from_parent(media, &blk);
62 if (ret)
63 return log_msg_ret("med", ret);
64 log_debug("blk=%s\n", blk->name);
65
66 ret = vbe_read_fit(blk, priv->area_start + priv->skip_offset,
67 priv->area_size, NULL, &load_addr, &len,
68 &bflow->name);
69 if (ret)
70 return log_msg_ret("vbe", ret);
71
72 /* set up the bootflow with the info we obtained */
73 bflow->blk = blk;
74 bflow->buf = map_sysmem(load_addr, len);
75 bflow->size = len;
76
77 return 0;
78 }
79
simple_load_from_image(struct spl_image_info * image,struct spl_boot_device * bootdev)80 static int simple_load_from_image(struct spl_image_info *image,
81 struct spl_boot_device *bootdev)
82 {
83 struct vbe_handoff *handoff;
84 int ret;
85
86 if (xpl_phase() != PHASE_VPL && xpl_phase() != PHASE_SPL &&
87 xpl_phase() != PHASE_TPL)
88 return -ENOENT;
89
90 ret = bloblist_ensure_size(BLOBLISTT_VBE, sizeof(struct vbe_handoff),
91 0, (void **)&handoff);
92 if (ret)
93 return log_msg_ret("ro", ret);
94
95 if (USE_BOOTMETH) {
96 struct udevice *meth, *bdev;
97 struct simple_priv *priv;
98 struct bootflow bflow;
99
100 vbe_find_first_device(&meth);
101 if (!meth)
102 return log_msg_ret("vd", -ENODEV);
103 log_debug("vbe dev %s\n", meth->name);
104 ret = device_probe(meth);
105 if (ret)
106 return log_msg_ret("probe", ret);
107
108 priv = dev_get_priv(meth);
109 log_debug("simple %s\n", priv->storage);
110 ret = bootdev_find_by_label(priv->storage, &bdev, NULL);
111 if (ret)
112 return log_msg_ret("bd", ret);
113 log_debug("bootdev %s\n", bdev->name);
114
115 bootflow_init(&bflow, bdev, meth);
116 ret = bootmeth_read_bootflow(meth, &bflow);
117 log_debug("\nfw ret=%d\n", ret);
118 if (ret)
119 return log_msg_ret("rd", ret);
120
121 /* jump to the image */
122 image->flags = SPL_SANDBOXF_ARG_IS_BUF;
123 image->arg = bflow.buf;
124 image->size = bflow.size;
125 log_debug("Image: %s at %p size %x\n", bflow.name, bflow.buf,
126 bflow.size);
127
128 /* this is not used from now on, so free it */
129 bootflow_free(&bflow);
130 } else {
131 struct udevice *media, *blk;
132 ulong offset, size;
133
134 ret = uclass_get_device_by_seq(UCLASS_MMC, 1, &media);
135 if (ret)
136 return log_msg_ret("vdv", ret);
137 ret = blk_get_from_parent(media, &blk);
138 if (ret)
139 return log_msg_ret("med", ret);
140 if (xpl_phase() == PHASE_TPL) {
141 offset = binman_sym(ulong, vpl, image_pos);
142 size = binman_sym(ulong, vpl, size);
143 } else {
144 offset = binman_sym(ulong, vbe_a, image_pos);
145 size = binman_sym(ulong, vbe_a, size);
146 printf("offset=%lx\n", offset);
147 }
148
149 ret = vbe_read_fit(blk, offset, size, image, NULL, NULL, NULL);
150 if (ret)
151 return log_msg_ret("vbe", ret);
152 }
153
154 /* Record that VBE was used in this phase */
155 handoff->phases |= 1 << xpl_phase();
156
157 return 0;
158 }
159 SPL_LOAD_IMAGE_METHOD("vbe_simple", 5, BOOT_DEVICE_VBE,
160 simple_load_from_image);
161