]>
Commit | Line | Data |
---|---|---|
fb1451be SG |
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 | ||
fb1451be SG |
9 | #include <bootstd.h> |
10 | #include <dm.h> | |
11 | #include <bootdev.h> | |
12 | #include <bootflow.h> | |
13 | #include <mapmem.h> | |
14 | #include <os.h> | |
15 | #include <test/suites.h> | |
16 | #include <test/ut.h> | |
17 | #include "bootstd_common.h" | |
18 | ||
19 | /* Allow reseting the USB-started flag */ | |
0c1413f6 | 20 | #if defined(CONFIG_USB_HOST) || defined(CONFIG_USB_GADGET) |
9fea3a79 | 21 | extern bool usb_started; |
0c1413f6 | 22 | #else |
9fea3a79 | 23 | #include <usb.h> |
0c1413f6 | 24 | #endif |
fb1451be SG |
25 | |
26 | /* Check 'bootdev list' command */ | |
27 | static int bootdev_test_cmd_list(struct unit_test_state *uts) | |
28 | { | |
29 | int probed; | |
30 | ||
31 | console_record_reset_enable(); | |
32 | for (probed = 0; probed < 2; probed++) { | |
33 | int probe_ch = probed ? '+' : ' '; | |
34 | ||
35 | ut_assertok(run_command(probed ? "bootdev list -p" : | |
36 | "bootdev list", 0)); | |
37 | ut_assert_nextline("Seq Probed Status Uclass Name"); | |
38 | ut_assert_nextlinen("---"); | |
39 | ut_assert_nextline("%3x [ %c ] %6s %-8s %s", 0, probe_ch, "OK", | |
40 | "mmc", "mmc2.bootdev"); | |
41 | ut_assert_nextline("%3x [ %c ] %6s %-8s %s", 1, probe_ch, "OK", | |
42 | "mmc", "mmc1.bootdev"); | |
43 | ut_assert_nextline("%3x [ %c ] %6s %-8s %s", 2, probe_ch, "OK", | |
44 | "mmc", "mmc0.bootdev"); | |
45 | ut_assert_nextlinen("---"); | |
46 | ut_assert_nextline("(3 bootdevs)"); | |
47 | ut_assert_console_end(); | |
48 | } | |
49 | ||
50 | return 0; | |
51 | } | |
52 | BOOTSTD_TEST(bootdev_test_cmd_list, UT_TESTF_DM | UT_TESTF_SCAN_FDT); | |
53 | ||
54 | /* Check 'bootdev select' and 'info' commands */ | |
55 | static int bootdev_test_cmd_select(struct unit_test_state *uts) | |
56 | { | |
57 | struct bootstd_priv *std; | |
58 | ||
59 | /* get access to the CLI's cur_bootdev */ | |
60 | ut_assertok(bootstd_get_priv(&std)); | |
61 | ||
62 | console_record_reset_enable(); | |
63 | ut_asserteq(1, run_command("bootdev info", 0)); | |
64 | ut_assert_nextlinen("Please use"); | |
65 | ut_assert_console_end(); | |
66 | ||
67 | /* select by sequence */ | |
68 | ut_assertok(run_command("bootdev select 0", 0)); | |
69 | ut_assert_console_end(); | |
70 | ||
71 | ut_assertok(run_command("bootdev info", 0)); | |
72 | ut_assert_nextline("Name: mmc2.bootdev"); | |
73 | ut_assert_nextline("Sequence: 0"); | |
74 | ut_assert_nextline("Status: Probed"); | |
75 | ut_assert_nextline("Uclass: mmc"); | |
76 | ut_assert_nextline("Bootflows: 0 (0 valid)"); | |
77 | ut_assert_console_end(); | |
78 | ||
79 | /* select by bootdev name */ | |
80 | ut_assertok(run_command("bootdev select mmc1.bootdev", 0)); | |
81 | ut_assert_console_end(); | |
82 | ut_assertnonnull(std->cur_bootdev); | |
83 | ut_asserteq_str("mmc1.bootdev", std->cur_bootdev->name); | |
84 | ||
85 | /* select by bootdev label*/ | |
86 | ut_assertok(run_command("bootdev select mmc1", 0)); | |
87 | ut_assert_console_end(); | |
88 | ut_assertnonnull(std->cur_bootdev); | |
89 | ut_asserteq_str("mmc1.bootdev", std->cur_bootdev->name); | |
90 | ||
91 | /* deselect */ | |
92 | ut_assertok(run_command("bootdev select", 0)); | |
93 | ut_assert_console_end(); | |
94 | ut_assertnull(std->cur_bootdev); | |
95 | ||
96 | ut_asserteq(1, run_command("bootdev info", 0)); | |
97 | ut_assert_nextlinen("Please use"); | |
98 | ut_assert_console_end(); | |
99 | ||
100 | return 0; | |
101 | } | |
102 | BOOTSTD_TEST(bootdev_test_cmd_select, UT_TESTF_DM | UT_TESTF_SCAN_FDT); | |
103 | ||
104 | /* Check bootdev labels */ | |
105 | static int bootdev_test_labels(struct unit_test_state *uts) | |
106 | { | |
107 | struct udevice *dev, *media; | |
d9f48579 | 108 | int mflags = 0; |
fb1451be | 109 | |
d9f48579 | 110 | ut_assertok(bootdev_find_by_label("mmc2", &dev, &mflags)); |
fb1451be | 111 | ut_asserteq(UCLASS_BOOTDEV, device_get_uclass_id(dev)); |
d9f48579 | 112 | ut_asserteq(0, mflags); |
fb1451be SG |
113 | media = dev_get_parent(dev); |
114 | ut_asserteq(UCLASS_MMC, device_get_uclass_id(media)); | |
115 | ut_asserteq_str("mmc2", media->name); | |
116 | ||
d9f48579 SG |
117 | /* Check method flags */ |
118 | ut_assertok(bootdev_find_by_label("pxe", &dev, &mflags)); | |
66e3dce7 SG |
119 | ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS | BOOTFLOW_METHF_PXE_ONLY, |
120 | mflags); | |
d9f48579 | 121 | ut_assertok(bootdev_find_by_label("dhcp", &dev, &mflags)); |
66e3dce7 SG |
122 | ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS | BOOTFLOW_METHF_DHCP_ONLY, |
123 | mflags); | |
d9f48579 | 124 | |
fb1451be | 125 | /* Check invalid uclass */ |
1736b4af SG |
126 | ut_asserteq(-EPFNOSUPPORT, |
127 | bootdev_find_by_label("fred0", &dev, &mflags)); | |
fb1451be SG |
128 | |
129 | /* Check unknown sequence number */ | |
d9f48579 | 130 | ut_asserteq(-ENOENT, bootdev_find_by_label("mmc6", &dev, &mflags)); |
fb1451be SG |
131 | |
132 | return 0; | |
133 | } | |
d9f48579 SG |
134 | BOOTSTD_TEST(bootdev_test_labels, UT_TESTF_DM | UT_TESTF_SCAN_FDT | |
135 | UT_TESTF_ETH_BOOTDEV); | |
fb1451be | 136 | |
66e3dce7 SG |
137 | /* Check bootdev_find_by_any() */ |
138 | static int bootdev_test_any(struct unit_test_state *uts) | |
139 | { | |
140 | struct udevice *dev, *media; | |
141 | int mflags; | |
142 | ||
143 | /* | |
144 | * with ethernet enabled we have 8 devices ahead of the mmc ones: | |
145 | * | |
146 | * ut_assertok(run_command("bootdev list", 0)); | |
147 | * Seq Probed Status Uclass Name | |
148 | * --- ------ ------ -------- ------------------ | |
149 | * 0 [ + ] OK ethernet eth@10002000.bootdev | |
150 | * 1 [ ] OK ethernet eth@10003000.bootdev | |
151 | * 2 [ ] OK ethernet sbe5.bootdev | |
152 | * 3 [ ] OK ethernet eth@10004000.bootdev | |
153 | * 4 [ ] OK ethernet phy-test-eth.bootdev | |
154 | * 5 [ ] OK ethernet dsa-test-eth.bootdev | |
155 | * 6 [ ] OK ethernet dsa-test@0.bootdev | |
156 | * 7 [ ] OK ethernet dsa-test@1.bootdev | |
157 | * 8 [ ] OK mmc mmc2.bootdev | |
158 | * 9 [ + ] OK mmc mmc1.bootdev | |
159 | * a [ ] OK mmc mmc0.bootdev | |
160 | */ | |
161 | console_record_reset_enable(); | |
162 | ut_assertok(bootdev_find_by_any("8", &dev, &mflags)); | |
163 | ut_asserteq(UCLASS_BOOTDEV, device_get_uclass_id(dev)); | |
164 | ut_asserteq(BOOTFLOW_METHF_SINGLE_DEV, mflags); | |
165 | media = dev_get_parent(dev); | |
166 | ut_asserteq(UCLASS_MMC, device_get_uclass_id(media)); | |
167 | ut_asserteq_str("mmc2", media->name); | |
168 | ut_assert_console_end(); | |
169 | ||
170 | /* there should not be this many bootdevs */ | |
171 | ut_asserteq(-ENODEV, bootdev_find_by_any("50", &dev, &mflags)); | |
172 | ut_assert_nextline("Cannot find '50' (err=-19)"); | |
173 | ut_assert_console_end(); | |
174 | ||
175 | /* Check method flags */ | |
176 | ut_assertok(bootdev_find_by_any("pxe", &dev, &mflags)); | |
177 | ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS | BOOTFLOW_METHF_PXE_ONLY, | |
178 | mflags); | |
179 | ||
180 | /* Check invalid uclass */ | |
181 | mflags = 123; | |
1736b4af SG |
182 | ut_asserteq(-EPFNOSUPPORT, bootdev_find_by_any("fred0", &dev, &mflags)); |
183 | ut_assert_nextline("Cannot find bootdev 'fred0' (err=-96)"); | |
66e3dce7 SG |
184 | ut_asserteq(123, mflags); |
185 | ut_assert_console_end(); | |
186 | ||
187 | return 0; | |
188 | } | |
189 | BOOTSTD_TEST(bootdev_test_any, UT_TESTF_DM | UT_TESTF_SCAN_FDT | | |
190 | UT_TESTF_ETH_BOOTDEV); | |
191 | ||
7ae83bfa SG |
192 | /* |
193 | * Check bootdev ordering with the bootdev-order property and boot_targets | |
194 | * environment variable | |
195 | */ | |
fb1451be SG |
196 | static int bootdev_test_order(struct unit_test_state *uts) |
197 | { | |
198 | struct bootflow_iter iter; | |
199 | struct bootflow bflow; | |
200 | ||
7ae83bfa SG |
201 | test_set_skip_delays(true); |
202 | ||
203 | /* Start up USB which gives us three additional bootdevs */ | |
204 | usb_started = false; | |
205 | ut_assertok(run_command("usb start", 0)); | |
206 | ||
fb1451be SG |
207 | /* |
208 | * First try the order set by the bootdev-order property | |
209 | * Like all sandbox unit tests this relies on the devicetree setting up | |
210 | * the required devices: | |
211 | * | |
212 | * mmc0 - nothing connected | |
213 | * mmc1 - connected to mmc1.img file | |
214 | * mmc2 - nothing connected | |
215 | */ | |
216 | ut_assertok(env_set("boot_targets", NULL)); | |
4b7cb058 | 217 | ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow)); |
fb1451be | 218 | ut_asserteq(2, iter.num_devs); |
a950f285 SG |
219 | ut_asserteq_str("mmc2.bootdev", iter.dev_used[0]->name); |
220 | ut_asserteq_str("mmc1.bootdev", iter.dev_used[1]->name); | |
fb1451be SG |
221 | bootflow_iter_uninit(&iter); |
222 | ||
223 | /* Use the environment variable to override it */ | |
7ae83bfa | 224 | ut_assertok(env_set("boot_targets", "mmc1 mmc2 usb")); |
4b7cb058 | 225 | ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow)); |
a950f285 | 226 | ut_asserteq(-ENODEV, bootflow_scan_next(&iter, &bflow)); |
7a790f01 | 227 | ut_asserteq(5, iter.num_devs); |
a950f285 SG |
228 | ut_asserteq_str("mmc1.bootdev", iter.dev_used[0]->name); |
229 | ut_asserteq_str("mmc2.bootdev", iter.dev_used[1]->name); | |
7ae83bfa SG |
230 | ut_asserteq_str("usb_mass_storage.lun0.bootdev", |
231 | iter.dev_used[2]->name); | |
fb1451be SG |
232 | bootflow_iter_uninit(&iter); |
233 | ||
16e19350 SG |
234 | /* Try a single uclass */ |
235 | ut_assertok(env_set("boot_targets", NULL)); | |
236 | ut_assertok(bootflow_scan_first(NULL, "mmc", &iter, 0, &bflow)); | |
237 | ut_asserteq(2, iter.num_devs); | |
238 | ||
7a790f01 SG |
239 | /* Now scan past mmc1 and make sure that only mmc0 shows up */ |
240 | ut_asserteq(-ENODEV, bootflow_scan_next(&iter, &bflow)); | |
241 | ut_asserteq(3, iter.num_devs); | |
242 | ut_asserteq_str("mmc2.bootdev", iter.dev_used[0]->name); | |
243 | ut_asserteq_str("mmc1.bootdev", iter.dev_used[1]->name); | |
244 | ut_asserteq_str("mmc0.bootdev", iter.dev_used[2]->name); | |
245 | bootflow_iter_uninit(&iter); | |
246 | ||
247 | /* Try a single uclass with boot_targets */ | |
248 | ut_assertok(env_set("boot_targets", "mmc")); | |
249 | ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow)); | |
250 | ut_asserteq(2, iter.num_devs); | |
251 | ||
252 | /* Now scan past mmc1 and make sure that only mmc0 shows up */ | |
16e19350 SG |
253 | ut_asserteq(-ENODEV, bootflow_scan_next(&iter, &bflow)); |
254 | ut_asserteq(3, iter.num_devs); | |
255 | ut_asserteq_str("mmc2.bootdev", iter.dev_used[0]->name); | |
256 | ut_asserteq_str("mmc1.bootdev", iter.dev_used[1]->name); | |
257 | ut_asserteq_str("mmc0.bootdev", iter.dev_used[2]->name); | |
258 | bootflow_iter_uninit(&iter); | |
259 | ||
7a790f01 SG |
260 | /* Try a single uclass with boot_targets */ |
261 | ut_assertok(env_set("boot_targets", "mmc usb")); | |
262 | ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow)); | |
263 | ut_asserteq(2, iter.num_devs); | |
264 | ||
265 | /* Now scan past mmc1 and make sure that the 3 USB devices show up */ | |
266 | ut_asserteq(-ENODEV, bootflow_scan_next(&iter, &bflow)); | |
267 | ut_asserteq(6, iter.num_devs); | |
268 | ut_asserteq_str("mmc2.bootdev", iter.dev_used[0]->name); | |
269 | ut_asserteq_str("mmc1.bootdev", iter.dev_used[1]->name); | |
270 | ut_asserteq_str("mmc0.bootdev", iter.dev_used[2]->name); | |
271 | ut_asserteq_str("usb_mass_storage.lun0.bootdev", | |
272 | iter.dev_used[3]->name); | |
273 | bootflow_iter_uninit(&iter); | |
274 | ||
a950f285 SG |
275 | return 0; |
276 | } | |
277 | BOOTSTD_TEST(bootdev_test_order, UT_TESTF_DM | UT_TESTF_SCAN_FDT); | |
278 | ||
279 | /* Check default bootdev ordering */ | |
280 | static int bootdev_test_order_default(struct unit_test_state *uts) | |
281 | { | |
282 | struct bootflow_iter iter; | |
283 | struct bootflow bflow; | |
284 | ||
fb1451be SG |
285 | /* |
286 | * Now drop both orderings, to check the default (prioriy/sequence) | |
287 | * ordering | |
288 | */ | |
289 | ut_assertok(env_set("boot_targets", NULL)); | |
290 | ut_assertok(bootstd_test_drop_bootdev_order(uts)); | |
291 | ||
4b7cb058 | 292 | ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow)); |
a950f285 SG |
293 | ut_asserteq(2, iter.num_devs); |
294 | ut_asserteq_str("mmc2.bootdev", iter.dev_used[0]->name); | |
295 | ut_asserteq_str("mmc1.bootdev", iter.dev_used[1]->name); | |
fb1451be | 296 | |
a950f285 | 297 | ut_asserteq(-ENODEV, bootflow_scan_next(&iter, &bflow)); |
fb1451be | 298 | ut_asserteq(3, iter.num_devs); |
a950f285 | 299 | ut_asserteq_str("mmc0.bootdev", iter.dev_used[2]->name); |
fb1451be SG |
300 | bootflow_iter_uninit(&iter); |
301 | ||
302 | return 0; | |
303 | } | |
a950f285 | 304 | BOOTSTD_TEST(bootdev_test_order_default, UT_TESTF_DM | UT_TESTF_SCAN_FDT); |
fb1451be SG |
305 | |
306 | /* Check bootdev ordering with the uclass priority */ | |
307 | static int bootdev_test_prio(struct unit_test_state *uts) | |
308 | { | |
309 | struct bootdev_uc_plat *ucp; | |
310 | struct bootflow_iter iter; | |
311 | struct bootflow bflow; | |
312 | struct udevice *blk; | |
313 | ||
04fb2b6e SG |
314 | test_set_skip_delays(true); |
315 | ||
a950f285 SG |
316 | /* disable ethernet since the hunter will run dhcp */ |
317 | test_set_eth_enable(false); | |
318 | ||
fb1451be SG |
319 | /* Start up USB which gives us three additional bootdevs */ |
320 | usb_started = false; | |
321 | ut_assertok(run_command("usb start", 0)); | |
322 | ||
323 | ut_assertok(bootstd_test_drop_bootdev_order(uts)); | |
324 | ||
325 | /* 3 MMC and 3 USB bootdevs: MMC should come before USB */ | |
326 | console_record_reset_enable(); | |
4b7cb058 | 327 | ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow)); |
a950f285 | 328 | ut_asserteq(-ENODEV, bootflow_scan_next(&iter, &bflow)); |
fb1451be | 329 | ut_asserteq(6, iter.num_devs); |
a950f285 | 330 | ut_asserteq_str("mmc2.bootdev", iter.dev_used[0]->name); |
fb1451be | 331 | ut_asserteq_str("usb_mass_storage.lun0.bootdev", |
a950f285 | 332 | iter.dev_used[3]->name); |
fb1451be | 333 | |
a950f285 | 334 | ut_assertok(bootdev_get_sibling_blk(iter.dev_used[3], &blk)); |
fb1451be SG |
335 | ut_asserteq_str("usb_mass_storage.lun0", blk->name); |
336 | ||
337 | /* adjust the priority of the first USB bootdev to the highest */ | |
a950f285 SG |
338 | ucp = dev_get_uclass_plat(iter.dev_used[3]); |
339 | ucp->prio = BOOTDEVP_1_PRE_SCAN; | |
fb1451be | 340 | |
a950f285 | 341 | /* try again but enable hunting, which brings in SCSI */ |
fb1451be | 342 | bootflow_iter_uninit(&iter); |
4f806f31 | 343 | ut_assertok(bootflow_scan_first(NULL, NULL, &iter, BOOTFLOWIF_HUNT, |
4b7cb058 | 344 | &bflow)); |
a950f285 SG |
345 | ut_asserteq(-ENODEV, bootflow_scan_next(&iter, &bflow)); |
346 | ut_asserteq(7, iter.num_devs); | |
fb1451be | 347 | ut_asserteq_str("usb_mass_storage.lun0.bootdev", |
a950f285 SG |
348 | iter.dev_used[0]->name); |
349 | ut_asserteq_str("mmc2.bootdev", iter.dev_used[1]->name); | |
fb1451be SG |
350 | |
351 | return 0; | |
352 | } | |
353 | BOOTSTD_TEST(bootdev_test_prio, UT_TESTF_DM | UT_TESTF_SCAN_FDT); | |
bd90b092 SG |
354 | |
355 | /* Check listing hunters */ | |
356 | static int bootdev_test_hunter(struct unit_test_state *uts) | |
357 | { | |
358 | struct bootstd_priv *std; | |
359 | ||
8c29b732 | 360 | usb_started = false; |
04fb2b6e SG |
361 | test_set_skip_delays(true); |
362 | ||
bd90b092 SG |
363 | /* get access to the used hunters */ |
364 | ut_assertok(bootstd_get_priv(&std)); | |
365 | ||
366 | console_record_reset_enable(); | |
367 | bootdev_list_hunters(std); | |
368 | ut_assert_nextline("Prio Used Uclass Hunter"); | |
369 | ut_assert_nextlinen("----"); | |
eacc2611 | 370 | ut_assert_nextline(" 6 ethernet eth_bootdev"); |
18552d2a | 371 | ut_assert_nextline(" 1 simple_bus (none)"); |
eacc2611 SG |
372 | ut_assert_nextline(" 5 ide ide_bootdev"); |
373 | ut_assert_nextline(" 2 mmc mmc_bootdev"); | |
374 | ut_assert_nextline(" 4 nvme nvme_bootdev"); | |
662cfa03 | 375 | ut_assert_nextline(" 4 qfw qfw_bootdev"); |
eacc2611 SG |
376 | ut_assert_nextline(" 4 scsi scsi_bootdev"); |
377 | ut_assert_nextline(" 4 spi_flash sf_bootdev"); | |
378 | ut_assert_nextline(" 5 usb usb_bootdev"); | |
379 | ut_assert_nextline(" 4 virtio virtio_bootdev"); | |
662cfa03 | 380 | ut_assert_nextline("(total hunters: 10)"); |
bd90b092 SG |
381 | ut_assert_console_end(); |
382 | ||
04fb2b6e SG |
383 | ut_assertok(bootdev_hunt("usb1", false)); |
384 | ut_assert_nextline( | |
385 | "Bus usb@1: scanning bus usb@1 for devices... 5 USB Device(s) found"); | |
c7b63d50 SG |
386 | ut_assert_console_end(); |
387 | ||
662cfa03 SG |
388 | /* USB is 7th in the list, so bit 8 */ |
389 | ut_asserteq(BIT(8), std->hunters_used); | |
04fb2b6e | 390 | |
bd90b092 SG |
391 | return 0; |
392 | } | |
393 | BOOTSTD_TEST(bootdev_test_hunter, UT_TESTF_DM | UT_TESTF_SCAN_FDT); | |
394 | ||
395 | /* Check 'bootdev hunt' command */ | |
396 | static int bootdev_test_cmd_hunt(struct unit_test_state *uts) | |
397 | { | |
398 | struct bootstd_priv *std; | |
399 | ||
04fb2b6e | 400 | test_set_skip_delays(true); |
8c29b732 | 401 | usb_started = false; |
04fb2b6e | 402 | |
bd90b092 SG |
403 | /* get access to the used hunters */ |
404 | ut_assertok(bootstd_get_priv(&std)); | |
405 | ||
406 | console_record_reset_enable(); | |
407 | ut_assertok(run_command("bootdev hunt -l", 0)); | |
408 | ut_assert_nextline("Prio Used Uclass Hunter"); | |
409 | ut_assert_nextlinen("----"); | |
eacc2611 | 410 | ut_assert_nextline(" 6 ethernet eth_bootdev"); |
662cfa03 | 411 | ut_assert_skip_to_line("(total hunters: 10)"); |
eacc2611 SG |
412 | ut_assert_console_end(); |
413 | ||
414 | /* Use the MMC hunter and see that it updates */ | |
415 | ut_assertok(run_command("bootdev hunt mmc", 0)); | |
416 | ut_assertok(run_command("bootdev hunt -l", 0)); | |
417 | ut_assert_skip_to_line(" 5 ide ide_bootdev"); | |
418 | ut_assert_nextline(" 2 * mmc mmc_bootdev"); | |
662cfa03 | 419 | ut_assert_skip_to_line("(total hunters: 10)"); |
bd90b092 SG |
420 | ut_assert_console_end(); |
421 | ||
422 | /* Scan all hunters */ | |
e4b69489 | 423 | test_set_eth_enable(false); |
eacc2611 | 424 | test_set_skip_delays(true); |
bd90b092 | 425 | ut_assertok(run_command("bootdev hunt", 0)); |
4146c823 | 426 | ut_assert_nextline("Hunting with: ethernet"); |
18552d2a SG |
427 | |
428 | /* This is the extension feature which has no uclass at present */ | |
429 | ut_assert_nextline("Hunting with: simple_bus"); | |
430 | ut_assert_nextline("Found 2 extension board(s)."); | |
0d77f8f1 | 431 | ut_assert_nextline("Hunting with: ide"); |
eacc2611 SG |
432 | |
433 | /* mmc hunter has already been used so should not run again */ | |
434 | ||
758c706c | 435 | ut_assert_nextline("Hunting with: nvme"); |
662cfa03 | 436 | ut_assert_nextline("Hunting with: qfw"); |
8f090b67 SG |
437 | ut_assert_nextline("Hunting with: scsi"); |
438 | ut_assert_nextline("scanning bus for devices..."); | |
0c1f4a9f SG |
439 | ut_assert_skip_to_line("Hunting with: spi_flash"); |
440 | ut_assert_nextline("Hunting with: usb"); | |
04fb2b6e SG |
441 | ut_assert_nextline( |
442 | "Bus usb@1: scanning bus usb@1 for devices... 5 USB Device(s) found"); | |
0c1f4a9f | 443 | ut_assert_nextline("Hunting with: virtio"); |
bd90b092 SG |
444 | ut_assert_console_end(); |
445 | ||
446 | /* List available hunters */ | |
447 | ut_assertok(run_command("bootdev hunt -l", 0)); | |
448 | ut_assert_nextlinen("Prio"); | |
449 | ut_assert_nextlinen("----"); | |
eacc2611 | 450 | ut_assert_nextline(" 6 * ethernet eth_bootdev"); |
18552d2a | 451 | ut_assert_nextline(" 1 * simple_bus (none)"); |
eacc2611 SG |
452 | ut_assert_nextline(" 5 * ide ide_bootdev"); |
453 | ut_assert_nextline(" 2 * mmc mmc_bootdev"); | |
454 | ut_assert_nextline(" 4 * nvme nvme_bootdev"); | |
662cfa03 | 455 | ut_assert_nextline(" 4 * qfw qfw_bootdev"); |
eacc2611 SG |
456 | ut_assert_nextline(" 4 * scsi scsi_bootdev"); |
457 | ut_assert_nextline(" 4 * spi_flash sf_bootdev"); | |
458 | ut_assert_nextline(" 5 * usb usb_bootdev"); | |
459 | ut_assert_nextline(" 4 * virtio virtio_bootdev"); | |
662cfa03 | 460 | ut_assert_nextline("(total hunters: 10)"); |
bd90b092 SG |
461 | ut_assert_console_end(); |
462 | ||
18552d2a | 463 | ut_asserteq(GENMASK(MAX_HUNTER, 0), std->hunters_used); |
bd90b092 SG |
464 | |
465 | return 0; | |
466 | } | |
467 | BOOTSTD_TEST(bootdev_test_cmd_hunt, UT_TESTF_DM | UT_TESTF_SCAN_FDT | | |
468 | UT_TESTF_ETH_BOOTDEV); | |
f0e358f0 | 469 | |
47aedc29 SG |
470 | /* Check searching for bootdevs using the hunters */ |
471 | static int bootdev_test_hunt_scan(struct unit_test_state *uts) | |
472 | { | |
473 | struct bootflow_iter iter; | |
474 | struct bootstd_priv *std; | |
475 | struct bootflow bflow; | |
476 | ||
477 | /* get access to the used hunters */ | |
478 | ut_assertok(bootstd_get_priv(&std)); | |
479 | ||
480 | ut_assertok(bootstd_test_drop_bootdev_order(uts)); | |
4b7cb058 | 481 | ut_assertok(bootflow_scan_first(NULL, NULL, &iter, |
4f806f31 SG |
482 | BOOTFLOWIF_SHOW | BOOTFLOWIF_HUNT | |
483 | BOOTFLOWIF_SKIP_GLOBAL, &bflow)); | |
47aedc29 SG |
484 | ut_asserteq(BIT(MMC_HUNTER) | BIT(1), std->hunters_used); |
485 | ||
486 | return 0; | |
487 | } | |
488 | BOOTSTD_TEST(bootdev_test_hunt_scan, UT_TESTF_DM | UT_TESTF_SCAN_FDT); | |
489 | ||
f0e358f0 SG |
490 | /* Check that only bootable partitions are processed */ |
491 | static int bootdev_test_bootable(struct unit_test_state *uts) | |
492 | { | |
493 | struct bootflow_iter iter; | |
494 | struct bootflow bflow; | |
495 | struct udevice *blk; | |
496 | ||
497 | memset(&iter, '\0', sizeof(iter)); | |
498 | memset(&bflow, '\0', sizeof(bflow)); | |
499 | iter.part = 0; | |
500 | ut_assertok(uclass_get_device_by_name(UCLASS_BLK, "mmc1.blk", &blk)); | |
501 | iter.dev = blk; | |
502 | ut_assertok(device_find_next_child(&iter.dev)); | |
503 | uclass_first_device(UCLASS_BOOTMETH, &bflow.method); | |
504 | ||
505 | /* | |
506 | * initially we don't have any knowledge of which partitions are | |
507 | * bootable, but mmc1 has two partitions, with the first one being | |
508 | * bootable | |
509 | */ | |
510 | iter.part = 2; | |
511 | ut_asserteq(-EINVAL, bootdev_find_in_blk(iter.dev, blk, &iter, &bflow)); | |
512 | ut_asserteq(0, iter.first_bootable); | |
513 | ||
514 | /* scan with part == 0 to get the partition info */ | |
515 | iter.part = 0; | |
516 | ut_asserteq(-ENOENT, bootdev_find_in_blk(iter.dev, blk, &iter, &bflow)); | |
517 | ut_asserteq(1, iter.first_bootable); | |
518 | ||
519 | /* now it will refuse to use non-bootable partitions */ | |
520 | iter.part = 2; | |
521 | ut_asserteq(-EINVAL, bootdev_find_in_blk(iter.dev, blk, &iter, &bflow)); | |
522 | ||
523 | return 0; | |
524 | } | |
525 | BOOTSTD_TEST(bootdev_test_bootable, UT_TESTF_DM | UT_TESTF_SCAN_FDT); | |
79a7d4a6 SG |
526 | |
527 | /* Check hunting for bootdev of a particular priority */ | |
528 | static int bootdev_test_hunt_prio(struct unit_test_state *uts) | |
529 | { | |
8c29b732 | 530 | usb_started = false; |
79a7d4a6 SG |
531 | test_set_skip_delays(true); |
532 | ||
533 | console_record_reset_enable(); | |
eacc2611 | 534 | ut_assertok(bootdev_hunt_prio(BOOTDEVP_4_SCAN_FAST, false)); |
79a7d4a6 SG |
535 | ut_assert_nextline("scanning bus for devices..."); |
536 | ut_assert_skip_to_line(" Type: Hard Disk"); | |
537 | ut_assert_nextlinen(" Capacity:"); | |
538 | ut_assert_console_end(); | |
539 | ||
540 | /* now try a different priority, verbosely */ | |
eacc2611 | 541 | ut_assertok(bootdev_hunt_prio(BOOTDEVP_5_SCAN_SLOW, true)); |
79a7d4a6 | 542 | ut_assert_nextline("Hunting with: ide"); |
79a7d4a6 SG |
543 | ut_assert_nextline("Hunting with: usb"); |
544 | ut_assert_nextline( | |
545 | "Bus usb@1: scanning bus usb@1 for devices... 5 USB Device(s) found"); | |
546 | ut_assert_console_end(); | |
547 | ||
548 | return 0; | |
549 | } | |
550 | BOOTSTD_TEST(bootdev_test_hunt_prio, UT_TESTF_DM | UT_TESTF_SCAN_FDT); | |
66e3dce7 SG |
551 | |
552 | /* Check hunting for bootdevs with a particular label */ | |
553 | static int bootdev_test_hunt_label(struct unit_test_state *uts) | |
554 | { | |
555 | struct udevice *dev, *old; | |
556 | struct bootstd_priv *std; | |
557 | int mflags; | |
558 | ||
8c29b732 SG |
559 | usb_started = false; |
560 | ||
66e3dce7 SG |
561 | /* get access to the used hunters */ |
562 | ut_assertok(bootstd_get_priv(&std)); | |
563 | ||
564 | /* scan an unknown uclass */ | |
565 | console_record_reset_enable(); | |
566 | old = (void *)&mflags; /* arbitrary pointer to check against dev */ | |
567 | dev = old; | |
568 | mflags = 123; | |
1736b4af | 569 | ut_asserteq(-EPFNOSUPPORT, |
66e3dce7 | 570 | bootdev_hunt_and_find_by_label("fred", &dev, &mflags)); |
66e3dce7 SG |
571 | ut_asserteq_ptr(old, dev); |
572 | ut_asserteq(123, mflags); | |
573 | ut_assert_console_end(); | |
574 | ut_asserteq(0, std->hunters_used); | |
575 | ||
576 | /* scan an invalid mmc controllers */ | |
577 | ut_asserteq(-ENOENT, | |
578 | bootdev_hunt_and_find_by_label("mmc4", &dev, &mflags)); | |
579 | ut_asserteq_ptr(old, dev); | |
580 | ut_asserteq(123, mflags); | |
66e3dce7 SG |
581 | ut_assert_console_end(); |
582 | ||
583 | ut_assertok(bootstd_test_check_mmc_hunter(uts)); | |
584 | ||
585 | /* scan for a particular mmc controller */ | |
586 | ut_assertok(bootdev_hunt_and_find_by_label("mmc1", &dev, &mflags)); | |
587 | ut_assertnonnull(dev); | |
588 | ut_asserteq_str("mmc1.bootdev", dev->name); | |
589 | ut_asserteq(0, mflags); | |
590 | ut_assert_console_end(); | |
591 | ||
592 | /* scan all of usb */ | |
593 | test_set_skip_delays(true); | |
594 | ut_assertok(bootdev_hunt_and_find_by_label("usb", &dev, &mflags)); | |
595 | ut_assertnonnull(dev); | |
596 | ut_asserteq_str("usb_mass_storage.lun0.bootdev", dev->name); | |
597 | ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS, mflags); | |
598 | ut_assert_nextlinen("Bus usb@1: scanning bus usb@1"); | |
599 | ut_assert_console_end(); | |
600 | ||
601 | return 0; | |
602 | } | |
603 | BOOTSTD_TEST(bootdev_test_hunt_label, UT_TESTF_DM | UT_TESTF_SCAN_FDT); | |
e4b69489 SG |
604 | |
605 | /* Check iterating to the next label in a list */ | |
606 | static int bootdev_test_next_label(struct unit_test_state *uts) | |
607 | { | |
608 | const char *const labels[] = {"mmc0", "scsi", "dhcp", "pxe", NULL}; | |
609 | struct bootflow_iter iter; | |
610 | struct bootstd_priv *std; | |
611 | struct bootflow bflow; | |
612 | struct udevice *dev; | |
613 | int mflags; | |
614 | ||
615 | test_set_eth_enable(false); | |
616 | ||
617 | /* get access to the used hunters */ | |
618 | ut_assertok(bootstd_get_priv(&std)); | |
619 | ||
620 | memset(&iter, '\0', sizeof(iter)); | |
621 | memset(&bflow, '\0', sizeof(bflow)); | |
622 | iter.part = 0; | |
623 | uclass_first_device(UCLASS_BOOTMETH, &bflow.method); | |
624 | iter.cur_label = -1; | |
625 | iter.labels = labels; | |
626 | ||
627 | dev = NULL; | |
628 | mflags = 123; | |
629 | ut_assertok(bootdev_next_label(&iter, &dev, &mflags)); | |
630 | console_record_reset_enable(); | |
631 | ut_assert_console_end(); | |
632 | ut_assertnonnull(dev); | |
633 | ut_asserteq_str("mmc0.bootdev", dev->name); | |
634 | ut_asserteq(0, mflags); | |
635 | ||
636 | ut_assertok(bootstd_test_check_mmc_hunter(uts)); | |
637 | ||
638 | ut_assertok(bootdev_next_label(&iter, &dev, &mflags)); | |
639 | ut_assert_nextline("scanning bus for devices..."); | |
640 | ut_assert_skip_to_line( | |
641 | " Capacity: 1.9 MB = 0.0 GB (4095 x 512)"); | |
642 | ut_assert_console_end(); | |
643 | ut_assertnonnull(dev); | |
644 | ut_asserteq_str("scsi.id0lun0.bootdev", dev->name); | |
645 | ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS, mflags); | |
646 | ||
662cfa03 SG |
647 | /* SCSI is 7th in the list, so bit 6 */ |
648 | ut_asserteq(BIT(MMC_HUNTER) | BIT(6), std->hunters_used); | |
e4b69489 SG |
649 | |
650 | ut_assertok(bootdev_next_label(&iter, &dev, &mflags)); | |
651 | ut_assert_console_end(); | |
652 | ut_assertnonnull(dev); | |
653 | ut_asserteq_str("eth@10002000.bootdev", dev->name); | |
654 | ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS | BOOTFLOW_METHF_DHCP_ONLY, | |
655 | mflags); | |
656 | ||
657 | /* dhcp: Ethernet is first so bit 0 */ | |
662cfa03 | 658 | ut_asserteq(BIT(MMC_HUNTER) | BIT(6) | BIT(0), std->hunters_used); |
e4b69489 SG |
659 | |
660 | ut_assertok(bootdev_next_label(&iter, &dev, &mflags)); | |
661 | ut_assert_console_end(); | |
662 | ut_assertnonnull(dev); | |
663 | ut_asserteq_str("eth@10002000.bootdev", dev->name); | |
664 | ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS | BOOTFLOW_METHF_PXE_ONLY, | |
665 | mflags); | |
666 | ||
667 | /* pxe: Ethernet is first so bit 0 */ | |
662cfa03 | 668 | ut_asserteq(BIT(MMC_HUNTER) | BIT(6) | BIT(0), std->hunters_used); |
e4b69489 SG |
669 | |
670 | mflags = 123; | |
671 | ut_asserteq(-ENODEV, bootdev_next_label(&iter, &dev, &mflags)); | |
672 | ut_asserteq(123, mflags); | |
673 | ut_assert_console_end(); | |
674 | ||
675 | /* no change */ | |
662cfa03 | 676 | ut_asserteq(BIT(MMC_HUNTER) | BIT(6) | BIT(0), std->hunters_used); |
e4b69489 SG |
677 | |
678 | return 0; | |
679 | } | |
680 | BOOTSTD_TEST(bootdev_test_next_label, UT_TESTF_DM | UT_TESTF_SCAN_FDT | | |
681 | UT_TESTF_ETH_BOOTDEV | UT_TESTF_SF_BOOTDEV); | |
43e89a30 SG |
682 | |
683 | ||
684 | /* Check iterating to the next prioirty in a list */ | |
685 | static int bootdev_test_next_prio(struct unit_test_state *uts) | |
686 | { | |
687 | struct bootflow_iter iter; | |
688 | struct bootstd_priv *std; | |
689 | struct bootflow bflow; | |
690 | struct udevice *dev; | |
691 | int ret; | |
692 | ||
91943ff7 | 693 | test_set_eth_enable(false); |
43e89a30 SG |
694 | test_set_skip_delays(true); |
695 | ||
696 | /* get access to the used hunters */ | |
697 | ut_assertok(bootstd_get_priv(&std)); | |
698 | ||
699 | memset(&iter, '\0', sizeof(iter)); | |
700 | memset(&bflow, '\0', sizeof(bflow)); | |
701 | iter.part = 0; | |
702 | uclass_first_device(UCLASS_BOOTMETH, &bflow.method); | |
703 | iter.cur_prio = 0; | |
4f806f31 | 704 | iter.flags = BOOTFLOWIF_SHOW; |
43e89a30 SG |
705 | |
706 | dev = NULL; | |
707 | console_record_reset_enable(); | |
708 | ut_assertok(bootdev_next_prio(&iter, &dev)); | |
709 | ut_assertnonnull(dev); | |
710 | ut_asserteq_str("mmc2.bootdev", dev->name); | |
711 | ||
712 | /* hunt flag not set, so this should not use any hunters */ | |
713 | ut_asserteq(0, std->hunters_used); | |
714 | ut_assert_console_end(); | |
715 | ||
716 | /* now try again with hunting enabled */ | |
4f806f31 | 717 | iter.flags = BOOTFLOWIF_SHOW | BOOTFLOWIF_HUNT; |
43e89a30 SG |
718 | iter.cur_prio = 0; |
719 | iter.part = 0; | |
720 | ||
721 | ut_assertok(bootdev_next_prio(&iter, &dev)); | |
722 | ut_asserteq_str("mmc2.bootdev", dev->name); | |
18552d2a SG |
723 | ut_assert_nextline("Hunting with: simple_bus"); |
724 | ut_assert_nextline("Found 2 extension board(s)."); | |
43e89a30 SG |
725 | ut_assert_nextline("Hunting with: mmc"); |
726 | ut_assert_console_end(); | |
727 | ||
18552d2a | 728 | ut_asserteq(BIT(MMC_HUNTER) | BIT(1), std->hunters_used); |
43e89a30 SG |
729 | |
730 | ut_assertok(bootdev_next_prio(&iter, &dev)); | |
731 | ut_asserteq_str("mmc1.bootdev", dev->name); | |
732 | ||
733 | ut_assertok(bootdev_next_prio(&iter, &dev)); | |
734 | ut_asserteq_str("mmc0.bootdev", dev->name); | |
735 | ut_assert_console_end(); | |
736 | ||
737 | ut_assertok(bootdev_next_prio(&iter, &dev)); | |
738 | ut_asserteq_str("spi.bin@0.bootdev", dev->name); | |
739 | ut_assert_skip_to_line("Hunting with: spi_flash"); | |
740 | ||
741 | /* | |
742 | * this scans all bootdevs of priority BOOTDEVP_4_SCAN_FAST before it | |
743 | * starts looking at the devices, so we se virtio as well | |
744 | */ | |
745 | ut_assert_nextline("Hunting with: virtio"); | |
746 | ut_assert_nextlinen("SF: Detected m25p16"); | |
747 | ||
748 | ut_assertok(bootdev_next_prio(&iter, &dev)); | |
749 | ut_asserteq_str("spi.bin@1.bootdev", dev->name); | |
750 | ut_assert_nextlinen("SF: Detected m25p16"); | |
751 | ut_assert_console_end(); | |
752 | ||
753 | /* keep going until there are no more bootdevs */ | |
754 | do { | |
755 | ret = bootdev_next_prio(&iter, &dev); | |
756 | } while (!ret); | |
757 | ut_asserteq(-ENODEV, ret); | |
758 | ut_assertnull(dev); | |
18552d2a | 759 | ut_asserteq(GENMASK(MAX_HUNTER, 0), std->hunters_used); |
43e89a30 SG |
760 | |
761 | ut_assert_skip_to_line("Hunting with: ethernet"); | |
762 | ut_assert_console_end(); | |
763 | ||
764 | return 0; | |
765 | } | |
766 | BOOTSTD_TEST(bootdev_test_next_prio, UT_TESTF_DM | UT_TESTF_SCAN_FDT | | |
767 | UT_TESTF_SF_BOOTDEV); |