1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Test for bootdev functions. All start with 'bootdev'
4  *
5  * Copyright 2021 Google LLC
6  * Written by Simon Glass <sjg@chromium.org>
7  */
8 
9 #include <bootdev.h>
10 #include <bootflow.h>
11 #include <bootmeth.h>
12 #include <bootstd.h>
13 #include <cli.h>
14 #include <dm.h>
15 #include <efi.h>
16 #include <efi_loader.h>
17 #include <env.h>
18 #include <expo.h>
19 #include <mapmem.h>
20 #ifdef CONFIG_SANDBOX
21 #include <asm/test.h>
22 #endif
23 #include <dm/device-internal.h>
24 #include <dm/lists.h>
25 #include <test/ut.h>
26 #include "bootstd_common.h"
27 #include "../../boot/bootflow_internal.h"
28 #include "../../boot/scene_internal.h"
29 
30 DECLARE_GLOBAL_DATA_PTR;
31 
32 extern U_BOOT_DRIVER(bootmeth_android);
33 extern U_BOOT_DRIVER(bootmeth_cros);
34 extern U_BOOT_DRIVER(bootmeth_2script);
35 
36 /* Use this as the vendor for EFI to tell the app to exit boot services */
37 static u16 __efi_runtime_data test_vendor[] = u"U-Boot testing";
38 
inject_response(struct unit_test_state * uts)39 static int inject_response(struct unit_test_state *uts)
40 {
41 	/*
42 	 * The image being booted presents a menu of options:
43 	 *
44 	 * Fedora-Workstation-armhfp-31-1.9 Boot Options.
45 	 * 1:   Fedora-Workstation-armhfp-31-1.9 (5.3.7-301.fc31.armv7hl)
46 	 * Enter choice:
47 	 *
48 	 * Provide input for this, to avoid waiting two seconds for a timeout.
49 	 */
50 	ut_asserteq(2, console_in_puts("1\n"));
51 
52 	return 0;
53 }
54 
55 /* Check 'bootflow scan/list' commands */
bootflow_cmd(struct unit_test_state * uts)56 static int bootflow_cmd(struct unit_test_state *uts)
57 {
58 	ut_assertok(run_command("bootdev select 1", 0));
59 	ut_assert_console_end();
60 	ut_assertok(run_command("bootflow scan -lH", 0));
61 	ut_assert_nextline("Scanning for bootflows in bootdev 'mmc1.bootdev'");
62 	ut_assert_nextline("Seq  Method       State   Uclass    Part  Name                      Filename");
63 	ut_assert_nextlinen("---");
64 	ut_assert_nextline("Scanning bootdev 'mmc2.bootdev':");
65 	ut_assert_nextline("Scanning bootdev 'mmc1.bootdev':");
66 	ut_assert_nextline("  0  extlinux     ready   mmc          1  mmc1.bootdev.part_1       /extlinux/extlinux.conf");
67 	ut_assert_nextline("No more bootdevs");
68 	ut_assert_nextlinen("---");
69 	ut_assert_nextline("(1 bootflow, 1 valid)");
70 	ut_assert_console_end();
71 
72 	ut_assertok(run_command("bootflow list", 0));
73 	ut_assert_nextline("Showing bootflows for bootdev 'mmc1.bootdev'");
74 	ut_assert_nextline("Seq  Method       State   Uclass    Part  Name                      Filename");
75 	ut_assert_nextlinen("---");
76 	ut_assert_nextline("  0  extlinux     ready   mmc          1  mmc1.bootdev.part_1       /extlinux/extlinux.conf");
77 	ut_assert_nextlinen("---");
78 	ut_assert_nextline("(1 bootflow, 1 valid)");
79 	ut_assert_console_end();
80 
81 	ut_assertok(run_command("bootstd images", 0));
82 	ut_assert_nextlinen("Seq");
83 	ut_assert_nextlinen("---");
84 	ut_assert_nextlinen("  0  mmc1.bootdev.part_1  extlinux_cfg");
85 	ut_assert_nextlinen("---");
86 	ut_assert_nextline("(1 image)");
87 	ut_assert_console_end();
88 
89 	return 0;
90 }
91 BOOTSTD_TEST(bootflow_cmd, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
92 
93 /* Check 'bootflow scan' with a label / seq */
bootflow_cmd_label(struct unit_test_state * uts)94 static int bootflow_cmd_label(struct unit_test_state *uts)
95 {
96 	test_set_eth_enable(false);
97 
98 	ut_assertok(run_command("bootflow scan -lH mmc1", 0));
99 	ut_assert_nextline("Scanning for bootflows with label 'mmc1'");
100 	ut_assert_skip_to_line("(1 bootflow, 1 valid)");
101 	ut_assert_console_end();
102 
103 	ut_assertok(run_command("bootflow scan -lH 0", 0));
104 	ut_assert_nextline("Scanning for bootflows with label '0'");
105 	ut_assert_skip_to_line("(0 bootflows, 0 valid)");
106 	ut_assert_console_end();
107 
108 	/*
109 	 * with ethernet enabled we have 8 devices ahead of the mmc ones:
110 	 *
111 	 * ut_assertok(run_command("bootdev list", 0));
112 	 * Seq  Probed  Status  Uclass    Name
113 	 * ---  ------  ------  --------  ------------------
114 	 * 0   [ + ]      OK  ethernet  eth@10002000.bootdev
115 	 * 1   [   ]      OK  ethernet  eth@10003000.bootdev
116 	 * 2   [   ]      OK  ethernet  sbe5.bootdev
117 	 * 3   [   ]      OK  ethernet  eth@10004000.bootdev
118 	 * 4   [   ]      OK  ethernet  phy-test-eth.bootdev
119 	 * 5   [   ]      OK  ethernet  dsa-test-eth.bootdev
120 	 * 6   [   ]      OK  ethernet  dsa-test@0.bootdev
121 	 * 7   [   ]      OK  ethernet  dsa-test@1.bootdev
122 	 * 8   [   ]      OK  mmc       mmc2.bootdev
123 	 * 9   [ + ]      OK  mmc       mmc1.bootdev
124 	 * a   [   ]      OK  mmc       mmc0.bootdev
125 	 *
126 	 * However with CONFIG_DSA_SANDBOX=n we have two fewer (dsa-test@0 and
127 	 * dsa-test@1).
128 	 */
129 	if (CONFIG_IS_ENABLED(DSA_SANDBOX)) {
130 		ut_assertok(run_command("bootflow scan -lH 9", 0));
131 		ut_assert_nextline("Scanning for bootflows with label '9'");
132 	} else {
133 		ut_assertok(run_command("bootflow scan -lH 7", 0));
134 		ut_assert_nextline("Scanning for bootflows with label '7'");
135 	}
136 	ut_assert_skip_to_line("(1 bootflow, 1 valid)");
137 
138 	ut_assertok(run_command("bootflow scan -lH 0", 0));
139 	ut_assert_nextline("Scanning for bootflows with label '0'");
140 	ut_assert_skip_to_line("(0 bootflows, 0 valid)");
141 	ut_assert_console_end();
142 
143 	return 0;
144 }
145 BOOTSTD_TEST(bootflow_cmd_label, UTF_DM | UTF_SCAN_FDT | UTF_ETH_BOOTDEV |
146 	     UTF_CONSOLE);
147 
148 /* Check 'bootflow scan/list' commands using all bootdevs */
bootflow_cmd_glob(struct unit_test_state * uts)149 static int bootflow_cmd_glob(struct unit_test_state *uts)
150 {
151 	ut_assertok(bootstd_test_drop_bootdev_order(uts));
152 
153 	ut_assertok(run_command("bootflow scan -lGH", 0));
154 	ut_assert_nextline("Scanning for bootflows in all bootdevs");
155 	ut_assert_nextline("Seq  Method       State   Uclass    Part  Name                      Filename");
156 	ut_assert_nextlinen("---");
157 	ut_assert_nextline("Scanning bootdev 'mmc2.bootdev':");
158 	ut_assert_nextline("Scanning bootdev 'mmc1.bootdev':");
159 	ut_assert_nextline("  0  extlinux     ready   mmc          1  mmc1.bootdev.part_1       /extlinux/extlinux.conf");
160 	ut_assert_nextline("Scanning bootdev 'mmc0.bootdev':");
161 	ut_assert_nextline("No more bootdevs");
162 	ut_assert_nextlinen("---");
163 	ut_assert_nextline("(1 bootflow, 1 valid)");
164 	ut_assert_console_end();
165 
166 	ut_assertok(run_command("bootflow list", 0));
167 	ut_assert_nextline("Showing all bootflows");
168 	ut_assert_nextline("Seq  Method       State   Uclass    Part  Name                      Filename");
169 	ut_assert_nextlinen("---");
170 	ut_assert_nextline("  0  extlinux     ready   mmc          1  mmc1.bootdev.part_1       /extlinux/extlinux.conf");
171 	ut_assert_nextlinen("---");
172 	ut_assert_nextline("(1 bootflow, 1 valid)");
173 	ut_assert_console_end();
174 
175 	return 0;
176 }
177 BOOTSTD_TEST(bootflow_cmd_glob, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
178 
179 /* Check 'bootflow scan -e' */
bootflow_cmd_scan_e(struct unit_test_state * uts)180 static int bootflow_cmd_scan_e(struct unit_test_state *uts)
181 {
182 	ut_assertok(bootstd_test_drop_bootdev_order(uts));
183 
184 	ut_assertok(run_command("bootflow scan -aleGH", 0));
185 	ut_assert_nextline("Scanning for bootflows in all bootdevs");
186 	ut_assert_nextline("Seq  Method       State   Uclass    Part  Name                      Filename");
187 	ut_assert_nextlinen("---");
188 	ut_assert_nextline("Scanning bootdev 'mmc2.bootdev':");
189 	ut_assert_nextline("  0  extlinux     media   mmc          0  mmc2.bootdev.whole        ");
190 	ut_assert_nextline("     ** No partition found, err=-93: Protocol not supported");
191 	ut_assert_nextline("  1  efi          media   mmc          0  mmc2.bootdev.whole        ");
192 	ut_assert_nextline("     ** No partition found, err=-93: Protocol not supported");
193 
194 	ut_assert_nextline("Scanning bootdev 'mmc1.bootdev':");
195 	ut_assert_nextline("  2  extlinux     media   mmc          0  mmc1.bootdev.whole        ");
196 	ut_assert_nextline("     ** No partition found, err=-2: No such file or directory");
197 	ut_assert_nextline("  3  efi          media   mmc          0  mmc1.bootdev.whole        ");
198 	ut_assert_nextline("     ** No partition found, err=-2: No such file or directory");
199 	ut_assert_nextline("  4  extlinux     ready   mmc          1  mmc1.bootdev.part_1       /extlinux/extlinux.conf");
200 	ut_assert_nextline(
201 		"  5  efi          fs      mmc          1  mmc1.bootdev.part_1       /EFI/BOOT/%s",
202 		efi_get_basename());
203 
204 	ut_assert_skip_to_line("Scanning bootdev 'mmc0.bootdev':");
205 	ut_assert_skip_to_line(
206 		" 3f  efi          media   mmc          0  mmc0.bootdev.whole        ");
207 	ut_assert_nextline("     ** No partition found, err=-93: Protocol not supported");
208 	ut_assert_nextline("No more bootdevs");
209 	ut_assert_nextlinen("---");
210 	ut_assert_nextline("(64 bootflows, 1 valid)");
211 	ut_assert_console_end();
212 
213 	ut_assertok(run_command("bootflow list", 0));
214 	ut_assert_nextline("Showing all bootflows");
215 	ut_assert_nextline("Seq  Method       State   Uclass    Part  Name                      Filename");
216 	ut_assert_nextlinen("---");
217 	ut_assert_nextline("  0  extlinux     media   mmc          0  mmc2.bootdev.whole        ");
218 	ut_assert_nextline("  1  efi          media   mmc          0  mmc2.bootdev.whole        ");
219 	ut_assert_skip_to_line(
220 		"  4  extlinux     ready   mmc          1  mmc1.bootdev.part_1       /extlinux/extlinux.conf");
221 	ut_assert_skip_to_line(" 3f  efi          media   mmc          0  mmc0.bootdev.whole        ");
222 	ut_assert_nextlinen("---");
223 	ut_assert_nextline("(64 bootflows, 1 valid)");
224 	ut_assert_console_end();
225 
226 	return 0;
227 }
228 BOOTSTD_TEST(bootflow_cmd_scan_e, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
229 
230 /* Check 'bootflow info' */
bootflow_cmd_info(struct unit_test_state * uts)231 static int bootflow_cmd_info(struct unit_test_state *uts)
232 {
233 	ut_assertok(run_command("bootdev select 1", 0));
234 	ut_assert_console_end();
235 	ut_assertok(run_command("bootflow scan", 0));
236 	ut_assert_console_end();
237 	ut_assertok(run_command("bootflow select 0", 0));
238 	ut_assert_console_end();
239 	ut_assertok(run_command("bootflow info", 0));
240 	ut_assert_nextline("Name:      mmc1.bootdev.part_1");
241 	ut_assert_nextline("Device:    mmc1.bootdev");
242 	ut_assert_nextline("Block dev: mmc1.blk");
243 	ut_assert_nextline("Method:    extlinux");
244 	ut_assert_nextline("State:     ready");
245 	ut_assert_nextline("Partition: 1");
246 	ut_assert_nextline("Subdir:    (none)");
247 	ut_assert_nextline("Filename:  /extlinux/extlinux.conf");
248 	ut_assert_nextlinen("Buffer:    ");
249 	ut_assert_nextline("Size:      253 (595 bytes)");
250 	ut_assert_nextline("OS:        Fedora-Workstation-armhfp-31-1.9 (5.3.7-301.fc31.armv7hl)");
251 	ut_assert_nextline("Cmdline:   (none)");
252 	ut_assert_nextline("Logo:      (none)");
253 	ut_assert_nextline("FDT:       <NULL>");
254 	ut_assert_nextline("Error:     0");
255 	ut_assert_console_end();
256 
257 	ut_assertok(run_command("bootflow info -d", 0));
258 	ut_assert_nextline("Name:      mmc1.bootdev.part_1");
259 	ut_assert_skip_to_line("Error:     0");
260 	ut_assert_nextline("Contents:");
261 	ut_assert_nextline("%s", "");
262 	ut_assert_nextline("# extlinux.conf generated by appliance-creator");
263 	ut_assert_skip_to_line("        initrd /initramfs-5.3.7-301.fc31.armv7hl.img");
264 	ut_assert_console_end();
265 
266 	return 0;
267 }
268 BOOTSTD_TEST(bootflow_cmd_info, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
269 
270 /* Check 'bootflow scan -b' to boot the first available bootdev */
bootflow_scan_boot(struct unit_test_state * uts)271 static int bootflow_scan_boot(struct unit_test_state *uts)
272 {
273 	ut_assertok(inject_response(uts));
274 	ut_assertok(run_command("bootflow scan -b", 0));
275 	ut_assert_nextline(
276 		"** Booting bootflow 'mmc1.bootdev.part_1' with extlinux");
277 	ut_assert_nextline("Ignoring unknown command: ui");
278 
279 	/*
280 	 * We expect it to get through to boot although sandbox always returns
281 	 * -EFAULT as it cannot actually boot the kernel
282 	 */
283 	ut_assert_skip_to_line("sandbox: continuing, as we cannot run Linux");
284 	ut_assert_nextline("Boot failed (err=-14)");
285 	ut_assert_console_end();
286 
287 	return 0;
288 }
289 BOOTSTD_TEST(bootflow_scan_boot, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
290 
291 /* Check iterating through available bootflows */
bootflow_iter(struct unit_test_state * uts)292 static int bootflow_iter(struct unit_test_state *uts)
293 {
294 	struct bootflow_iter iter;
295 	struct bootflow bflow;
296 
297 	bootstd_clear_glob();
298 
299 	/* The first device is mmc2.bootdev which has no media */
300 	ut_asserteq(-EPROTONOSUPPORT,
301 		    bootflow_scan_first(NULL, NULL, &iter, BOOTFLOWIF_ALL |
302 					BOOTFLOWIF_SKIP_GLOBAL |
303 					BOOTFLOWIF_ONLY_BOOTABLE, &bflow));
304 	ut_asserteq(2, iter.num_methods);
305 	ut_asserteq(0, iter.cur_method);
306 	ut_asserteq(0, iter.part);
307 	ut_asserteq(0, iter.max_part);
308 	ut_asserteq_str("extlinux", iter.method->name);
309 	ut_asserteq(0, bflow.err);
310 
311 	/*
312 	 * This shows MEDIA even though there is none, since in
313 	 * bootdev_find_in_blk() we call part_get_info() which returns
314 	 * -EPROTONOSUPPORT. Ideally it would return -EEOPNOTSUPP and we would
315 	 * know.
316 	 */
317 	ut_asserteq(BOOTFLOWST_MEDIA, bflow.state);
318 
319 	ut_asserteq(-EPROTONOSUPPORT, bootflow_scan_next(&iter, &bflow));
320 	ut_asserteq(2, iter.num_methods);
321 	ut_asserteq(1, iter.cur_method);
322 	ut_asserteq(0, iter.part);
323 	ut_asserteq(0, iter.max_part);
324 	ut_asserteq_str("efi", iter.method->name);
325 	ut_asserteq(0, bflow.err);
326 	ut_asserteq(BOOTFLOWST_MEDIA, bflow.state);
327 	bootflow_free(&bflow);
328 
329 	/* The next device is mmc1.bootdev - at first we use the whole device */
330 	ut_asserteq(-ENOENT, bootflow_scan_next(&iter, &bflow));
331 	ut_asserteq(2, iter.num_methods);
332 	ut_asserteq(0, iter.cur_method);
333 	ut_asserteq(0, iter.part);
334 	ut_asserteq(0x1e, iter.max_part);
335 	ut_asserteq_str("extlinux", iter.method->name);
336 	ut_asserteq(0, bflow.err);
337 	ut_asserteq(BOOTFLOWST_MEDIA, bflow.state);
338 	bootflow_free(&bflow);
339 
340 	ut_asserteq(-ENOENT, bootflow_scan_next(&iter, &bflow));
341 	ut_asserteq(2, iter.num_methods);
342 	ut_asserteq(1, iter.cur_method);
343 	ut_asserteq(0, iter.part);
344 	ut_asserteq(0x1e, iter.max_part);
345 	ut_asserteq_str("efi", iter.method->name);
346 	ut_asserteq(0, bflow.err);
347 	ut_asserteq(BOOTFLOWST_MEDIA, bflow.state);
348 	bootflow_free(&bflow);
349 
350 	/* Then more to partition 1 where we find something */
351 	ut_assertok(bootflow_scan_next(&iter, &bflow));
352 	ut_asserteq(2, iter.num_methods);
353 	ut_asserteq(0, iter.cur_method);
354 	ut_asserteq(1, iter.part);
355 	ut_asserteq(0x1e, iter.max_part);
356 	ut_asserteq_str("extlinux", iter.method->name);
357 	ut_asserteq(0, bflow.err);
358 	ut_asserteq(BOOTFLOWST_READY, bflow.state);
359 	bootflow_free(&bflow);
360 
361 	ut_asserteq(-ENOENT, bootflow_scan_next(&iter, &bflow));
362 	ut_asserteq(2, iter.num_methods);
363 	ut_asserteq(1, iter.cur_method);
364 	ut_asserteq(1, iter.part);
365 	ut_asserteq(0x1e, iter.max_part);
366 	ut_asserteq_str("efi", iter.method->name);
367 	ut_asserteq(0, bflow.err);
368 	ut_asserteq(BOOTFLOWST_FS, bflow.state);
369 	bootflow_free(&bflow);
370 
371 	/* Then more to partition 2 which exists but is not bootable */
372 	ut_asserteq(-EINVAL, bootflow_scan_next(&iter, &bflow));
373 	ut_asserteq(2, iter.num_methods);
374 	ut_asserteq(0, iter.cur_method);
375 	ut_asserteq(2, iter.part);
376 	ut_asserteq(0x1e, iter.max_part);
377 	ut_asserteq_str("extlinux", iter.method->name);
378 	ut_asserteq(0, bflow.err);
379 	ut_asserteq(BOOTFLOWST_MEDIA, bflow.state);
380 	bootflow_free(&bflow);
381 
382 	bootflow_iter_uninit(&iter);
383 
384 	ut_assert_console_end();
385 
386 	return 0;
387 }
388 BOOTSTD_TEST(bootflow_iter, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
389 
390 #if defined(CONFIG_SANDBOX) && defined(CONFIG_BOOTMETH_GLOBAL)
391 /* Check using the system bootdev */
bootflow_system(struct unit_test_state * uts)392 static int bootflow_system(struct unit_test_state *uts)
393 {
394 	struct udevice *bootstd, *dev;
395 
396 	if (!IS_ENABLED(CONFIG_EFI_BOOTMGR))
397 		return -EAGAIN;
398 	ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd));
399 	ut_assertok(device_bind(bootstd, DM_DRIVER_GET(bootmeth_3efi_mgr),
400 				"efi_mgr", 0, ofnode_null(), &dev));
401 	ut_assertok(device_probe(dev));
402 	sandbox_set_fake_efi_mgr_dev(dev, true);
403 
404 	/* We should get a single 'bootmgr' method right at the end */
405 	bootstd_clear_glob();
406 	ut_assertok(run_command("bootflow scan -lH", 0));
407 	ut_assert_skip_to_line(
408 		"  0  efi_mgr      ready   (none)       0  <NULL>                    ");
409 	ut_assert_skip_to_line("No more bootdevs");
410 	ut_assert_skip_to_line("(2 bootflows, 2 valid)");
411 	ut_assert_console_end();
412 
413 	return 0;
414 }
415 BOOTSTD_TEST(bootflow_system, UTF_DM | UTF_SCAN_PDATA | UTF_SCAN_FDT |
416 	     UTF_CONSOLE);
417 #endif
418 
419 /* Check disabling a bootmethod if it requests it */
bootflow_iter_disable(struct unit_test_state * uts)420 static int bootflow_iter_disable(struct unit_test_state *uts)
421 {
422 	struct udevice *bootstd, *dev;
423 	struct bootflow_iter iter;
424 	struct bootflow bflow;
425 	int i;
426 
427 	/* Add the EFI bootmgr driver */
428 	ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd));
429 	ut_assertok(device_bind_driver(bootstd, "bootmeth_sandbox", "sandbox",
430 				       &dev));
431 
432 	ut_assertok(bootstd_test_drop_bootdev_order(uts));
433 
434 	bootstd_clear_glob();
435 	ut_assertok(inject_response(uts));
436 	ut_assertok(run_command("bootflow scan -lbH", 0));
437 
438 	/* Try to boot the bootmgr flow, which will fail */
439 	console_record_reset_enable();
440 	ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow));
441 	ut_asserteq(3, iter.num_methods);
442 	ut_asserteq_str("sandbox", iter.method->name);
443 	ut_assertok(inject_response(uts));
444 	ut_asserteq(-ENOTSUPP, bootflow_run_boot(&iter, &bflow));
445 
446 	ut_assert_skip_to_line("Boot method 'sandbox' failed and will not be retried");
447 	ut_assert_console_end();
448 
449 	/* Check that the sandbox bootmeth has been removed */
450 	ut_asserteq(2, iter.num_methods);
451 	for (i = 0; i < iter.num_methods; i++)
452 		ut_assert(strcmp("sandbox", iter.method_order[i]->name));
453 
454 	return 0;
455 }
456 BOOTSTD_TEST(bootflow_iter_disable, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
457 
458 /* Check 'bootflow scan' with a bootmeth ordering including a global bootmeth */
bootflow_scan_glob_bootmeth(struct unit_test_state * uts)459 static int bootflow_scan_glob_bootmeth(struct unit_test_state *uts)
460 {
461 	if (!IS_ENABLED(CONFIG_BOOTMETH_GLOBAL))
462 		return -EAGAIN;
463 
464 	ut_assertok(bootstd_test_drop_bootdev_order(uts));
465 
466 	/*
467 	 * Make sure that the -G flag makes the scan fail, since this is not
468 	 * supported when an ordering is provided
469 	 */
470 	ut_assertok(bootmeth_set_order("efi firmware0"));
471 	ut_assertok(run_command("bootflow scan -lGH", 0));
472 	ut_assert_nextline("Scanning for bootflows in all bootdevs");
473 	ut_assert_nextline(
474 		"Seq  Method       State   Uclass    Part  Name                      Filename");
475 	ut_assert_nextlinen("---");
476 	ut_assert_nextlinen("---");
477 	ut_assert_nextline("(0 bootflows, 0 valid)");
478 	ut_assert_console_end();
479 
480 	ut_assertok(run_command("bootflow scan -lH", 0));
481 	ut_assert_nextline("Scanning for bootflows in all bootdevs");
482 	ut_assert_nextline(
483 		"Seq  Method       State   Uclass    Part  Name                      Filename");
484 	ut_assert_nextlinen("---");
485 	ut_assert_nextline("Scanning global bootmeth 'firmware0':");
486 	ut_assert_nextline("Scanning bootdev 'mmc2.bootdev':");
487 	ut_assert_nextline("Scanning bootdev 'mmc1.bootdev':");
488 	ut_assert_nextline("Scanning bootdev 'mmc0.bootdev':");
489 	ut_assert_nextline("No more bootdevs");
490 	ut_assert_nextlinen("---");
491 	ut_assert_nextline("(0 bootflows, 0 valid)");
492 	ut_assert_console_end();
493 
494 	return 0;
495 }
496 BOOTSTD_TEST(bootflow_scan_glob_bootmeth, UTF_DM | UTF_SCAN_FDT |
497 	     UTF_CONSOLE);
498 
499 /* Check 'bootflow boot' to boot a selected bootflow */
bootflow_cmd_boot(struct unit_test_state * uts)500 static int bootflow_cmd_boot(struct unit_test_state *uts)
501 {
502 	ut_assertok(run_command("bootdev select 1", 0));
503 	ut_assert_console_end();
504 	ut_assertok(run_command("bootflow scan", 0));
505 	ut_assert_console_end();
506 	ut_assertok(run_command("bootflow select 0", 0));
507 	ut_assert_console_end();
508 
509 	ut_assertok(inject_response(uts));
510 	ut_asserteq(1, run_command("bootflow boot", 0));
511 	ut_assert_nextline(
512 		"** Booting bootflow 'mmc1.bootdev.part_1' with extlinux");
513 	ut_assert_nextline("Ignoring unknown command: ui");
514 
515 	/*
516 	 * We expect it to get through to boot although sandbox always returns
517 	 * -EFAULT as it cannot actually boot the kernel
518 	 */
519 	ut_assert_skip_to_line("sandbox: continuing, as we cannot run Linux");
520 	ut_assert_nextline("Boot failed (err=-14)");
521 	ut_assert_console_end();
522 
523 	return 0;
524 }
525 BOOTSTD_TEST(bootflow_cmd_boot, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
526 
527 /**
528  * prep_mmc_bootdev() - Set up an mmc bootdev so we can access other distros
529  *
530  * After calling this function, set std->bootdev_order to *@old_orderp to
531  * restore normal operation of bootstd (i.e. with the original bootdev order)
532  *
533  * @uts: Unit test state
534  * @mmc_dev: MMC device to use, e.g. "mmc4". Note that this must remain valid
535  *	in the caller until
536  * @bind_cros: true to bind the ChromiumOS and Android bootmeths
537  * @old_orderp: Returns the original bootdev order, which must be restored
538  * Returns 0 on success, -ve on failure
539  */
prep_mmc_bootdev(struct unit_test_state * uts,const char * mmc_dev,bool bind_cros_android,const char *** old_orderp)540 static int prep_mmc_bootdev(struct unit_test_state *uts, const char *mmc_dev,
541 			    bool bind_cros_android, const char ***old_orderp)
542 {
543 	static const char *order[] = {"mmc2", "mmc1", NULL, NULL};
544 	struct udevice *dev, *bootstd;
545 	struct bootstd_priv *std;
546 	const char **old_order;
547 	ofnode root, node;
548 
549 	order[2] = mmc_dev;
550 
551 	/* Enable the requested mmc node since we need a second bootflow */
552 	root = oftree_root(oftree_default());
553 	node = ofnode_find_subnode(root, mmc_dev);
554 	ut_assert(ofnode_valid(node));
555 	ut_assertok(lists_bind_fdt(gd->dm_root, node, &dev, NULL, false));
556 
557 	/* Enable the script bootmeth too */
558 	ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd));
559 	ut_assertok(device_bind(bootstd, DM_DRIVER_REF(bootmeth_2script),
560 				"script", 0, ofnode_null(), &dev));
561 
562 	/* Enable the cros bootmeth if needed */
563 	if (IS_ENABLED(CONFIG_BOOTMETH_CROS) && bind_cros_android) {
564 		ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd));
565 		ut_assertok(device_bind(bootstd, DM_DRIVER_REF(bootmeth_cros),
566 					"cros", 0, ofnode_null(), &dev));
567 	}
568 
569 	/* Enable the android bootmeths if needed */
570 	if (IS_ENABLED(CONFIG_BOOTMETH_ANDROID) && bind_cros_android) {
571 		ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd));
572 		ut_assertok(device_bind(bootstd, DM_DRIVER_REF(bootmeth_android),
573 					"android", 0, ofnode_null(), &dev));
574 	}
575 
576 	/* Change the order to include the device */
577 	std = dev_get_priv(bootstd);
578 	old_order = std->bootdev_order;
579 	std->bootdev_order = order;
580 	*old_orderp = old_order;
581 
582 	return 0;
583 }
584 
585 /**
586  * scan_mmc_bootdev() - Set up an mmc bootdev so we can access other distros
587  *
588  * @uts: Unit test state
589  * @mmc_dev: MMC device to use, e.g. "mmc4"
590  * @bind_cros: true to bind the ChromiumOS bootmeth
591  * Returns 0 on success, -ve on failure
592  */
scan_mmc_bootdev(struct unit_test_state * uts,const char * mmc_dev,bool bind_cros)593 static int scan_mmc_bootdev(struct unit_test_state *uts, const char *mmc_dev,
594 			    bool bind_cros)
595 {
596 	struct bootstd_priv *std;
597 	struct udevice *bootstd;
598 	const char **old_order;
599 
600 	ut_assertok(prep_mmc_bootdev(uts, mmc_dev, bind_cros, &old_order));
601 
602 	ut_assertok(run_command("bootflow scan", 0));
603 	ut_assert_console_end();
604 
605 	/* Restore the order used by the device tree */
606 	ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd));
607 	std = dev_get_priv(bootstd);
608 	std->bootdev_order = old_order;
609 
610 	return 0;
611 }
612 
613 /**
614  * scan_mmc_android_bootdev() - Set up an mmc bootdev so we can access other
615  * distros. Android bootflow might print "ANDROID:*" while scanning
616  *
617  * @uts: Unit test state
618  * @mmc_dev: MMC device to use, e.g. "mmc4"
619  * Returns 0 on success, -ve on failure
620  */
scan_mmc_android_bootdev(struct unit_test_state * uts,const char * mmc_dev)621 static int scan_mmc_android_bootdev(struct unit_test_state *uts, const char *mmc_dev)
622 {
623 	struct bootstd_priv *std;
624 	struct udevice *bootstd;
625 	const char **old_order;
626 
627 	ut_assertok(prep_mmc_bootdev(uts, mmc_dev, true, &old_order));
628 
629 	ut_assertok(run_command("bootflow scan", 0));
630 	/* Android bootflow might print one or two 'ANDROID:*' logs */
631 	ut_check_skipline(uts);
632 	ut_check_skipline(uts);
633 	ut_assert_console_end();
634 
635 	/* Restore the order used by the device tree */
636 	ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd));
637 	std = dev_get_priv(bootstd);
638 	std->bootdev_order = old_order;
639 
640 	return 0;
641 }
642 
643 /**
644  * scan_mmc4_bootdev() - Set up the mmc4 bootdev so we can access a fake Armbian
645  *
646  * @uts: Unit test state
647  * Returns 0 on success, -ve on failure
648  */
scan_mmc4_bootdev(struct unit_test_state * uts)649 static int scan_mmc4_bootdev(struct unit_test_state *uts)
650 {
651 	ut_assertok(scan_mmc_bootdev(uts, "mmc4", false));
652 
653 	return 0;
654 }
655 
656 /* Check 'bootflow menu' to select a bootflow */
bootflow_cmd_menu(struct unit_test_state * uts)657 static int bootflow_cmd_menu(struct unit_test_state *uts)
658 {
659 	struct bootstd_priv *std;
660 	char prev[3];
661 
662 	/* get access to the current bootflow */
663 	ut_assertok(bootstd_get_priv(&std));
664 
665 	ut_assertok(scan_mmc4_bootdev(uts));
666 
667 	/* Add keypresses to move to and select the second one in the list */
668 	prev[0] = CTL_CH('n');
669 	prev[1] = '\r';
670 	prev[2] = '\0';
671 	ut_asserteq(2, console_in_puts(prev));
672 
673 	ut_assertok(run_command("bootflow menu", 0));
674 	ut_assert_nextline("Selected: Armbian");
675 	ut_assertnonnull(std->cur_bootflow);
676 	ut_assert_console_end();
677 
678 	/* Check not selecting anything */
679 	prev[0] = '\e';
680 	prev[1] = '\0';
681 	ut_asserteq(1, console_in_puts(prev));
682 
683 	ut_asserteq(1, run_command("bootflow menu", 0));
684 	ut_assertnull(std->cur_bootflow);
685 	ut_assert_nextline("Nothing chosen");
686 	ut_assert_console_end();
687 
688 	return 0;
689 }
690 BOOTSTD_TEST(bootflow_cmd_menu, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
691 
692 /* Check 'bootflow scan -m' to select a bootflow using a menu */
bootflow_scan_menu(struct unit_test_state * uts)693 static int bootflow_scan_menu(struct unit_test_state *uts)
694 {
695 	struct bootstd_priv *std;
696 	const char **old_order, **new_order;
697 	char prev[3];
698 
699 	/* get access to the current bootflow */
700 	ut_assertok(bootstd_get_priv(&std));
701 
702 	ut_assertok(prep_mmc_bootdev(uts, "mmc4", false, &old_order));
703 
704 	/* Add keypresses to move to and select the second one in the list */
705 	prev[0] = CTL_CH('n');
706 	prev[1] = '\r';
707 	prev[2] = '\0';
708 	ut_asserteq(2, console_in_puts(prev));
709 
710 	ut_assertok(run_command("bootflow scan -lm", 0));
711 	new_order = std->bootdev_order;
712 	std->bootdev_order = old_order;
713 
714 	ut_assert_skip_to_line("No more bootdevs");
715 	ut_assert_nextlinen("--");
716 	ut_assert_nextline("(2 bootflows, 2 valid)");
717 
718 	ut_assert_nextline("Selected: Armbian");
719 	ut_assertnonnull(std->cur_bootflow);
720 	ut_assert_console_end();
721 
722 	/* Check not selecting anything */
723 	prev[0] = '\e';
724 	prev[1] = '\0';
725 	ut_asserteq(1, console_in_puts(prev));
726 
727 	std->bootdev_order = new_order; /* Blue Monday */
728 	ut_assertok(run_command("bootflow scan -lm", 0));
729 	std->bootdev_order = old_order;
730 
731 	ut_assertnull(std->cur_bootflow);
732 	ut_assert_skip_to_line("(2 bootflows, 2 valid)");
733 	ut_assert_nextline("Nothing chosen");
734 	ut_assert_console_end();
735 
736 	return 0;
737 }
738 BOOTSTD_TEST(bootflow_scan_menu, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
739 
740 /* Check 'bootflow scan -mb' to select and boot a bootflow using a menu */
bootflow_scan_menu_boot(struct unit_test_state * uts)741 static int bootflow_scan_menu_boot(struct unit_test_state *uts)
742 {
743 	struct bootstd_priv *std;
744 	const char **old_order;
745 	char prev[3];
746 
747 	/* get access to the current bootflow */
748 	ut_assertok(bootstd_get_priv(&std));
749 
750 	ut_assertok(prep_mmc_bootdev(uts, "mmc4", false, &old_order));
751 
752 	/* Add keypresses to move to and select the second one in the list */
753 	prev[0] = CTL_CH('n');
754 	prev[1] = '\r';
755 	prev[2] = '\0';
756 	ut_asserteq(2, console_in_puts(prev));
757 
758 	ut_assertok(run_command("bootflow scan -lmb", 0));
759 	std->bootdev_order = old_order;
760 
761 	ut_assert_skip_to_line("(2 bootflows, 2 valid)");
762 
763 	ut_assert_nextline("Selected: Armbian");
764 
765 	if (gd->flags & GD_FLG_HUSH_OLD_PARSER) {
766 		/*
767 		 * With old hush, despite booti failing to boot, i.e. returning
768 		 * CMD_RET_FAILURE, run_command() returns 0 which leads bootflow_boot(), as
769 		 * we are using bootmeth_script here, to return -EFAULT.
770 		 */
771 		ut_assert_skip_to_line("Boot failed (err=-14)");
772 	} else if (gd->flags & GD_FLG_HUSH_MODERN_PARSER) {
773 		/*
774 		 * While with modern one, run_command() propagates CMD_RET_FAILURE returned
775 		 * by booti, so we get 1 here.
776 		 */
777 		ut_assert_skip_to_line("Boot failed (err=1)");
778 	}
779 	ut_assertnonnull(std->cur_bootflow);
780 	ut_assert_console_end();
781 
782 	return 0;
783 }
784 BOOTSTD_TEST(bootflow_scan_menu_boot, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
785 
786 /* Check searching for a single bootdev using the hunters */
bootflow_cmd_hunt_single(struct unit_test_state * uts)787 static int bootflow_cmd_hunt_single(struct unit_test_state *uts)
788 {
789 	struct bootstd_priv *std;
790 
791 	/* get access to the used hunters */
792 	ut_assertok(bootstd_get_priv(&std));
793 
794 	ut_assertok(bootstd_test_drop_bootdev_order(uts));
795 
796 	ut_assertok(run_command("bootflow scan -l mmc1", 0));
797 	ut_assert_nextline("Scanning for bootflows with label 'mmc1'");
798 	ut_assert_skip_to_line("(1 bootflow, 1 valid)");
799 	ut_assert_console_end();
800 
801 	/* check that the hunter was used */
802 	ut_asserteq(BIT(MMC_HUNTER) | BIT(1), std->hunters_used);
803 
804 	return 0;
805 }
806 BOOTSTD_TEST(bootflow_cmd_hunt_single, UTF_DM | UTF_SCAN_FDT |
807 	     UTF_CONSOLE);
808 
809 /* Check searching for a uclass label using the hunters */
bootflow_cmd_hunt_label(struct unit_test_state * uts)810 static int bootflow_cmd_hunt_label(struct unit_test_state *uts)
811 {
812 	struct bootstd_priv *std;
813 
814 	/* get access to the used hunters */
815 	ut_assertok(bootstd_get_priv(&std));
816 
817 	test_set_skip_delays(true);
818 	test_set_eth_enable(false);
819 	ut_assertok(bootstd_test_drop_bootdev_order(uts));
820 
821 	ut_assertok(run_command("bootflow scan -l mmc", 0));
822 
823 	/* check that the hunter was used */
824 	ut_asserteq(BIT(MMC_HUNTER) | BIT(1), std->hunters_used);
825 
826 	/* check that we got the mmc1 bootflow */
827 	ut_assert_nextline("Scanning for bootflows with label 'mmc'");
828 	ut_assert_nextlinen("Seq");
829 	ut_assert_nextlinen("---");
830 	ut_assert_nextline("Hunting with: simple_bus");
831 	ut_assert_nextline("Found 2 extension board(s).");
832 	ut_assert_nextline("Hunting with: mmc");
833 	ut_assert_nextline("Scanning bootdev 'mmc2.bootdev':");
834 	ut_assert_nextline("Scanning bootdev 'mmc1.bootdev':");
835 	ut_assert_nextline(
836 		"  0  extlinux     ready   mmc          1  mmc1.bootdev.part_1       /extlinux/extlinux.conf");
837 	ut_assert_nextline("Scanning bootdev 'mmc0.bootdev':");
838 	ut_assert_skip_to_line("(1 bootflow, 1 valid)");
839 	ut_assert_console_end();
840 
841 	return 0;
842 }
843 BOOTSTD_TEST(bootflow_cmd_hunt_label, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
844 
845 /**
846  * check_font() - Check that the font size for an item matches expectations
847  *
848  * @uts: Unit test state
849  * @scn: Scene containing the text object
850  * @id: ID of the text object
851  * Returns 0 on success, -ve on failure
852  */
check_font(struct unit_test_state * uts,struct scene * scn,uint id,int font_size)853 static int check_font(struct unit_test_state *uts, struct scene *scn, uint id,
854 		      int font_size)
855 {
856 	struct scene_obj_txt *txt;
857 
858 	txt = scene_obj_find(scn, id, SCENEOBJT_TEXT);
859 	ut_assertnonnull(txt);
860 
861 	ut_asserteq(font_size, txt->gen.font_size);
862 
863 	return 0;
864 }
865 
866 /* Check themes work with a bootflow menu */
bootflow_menu_theme(struct unit_test_state * uts)867 static int bootflow_menu_theme(struct unit_test_state *uts)
868 {
869 	const int font_size = 30;
870 	struct scene *scn;
871 	struct expo *exp;
872 	ofnode node;
873 	int i;
874 
875 	if (!CONFIG_IS_ENABLED(BOOTSTD_MENU))
876 		return -EAGAIN;
877 
878 	ut_assertok(scan_mmc4_bootdev(uts));
879 
880 	ut_assertok(bootflow_menu_new(&exp));
881 	ut_assertok(bootflow_menu_add_all(exp));
882 	node = ofnode_path("/bootstd/theme");
883 	ut_assert(ofnode_valid(node));
884 	ut_assertok(expo_apply_theme(exp, node));
885 
886 	scn = expo_lookup_scene_id(exp, MAIN);
887 	ut_assertnonnull(scn);
888 
889 	/*
890 	 * Check that the txt objects have the correct font size from the
891 	 * device tree node: bootstd/theme
892 	 *
893 	 * Check both menu items, since there are two bootflows
894 	 */
895 	for (i = OBJ_PROMPT1A; i <= OBJ_AUTOBOOT; i++)
896 		ut_assertok(check_font(uts, scn, i, font_size));
897 	for (i = 0; i < 2; i++) {
898 		ut_assertok(check_font(uts, scn, ITEM_DESC + i, font_size));
899 		ut_assertok(check_font(uts, scn, ITEM_KEY + i, font_size));
900 		ut_assertok(check_font(uts, scn, ITEM_LABEL + i, font_size));
901 	}
902 
903 	expo_destroy(exp);
904 
905 	return 0;
906 }
907 BOOTSTD_TEST(bootflow_menu_theme, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
908 
909 /**
910  * check_arg() - Check both the normal case and the buffer-overflow case
911  *
912  * @uts: Unit-test state
913  * @expect_ret: Expected return value (i.e. buffer length)
914  * @expect_str: String expected to be returned
915  * @buf: Buffer to use
916  * @from: Original cmdline to update
917  * @arg: Argument to update (e.g. "console")
918  * @val: Value to set (e.g. "ttyS2") or NULL to delete the argument if present,
919  * "" to set it to an empty value (e.g. "console=") and BOOTFLOWCL_EMPTY to add
920  * it without any value ("initrd")
921  */
check_arg(struct unit_test_state * uts,int expect_ret,const char * expect_str,char * buf,const char * from,const char * arg,const char * val)922 static int check_arg(struct unit_test_state *uts, int expect_ret,
923 		     const char *expect_str, char *buf, const char *from,
924 		     const char *arg, const char *val)
925 {
926 	/* check for writing outside the reported bounds */
927 	buf[expect_ret] = '[';
928 	ut_asserteq(expect_ret,
929 		    cmdline_set_arg(buf, expect_ret, from, arg, val, NULL));
930 	ut_asserteq_str(expect_str, buf);
931 	ut_asserteq('[', buf[expect_ret]);
932 
933 	/* do the test again but with one less byte in the buffer */
934 	ut_asserteq(-E2BIG, cmdline_set_arg(buf, expect_ret - 1, from, arg,
935 					    val, NULL));
936 
937 	return 0;
938 }
939 
940 /* Test of bootflow_cmdline_set_arg() */
test_bootflow_cmdline_set(struct unit_test_state * uts)941 static int test_bootflow_cmdline_set(struct unit_test_state *uts)
942 {
943 	char buf[50];
944 	const int size = sizeof(buf);
945 
946 	/*
947 	 * note that buffer-overflow tests are immediately each test case, just
948 	 * top keep the code together
949 	 */
950 
951 	/* add an arg that doesn't already exist, starting from empty */
952 	ut_asserteq(-ENOENT, cmdline_set_arg(buf, size, NULL, "me", NULL,
953 					     NULL));
954 
955 	ut_assertok(check_arg(uts, 3, "me", buf, NULL, "me", BOOTFLOWCL_EMPTY));
956 	ut_assertok(check_arg(uts, 4, "me=", buf, NULL, "me", ""));
957 	ut_assertok(check_arg(uts, 8, "me=fred", buf, NULL, "me", "fred"));
958 
959 	/* add an arg that doesn't already exist, starting from non-empty */
960 	ut_assertok(check_arg(uts, 11, "arg=123 me", buf, "arg=123", "me",
961 			      BOOTFLOWCL_EMPTY));
962 	ut_assertok(check_arg(uts, 12, "arg=123 me=", buf, "arg=123", "me",
963 			      ""));
964 	ut_assertok(check_arg(uts, 16, "arg=123 me=fred", buf, "arg=123", "me",
965 			      "fred"));
966 
967 	/* update an arg at the start */
968 	ut_assertok(check_arg(uts, 1, "", buf, "arg=123", "arg", NULL));
969 	ut_assertok(check_arg(uts, 4, "arg", buf, "arg=123", "arg",
970 			      BOOTFLOWCL_EMPTY));
971 	ut_assertok(check_arg(uts, 5, "arg=", buf, "arg=123", "arg", ""));
972 	ut_assertok(check_arg(uts, 6, "arg=1", buf, "arg=123", "arg", "1"));
973 	ut_assertok(check_arg(uts, 9, "arg=1234", buf, "arg=123", "arg",
974 			      "1234"));
975 
976 	/* update an arg at the end */
977 	ut_assertok(check_arg(uts, 5, "mary", buf, "mary arg=123", "arg",
978 			      NULL));
979 	ut_assertok(check_arg(uts, 9, "mary arg", buf, "mary arg=123", "arg",
980 			      BOOTFLOWCL_EMPTY));
981 	ut_assertok(check_arg(uts, 10, "mary arg=", buf, "mary arg=123", "arg",
982 			      ""));
983 	ut_assertok(check_arg(uts, 11, "mary arg=1", buf, "mary arg=123", "arg",
984 			      "1"));
985 	ut_assertok(check_arg(uts, 14, "mary arg=1234", buf, "mary arg=123",
986 			      "arg", "1234"));
987 
988 	/* update an arg in the middle */
989 	ut_assertok(check_arg(uts, 16, "mary=abc john=2", buf,
990 			      "mary=abc arg=123 john=2", "arg", NULL));
991 	ut_assertok(check_arg(uts, 20, "mary=abc arg john=2", buf,
992 			      "mary=abc arg=123 john=2", "arg",
993 			      BOOTFLOWCL_EMPTY));
994 	ut_assertok(check_arg(uts, 21, "mary=abc arg= john=2", buf,
995 			      "mary=abc arg=123 john=2", "arg", ""));
996 	ut_assertok(check_arg(uts, 22, "mary=abc arg=1 john=2", buf,
997 			      "mary=abc arg=123 john=2", "arg", "1"));
998 	ut_assertok(check_arg(uts, 25, "mary=abc arg=1234 john=2", buf,
999 			      "mary=abc arg=123 john=2", "arg", "1234"));
1000 
1001 	/* handle existing args with quotes */
1002 	ut_assertok(check_arg(uts, 16, "mary=\"abc\" john", buf,
1003 			      "mary=\"abc\" arg=123 john", "arg", NULL));
1004 
1005 	/* handle existing args with quoted spaces */
1006 	ut_assertok(check_arg(uts, 20, "mary=\"abc def\" john", buf,
1007 			      "mary=\"abc def\" arg=123 john", "arg", NULL));
1008 
1009 	ut_assertok(check_arg(uts, 34, "mary=\"abc def\" arg=123 john def=4",
1010 			      buf, "mary=\"abc def\" arg=123 john", "def",
1011 			      "4"));
1012 
1013 	/* quote at the start */
1014 	ut_asserteq(-EBADF, cmdline_set_arg(buf, size,
1015 					    "mary=\"abc def\" arg=\"123 456\"",
1016 					    "arg", "\"4 5 6", NULL));
1017 
1018 	/* quote at the end */
1019 	ut_asserteq(-EBADF, cmdline_set_arg(buf, size,
1020 					    "mary=\"abc def\" arg=\"123 456\"",
1021 					    "arg", "4 5 6\"", NULL));
1022 
1023 	/* quote in the middle */
1024 	ut_asserteq(-EBADF, cmdline_set_arg(buf, size,
1025 					    "mary=\"abc def\" arg=\"123 456\"",
1026 					    "arg", "\"4 \"5 6\"", NULL));
1027 
1028 	/* handle updating a quoted arg */
1029 	ut_assertok(check_arg(uts, 27, "mary=\"abc def\" arg=\"4 5 6\"", buf,
1030 			      "mary=\"abc def\" arg=\"123 456\"", "arg",
1031 			      "4 5 6"));
1032 
1033 	/* changing a quoted arg to a non-quoted arg */
1034 	ut_assertok(check_arg(uts, 23, "mary=\"abc def\" arg=789", buf,
1035 			      "mary=\"abc def\" arg=\"123 456\"", "arg",
1036 			      "789"));
1037 
1038 	/* changing a non-quoted arg to a quoted arg */
1039 	ut_assertok(check_arg(uts, 29, "mary=\"abc def\" arg=\"456 789\"", buf,
1040 			      "mary=\"abc def\" arg=123", "arg", "456 789"));
1041 
1042 	/* handling of spaces */
1043 	ut_assertok(check_arg(uts, 8, "arg=123", buf, " ", "arg", "123"));
1044 	ut_assertok(check_arg(uts, 8, "arg=123", buf, "   ", "arg", "123"));
1045 	ut_assertok(check_arg(uts, 13, "john arg=123", buf, " john  ", "arg",
1046 			      "123"));
1047 	ut_assertok(check_arg(uts, 13, "john arg=123", buf, " john  arg=123  ",
1048 			      "arg", "123"));
1049 	ut_assertok(check_arg(uts, 18, "john arg=123 mary", buf,
1050 			      " john  arg=123 mary ", "arg", "123"));
1051 
1052 	/* unchanged arg */
1053 	ut_assertok(check_arg(uts, 3, "me", buf, "me", "me", BOOTFLOWCL_EMPTY));
1054 
1055 	/* arg which starts with the same name */
1056 	ut_assertok(check_arg(uts, 28, "mary=abc johnathon=2 john=3", buf,
1057 			      "mary=abc johnathon=2 john=1", "john", "3"));
1058 
1059 	return 0;
1060 }
1061 BOOTSTD_TEST(test_bootflow_cmdline_set, 0);
1062 
1063 /* Test of bootflow_cmdline_set_arg() */
bootflow_set_arg(struct unit_test_state * uts)1064 static int bootflow_set_arg(struct unit_test_state *uts)
1065 {
1066 	struct bootflow s_bflow, *bflow = &s_bflow;
1067 	ulong mem_start;
1068 
1069 	ut_assertok(env_set("bootargs", NULL));
1070 
1071 	mem_start = ut_check_delta(0);
1072 
1073 	/* Do a simple sanity check. Rely on bootflow_cmdline() for the rest */
1074 	bflow->cmdline = NULL;
1075 	ut_assertok(bootflow_cmdline_set_arg(bflow, "fred", "123", false));
1076 	ut_asserteq_str(bflow->cmdline, "fred=123");
1077 
1078 	ut_assertok(bootflow_cmdline_set_arg(bflow, "mary", "and here", false));
1079 	ut_asserteq_str(bflow->cmdline, "fred=123 mary=\"and here\"");
1080 
1081 	ut_assertok(bootflow_cmdline_set_arg(bflow, "mary", NULL, false));
1082 	ut_asserteq_str(bflow->cmdline, "fred=123");
1083 	ut_assertok(bootflow_cmdline_set_arg(bflow, "fred", NULL, false));
1084 	ut_asserteq_ptr(bflow->cmdline, NULL);
1085 
1086 	ut_asserteq(0, ut_check_delta(mem_start));
1087 
1088 	ut_assertok(bootflow_cmdline_set_arg(bflow, "mary", "here", true));
1089 	ut_asserteq_str("mary=here", env_get("bootargs"));
1090 	ut_assertok(env_set("bootargs", NULL));
1091 
1092 	return 0;
1093 }
1094 BOOTSTD_TEST(bootflow_set_arg, 0);
1095 
1096 /* Test of bootflow_cmdline_get_arg() */
bootflow_cmdline_get(struct unit_test_state * uts)1097 static int bootflow_cmdline_get(struct unit_test_state *uts)
1098 {
1099 	int pos;
1100 
1101 	/* empty string */
1102 	ut_asserteq(-ENOENT, cmdline_get_arg("", "fred", &pos));
1103 
1104 	/* arg with empty value */
1105 	ut_asserteq(0, cmdline_get_arg("fred= mary", "fred", &pos));
1106 	ut_asserteq(5, pos);
1107 
1108 	/* arg with a value */
1109 	ut_asserteq(2, cmdline_get_arg("fred=23", "fred", &pos));
1110 	ut_asserteq(5, pos);
1111 
1112 	/* arg with a value */
1113 	ut_asserteq(3, cmdline_get_arg("mary=1 fred=234", "fred", &pos));
1114 	ut_asserteq(12, pos);
1115 
1116 	/* arg with a value, after quoted arg */
1117 	ut_asserteq(3, cmdline_get_arg("mary=\"1 2\" fred=234", "fred", &pos));
1118 	ut_asserteq(16, pos);
1119 
1120 	/* arg in the middle */
1121 	ut_asserteq(0, cmdline_get_arg("mary=\"1 2\" fred john=23", "fred",
1122 				       &pos));
1123 	ut_asserteq(15, pos);
1124 
1125 	/* quoted arg */
1126 	ut_asserteq(3, cmdline_get_arg("mary=\"1 2\" fred=\"3 4\" john=23",
1127 				       "fred", &pos));
1128 	ut_asserteq(17, pos);
1129 
1130 	/* args starting with the same prefix */
1131 	ut_asserteq(1, cmdline_get_arg("mary=abc johnathon=3 john=1", "john",
1132 				       &pos));
1133 	ut_asserteq(26, pos);
1134 
1135 	return 0;
1136 }
1137 BOOTSTD_TEST(bootflow_cmdline_get, 0);
1138 
bootflow_cmdline(struct unit_test_state * uts)1139 static int bootflow_cmdline(struct unit_test_state *uts)
1140 {
1141 	ut_assertok(run_command("bootflow scan mmc", 0));
1142 	ut_assertok(run_command("bootflow sel 0", 0));
1143 
1144 	ut_asserteq(1, run_command("bootflow cmdline get fred", 0));
1145 	ut_assert_nextline("Argument not found");
1146 	ut_assert_console_end();
1147 
1148 	ut_asserteq(0, run_command("bootflow cmdline set fred 123", 0));
1149 	ut_asserteq(0, run_command("bootflow cmdline get fred", 0));
1150 	ut_assert_nextline("123");
1151 
1152 	ut_asserteq(0, run_command("bootflow cmdline set mary abc", 0));
1153 	ut_asserteq(0, run_command("bootflow cmdline get mary", 0));
1154 	ut_assert_nextline("abc");
1155 
1156 	ut_asserteq(0, run_command("bootflow cmdline delete fred", 0));
1157 	ut_asserteq(1, run_command("bootflow cmdline get fred", 0));
1158 	ut_assert_nextline("Argument not found");
1159 
1160 	ut_asserteq(0, run_command("bootflow cmdline clear mary", 0));
1161 	ut_asserteq(0, run_command("bootflow cmdline get mary", 0));
1162 	ut_assert_nextline_empty();
1163 
1164 	ut_asserteq(0, run_command("bootflow cmdline set mary abc", 0));
1165 	ut_asserteq(0, run_command("bootflow cmdline set mary", 0));
1166 	ut_assert_console_end();
1167 
1168 	return 0;
1169 }
1170 BOOTSTD_TEST(bootflow_cmdline, UTF_CONSOLE);
1171 
1172 /* test a few special changes to a long command line */
bootflow_cmdline_special(struct unit_test_state * uts)1173 static int bootflow_cmdline_special(struct unit_test_state *uts)
1174 {
1175 	char buf[500];
1176 	int pos;
1177 
1178 	/*
1179 	 * check handling of an argument which has an embedded '=', as well as
1180 	 * handling of a argument which partially matches ("ro" and "root")
1181 	 */
1182 	ut_asserteq(32, cmdline_set_arg(
1183 		buf, sizeof(buf),
1184 		"loglevel=7 root=PARTUUID=d68352e3 rootwait ro noinitrd",
1185 		"root", NULL, &pos));
1186 	ut_asserteq_str("loglevel=7 rootwait ro noinitrd", buf);
1187 
1188 	return 0;
1189 }
1190 BOOTSTD_TEST(bootflow_cmdline_special, 0);
1191 
1192 /* Test ChromiumOS bootmeth */
bootflow_cros(struct unit_test_state * uts)1193 static int bootflow_cros(struct unit_test_state *uts)
1194 {
1195 	ut_assertok(scan_mmc_bootdev(uts, "mmc5", true));
1196 	ut_assertok(run_command("bootflow list", 0));
1197 
1198 	ut_assert_nextlinen("Showing all");
1199 	ut_assert_nextlinen("Seq");
1200 	ut_assert_nextlinen("---");
1201 	ut_assert_nextlinen("  0  extlinux");
1202 	ut_assert_nextlinen("  1  cros         ready   mmc          2  mmc5.bootdev.part_2       ");
1203 	ut_assert_nextlinen("  2  cros         ready   mmc          4  mmc5.bootdev.part_4       ");
1204 	ut_assert_nextlinen("---");
1205 	ut_assert_skip_to_line("(3 bootflows, 3 valid)");
1206 
1207 	ut_assertok(run_command("bootstd images", 0));
1208 	ut_assert_nextlinen("Seq");
1209 	ut_assert_nextlinen("---");
1210 	ut_assert_nextlinen("  0  mmc1.bootdev.part_1  extlinux_cfg");
1211 	ut_assert_nextlinen("  1  mmc5.bootdev.part_2  x86_setup");
1212 	ut_assert_nextlinen("  1  mmc5.bootdev.part_2  cmdline");
1213 	ut_assert_nextlinen("  1  mmc5.bootdev.part_2  kernel                 -      4000  kernel");
1214 	ut_assert_nextlinen("  2  mmc5.bootdev.part_4  x86_setup");
1215 	ut_assert_nextlinen("  2  mmc5.bootdev.part_4  cmdline");
1216 	ut_assert_nextlinen("  2  mmc5.bootdev.part_4  kernel                 -      4000  kernel");
1217 	ut_assert_nextlinen("---");
1218 	ut_assert_nextline("(7 images)");
1219 
1220 	ut_assert_console_end();
1221 
1222 	return 0;
1223 }
1224 BOOTSTD_TEST(bootflow_cros, UTF_CONSOLE | UTF_DM | UTF_SCAN_FDT);
1225 
1226 /* Test Android bootmeth  with boot image version 4 */
bootflow_android_image_v4(struct unit_test_state * uts)1227 static int bootflow_android_image_v4(struct unit_test_state *uts)
1228 {
1229 	if (!IS_ENABLED(CONFIG_BOOTMETH_ANDROID))
1230 		return -EAGAIN;
1231 
1232 	ut_assertok(scan_mmc_android_bootdev(uts, "mmc7"));
1233 	ut_assertok(run_command("bootflow list", 0));
1234 
1235 	ut_assert_nextlinen("Showing all");
1236 	ut_assert_nextlinen("Seq");
1237 	ut_assert_nextlinen("---");
1238 	ut_assert_nextlinen("  0  extlinux");
1239 	ut_assert_nextlinen("  1  android      ready   mmc          0  mmc7.bootdev.whole        ");
1240 	ut_assert_nextlinen("---");
1241 	ut_assert_skip_to_line("(2 bootflows, 2 valid)");
1242 
1243 	ut_assert_console_end();
1244 
1245 	return 0;
1246 }
1247 BOOTSTD_TEST(bootflow_android_image_v4, UTF_CONSOLE | UTF_DM | UTF_SCAN_FDT);
1248 
1249 /* Test Android bootmeth with boot image version 2 */
bootflow_android_image_v2(struct unit_test_state * uts)1250 static int bootflow_android_image_v2(struct unit_test_state *uts)
1251 {
1252 	if (!IS_ENABLED(CONFIG_BOOTMETH_ANDROID))
1253 		return -EAGAIN;
1254 
1255 	ut_assertok(scan_mmc_android_bootdev(uts, "mmc8"));
1256 	ut_assertok(run_command("bootflow list", 0));
1257 
1258 	ut_assert_nextlinen("Showing all");
1259 	ut_assert_nextlinen("Seq");
1260 	ut_assert_nextlinen("---");
1261 	ut_assert_nextlinen("  0  extlinux");
1262 	ut_assert_nextlinen("  1  android      ready   mmc          0  mmc8.bootdev.whole        ");
1263 	ut_assert_nextlinen("---");
1264 	ut_assert_skip_to_line("(2 bootflows, 2 valid)");
1265 
1266 	ut_assert_console_end();
1267 
1268 	return 0;
1269 }
1270 BOOTSTD_TEST(bootflow_android_image_v2, UTF_CONSOLE | UTF_DM | UTF_SCAN_FDT);
1271 
1272 /* Test EFI bootmeth */
bootflow_efi(struct unit_test_state * uts)1273 static int bootflow_efi(struct unit_test_state *uts)
1274 {
1275 	static const char *order[] = {"mmc1", "usb", NULL};
1276 	struct bootstd_priv *std;
1277 	struct udevice *bootstd;
1278 	const char **old_order;
1279 
1280 	ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd));
1281 	std = dev_get_priv(bootstd);
1282 	old_order = std->bootdev_order;
1283 	std->bootdev_order = order;
1284 
1285 	/* disable ethernet since the hunter will run dhcp */
1286 	test_set_eth_enable(false);
1287 
1288 	/* make USB scan without delays */
1289 	test_set_skip_delays(true);
1290 
1291 	bootstd_reset_usb();
1292 
1293 	ut_assertok(run_command("bootflow scan", 0));
1294 	ut_assert_skip_to_line(
1295 		"Bus usb@1: 5 USB Device(s) found");
1296 
1297 	ut_assertok(run_command("bootflow list", 0));
1298 
1299 	ut_assert_nextlinen("Showing all");
1300 	ut_assert_nextlinen("Seq");
1301 	ut_assert_nextlinen("---");
1302 	ut_assert_nextlinen("  0  extlinux");
1303 	ut_assert_nextlinen(
1304 		"  1  efi          ready   usb_mass_    1  usb_mass_storage.lun0.boo /EFI/BOOT/BOOTSBOX.EFI");
1305 	ut_assert_nextlinen("---");
1306 	ut_assert_skip_to_line("(2 bootflows, 2 valid)");
1307 	ut_assert_console_end();
1308 
1309 	ut_assertok(run_command("bootflow select 1", 0));
1310 	ut_assert_console_end();
1311 
1312 	systab.fw_vendor = test_vendor;
1313 
1314 	ut_asserteq(1, run_command("bootflow boot", 0));
1315 	ut_assert_nextline(
1316 		"** Booting bootflow 'usb_mass_storage.lun0.bootdev.part_1' with efi");
1317 	if (IS_ENABLED(CONFIG_LOGF_FUNC))
1318 		ut_assert_skip_to_line("       efi_run_image() Booting /\\EFI\\BOOT\\BOOTSBOX.EFI");
1319 	else
1320 		ut_assert_skip_to_line("Booting /\\EFI\\BOOT\\BOOTSBOX.EFI");
1321 
1322 	/* TODO: Why the \r ? */
1323 	ut_assert_nextline("U-Boot test app for EFI_LOADER\r");
1324 	ut_assert_nextline("Exiting test app");
1325 	ut_assert_nextline("Boot failed (err=-14)");
1326 
1327 	ut_assert_console_end();
1328 
1329 	ut_assertok(bootstd_test_drop_bootdev_order(uts));
1330 
1331 	return 0;
1332 }
1333 BOOTSTD_TEST(bootflow_efi, UTF_CONSOLE);
1334 
1335 /* Check 'bootflow scan' provides a list of images */
bootstd_images(struct unit_test_state * uts)1336 static int bootstd_images(struct unit_test_state *uts)
1337 {
1338 	static const char *order[] = {"mmc2", "mmc1", "mmc4", "mmc5", NULL};
1339 	const struct legacy_img_hdr *hdr;
1340 	const struct bootflow_img *img;
1341 	const struct bootflow *bflow;
1342 	struct bootstd_priv *std;
1343 	const char **old_order;
1344 	struct udevice *dev;
1345 	ofnode root, node;
1346 	ulong data, len;
1347 	char *ptr;
1348 
1349 	/* get access to the current bootflow */
1350 	ut_assertok(bootstd_get_priv(&std));
1351 
1352 	ut_assertok(prep_mmc_bootdev(uts, "mmc4", true, &old_order));
1353 
1354 	/* bind mmc5 too, for cros */
1355 	root = oftree_root(oftree_default());
1356 	node = ofnode_find_subnode(root, "mmc5");
1357 	ut_assert(ofnode_valid(node));
1358 	ut_assertok(lists_bind_fdt(gd->dm_root, node, &dev, NULL, false));
1359 
1360 	std->bootdev_order = order;
1361 	ut_assertok(run_command("bootflow scan", 0));
1362 	ut_assert_console_end();
1363 	std->bootdev_order = old_order;
1364 
1365 	ut_assertok(run_command("bootflow list", 0));
1366 	ut_assert_skip_to_line("(4 bootflows, 4 valid)");
1367 
1368 	ut_assertok(run_command("bootstd images", 0));
1369 	ut_assert_nextlinen("Seq");
1370 	ut_assert_nextlinen("---");
1371 	ut_assert_nextlinen("  0  mmc1.bootdev.part_1  extlinux_cfg");
1372 	ut_assert_nextlinen("  1  mmc4.bootdev.part_1  script");
1373 	ut_assert_nextlinen("  1  mmc4.bootdev.part_1  logo");
1374 	ut_assert_nextlinen("  2  mmc5.bootdev.part_2  x86_setup");
1375 	ut_assert_nextlinen("  2  mmc5.bootdev.part_2  cmdline");
1376 	ut_assert_nextlinen("  2  mmc5.bootdev.part_2  kernel                 -");
1377 	ut_assert_nextlinen("  3  mmc5.bootdev.part_4  x86_setup");
1378 	ut_assert_nextlinen("  3  mmc5.bootdev.part_4  cmdline");
1379 	ut_assert_nextlinen("  3  mmc5.bootdev.part_4  kernel                 -");
1380 	ut_assert_nextlinen("---");
1381 	ut_assert_nextline("(9 images)");
1382 
1383 	/* check the first image */
1384 	bflow = alist_get(&std->bootflows, 0, struct bootflow);
1385 	img = alist_get(&bflow->images, 0, struct bootflow_img);
1386 	ut_asserteq_strn("# extlinux.conf", map_sysmem(img->addr, 0));
1387 
1388 	/* check the second image */
1389 	bflow = alist_get(&std->bootflows, 1, struct bootflow);
1390 	img = alist_get(&bflow->images, 0, struct bootflow_img);
1391 
1392 	/* this is the length of the script in bytes */
1393 	hdr = map_sysmem(img->addr, 0);
1394 	image_multi_getimg(hdr, 0, &data, &len);
1395 	ptr = (void *)data;
1396 	ut_asserteq_strn("# DO NOT EDIT THIS FILE", ptr);
1397 
1398 	/* check the ChromiumOS images */
1399 	bflow = alist_get(&std->bootflows, 2, struct bootflow);
1400 	img = alist_get(&bflow->images, 1, struct bootflow_img);
1401 	ptr = map_sysmem(img->addr, 0);
1402 	ut_asserteq_strn("BOOT_IMAGE=/vmlinuz-5.15.0-121-generic root=", ptr);
1403 
1404 	/*
1405 	 * the x86 setup is not a real binary, so just check that it is empty,
1406 	 * so that if this changes in the future someone will notice and update
1407 	 * this test
1408 	 */
1409 	img = alist_get(&bflow->images, 0, struct bootflow_img);
1410 	ptr = map_sysmem(img->addr, 0);
1411 	ut_asserteq(0, *(ulong *)ptr);
1412 
1413 	ut_assert_console_end();
1414 
1415 	return 0;
1416 }
1417 BOOTSTD_TEST(bootstd_images, UTF_CONSOLE);
1418