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 <common.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 <memalign.h>
22#include <mmc.h>
23#include <spl.h>
24#include <vbe.h>
25#include <dm/device-internal.h>
26#include "vbe_simple.h"
27
28/**
29 * vbe_simple_read_bootflow_fw() - Create a bootflow for firmware
30 *
31 * Locates and loads the firmware image (FIT) needed for the next phase. The FIT
32 * should ideally use external data, to reduce the amount of it that needs to be
33 * read.
34 *
35 * @bdev: bootdev device containing the firmwre
36 * @meth: VBE simple bootmeth
37 * @blow: Place to put the created bootflow, on success
38 * @return 0 if OK, -ve on error
39 */
40int vbe_simple_read_bootflow_fw(struct udevice *dev, struct bootflow *bflow)
41{
42	ALLOC_CACHE_ALIGN_BUFFER(u8, sbuf, MMC_MAX_BLOCK_LEN);
43	struct udevice *media = dev_get_parent(bflow->dev);
44	struct udevice *meth = bflow->method;
45	struct simple_priv *priv = dev_get_priv(meth);
46	const char *fit_uname, *fit_uname_config;
47	struct bootm_headers images = {};
48	ulong offset, size, blknum, addr, len, load_addr, num_blks;
49	enum image_phase_t phase;
50	struct blk_desc *desc;
51	struct udevice *blk;
52	int node, ret;
53	void *buf;
54
55	log_debug("media=%s\n", media->name);
56	ret = blk_get_from_parent(media, &blk);
57	if (ret)
58		return log_msg_ret("med", ret);
59	log_debug("blk=%s\n", blk->name);
60	desc = dev_get_uclass_plat(blk);
61
62	offset = priv->area_start + priv->skip_offset;
63
64	/* read in one block to find the FIT size */
65	blknum =  offset / desc->blksz;
66	log_debug("read at %lx, blknum %lx\n", offset, blknum);
67	ret = blk_read(blk, blknum, 1, sbuf);
68	if (ret < 0)
69		return log_msg_ret("rd", ret);
70
71	ret = fdt_check_header(sbuf);
72	if (ret < 0)
73		return log_msg_ret("fdt", -EINVAL);
74	size = fdt_totalsize(sbuf);
75	if (size > priv->area_size)
76		return log_msg_ret("fdt", -E2BIG);
77	log_debug("FIT size %lx\n", size);
78
79	/*
80	 * Load the FIT into the SPL memory. This is typically a FIT with
81	 * external data, so this is quite small, perhaps a few KB.
82	 */
83	addr = CONFIG_VAL(TEXT_BASE);
84	buf = map_sysmem(addr, size);
85	num_blks = DIV_ROUND_UP(size, desc->blksz);
86	log_debug("read %lx, %lx blocks to %lx / %p\n", size, num_blks, addr,
87		  buf);
88	ret = blk_read(blk, blknum, num_blks, buf);
89	if (ret < 0)
90		return log_msg_ret("rd", ret);
91
92	/* figure out the phase to load */
93	phase = IS_ENABLED(CONFIG_VPL_BUILD) ? IH_PHASE_SPL : IH_PHASE_U_BOOT;
94
95	/*
96	 * Load the image from the FIT. We ignore any load-address information
97	 * so in practice this simply locates the image in the external-data
98	 * region and returns its address and size. Since we only loaded the FIT
99	 * itself, only a part of the image will be present, at best.
100	 */
101	fit_uname = NULL;
102	fit_uname_config = NULL;
103	log_debug("loading FIT\n");
104	ret = fit_image_load(&images, addr, &fit_uname, &fit_uname_config,
105			     IH_ARCH_SANDBOX, image_ph(phase, IH_TYPE_FIRMWARE),
106			     BOOTSTAGE_ID_FIT_SPL_START, FIT_LOAD_IGNORED,
107			     &load_addr, &len);
108	if (ret < 0)
109		return log_msg_ret("ld", ret);
110	node = ret;
111	log_debug("loaded to %lx\n", load_addr);
112
113	/* For FIT external data, read in the external data */
114	if (load_addr + len > addr + size) {
115		ulong base, full_size;
116		void *base_buf;
117
118		/* Find the start address to load from */
119		base = ALIGN_DOWN(load_addr, desc->blksz);
120
121		/*
122		 * Get the total number of bytes to load, taking care of
123		 * block alignment
124		 */
125		full_size = load_addr + len - base;
126
127		/*
128		 * Get the start block number, number of blocks and the address
129		 * to load to, then load the blocks
130		 */
131		blknum = (offset + base - addr) / desc->blksz;
132		num_blks = DIV_ROUND_UP(full_size, desc->blksz);
133		base_buf = map_sysmem(base, full_size);
134		ret = blk_read(blk, blknum, num_blks, base_buf);
135		log_debug("read %lx %lx, %lx blocks to %lx / %p: ret=%d\n",
136			  blknum, full_size, num_blks, base, base_buf, ret);
137		if (ret < 0)
138			return log_msg_ret("rd", ret);
139	}
140
141	/* set up the bootflow with the info we obtained */
142	bflow->name = strdup(fdt_get_name(buf, node, NULL));
143	if (!bflow->name)
144		return log_msg_ret("name", -ENOMEM);
145	bflow->blk = blk;
146	bflow->buf = map_sysmem(load_addr, len);
147	bflow->size = len;
148
149	return 0;
150}
151
152static int simple_load_from_image(struct spl_image_info *spl_image,
153				  struct spl_boot_device *bootdev)
154{
155	struct udevice *meth, *bdev;
156	struct simple_priv *priv;
157	struct bootflow bflow;
158	struct vbe_handoff *handoff;
159	int ret;
160
161	if (spl_phase() != PHASE_VPL && spl_phase() != PHASE_SPL)
162		return -ENOENT;
163
164	ret = bloblist_ensure_size(BLOBLISTT_VBE, sizeof(struct vbe_handoff),
165				   0, (void **)&handoff);
166	if (ret)
167		return log_msg_ret("ro", ret);
168
169	vbe_find_first_device(&meth);
170	if (!meth)
171		return log_msg_ret("vd", -ENODEV);
172	log_debug("vbe dev %s\n", meth->name);
173	ret = device_probe(meth);
174	if (ret)
175		return log_msg_ret("probe", ret);
176
177	priv = dev_get_priv(meth);
178	log_debug("simple %s\n", priv->storage);
179	ret = bootdev_find_by_label(priv->storage, &bdev, NULL);
180	if (ret)
181		return log_msg_ret("bd", ret);
182	log_debug("bootdev %s\n", bdev->name);
183
184	bootflow_init(&bflow, bdev, meth);
185	ret = bootmeth_read_bootflow(meth, &bflow);
186	log_debug("\nfw ret=%d\n", ret);
187	if (ret)
188		return log_msg_ret("rd", ret);
189
190	/* jump to the image */
191	spl_image->flags = SPL_SANDBOXF_ARG_IS_BUF;
192	spl_image->arg = bflow.buf;
193	spl_image->size = bflow.size;
194	log_debug("Image: %s at %p size %x\n", bflow.name, bflow.buf,
195		  bflow.size);
196
197	/* this is not used from now on, so free it */
198	bootflow_free(&bflow);
199
200	/* Record that VBE was used in this phase */
201	handoff->phases |= 1 << spl_phase();
202
203	return 0;
204}
205SPL_LOAD_IMAGE_METHOD("vbe_simple", 5, BOOT_DEVICE_VBE,
206		      simple_load_from_image);
207