"Das U-Boot" Source Tree
at jcs/rk3128 950 lines 23 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright 2021 Google LLC 4 * Written by Simon Glass <sjg@chromium.org> 5 */ 6 7#define LOG_CATEGORY UCLASS_BOOTSTD 8 9#include <dm.h> 10#include <bootdev.h> 11#include <bootflow.h> 12#include <bootmeth.h> 13#include <bootstd.h> 14#include <fs.h> 15#include <log.h> 16#include <malloc.h> 17#include <part.h> 18#include <sort.h> 19#include <spl.h> 20#include <dm/device-internal.h> 21#include <dm/lists.h> 22#include <dm/uclass-internal.h> 23 24enum { 25 /* 26 * Set some sort of limit on the number of partitions a bootdev can 27 * have. Note that for disks this limits the partitions numbers that 28 * are scanned to 1..MAX_BOOTFLOWS_PER_BOOTDEV 29 */ 30 MAX_PART_PER_BOOTDEV = 30, 31 32 /* Maximum supported length of the "boot_targets" env string */ 33 BOOT_TARGETS_MAX_LEN = 100, 34}; 35 36int bootdev_first_bootflow(struct udevice *dev, struct bootflow **bflowp) 37{ 38 struct bootstd_priv *std; 39 struct bootflow *bflow; 40 int ret; 41 42 ret = bootstd_get_priv(&std); 43 if (ret) 44 return log_msg_ret("bff", ret); 45 46 bflow = alist_getw(&std->bootflows, 0, struct bootflow); 47 if (!bflow) 48 return -ENOENT; 49 *bflowp = bflow; 50 51 return 0; 52} 53 54int bootdev_next_bootflow(struct bootflow **bflowp) 55{ 56 struct bootstd_priv *std; 57 struct bootflow *bflow; 58 int ret; 59 60 ret = bootstd_get_priv(&std); 61 if (ret) 62 return log_msg_ret("bff", ret); 63 64 bflow = alist_nextw(&std->bootflows, *bflowp); 65 if (!bflow) 66 return -ENOENT; 67 *bflowp = bflow; 68 69 return 0; 70} 71 72int bootdev_bind(struct udevice *parent, const char *drv_name, const char *name, 73 struct udevice **devp) 74{ 75 struct udevice *dev; 76 char dev_name[30]; 77 char *str; 78 int ret; 79 80 snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name); 81 str = strdup(dev_name); 82 if (!str) 83 return -ENOMEM; 84 ret = device_bind_driver(parent, drv_name, str, &dev); 85 if (ret) 86 return ret; 87 device_set_name_alloced(dev); 88 *devp = dev; 89 90 return 0; 91} 92 93int bootdev_find_in_blk(struct udevice *dev, struct udevice *blk, 94 struct bootflow_iter *iter, struct bootflow *bflow) 95{ 96 struct bootmeth_uc_plat *plat = dev_get_uclass_plat(bflow->method); 97 bool allow_any_part = plat->flags & BOOTMETHF_ANY_PART; 98 struct blk_desc *desc = dev_get_uclass_plat(blk); 99 struct disk_partition info; 100 char partstr[20]; 101 char name[60]; 102 int ret; 103 104 /* Sanity check */ 105 if (iter->part >= MAX_PART_PER_BOOTDEV) 106 return log_msg_ret("max", -ESHUTDOWN); 107 108 bflow->blk = blk; 109 if (iter->part) 110 snprintf(partstr, sizeof(partstr), "part_%x", iter->part); 111 else 112 strcpy(partstr, "whole"); 113 snprintf(name, sizeof(name), "%s.%s", dev->name, partstr); 114 bflow->name = strdup(name); 115 if (!bflow->name) 116 return log_msg_ret("name", -ENOMEM); 117 118 bflow->part = iter->part; 119 120 ret = bootmeth_check(bflow->method, iter); 121 if (ret) 122 return log_msg_ret("check", ret); 123 124 /* 125 * partition numbers start at 0 so this cannot succeed, but it can tell 126 * us whether there is valid media there 127 */ 128 ret = part_get_info(desc, iter->part, &info); 129 log_debug("part_get_info() returned %d\n", ret); 130 if (!iter->part && ret == -ENOENT) 131 ret = 0; 132 133 /* 134 * This error indicates the media is not present. Otherwise we just 135 * blindly scan the next partition. We could be more intelligent here 136 * and check which partition numbers actually exist. 137 */ 138 if (ret == -EOPNOTSUPP) 139 ret = -ESHUTDOWN; 140 else 141 bflow->state = BOOTFLOWST_MEDIA; 142 if (ret && !allow_any_part) { 143 /* allow partition 1 to be missing */ 144 if (iter->part == 1) { 145 iter->max_part = 3; 146 ret = -ENOENT; 147 } 148 149 return log_msg_ret("part", ret); 150 } 151 152 /* 153 * Currently we don't get the number of partitions, so just 154 * assume a large number 155 */ 156 iter->max_part = MAX_PART_PER_BOOTDEV; 157 158 if (iter->flags & BOOTFLOWIF_SINGLE_PARTITION) { 159 /* a particular partition was specified, scan it without checking */ 160 } else if (!iter->part) { 161 /* This is the whole disk, check if we have bootable partitions */ 162 iter->first_bootable = part_get_bootable(desc); 163 log_debug("checking bootable=%d\n", iter->first_bootable); 164 } else if (allow_any_part) { 165 /* 166 * allow any partition to be scanned, by skipping any checks 167 * for filesystems or partition contents on this disk 168 */ 169 170 /* if there are bootable partitions, scan only those */ 171 } else if ((iter->flags & BOOTFLOWIF_ONLY_BOOTABLE) && 172 iter->first_bootable >= 0 && 173 (iter->first_bootable ? !info.bootable : iter->part != 1)) { 174 log_debug("Skipping non-bootable partition %d\n", iter->part); 175 return log_msg_ret("boot", -EINVAL); 176 } else { 177 ret = fs_set_blk_dev_with_part(desc, bflow->part); 178 bflow->state = BOOTFLOWST_PART; 179 if (ret) 180 return log_msg_ret("fs", ret); 181 182 log_debug("%s: Found partition %x type %x fstype %d\n", 183 blk->name, bflow->part, 184 IS_ENABLED(CONFIG_DOS_PARTITION) ? 185 disk_partition_sys_ind(&info) : 0, 186 ret ? -1 : fs_get_type()); 187 bflow->blk = blk; 188 bflow->state = BOOTFLOWST_FS; 189 } 190 191 log_debug("method %s\n", bflow->method->name); 192 ret = bootmeth_read_bootflow(bflow->method, bflow); 193 if (ret) 194 return log_msg_ret("method", ret); 195 196 return 0; 197} 198 199void bootdev_list(bool probe) 200{ 201 struct udevice *dev; 202 int ret; 203 int i; 204 205 printf("Seq Probed Status Uclass Name\n"); 206 printf("--- ------ ------ -------- ------------------\n"); 207 if (probe) 208 ret = uclass_first_device_check(UCLASS_BOOTDEV, &dev); 209 else 210 ret = uclass_find_first_device(UCLASS_BOOTDEV, &dev); 211 for (i = 0; dev; i++) { 212 printf("%3x [ %c ] %6s %-9.9s %s\n", dev_seq(dev), 213 device_active(dev) ? '+' : ' ', 214 ret ? simple_itoa(-ret) : "OK", 215 dev_get_uclass_name(dev_get_parent(dev)), dev->name); 216 if (probe) 217 ret = uclass_next_device_check(&dev); 218 else 219 ret = uclass_find_next_device(&dev); 220 } 221 printf("--- ------ ------ -------- ------------------\n"); 222 printf("(%d bootdev%s)\n", i, i != 1 ? "s" : ""); 223} 224 225int bootdev_setup_for_dev(struct udevice *parent, const char *drv_name) 226{ 227 struct udevice *bdev; 228 int ret; 229 230 ret = device_find_first_child_by_uclass(parent, UCLASS_BOOTDEV, 231 &bdev); 232 if (ret) { 233 if (ret != -ENODEV) { 234 log_debug("Cannot access bootdev device\n"); 235 return ret; 236 } 237 238 ret = bootdev_bind(parent, drv_name, "bootdev", &bdev); 239 if (ret) { 240 log_debug("Cannot create bootdev device\n"); 241 return ret; 242 } 243 } 244 245 return 0; 246} 247 248static int bootdev_get_suffix_start(struct udevice *dev, const char *suffix) 249{ 250 int len, slen; 251 252 len = strlen(dev->name); 253 slen = strlen(suffix); 254 if (len > slen && !strcmp(suffix, dev->name + len - slen)) 255 return len - slen; 256 257 return len; 258} 259 260int bootdev_setup_for_sibling_blk(struct udevice *blk, const char *drv_name) 261{ 262 struct udevice *parent, *dev; 263 char dev_name[50]; 264 int ret, len; 265 266 len = bootdev_get_suffix_start(blk, ".blk"); 267 if (xpl_phase() < PHASE_BOARD_R) { 268 strlcpy(dev_name, blk->name, sizeof(dev_name) - 5); 269 strcat(dev_name, ".sib"); 270 } else { 271 snprintf(dev_name, sizeof(dev_name), "%.*s.%s", len, blk->name, 272 "bootdev"); 273 } 274 275 parent = dev_get_parent(blk); 276 ret = device_find_child_by_name(parent, dev_name, &dev); 277 if (ret) { 278 char *str; 279 280 if (ret != -ENODEV) { 281 log_debug("Cannot access bootdev device\n"); 282 return ret; 283 } 284 str = strdup(dev_name); 285 if (!str) 286 return -ENOMEM; 287 288 ret = device_bind_driver(parent, drv_name, str, &dev); 289 if (ret) { 290 log_debug("Cannot create bootdev device\n"); 291 return ret; 292 } 293 device_set_name_alloced(dev); 294 } 295 296 return 0; 297} 298 299int bootdev_get_sibling_blk(struct udevice *dev, struct udevice **blkp) 300{ 301 struct udevice *parent = dev_get_parent(dev); 302 struct udevice *blk; 303 int ret, len; 304 305 if (device_get_uclass_id(dev) != UCLASS_BOOTDEV) 306 return -EINVAL; 307 308 /* 309 * This should always work if bootdev_setup_for_sibling_blk() was used 310 */ 311 len = bootdev_get_suffix_start(dev, ".bootdev"); 312 ret = device_find_child_by_namelen(parent, dev->name, len, &blk); 313 if (ret) { 314 char dev_name[50]; 315 316 snprintf(dev_name, sizeof(dev_name), "%.*s.blk", len, 317 dev->name); 318 ret = device_find_child_by_name(parent, dev_name, &blk); 319 if (ret) 320 return log_msg_ret("find", ret); 321 } 322 ret = device_probe(blk); 323 if (ret) 324 return log_msg_ret("act", ret); 325 *blkp = blk; 326 327 return 0; 328} 329 330int bootdev_get_from_blk(struct udevice *blk, struct udevice **bootdevp) 331{ 332 struct udevice *parent = dev_get_parent(blk); 333 struct udevice *bootdev; 334 char dev_name[50]; 335 int ret, len; 336 337 if (device_get_uclass_id(blk) != UCLASS_BLK) 338 return -EINVAL; 339 340 /* This should always work if bootdev_setup_for_sibling_blk() was used */ 341 len = bootdev_get_suffix_start(blk, ".blk"); 342 snprintf(dev_name, sizeof(dev_name), "%.*s.%s", len, blk->name, 343 "bootdev"); 344 ret = device_find_child_by_name(parent, dev_name, &bootdev); 345 if (ret) 346 return log_msg_ret("find", ret); 347 *bootdevp = bootdev; 348 349 return 0; 350} 351 352int bootdev_unbind_dev(struct udevice *parent) 353{ 354 struct udevice *dev; 355 int ret; 356 357 ret = device_find_first_child_by_uclass(parent, UCLASS_BOOTDEV, &dev); 358 if (!ret) { 359 ret = device_remove(dev, DM_REMOVE_NORMAL); 360 if (ret) 361 return log_msg_ret("rem", ret); 362 ret = device_unbind(dev); 363 if (ret) 364 return log_msg_ret("unb", ret); 365 } 366 367 return 0; 368} 369 370/** 371 * label_to_uclass() - Convert a label to a uclass and sequence number 372 * 373 * @label: Label to look up (e.g. "mmc1" or "mmc0") 374 * @seqp: Returns the sequence number, or -1 if none 375 * @method_flagsp: If non-NULL, returns any flags implied by the label 376 * (enum bootflow_meth_flags_t), 0 if none 377 * Returns: sequence number on success, -EPFNOSUPPORT is the uclass is not 378 * known, other -ve error code on other error 379 */ 380static int label_to_uclass(const char *label, int *seqp, int *method_flagsp) 381{ 382 int seq, len, method_flags; 383 enum uclass_id id; 384 const char *end; 385 386 method_flags = 0; 387 seq = trailing_strtoln_end(label, NULL, &end); 388 len = end - label; 389 if (!len) 390 return -EINVAL; 391 id = uclass_get_by_namelen(label, len); 392 log_debug("find %s: seq=%d, id=%d/%s\n", label, seq, id, 393 uclass_get_name(id)); 394 if (id == UCLASS_INVALID) { 395 /* try some special cases */ 396 if (IS_ENABLED(CONFIG_BOOTDEV_SPI_FLASH) && 397 !strncmp("spi", label, len)) { 398 id = UCLASS_SPI_FLASH; 399 } else if (IS_ENABLED(CONFIG_BOOTDEV_ETH) && 400 !strncmp("pxe", label, len)) { 401 id = UCLASS_ETH; 402 method_flags |= BOOTFLOW_METHF_PXE_ONLY; 403 } else if (IS_ENABLED(CONFIG_BOOTDEV_ETH) && 404 !strncmp("dhcp", label, len)) { 405 id = UCLASS_ETH; 406 method_flags |= BOOTFLOW_METHF_DHCP_ONLY; 407 } else { 408 return -EPFNOSUPPORT; 409 } 410 } 411 if (id == UCLASS_USB) 412 id = UCLASS_MASS_STORAGE; 413 *seqp = seq; 414 if (method_flagsp) 415 *method_flagsp = method_flags; 416 417 return id; 418} 419 420int bootdev_find_by_label(const char *label, struct udevice **devp, 421 int *method_flagsp) 422{ 423 int seq, ret, method_flags = 0; 424 struct udevice *media; 425 struct uclass *uc; 426 enum uclass_id id; 427 428 if (!CONFIG_IS_ENABLED(BLK)) 429 return -ENOSYS; 430 431 ret = label_to_uclass(label, &seq, &method_flags); 432 if (ret < 0) 433 return log_msg_ret("uc", ret); 434 id = ret; 435 436 /* Iterate through devices in the media uclass (e.g. UCLASS_MMC) */ 437 uclass_id_foreach_dev(id, media, uc) { 438 struct udevice *bdev, *blk; 439 int ret; 440 441 /* if there is no seq, match anything */ 442 if (seq != -1 && dev_seq(media) != seq) { 443 log_debug("- skip, media seq=%d\n", dev_seq(media)); 444 continue; 445 } 446 447 ret = device_find_first_child_by_uclass(media, UCLASS_BOOTDEV, 448 &bdev); 449 if (ret) { 450 log_debug("- looking via blk, seq=%d, id=%d\n", seq, 451 id); 452 ret = blk_find_device(id, seq, &blk); 453 if (!ret) { 454 log_debug("- get from blk %s\n", blk->name); 455 ret = bootdev_get_from_blk(blk, &bdev); 456 } 457 } 458 if (!ret) { 459 log_debug("- found %s\n", bdev->name); 460 *devp = bdev; 461 462 /* 463 * if no sequence number was provided, we must scan all 464 * bootdevs for this media uclass 465 */ 466 if (seq == -1) 467 method_flags |= BOOTFLOW_METHF_SINGLE_UCLASS; 468 if (method_flagsp) 469 *method_flagsp = method_flags; 470 log_debug("method flags %x\n", method_flags); 471 return 0; 472 } 473 log_debug("- no device in %s\n", media->name); 474 } 475 476 return -ENOENT; 477} 478 479int bootdev_find_by_any(const char *name, struct udevice **devp, 480 int *method_flagsp) 481{ 482 struct udevice *dev; 483 int method_flags = 0; 484 int ret = -ENODEV, seq; 485 char *endp; 486 487 seq = simple_strtol(name, &endp, 16); 488 489 /* Select by name, label or number */ 490 if (*endp) { 491 ret = uclass_get_device_by_name(UCLASS_BOOTDEV, name, &dev); 492 if (ret == -ENODEV) { 493 ret = bootdev_find_by_label(name, &dev, &method_flags); 494 if (ret) { 495 printf("Cannot find bootdev '%s' (err=%d)\n", 496 name, ret); 497 return log_msg_ret("lab", ret); 498 } 499 ret = device_probe(dev); 500 } 501 if (ret) { 502 printf("Cannot probe bootdev '%s' (err=%d)\n", name, 503 ret); 504 return log_msg_ret("pro", ret); 505 } 506 } else if (IS_ENABLED(CONFIG_BOOTSTD_FULL)) { 507 ret = uclass_get_device_by_seq(UCLASS_BOOTDEV, seq, &dev); 508 method_flags |= BOOTFLOW_METHF_SINGLE_DEV; 509 } 510 if (ret) { 511 printf("Cannot find '%s' (err=%d)\n", name, ret); 512 return ret; 513 } 514 515 *devp = dev; 516 if (method_flagsp) 517 *method_flagsp = method_flags; 518 519 return 0; 520} 521 522int bootdev_hunt_and_find_by_label(const char *label, struct udevice **devp, 523 int *method_flagsp) 524{ 525 int ret; 526 527 ret = bootdev_hunt(label, false); 528 if (ret) 529 return log_msg_ret("scn", ret); 530 ret = bootdev_find_by_label(label, devp, method_flagsp); 531 if (ret) 532 return log_msg_ret("fnd", ret); 533 534 return 0; 535} 536 537static int default_get_bootflow(struct udevice *dev, struct bootflow_iter *iter, 538 struct bootflow *bflow) 539{ 540 struct udevice *blk; 541 int ret; 542 543 ret = bootdev_get_sibling_blk(dev, &blk); 544 log_debug("sibling_blk ret=%d, blk=%s\n", ret, 545 ret ? "(none)" : blk->name); 546 /* 547 * If there is no media, indicate that no more partitions should be 548 * checked 549 */ 550 if (ret == -EOPNOTSUPP) 551 ret = -ESHUTDOWN; 552 if (ret) 553 return log_msg_ret("blk", ret); 554 assert(blk); 555 ret = bootdev_find_in_blk(dev, blk, iter, bflow); 556 if (ret) 557 return log_msg_ret("find", ret); 558 559 return 0; 560} 561 562int bootdev_get_bootflow(struct udevice *dev, struct bootflow_iter *iter, 563 struct bootflow *bflow) 564{ 565 const struct bootdev_ops *ops = bootdev_get_ops(dev); 566 567 log_debug("->get_bootflow %s,%x=%p\n", dev->name, iter->part, 568 ops->get_bootflow); 569 bootflow_init(bflow, dev, iter->method); 570 if (!ops->get_bootflow) 571 return default_get_bootflow(dev, iter, bflow); 572 573 return ops->get_bootflow(dev, iter, bflow); 574} 575 576int bootdev_next_label(struct bootflow_iter *iter, struct udevice **devp, 577 int *method_flagsp) 578{ 579 struct udevice *dev; 580 581 log_debug("next\n"); 582 if (iter->cur_label >= 0 && !iter->labels[iter->cur_label]) 583 return log_msg_ret("fil", -ENODEV); 584 585 for (dev = NULL; !dev && iter->labels[++iter->cur_label];) { 586 const char *label = iter->labels[iter->cur_label]; 587 int ret; 588 589 log_debug("Scanning: %s\n", label); 590 ret = bootdev_hunt_and_find_by_label(label, &dev, 591 method_flagsp); 592 if (iter->flags & BOOTFLOWIF_SHOW) { 593 if (ret == -EPFNOSUPPORT) { 594 log_warning("Unknown uclass '%s' in label\n", 595 label); 596 } else if (ret == -ENOENT) { 597 /* 598 * looking for, e.g. 'scsi0' should find 599 * something if SCSI is present 600 */ 601 if (!trailing_strtol(label)) { 602 log_warning("No bootdevs for '%s'\n", 603 label); 604 } 605 } 606 } 607 608 } 609 610 if (!dev) 611 return log_msg_ret("fin", -ENODEV); 612 *devp = dev; 613 614 return 0; 615} 616 617int bootdev_next_prio(struct bootflow_iter *iter, struct udevice **devp) 618{ 619 struct udevice *dev = *devp; 620 bool found; 621 int ret; 622 623 /* find the next device with this priority */ 624 *devp = NULL; 625 log_debug("next prio %d: dev=%p/%s\n", iter->cur_prio, dev, 626 dev ? dev->name : "none"); 627 found = false; 628 do { 629 /* 630 * Don't probe devices here since they may not be of the 631 * required priority 632 */ 633 if (!dev) 634 uclass_find_first_device(UCLASS_BOOTDEV, &dev); 635 else 636 uclass_find_next_device(&dev); 637 found = false; 638 639 /* scan for the next device with the correct priority */ 640 while (dev) { 641 struct bootdev_uc_plat *plat; 642 643 plat = dev_get_uclass_plat(dev); 644 log_debug("- %s: %d, want %d\n", dev->name, plat->prio, 645 iter->cur_prio); 646 if (plat->prio == iter->cur_prio) 647 break; 648 uclass_find_next_device(&dev); 649 } 650 651 /* none found for this priority, so move to the next */ 652 if (!dev) { 653 log_debug("None found at prio %d, moving to %d\n", 654 iter->cur_prio, iter->cur_prio + 1); 655 if (++iter->cur_prio == BOOTDEVP_COUNT) 656 return log_msg_ret("fin", -ENODEV); 657 658 if (iter->flags & BOOTFLOWIF_HUNT) { 659 /* hunt to find new bootdevs */ 660 ret = bootdev_hunt_prio(iter->cur_prio, 661 iter->flags & 662 BOOTFLOWIF_SHOW); 663 log_debug("- bootdev_hunt_prio() ret %d\n", 664 ret); 665 if (ret) 666 return log_msg_ret("hun", ret); 667 } 668 } else { 669 ret = device_probe(dev); 670 if (ret) 671 log_debug("Device '%s' failed to probe\n", 672 dev->name); 673 else 674 found = true; 675 } 676 } while (!found); 677 678 *devp = dev; 679 680 return 0; 681} 682 683int bootdev_setup_iter(struct bootflow_iter *iter, const char *label, 684 struct udevice **devp, int *method_flagsp) 685{ 686 struct udevice *bootstd, *dev = NULL; 687 bool show = iter->flags & BOOTFLOWIF_SHOW; 688 int method_flags; 689 char buf[32]; 690 int ret; 691 692 if (label) { 693 const char *end = strchr(label, ':'); 694 695 if (end) { 696 size_t len = (size_t)(end - label); 697 const char *part = end + 1; 698 699 if (len + 1 > sizeof(buf)) { 700 log_err("label \"%s\" is way too long\n", label); 701 return -EINVAL; 702 } 703 704 memcpy(buf, label, len); 705 buf[len] = '\0'; 706 label = buf; 707 708 unsigned long tmp; 709 710 if (strict_strtoul(part, 0, &tmp)) { 711 log_err("Invalid partition number: %s\n", part); 712 return -EINVAL; 713 } 714 715 iter->flags |= BOOTFLOWIF_SINGLE_PARTITION; 716 iter->part = tmp; 717 } 718 } 719 720 ret = uclass_first_device_err(UCLASS_BOOTSTD, &bootstd); 721 if (ret) { 722 log_err("Missing bootstd device\n"); 723 return log_msg_ret("std", ret); 724 } 725 726 /* hunt for any pre-scan devices */ 727 if (iter->flags & BOOTFLOWIF_HUNT) { 728 ret = bootdev_hunt_prio(BOOTDEVP_1_PRE_SCAN, show); 729 log_debug("- bootdev_hunt_prio() ret %d\n", ret); 730 if (ret) 731 return log_msg_ret("pre", ret); 732 } 733 734 /* Handle scanning a single device */ 735 if (IS_ENABLED(CONFIG_BOOTSTD_FULL) && label) { 736 if (iter->flags & BOOTFLOWIF_HUNT) { 737 ret = bootdev_hunt(label, show); 738 if (ret) 739 return log_msg_ret("hun", ret); 740 } 741 ret = bootdev_find_by_any(label, &dev, &method_flags); 742 if (ret) 743 return log_msg_ret("lab", ret); 744 745 log_debug("method_flags: %x\n", method_flags); 746 if (method_flags & BOOTFLOW_METHF_SINGLE_UCLASS) 747 iter->flags |= BOOTFLOWIF_SINGLE_UCLASS; 748 else if (method_flags & BOOTFLOW_METHF_SINGLE_DEV) 749 iter->flags |= BOOTFLOWIF_SINGLE_DEV; 750 else 751 iter->flags |= BOOTFLOWIF_SINGLE_MEDIA; 752 log_debug("Selected label: %s, flags %x\n", label, iter->flags); 753 } else { 754 bool ok; 755 756 /* This either returns a non-empty list or NULL */ 757 iter->labels = bootstd_get_bootdev_order(bootstd, &ok); 758 if (!ok) 759 return log_msg_ret("ord", -ENOMEM); 760 log_debug("setup labels %p\n", iter->labels); 761 if (iter->labels) { 762 iter->cur_label = -1; 763 ret = bootdev_next_label(iter, &dev, &method_flags); 764 } else { 765 ret = bootdev_next_prio(iter, &dev); 766 method_flags = 0; 767 } 768 if (!dev) 769 return log_msg_ret("fin", -ENOENT); 770 log_debug("Selected bootdev: %s\n", dev->name); 771 } 772 773 ret = device_probe(dev); 774 if (ret) 775 return log_msg_ret("probe", ret); 776 if (method_flagsp) 777 *method_flagsp = method_flags; 778 *devp = dev; 779 780 return 0; 781} 782 783static int bootdev_hunt_drv(struct bootdev_hunter *info, uint seq, bool show) 784{ 785 const char *name = uclass_get_name(info->uclass); 786 struct bootstd_priv *std; 787 int ret; 788 789 ret = bootstd_get_priv(&std); 790 if (ret) 791 return log_msg_ret("std", ret); 792 793 if (!(std->hunters_used & BIT(seq))) { 794 if (show) 795 printf("Hunting with: %s\n", 796 uclass_get_name(info->uclass)); 797 log_debug("Hunting with: %s\n", name); 798 if (info->hunt) { 799 ret = info->hunt(info, show); 800 log_debug(" - hunt result %d\n", ret); 801 if (ret && ret != -ENOENT) 802 return ret; 803 } 804 std->hunters_used |= BIT(seq); 805 } 806 807 return 0; 808} 809 810int bootdev_hunt(const char *spec, bool show) 811{ 812 struct bootdev_hunter *start; 813 const char *end; 814 int n_ent, i; 815 int result; 816 size_t len; 817 818 start = ll_entry_start(struct bootdev_hunter, bootdev_hunter); 819 n_ent = ll_entry_count(struct bootdev_hunter, bootdev_hunter); 820 result = 0; 821 822 len = SIZE_MAX; 823 if (spec) { 824 trailing_strtoln_end(spec, NULL, &end); 825 len = end - spec; 826 } 827 828 for (i = 0; i < n_ent; i++) { 829 struct bootdev_hunter *info = start + i; 830 const char *name = uclass_get_name(info->uclass); 831 int ret; 832 833 log_debug("looking at %.*s for %s\n", 834 (int)max(strlen(name), len), spec, name); 835 if (spec && strncmp(spec, name, max(strlen(name), len))) { 836 if (info->uclass != UCLASS_ETH || 837 (strcmp("dhcp", spec) && strcmp("pxe", spec))) 838 continue; 839 } 840 ret = bootdev_hunt_drv(info, i, show); 841 if (ret) 842 result = ret; 843 } 844 845 return result; 846} 847 848int bootdev_unhunt(enum uclass_id id) 849{ 850 struct bootdev_hunter *start; 851 int n_ent, i; 852 853 start = ll_entry_start(struct bootdev_hunter, bootdev_hunter); 854 n_ent = ll_entry_count(struct bootdev_hunter, bootdev_hunter); 855 for (i = 0; i < n_ent; i++) { 856 struct bootdev_hunter *info = start + i; 857 858 if (info->uclass == id) { 859 struct bootstd_priv *std; 860 int ret; 861 862 ret = bootstd_get_priv(&std); 863 if (ret) 864 return log_msg_ret("std", ret); 865 if (!(std->hunters_used & BIT(i))) 866 return -EALREADY; 867 std->hunters_used &= ~BIT(i); 868 return 0; 869 } 870 } 871 872 return -ENOENT; 873} 874 875int bootdev_hunt_prio(enum bootdev_prio_t prio, bool show) 876{ 877 struct bootdev_hunter *start; 878 int n_ent, i; 879 int result; 880 881 start = ll_entry_start(struct bootdev_hunter, bootdev_hunter); 882 n_ent = ll_entry_count(struct bootdev_hunter, bootdev_hunter); 883 result = 0; 884 885 log_debug("Hunting for priority %d\n", prio); 886 for (i = 0; i < n_ent; i++) { 887 struct bootdev_hunter *info = start + i; 888 int ret; 889 890 if (prio != info->prio) 891 continue; 892 ret = bootdev_hunt_drv(info, i, show); 893 log_debug("bootdev_hunt_drv() return %d\n", ret); 894 if (ret && ret != -ENOENT) 895 result = ret; 896 } 897 log_debug("exit %d\n", result); 898 899 return result; 900} 901 902void bootdev_list_hunters(struct bootstd_priv *std) 903{ 904 struct bootdev_hunter *orig, *start; 905 int n_ent, i; 906 907 orig = ll_entry_start(struct bootdev_hunter, bootdev_hunter); 908 n_ent = ll_entry_count(struct bootdev_hunter, bootdev_hunter); 909 910 /* 911 * workaround for strange bug in clang-12 which sees all the below data 912 * as zeroes. Any access of start seems to fix it, such as 913 * 914 * printf("%p", start); 915 * 916 * Use memcpy() to force the correct behaviour. 917 */ 918 memcpy(&start, &orig, sizeof(orig)); 919 printf("%4s %4s %-15s %s\n", "Prio", "Used", "Uclass", "Hunter"); 920 printf("%4s %4s %-15s %s\n", "----", "----", "---------------", "---------------"); 921 for (i = 0; i < n_ent; i++) { 922 struct bootdev_hunter *info = start + i; 923 924 printf("%4d %4s %-15s %s\n", info->prio, 925 std->hunters_used & BIT(i) ? "*" : "", 926 uclass_get_name(info->uclass), 927 info->drv ? info->drv->name : "(none)"); 928 } 929 930 printf("(total hunters: %d)\n", n_ent); 931} 932 933static int bootdev_pre_unbind(struct udevice *dev) 934{ 935 int ret; 936 937 ret = bootstd_clear_bootflows_for_bootdev(dev); 938 if (ret) 939 return log_msg_ret("bun", ret); 940 941 return 0; 942} 943 944UCLASS_DRIVER(bootdev) = { 945 .id = UCLASS_BOOTDEV, 946 .name = "bootdev", 947 .flags = DM_UC_FLAG_SEQ_ALIAS, 948 .per_device_plat_auto = sizeof(struct bootdev_uc_plat), 949 .pre_unbind = bootdev_pre_unbind, 950};