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