blob: a2ed8ac774f973329a3e30b2ebe7c072e6c99c2c [file] [log] [blame]
Simon Glassfb1451b2022-04-24 23:31:24 -06001// 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 <common.h>
10#include <bootdev.h>
11#include <bootflow.h>
12#include <bootstd.h>
13#include <dm.h>
14#include <dm/lists.h>
15#include <test/suites.h>
16#include <test/ut.h>
17#include "bootstd_common.h"
18
Simon Glassf25f5752022-07-30 15:52:16 -060019static int inject_response(struct unit_test_state *uts)
20{
21 /*
22 * The image being booted presents a menu of options:
23 *
24 * Fedora-Workstation-armhfp-31-1.9 Boot Options.
25 * 1: Fedora-Workstation-armhfp-31-1.9 (5.3.7-301.fc31.armv7hl)
26 * Enter choice:
27 *
28 * Provide input for this, to avoid waiting two seconds for a timeout.
29 */
30 ut_asserteq(2, console_in_puts("1\n"));
31
32 return 0;
33}
34
Simon Glassfb1451b2022-04-24 23:31:24 -060035/* Check 'bootflow scan/list' commands */
36static int bootflow_cmd(struct unit_test_state *uts)
37{
38 console_record_reset_enable();
39 ut_assertok(run_command("bootdev select 1", 0));
40 ut_assert_console_end();
41 ut_assertok(run_command("bootflow scan -l", 0));
42 ut_assert_nextline("Scanning for bootflows in bootdev 'mmc1.bootdev'");
43 ut_assert_nextline("Seq Method State Uclass Part Name Filename");
44 ut_assert_nextlinen("---");
45 ut_assert_nextline(" 0 syslinux ready mmc 1 mmc1.bootdev.part_1 /extlinux/extlinux.conf");
46 ut_assert_nextlinen("---");
47 ut_assert_nextline("(1 bootflow, 1 valid)");
48 ut_assert_console_end();
49
50 ut_assertok(run_command("bootflow list", 0));
51 ut_assert_nextline("Showing bootflows for bootdev 'mmc1.bootdev'");
52 ut_assert_nextline("Seq Method State Uclass Part Name Filename");
53 ut_assert_nextlinen("---");
54 ut_assert_nextline(" 0 syslinux ready mmc 1 mmc1.bootdev.part_1 /extlinux/extlinux.conf");
55 ut_assert_nextlinen("---");
56 ut_assert_nextline("(1 bootflow, 1 valid)");
57 ut_assert_console_end();
58
59 return 0;
60}
61BOOTSTD_TEST(bootflow_cmd, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
62
63/* Check 'bootflow scan' with a name / label / seq */
64static int bootflow_cmd_label(struct unit_test_state *uts)
65{
66 console_record_reset_enable();
67 ut_assertok(run_command("bootflow scan -l mmc1", 0));
68 ut_assert_nextline("Scanning for bootflows in bootdev 'mmc1.bootdev'");
69 ut_assert_skip_to_line("(1 bootflow, 1 valid)");
70 ut_assert_console_end();
71
72 ut_assertok(run_command("bootflow scan -l mmc0.bootdev", 0));
73 ut_assert_nextline("Scanning for bootflows in bootdev 'mmc0.bootdev'");
74 ut_assert_skip_to_line("(0 bootflows, 0 valid)");
75 ut_assert_console_end();
76
77 ut_assertok(run_command("bootflow scan -l 0", 0));
78 ut_assert_nextline("Scanning for bootflows in bootdev 'mmc2.bootdev'");
79 ut_assert_skip_to_line("(0 bootflows, 0 valid)");
80 ut_assert_console_end();
81
82 return 0;
83}
84BOOTSTD_TEST(bootflow_cmd_label, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
85
86/* Check 'bootflow scan/list' commands using all bootdevs */
87static int bootflow_cmd_glob(struct unit_test_state *uts)
88{
89 ut_assertok(bootstd_test_drop_bootdev_order(uts));
90
91 console_record_reset_enable();
92 ut_assertok(run_command("bootflow scan -l", 0));
93 ut_assert_nextline("Scanning for bootflows in all bootdevs");
94 ut_assert_nextline("Seq Method State Uclass Part Name Filename");
95 ut_assert_nextlinen("---");
96 ut_assert_nextline("Scanning bootdev 'mmc2.bootdev':");
97 ut_assert_nextline("Scanning bootdev 'mmc1.bootdev':");
98 ut_assert_nextline(" 0 syslinux ready mmc 1 mmc1.bootdev.part_1 /extlinux/extlinux.conf");
99 ut_assert_nextline("Scanning bootdev 'mmc0.bootdev':");
100 ut_assert_nextline("No more bootdevs");
101 ut_assert_nextlinen("---");
102 ut_assert_nextline("(1 bootflow, 1 valid)");
103 ut_assert_console_end();
104
105 ut_assertok(run_command("bootflow list", 0));
106 ut_assert_nextline("Showing all bootflows");
107 ut_assert_nextline("Seq Method State Uclass Part Name Filename");
108 ut_assert_nextlinen("---");
109 ut_assert_nextline(" 0 syslinux ready mmc 1 mmc1.bootdev.part_1 /extlinux/extlinux.conf");
110 ut_assert_nextlinen("---");
111 ut_assert_nextline("(1 bootflow, 1 valid)");
112 ut_assert_console_end();
113
114 return 0;
115}
116BOOTSTD_TEST(bootflow_cmd_glob, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
117
118/* Check 'bootflow scan -e' */
119static int bootflow_cmd_scan_e(struct unit_test_state *uts)
120{
121 ut_assertok(bootstd_test_drop_bootdev_order(uts));
122
123 console_record_reset_enable();
124 ut_assertok(run_command("bootflow scan -ale", 0));
125 ut_assert_nextline("Scanning for bootflows in all bootdevs");
126 ut_assert_nextline("Seq Method State Uclass Part Name Filename");
127 ut_assert_nextlinen("---");
128 ut_assert_nextline("Scanning bootdev 'mmc2.bootdev':");
129 ut_assert_nextline(" 0 syslinux media mmc 0 mmc2.bootdev.whole <NULL>");
130 ut_assert_nextline(" ** No partition found, err=-93");
131 ut_assert_nextline(" 1 efi media mmc 0 mmc2.bootdev.whole <NULL>");
132 ut_assert_nextline(" ** No partition found, err=-93");
133
134 ut_assert_nextline("Scanning bootdev 'mmc1.bootdev':");
135 ut_assert_nextline(" 2 syslinux media mmc 0 mmc1.bootdev.whole <NULL>");
136 ut_assert_nextline(" ** No partition found, err=-2");
137 ut_assert_nextline(" 3 efi media mmc 0 mmc1.bootdev.whole <NULL>");
138 ut_assert_nextline(" ** No partition found, err=-2");
139 ut_assert_nextline(" 4 syslinux ready mmc 1 mmc1.bootdev.part_1 /extlinux/extlinux.conf");
140 ut_assert_nextline(" 5 efi fs mmc 1 mmc1.bootdev.part_1 efi/boot/bootsbox.efi");
141
142 ut_assert_skip_to_line("Scanning bootdev 'mmc0.bootdev':");
143 ut_assert_skip_to_line(" 3f efi media mmc 0 mmc0.bootdev.whole <NULL>");
144 ut_assert_nextline(" ** No partition found, err=-93");
145 ut_assert_nextline("No more bootdevs");
146 ut_assert_nextlinen("---");
147 ut_assert_nextline("(64 bootflows, 1 valid)");
148 ut_assert_console_end();
149
150 ut_assertok(run_command("bootflow list", 0));
151 ut_assert_nextline("Showing all bootflows");
152 ut_assert_nextline("Seq Method State Uclass Part Name Filename");
153 ut_assert_nextlinen("---");
154 ut_assert_nextline(" 0 syslinux media mmc 0 mmc2.bootdev.whole <NULL>");
155 ut_assert_nextline(" 1 efi media mmc 0 mmc2.bootdev.whole <NULL>");
156 ut_assert_skip_to_line(" 4 syslinux ready mmc 1 mmc1.bootdev.part_1 /extlinux/extlinux.conf");
157 ut_assert_skip_to_line(" 3f efi media mmc 0 mmc0.bootdev.whole <NULL>");
158 ut_assert_nextlinen("---");
159 ut_assert_nextline("(64 bootflows, 1 valid)");
160 ut_assert_console_end();
161
162 return 0;
163}
164BOOTSTD_TEST(bootflow_cmd_scan_e, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
165
166/* Check 'bootflow info' */
167static int bootflow_cmd_info(struct unit_test_state *uts)
168{
169 console_record_reset_enable();
170 ut_assertok(run_command("bootdev select 1", 0));
171 ut_assert_console_end();
172 ut_assertok(run_command("bootflow scan", 0));
173 ut_assert_console_end();
174 ut_assertok(run_command("bootflow select 0", 0));
175 ut_assert_console_end();
176 ut_assertok(run_command("bootflow info", 0));
177 ut_assert_nextline("Name: mmc1.bootdev.part_1");
178 ut_assert_nextline("Device: mmc1.bootdev");
179 ut_assert_nextline("Block dev: mmc1.blk");
180 ut_assert_nextline("Method: syslinux");
181 ut_assert_nextline("State: ready");
182 ut_assert_nextline("Partition: 1");
183 ut_assert_nextline("Subdir: (none)");
184 ut_assert_nextline("Filename: /extlinux/extlinux.conf");
185 ut_assert_nextlinen("Buffer: ");
186 ut_assert_nextline("Size: 253 (595 bytes)");
187 ut_assert_nextline("Error: 0");
188 ut_assert_console_end();
189
190 ut_assertok(run_command("bootflow info -d", 0));
191 ut_assert_nextline("Name: mmc1.bootdev.part_1");
192 ut_assert_skip_to_line("Error: 0");
193 ut_assert_nextline("Contents:");
194 ut_assert_nextline("%s", "");
195 ut_assert_nextline("# extlinux.conf generated by appliance-creator");
196 ut_assert_skip_to_line(" initrd /initramfs-5.3.7-301.fc31.armv7hl.img");
197 ut_assert_console_end();
198
199 return 0;
200}
201BOOTSTD_TEST(bootflow_cmd_info, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
202
203/* Check 'bootflow scan -b' to boot the first available bootdev */
204static int bootflow_scan_boot(struct unit_test_state *uts)
205{
206 console_record_reset_enable();
Simon Glassf25f5752022-07-30 15:52:16 -0600207 ut_assertok(inject_response(uts));
Simon Glassfb1451b2022-04-24 23:31:24 -0600208 ut_assertok(run_command("bootflow scan -b", 0));
209 ut_assert_nextline(
210 "** Booting bootflow 'mmc1.bootdev.part_1' with syslinux");
211 ut_assert_nextline("Ignoring unknown command: ui");
212
213 /*
214 * We expect it to get through to boot although sandbox always returns
215 * -EFAULT as it cannot actually boot the kernel
216 */
217 ut_assert_skip_to_line("sandbox: continuing, as we cannot run Linux");
218 ut_assert_nextline("Boot failed (err=-14)");
219 ut_assert_console_end();
220
221 return 0;
222}
223BOOTSTD_TEST(bootflow_scan_boot, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
224
225/* Check iterating through available bootflows */
226static int bootflow_iter(struct unit_test_state *uts)
227{
228 struct bootflow_iter iter;
229 struct bootflow bflow;
230
231 bootstd_clear_glob();
232
233 /* The first device is mmc2.bootdev which has no media */
234 ut_asserteq(-EPROTONOSUPPORT,
235 bootflow_scan_first(&iter, BOOTFLOWF_ALL, &bflow));
236 ut_asserteq(2, iter.num_methods);
237 ut_asserteq(0, iter.cur_method);
238 ut_asserteq(0, iter.part);
239 ut_asserteq(0, iter.max_part);
240 ut_asserteq_str("syslinux", iter.method->name);
241 ut_asserteq(0, bflow.err);
242
243 /*
244 * This shows MEDIA even though there is none, since int
245 * bootdev_find_in_blk() we call part_get_info() which returns
246 * -EPROTONOSUPPORT. Ideally it would return -EEOPNOTSUPP and we would
247 * know.
248 */
249 ut_asserteq(BOOTFLOWST_MEDIA, bflow.state);
250
251 ut_asserteq(-EPROTONOSUPPORT, bootflow_scan_next(&iter, &bflow));
252 ut_asserteq(2, iter.num_methods);
253 ut_asserteq(1, iter.cur_method);
254 ut_asserteq(0, iter.part);
255 ut_asserteq(0, iter.max_part);
256 ut_asserteq_str("efi", iter.method->name);
257 ut_asserteq(0, bflow.err);
258 ut_asserteq(BOOTFLOWST_MEDIA, bflow.state);
259 bootflow_free(&bflow);
260
261 /* The next device is mmc1.bootdev - at first we use the whole device */
262 ut_asserteq(-ENOENT, bootflow_scan_next(&iter, &bflow));
263 ut_asserteq(2, iter.num_methods);
264 ut_asserteq(0, iter.cur_method);
265 ut_asserteq(0, iter.part);
266 ut_asserteq(0x1e, iter.max_part);
267 ut_asserteq_str("syslinux", iter.method->name);
268 ut_asserteq(0, bflow.err);
269 ut_asserteq(BOOTFLOWST_MEDIA, bflow.state);
270 bootflow_free(&bflow);
271
272 ut_asserteq(-ENOENT, bootflow_scan_next(&iter, &bflow));
273 ut_asserteq(2, iter.num_methods);
274 ut_asserteq(1, iter.cur_method);
275 ut_asserteq(0, iter.part);
276 ut_asserteq(0x1e, iter.max_part);
277 ut_asserteq_str("efi", iter.method->name);
278 ut_asserteq(0, bflow.err);
279 ut_asserteq(BOOTFLOWST_MEDIA, bflow.state);
280 bootflow_free(&bflow);
281
282 /* Then more to partition 1 where we find something */
283 ut_assertok(bootflow_scan_next(&iter, &bflow));
284 ut_asserteq(2, iter.num_methods);
285 ut_asserteq(0, iter.cur_method);
286 ut_asserteq(1, iter.part);
287 ut_asserteq(0x1e, iter.max_part);
288 ut_asserteq_str("syslinux", iter.method->name);
289 ut_asserteq(0, bflow.err);
290 ut_asserteq(BOOTFLOWST_READY, bflow.state);
291 bootflow_free(&bflow);
292
293 ut_asserteq(-ENOENT, bootflow_scan_next(&iter, &bflow));
294 ut_asserteq(2, iter.num_methods);
295 ut_asserteq(1, iter.cur_method);
296 ut_asserteq(1, iter.part);
297 ut_asserteq(0x1e, iter.max_part);
298 ut_asserteq_str("efi", iter.method->name);
299 ut_asserteq(0, bflow.err);
300 ut_asserteq(BOOTFLOWST_FS, bflow.state);
301 bootflow_free(&bflow);
302
303 /* Then more to partition 2 which doesn't exist */
304 ut_asserteq(-ENOENT, bootflow_scan_next(&iter, &bflow));
305 ut_asserteq(2, iter.num_methods);
306 ut_asserteq(0, iter.cur_method);
307 ut_asserteq(2, iter.part);
308 ut_asserteq(0x1e, iter.max_part);
309 ut_asserteq_str("syslinux", iter.method->name);
310 ut_asserteq(0, bflow.err);
311 ut_asserteq(BOOTFLOWST_MEDIA, bflow.state);
312 bootflow_free(&bflow);
313
314 bootflow_iter_uninit(&iter);
315
316 ut_assert_console_end();
317
318 return 0;
319}
320BOOTSTD_TEST(bootflow_iter, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
321
322/* Check using the system bootdev */
323static int bootflow_system(struct unit_test_state *uts)
324{
325 struct udevice *bootstd, *dev;
326
327 /* Add the EFI bootmgr driver */
328 ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd));
329 ut_assertok(device_bind_driver(bootstd, "bootmeth_efi_mgr", "bootmgr",
330 &dev));
331
332 /* Add the system bootdev that it uses */
333 ut_assertok(device_bind_driver(bootstd, "system_bootdev",
334 "system-bootdev", &dev));
335
336 ut_assertok(bootstd_test_drop_bootdev_order(uts));
337
338 /* We should get a single 'bootmgr' method right at the end */
339 bootstd_clear_glob();
340 console_record_reset_enable();
341 ut_assertok(run_command("bootflow scan -l", 0));
342 ut_assert_skip_to_line(" 1 bootmgr ready bootstd 0 <NULL> <NULL>");
343 ut_assert_nextline("No more bootdevs");
344 ut_assert_skip_to_line("(2 bootflows, 2 valid)");
345 ut_assert_console_end();
346
347 return 0;
348}
349BOOTSTD_TEST(bootflow_system, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
350
351/* Check disabling a bootmethod if it requests it */
352static int bootflow_iter_disable(struct unit_test_state *uts)
353{
354 struct udevice *bootstd, *dev;
355 struct bootflow_iter iter;
356 struct bootflow bflow;
357 int i;
358
359 /* Add the EFI bootmgr driver */
360 ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd));
361 ut_assertok(device_bind_driver(bootstd, "bootmeth_sandbox", "sandbox",
362 &dev));
363
364 /* Add the system bootdev that it uses */
365 ut_assertok(device_bind_driver(bootstd, "system_bootdev",
366 "system-bootdev", &dev));
367
368 ut_assertok(bootstd_test_drop_bootdev_order(uts));
369
370 bootstd_clear_glob();
Simon Glassf25f5752022-07-30 15:52:16 -0600371 console_record_reset_enable();
372 ut_assertok(inject_response(uts));
Simon Glassfb1451b2022-04-24 23:31:24 -0600373 ut_assertok(run_command("bootflow scan -lb", 0));
374
375 /* Try to boot the bootmgr flow, which will fail */
376 console_record_reset_enable();
377 ut_assertok(bootflow_scan_first(&iter, 0, &bflow));
378 ut_asserteq(3, iter.num_methods);
379 ut_asserteq_str("sandbox", iter.method->name);
Simon Glassf25f5752022-07-30 15:52:16 -0600380 ut_assertok(inject_response(uts));
Simon Glassfb1451b2022-04-24 23:31:24 -0600381 ut_asserteq(-ENOTSUPP, bootflow_run_boot(&iter, &bflow));
382
383 ut_assert_skip_to_line("Boot method 'sandbox' failed and will not be retried");
384 ut_assert_console_end();
385
386 /* Check that the sandbox bootmeth has been removed */
387 ut_asserteq(2, iter.num_methods);
388 for (i = 0; i < iter.num_methods; i++)
389 ut_assert(strcmp("sandbox", iter.method_order[i]->name));
390
391 return 0;
392}
393BOOTSTD_TEST(bootflow_iter_disable, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
394
395/* Check 'bootflow boot' to boot a selected bootflow */
396static int bootflow_cmd_boot(struct unit_test_state *uts)
397{
398 console_record_reset_enable();
399 ut_assertok(run_command("bootdev select 1", 0));
400 ut_assert_console_end();
401 ut_assertok(run_command("bootflow scan", 0));
402 ut_assert_console_end();
403 ut_assertok(run_command("bootflow select 0", 0));
404 ut_assert_console_end();
Simon Glassf25f5752022-07-30 15:52:16 -0600405
406 ut_assertok(inject_response(uts));
Simon Glassfb1451b2022-04-24 23:31:24 -0600407 ut_asserteq(1, run_command("bootflow boot", 0));
408 ut_assert_nextline(
409 "** Booting bootflow 'mmc1.bootdev.part_1' with syslinux");
410 ut_assert_nextline("Ignoring unknown command: ui");
411
412 /*
413 * We expect it to get through to boot although sandbox always returns
414 * -EFAULT as it cannot actually boot the kernel
415 */
416 ut_assert_skip_to_line("sandbox: continuing, as we cannot run Linux");
417 ut_assert_nextline("Boot failed (err=-14)");
418 ut_assert_console_end();
419
420 return 0;
421}
422BOOTSTD_TEST(bootflow_cmd_boot, UT_TESTF_DM | UT_TESTF_SCAN_FDT);