"Das U-Boot" Source Tree
at master 1011 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 <bootdev.h> 10#include <bootflow.h> 11#include <bootmeth.h> 12#include <bootstd.h> 13#include <dm.h> 14#include <env_internal.h> 15#include <malloc.h> 16#include <serial.h> 17#include <dm/device-internal.h> 18#include <dm/uclass-internal.h> 19 20/* error codes used to signal running out of things */ 21enum { 22 BF_NO_MORE_PARTS = -ESHUTDOWN, 23 BF_NO_MORE_DEVICES = -ENODEV, 24}; 25 26static const char *const bootflow_img[BFI_COUNT - BFI_FIRST] = { 27 "extlinux_cfg", 28 "logo", 29 "efi", 30 "cmdline", 31}; 32 33/** 34 * bootflow_state - name for each state 35 * 36 * See enum bootflow_state_t for what each of these means 37 */ 38static const char *const bootflow_state[BOOTFLOWST_COUNT] = { 39 "base", 40 "media", 41 "part", 42 "fs", 43 "file", 44 "ready", 45}; 46 47const char *bootflow_state_get_name(enum bootflow_state_t state) 48{ 49 /* This doesn't need to be a useful name, since it will never occur */ 50 if (state < 0 || state >= BOOTFLOWST_COUNT) 51 return "?"; 52 53 return bootflow_state[state]; 54} 55 56int bootflow_first_glob(struct bootflow **bflowp) 57{ 58 struct bootstd_priv *std; 59 int ret; 60 61 ret = bootstd_get_priv(&std); 62 if (ret) 63 return ret; 64 65 if (!std->bootflows.count) 66 return -ENOENT; 67 68 *bflowp = alist_getw(&std->bootflows, 0, struct bootflow); 69 70 return 0; 71} 72 73int bootflow_next_glob(struct bootflow **bflowp) 74{ 75 struct bootstd_priv *std; 76 int ret; 77 78 ret = bootstd_get_priv(&std); 79 if (ret) 80 return ret; 81 82 *bflowp = alist_nextw(&std->bootflows, *bflowp); 83 if (!*bflowp) 84 return -ENOENT; 85 86 return 0; 87} 88 89void bootflow_iter_init(struct bootflow_iter *iter, int flags) 90{ 91 memset(iter, '\0', sizeof(*iter)); 92 iter->first_glob_method = -1; 93 iter->flags = flags; 94 95 /* remember the first bootdevs we see */ 96 iter->max_devs = BOOTFLOW_MAX_USED_DEVS; 97} 98 99void bootflow_iter_uninit(struct bootflow_iter *iter) 100{ 101 free(iter->method_order); 102} 103 104int bootflow_iter_drop_bootmeth(struct bootflow_iter *iter, 105 const struct udevice *bmeth) 106{ 107 /* We only support disabling the current bootmeth */ 108 if (bmeth != iter->method || iter->cur_method >= iter->num_methods || 109 iter->method_order[iter->cur_method] != bmeth) 110 return -EINVAL; 111 112 memmove(&iter->method_order[iter->cur_method], 113 &iter->method_order[iter->cur_method + 1], 114 (iter->num_methods - iter->cur_method - 1) * sizeof(void *)); 115 116 iter->num_methods--; 117 118 return 0; 119} 120 121/** 122 * bootflow_iter_set_dev() - switch to the next bootdev when iterating 123 * 124 * This sets iter->dev, records the device in the dev_used[] list and shows a 125 * message if required 126 * 127 * @iter: Iterator to update 128 * @dev: Bootdev to use, or NULL if there are no more 129 */ 130static void bootflow_iter_set_dev(struct bootflow_iter *iter, 131 struct udevice *dev, int method_flags) 132{ 133 struct bootmeth_uc_plat *ucp = dev_get_uclass_plat(iter->method); 134 135 log_debug("iter: Setting dev to %s, flags %x\n", 136 dev ? dev->name : "(none)", method_flags); 137 iter->dev = dev; 138 iter->method_flags = method_flags; 139 140 if (IS_ENABLED(CONFIG_BOOTSTD_FULL)) { 141 /* record the device for later */ 142 if (dev && iter->num_devs < iter->max_devs) 143 iter->dev_used[iter->num_devs++] = dev; 144 145 if ((iter->flags & (BOOTFLOWIF_SHOW | BOOTFLOWIF_SINGLE_DEV)) == 146 BOOTFLOWIF_SHOW) { 147 if (dev) 148 printf("Scanning bootdev '%s':\n", dev->name); 149 else if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && 150 ucp->flags & BOOTMETHF_GLOBAL) 151 printf("Scanning global bootmeth '%s':\n", 152 iter->method->name); 153 else 154 printf("No more bootdevs\n"); 155 } 156 } 157} 158 159/** 160 * scan_next_in_uclass() - Scan for the next bootdev in the same media uclass 161 * 162 * Move through the following bootdevs until we find another in this media 163 * uclass, or run out 164 * 165 * @devp: On entry, the device to check, on exit the new device, or NULL if 166 * there is none 167 */ 168static void scan_next_in_uclass(struct udevice **devp) 169{ 170 struct udevice *dev = *devp; 171 enum uclass_id cur_id = device_get_uclass_id(dev->parent); 172 173 do { 174 uclass_find_next_device(&dev); 175 } while (dev && cur_id != device_get_uclass_id(dev->parent)); 176 177 *devp = dev; 178} 179 180/** 181 * iter_incr() - Move to the next item (method, part, bootdev) 182 * 183 * Return: 0 if OK, BF_NO_MORE_DEVICES if there are no more bootdevs 184 */ 185static int iter_incr(struct bootflow_iter *iter) 186{ 187 struct udevice *dev; 188 bool inc_dev = true; 189 bool global; 190 int ret; 191 192 log_debug("entry: err=%d\n", iter->err); 193 global = iter->doing_global; 194 195 if (iter->err == BF_NO_MORE_DEVICES) 196 return BF_NO_MORE_DEVICES; 197 198 if (iter->err != BF_NO_MORE_PARTS) { 199 /* Get the next boothmethod */ 200 if (++iter->cur_method < iter->num_methods) { 201 iter->method = iter->method_order[iter->cur_method]; 202 return 0; 203 } 204 205 /* 206 * If we have finished scanning the global bootmeths, start the 207 * normal bootdev scan 208 */ 209 if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && global) { 210 iter->num_methods = iter->first_glob_method; 211 iter->doing_global = false; 212 213 /* 214 * Don't move to the next dev as we haven't tried this 215 * one yet! 216 */ 217 inc_dev = false; 218 } 219 } 220 221 if (iter->flags & BOOTFLOWIF_SINGLE_PARTITION) 222 return BF_NO_MORE_DEVICES; 223 224 /* No more bootmeths; start at the first one, and... */ 225 iter->cur_method = 0; 226 iter->method = iter->method_order[iter->cur_method]; 227 228 if (iter->err != BF_NO_MORE_PARTS) { 229 /* ...select next partition */ 230 if (++iter->part <= iter->max_part) 231 return 0; 232 } 233 234 /* No more partitions; start at the first one and... */ 235 iter->part = 0; 236 237 /* 238 * Note: as far as we know, there is no partition table on the next 239 * bootdev, so set max_part to 0 until we discover otherwise. See 240 * bootdev_find_in_blk() for where this is set. 241 */ 242 iter->max_part = 0; 243 244 /* ...select next bootdev */ 245 if (iter->flags & BOOTFLOWIF_SINGLE_DEV) { 246 ret = -ENOENT; 247 } else { 248 int method_flags; 249 250 ret = 0; 251 dev = iter->dev; 252 log_debug("inc_dev=%d\n", inc_dev); 253 if (!inc_dev) { 254 ret = bootdev_setup_iter(iter, NULL, &dev, 255 &method_flags); 256 } else if (IS_ENABLED(CONFIG_BOOTSTD_FULL) && 257 (iter->flags & BOOTFLOWIF_SINGLE_UCLASS)) { 258 scan_next_in_uclass(&dev); 259 if (!dev) { 260 log_debug("finished uclass %s\n", 261 dev_get_uclass_name(dev)); 262 ret = -ENODEV; 263 } 264 } else if (IS_ENABLED(CONFIG_BOOTSTD_FULL) && 265 iter->flags & BOOTFLOWIF_SINGLE_MEDIA) { 266 log_debug("next in single\n"); 267 method_flags = 0; 268 do { 269 /* 270 * Move to the next bootdev child of this media 271 * device. This ensures that we cover all the 272 * available SCSI IDs and LUNs. 273 */ 274 device_find_next_child(&dev); 275 log_debug("- next %s\n", 276 dev ? dev->name : "(none)"); 277 } while (dev && device_get_uclass_id(dev) != 278 UCLASS_BOOTDEV); 279 if (!dev) { 280 log_debug("finished uclass %s\n", 281 dev_get_uclass_name(dev)); 282 ret = -ENODEV; 283 } 284 } else { 285 log_debug("labels %p\n", iter->labels); 286 if (iter->labels) { 287 /* 288 * when the label is "mmc" we want to scan all 289 * mmc bootdevs, not just the first. See 290 * bootdev_find_by_label() where this flag is 291 * set up 292 */ 293 if (iter->method_flags & 294 BOOTFLOW_METHF_SINGLE_UCLASS) { 295 scan_next_in_uclass(&dev); 296 log_debug("looking for next device %s: %s\n", 297 iter->dev->name, 298 dev ? dev->name : "<none>"); 299 } else { 300 dev = NULL; 301 } 302 if (!dev) { 303 log_debug("looking at next label\n"); 304 ret = bootdev_next_label(iter, &dev, 305 &method_flags); 306 } 307 } else { 308 ret = bootdev_next_prio(iter, &dev); 309 method_flags = 0; 310 } 311 } 312 log_debug("ret=%d, dev=%p %s\n", ret, dev, 313 dev ? dev->name : "none"); 314 if (ret) { 315 bootflow_iter_set_dev(iter, NULL, 0); 316 } else { 317 /* 318 * Probe the bootdev. This does not probe any attached 319 * block device, since they are siblings 320 */ 321 ret = device_probe(dev); 322 log_debug("probe %s %d\n", dev->name, ret); 323 if (!log_msg_ret("probe", ret)) 324 bootflow_iter_set_dev(iter, dev, method_flags); 325 } 326 } 327 328 /* if there are no more bootdevs, give up */ 329 if (ret) 330 return log_msg_ret("incr", BF_NO_MORE_DEVICES); 331 332 return 0; 333} 334 335/** 336 * bootflow_check() - Check if a bootflow can be obtained 337 * 338 * @iter: Provides part, bootmeth to use 339 * @bflow: Bootflow to update on success 340 * Return: 0 if OK, -ENOSYS if there is no bootflow support on this device, 341 * BF_NO_MORE_PARTS if there are no more partitions on bootdev 342 */ 343static int bootflow_check(struct bootflow_iter *iter, struct bootflow *bflow) 344{ 345 struct udevice *dev; 346 int ret; 347 348 if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && iter->doing_global) { 349 bootflow_iter_set_dev(iter, NULL, 0); 350 ret = bootmeth_get_bootflow(iter->method, bflow); 351 if (ret) 352 return log_msg_ret("glob", ret); 353 354 return 0; 355 } 356 357 dev = iter->dev; 358 ret = bootdev_get_bootflow(dev, iter, bflow); 359 360 /* If we got a valid bootflow, return it */ 361 if (!ret) { 362 log_debug("Bootdev '%s' part %d method '%s': Found bootflow\n", 363 dev->name, iter->part, iter->method->name); 364 return 0; 365 } 366 367 /* Unless there is nothing more to try, move to the next device */ 368 if (ret != BF_NO_MORE_PARTS && ret != -ENOSYS) { 369 log_debug("Bootdev '%s' part %d method '%s': Error %d\n", 370 dev->name, iter->part, iter->method->name, ret); 371 /* 372 * For 'all' we return all bootflows, even 373 * those with errors 374 */ 375 if (iter->flags & BOOTFLOWIF_ALL) 376 return log_msg_ret("all", ret); 377 } 378 379 return log_msg_ret("check", ret); 380} 381 382int bootflow_scan_first(struct udevice *dev, const char *label, 383 struct bootflow_iter *iter, int flags, 384 struct bootflow *bflow) 385{ 386 int ret; 387 388 if (dev || label) 389 flags |= BOOTFLOWIF_SKIP_GLOBAL; 390 bootflow_iter_init(iter, flags); 391 392 /* 393 * Set up the ordering of bootmeths. This sets iter->doing_global and 394 * iter->first_glob_method if we are starting with the global bootmeths 395 */ 396 ret = bootmeth_setup_iter_order(iter, !(flags & BOOTFLOWIF_SKIP_GLOBAL)); 397 if (ret) 398 return log_msg_ret("obmeth", -ENODEV); 399 400 /* Find the first bootmeth (there must be at least one!) */ 401 iter->method = iter->method_order[iter->cur_method]; 402 403 if (!IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) || !iter->doing_global) { 404 struct udevice *dev = NULL; 405 int method_flags; 406 407 ret = bootdev_setup_iter(iter, label, &dev, &method_flags); 408 if (ret) 409 return log_msg_ret("obdev", -ENODEV); 410 411 bootflow_iter_set_dev(iter, dev, method_flags); 412 } 413 414 ret = bootflow_check(iter, bflow); 415 if (ret) { 416 log_debug("check - ret=%d\n", ret); 417 if (ret != BF_NO_MORE_PARTS && ret != -ENOSYS) { 418 if (iter->flags & BOOTFLOWIF_ALL) 419 return log_msg_ret("all", ret); 420 } 421 iter->err = ret; 422 ret = bootflow_scan_next(iter, bflow); 423 if (ret) 424 return log_msg_ret("get", ret); 425 } 426 427 return 0; 428} 429 430int bootflow_scan_next(struct bootflow_iter *iter, struct bootflow *bflow) 431{ 432 int ret; 433 434 do { 435 ret = iter_incr(iter); 436 log_debug("iter_incr: ret=%d\n", ret); 437 if (ret == BF_NO_MORE_DEVICES) 438 return log_msg_ret("done", ret); 439 440 if (!ret) { 441 ret = bootflow_check(iter, bflow); 442 log_debug("check - ret=%d\n", ret); 443 if (!ret) 444 return 0; 445 iter->err = ret; 446 if (ret != BF_NO_MORE_PARTS && ret != -ENOSYS) { 447 if (iter->flags & BOOTFLOWIF_ALL) 448 return log_msg_ret("all", ret); 449 } 450 } else { 451 log_debug("incr failed, err=%d\n", ret); 452 iter->err = ret; 453 } 454 455 } while (1); 456} 457 458void bootflow_init(struct bootflow *bflow, struct udevice *bootdev, 459 struct udevice *meth) 460{ 461 memset(bflow, '\0', sizeof(*bflow)); 462 bflow->dev = bootdev; 463 bflow->method = meth; 464 bflow->state = BOOTFLOWST_BASE; 465 alist_init_struct(&bflow->images, struct bootflow_img); 466} 467 468void bootflow_free(struct bootflow *bflow) 469{ 470 struct bootflow_img *img; 471 472 free(bflow->name); 473 free(bflow->subdir); 474 free(bflow->fname); 475 if (!(bflow->flags & BOOTFLOWF_STATIC_BUF)) 476 free(bflow->buf); 477 free(bflow->os_name); 478 free(bflow->fdt_fname); 479 free(bflow->bootmeth_priv); 480 481 alist_for_each(img, &bflow->images) 482 free(img->fname); 483 alist_empty(&bflow->images); 484} 485 486void bootflow_remove(struct bootflow *bflow) 487{ 488 bootflow_free(bflow); 489} 490 491#if CONFIG_IS_ENABLED(BOOTSTD_FULL) 492int bootflow_read_all(struct bootflow *bflow) 493{ 494 int ret; 495 496 if (bflow->state != BOOTFLOWST_READY) 497 return log_msg_ret("rd", -EPROTO); 498 499 ret = bootmeth_read_all(bflow->method, bflow); 500 if (ret) 501 return log_msg_ret("rd2", ret); 502 503 return 0; 504} 505#endif /* BOOTSTD_FULL */ 506 507int bootflow_boot(struct bootflow *bflow) 508{ 509 int ret; 510 511 if (bflow->state != BOOTFLOWST_READY) 512 return log_msg_ret("load", -EPROTO); 513 514 ret = bootmeth_boot(bflow->method, bflow); 515 if (ret) 516 return log_msg_ret("boot", ret); 517 518 /* 519 * internal error, should not get here since we should have booted 520 * something or returned an error 521 */ 522 523 return log_msg_ret("end", -EFAULT); 524} 525 526int bootflow_run_boot(struct bootflow_iter *iter, struct bootflow *bflow) 527{ 528 int ret; 529 530 printf("** Booting bootflow '%s' with %s\n", bflow->name, 531 bflow->method->name); 532 if (IS_ENABLED(CONFIG_OF_HAS_PRIOR_STAGE) && 533 (bflow->flags & BOOTFLOWF_USE_PRIOR_FDT)) 534 printf("Using prior-stage device tree\n"); 535 ret = bootflow_boot(bflow); 536 if (!IS_ENABLED(CONFIG_BOOTSTD_FULL)) { 537 printf("Boot failed (err=%d)\n", ret); 538 return ret; 539 } 540 541 switch (ret) { 542 case -EPROTO: 543 printf("Bootflow not loaded (state '%s')\n", 544 bootflow_state_get_name(bflow->state)); 545 break; 546 case -ENOSYS: 547 printf("Boot method '%s' not supported\n", bflow->method->name); 548 break; 549 case -ENOTSUPP: 550 /* Disable this bootflow for this iteration */ 551 if (iter) { 552 int ret2; 553 554 ret2 = bootflow_iter_drop_bootmeth(iter, bflow->method); 555 if (!ret2) { 556 printf("Boot method '%s' failed and will not be retried\n", 557 bflow->method->name); 558 } 559 } 560 561 break; 562 default: 563 printf("Boot failed (err=%d)\n", ret); 564 break; 565 } 566 567 return ret; 568} 569 570int bootflow_iter_check_blk(const struct bootflow_iter *iter) 571{ 572 const struct udevice *media = dev_get_parent(iter->dev); 573 enum uclass_id id = device_get_uclass_id(media); 574 575 log_debug("uclass %d: %s\n", id, uclass_get_name(id)); 576 if (id != UCLASS_ETH && id != UCLASS_BOOTSTD && id != UCLASS_QFW) 577 return 0; 578 579 return -ENOTSUPP; 580} 581 582int bootflow_iter_check_mmc(const struct bootflow_iter *iter) 583{ 584 const struct udevice *media = dev_get_parent(iter->dev); 585 enum uclass_id id = device_get_uclass_id(media); 586 587 log_debug("uclass %d: %s\n", id, uclass_get_name(id)); 588 if (id == UCLASS_MMC) 589 return 0; 590 591 return -ENOTSUPP; 592} 593 594int bootflow_iter_check_sf(const struct bootflow_iter *iter) 595{ 596 const struct udevice *media = dev_get_parent(iter->dev); 597 enum uclass_id id = device_get_uclass_id(media); 598 599 log_debug("uclass %d: %s\n", id, uclass_get_name(id)); 600 if (id == UCLASS_SPI_FLASH) 601 return 0; 602 603 return -ENOTSUPP; 604} 605 606int bootflow_iter_check_net(const struct bootflow_iter *iter) 607{ 608 const struct udevice *media = dev_get_parent(iter->dev); 609 enum uclass_id id = device_get_uclass_id(media); 610 611 log_debug("uclass %d: %s\n", id, uclass_get_name(id)); 612 if (id == UCLASS_ETH) 613 return 0; 614 615 return -ENOTSUPP; 616} 617 618int bootflow_iter_check_system(const struct bootflow_iter *iter) 619{ 620 const struct udevice *media = dev_get_parent(iter->dev); 621 enum uclass_id id = device_get_uclass_id(media); 622 623 log_debug("uclass %d: %s\n", id, uclass_get_name(id)); 624 if (id == UCLASS_BOOTSTD) 625 return 0; 626 627 return -ENOTSUPP; 628} 629 630/** 631 * bootflow_cmdline_set() - Set the command line for a bootflow 632 * 633 * @value: New command-line string 634 * Returns 0 if OK, -ENOENT if no current bootflow, -ENOMEM if out of memory 635 */ 636int bootflow_cmdline_set(struct bootflow *bflow, const char *value) 637{ 638 char *cmdline = NULL; 639 640 if (value) { 641 cmdline = strdup(value); 642 if (!cmdline) 643 return -ENOMEM; 644 } 645 646 free(bflow->cmdline); 647 bflow->cmdline = cmdline; 648 649 return 0; 650} 651 652#ifdef CONFIG_BOOTSTD_FULL 653/** 654 * on_bootargs() - Update the cmdline of a bootflow 655 */ 656static int on_bootargs(const char *name, const char *value, enum env_op op, 657 int flags) 658{ 659 struct bootstd_priv *std; 660 struct bootflow *bflow; 661 int ret; 662 663 ret = bootstd_get_priv(&std); 664 if (ret) 665 return 0; 666 bflow = std->cur_bootflow; 667 if (!bflow) 668 return 0; 669 670 switch (op) { 671 case env_op_create: 672 case env_op_overwrite: 673 ret = bootflow_cmdline_set(bflow, value); 674 if (ret && ret != ENOENT) 675 return 1; 676 return 0; 677 case env_op_delete: 678 bootflow_cmdline_set(bflow, NULL); 679 fallthrough; 680 default: 681 return 0; 682 } 683} 684U_BOOT_ENV_CALLBACK(bootargs, on_bootargs); 685#endif 686 687/** 688 * copy_in() - Copy a string into a cmdline buffer 689 * 690 * @buf: Buffer to copy into 691 * @end: End of buffer (pointer to char after the end) 692 * @arg: String to copy from 693 * @len: Number of chars to copy from @arg (note that this is not usually the 694 * sane as strlen(arg) since the string may contain following arguments) 695 * @new_val: Value to put after arg, or BOOTFLOWCL_EMPTY to use an empty value 696 * with no '=' sign 697 * Returns: Number of chars written to @buf 698 */ 699static int copy_in(char *buf, char *end, const char *arg, int len, 700 const char *new_val) 701{ 702 char *to = buf; 703 704 /* copy the arg name */ 705 if (to + len >= end) 706 return -E2BIG; 707 memcpy(to, arg, len); 708 to += len; 709 710 if (new_val == BOOTFLOWCL_EMPTY) { 711 /* no value */ 712 } else { 713 bool need_quote = strchr(new_val, ' '); 714 len = strlen(new_val); 715 716 /* need space for value, equals sign and maybe two quotes */ 717 if (to + 1 + (need_quote ? 2 : 0) + len >= end) 718 return -E2BIG; 719 *to++ = '='; 720 if (need_quote) 721 *to++ = '"'; 722 memcpy(to, new_val, len); 723 to += len; 724 if (need_quote) 725 *to++ = '"'; 726 } 727 728 return to - buf; 729} 730 731int cmdline_set_arg(char *buf, int maxlen, const char *cmdline, 732 const char *set_arg, const char *new_val, int *posp) 733{ 734 bool found_arg = false; 735 const char *from; 736 char *to, *end; 737 int set_arg_len; 738 char empty = '\0'; 739 int ret; 740 741 from = cmdline ?: &empty; 742 743 /* check if the value has quotes inside */ 744 if (new_val && new_val != BOOTFLOWCL_EMPTY && strchr(new_val, '"')) 745 return -EBADF; 746 747 set_arg_len = strlen(set_arg); 748 for (to = buf, end = buf + maxlen; *from;) { 749 const char *val, *arg_end, *val_end, *p; 750 bool in_quote; 751 752 if (to >= end) 753 return -E2BIG; 754 while (*from == ' ') 755 from++; 756 if (!*from) 757 break; 758 759 /* find the end of this arg */ 760 val = NULL; 761 arg_end = NULL; 762 val_end = NULL; 763 in_quote = false; 764 for (p = from;; p++) { 765 if (in_quote) { 766 if (!*p) 767 return -EINVAL; 768 if (*p == '"') 769 in_quote = false; 770 continue; 771 } 772 if (*p == '=' && !arg_end) { 773 arg_end = p; 774 val = p + 1; 775 } else if (*p == '"') { 776 in_quote = true; 777 } else if (!*p || *p == ' ') { 778 val_end = p; 779 if (!arg_end) 780 arg_end = p; 781 break; 782 } 783 } 784 /* 785 * At this point val_end points to the end of the value, or the 786 * last char after the arg name, if there is no label. 787 * arg_end is the char after the arg name 788 * val points to the value, or NULL if there is none 789 * char after the value. 790 * 791 * fred=1234 792 * ^ ^^ ^ 793 * from || | 794 * / \ \ 795 * arg_end val val_end 796 */ 797 log_debug("from %s arg_end %ld val %ld val_end %ld\n", from, 798 (long)(arg_end - from), (long)(val - from), 799 (long)(val_end - from)); 800 801 if (to != buf) { 802 if (to >= end) 803 return -E2BIG; 804 *to++ = ' '; 805 } 806 807 /* if this is the target arg, update it */ 808 if (arg_end - from == set_arg_len && 809 !strncmp(from, set_arg, set_arg_len)) { 810 if (!buf) { 811 bool has_quote = val_end[-1] == '"'; 812 813 /* 814 * exclude any start/end quotes from 815 * calculations 816 */ 817 if (!val) 818 val = val_end; 819 *posp = val - cmdline + has_quote; 820 return val_end - val - 2 * has_quote; 821 } 822 found_arg = true; 823 if (!new_val) { 824 /* delete this arg */ 825 from = val_end + (*val_end == ' '); 826 log_debug("delete from: %s\n", from); 827 if (to != buf) 828 to--; /* drop the space we added */ 829 continue; 830 } 831 832 ret = copy_in(to, end, from, arg_end - from, new_val); 833 if (ret < 0) 834 return ret; 835 to += ret; 836 837 /* if not the target arg, copy it unchanged */ 838 } else if (to) { 839 int len; 840 841 len = val_end - from; 842 if (to + len >= end) 843 return -E2BIG; 844 memcpy(to, from, len); 845 to += len; 846 } 847 from = val_end; 848 } 849 850 /* If we didn't find the arg, add it */ 851 if (!found_arg) { 852 /* trying to delete something that is not there */ 853 if (!new_val || !buf) 854 return -ENOENT; 855 if (to >= end) 856 return -E2BIG; 857 858 /* add a space to separate it from the previous arg */ 859 if (to != buf && to[-1] != ' ') 860 *to++ = ' '; 861 ret = copy_in(to, end, set_arg, set_arg_len, new_val); 862 log_debug("ret=%d, to: %s buf: %s\n", ret, to, buf); 863 if (ret < 0) 864 return ret; 865 to += ret; 866 } 867 868 /* delete any trailing space */ 869 if (to > buf && to[-1] == ' ') 870 to--; 871 872 if (to >= end) 873 return -E2BIG; 874 *to++ = '\0'; 875 876 return to - buf; 877} 878 879int bootflow_cmdline_set_arg(struct bootflow *bflow, const char *set_arg, 880 const char *new_val, bool set_env) 881{ 882 char buf[2048]; 883 char *cmd = NULL; 884 int ret; 885 886 ret = cmdline_set_arg(buf, sizeof(buf), bflow->cmdline, set_arg, 887 new_val, NULL); 888 if (ret < 0) 889 return ret; 890 891 ret = bootflow_cmdline_set(bflow, buf); 892 if (*buf) { 893 cmd = strdup(buf); 894 if (!cmd) 895 return -ENOMEM; 896 } 897 free(bflow->cmdline); 898 bflow->cmdline = cmd; 899 900 if (set_env) { 901 ret = env_set("bootargs", bflow->cmdline); 902 if (ret) 903 return ret; 904 } 905 906 return 0; 907} 908 909int cmdline_get_arg(const char *cmdline, const char *arg, int *posp) 910{ 911 int ret; 912 913 ret = cmdline_set_arg(NULL, 1, cmdline, arg, NULL, posp); 914 915 return ret; 916} 917 918int bootflow_cmdline_get_arg(struct bootflow *bflow, const char *arg, 919 const char **val) 920{ 921 int ret; 922 int pos; 923 924 ret = cmdline_get_arg(bflow->cmdline, arg, &pos); 925 if (ret < 0) 926 return ret; 927 *val = bflow->cmdline + pos; 928 929 return ret; 930} 931 932int bootflow_cmdline_auto(struct bootflow *bflow, const char *arg) 933{ 934 struct serial_device_info info; 935 char buf[50]; 936 int ret; 937 938 ret = serial_getinfo(gd->cur_serial_dev, &info); 939 if (ret) 940 return ret; 941 942 *buf = '\0'; 943 if (!strcmp("earlycon", arg) && info.type == SERIAL_CHIP_16550_COMPATIBLE) { 944 snprintf(buf, sizeof(buf), 945 "uart8250,mmio32,%#lx,%dn8", info.addr, 946 info.baudrate); 947 } else if (!strcmp("earlycon", arg) && info.type == SERIAL_CHIP_PL01X) { 948 snprintf(buf, sizeof(buf), 949 "pl011,mmio32,%#lx,%dn8", info.addr, 950 info.baudrate); 951 } else if (!strcmp("console", arg) && info.type == SERIAL_CHIP_16550_COMPATIBLE) { 952 snprintf(buf, sizeof(buf), 953 "ttyS0,%dn8", info.baudrate); 954 } 955 956 if (!*buf) { 957 printf("Unknown param '%s\n", arg); 958 return -ENOENT; 959 } 960 961 ret = bootflow_cmdline_set_arg(bflow, arg, buf, true); 962 if (ret) 963 return ret; 964 965 return 0; 966} 967 968const char *bootflow_img_type_name(enum bootflow_img_t type) 969{ 970 const char *name; 971 972 if (type >= BFI_FIRST && type < BFI_COUNT) 973 name = bootflow_img[type - BFI_FIRST]; 974 else 975 name = genimg_get_type_short_name(type); 976 977 return name; 978} 979 980struct bootflow_img *bootflow_img_add(struct bootflow *bflow, const char *fname, 981 enum bootflow_img_t type, ulong addr, 982 ulong size) 983{ 984 struct bootflow_img img, *ptr; 985 986 memset(&img, '\0', sizeof(struct bootflow_img)); 987 img.fname = strdup(fname); 988 if (!img.fname) 989 return NULL; 990 991 img.type = type; 992 img.addr = addr; 993 img.size = size; 994 ptr = alist_add(&bflow->images, img); 995 if (!ptr) 996 return NULL; 997 998 return ptr; 999} 1000 1001int bootflow_get_seq(const struct bootflow *bflow) 1002{ 1003 struct bootstd_priv *std; 1004 int ret; 1005 1006 ret = bootstd_get_priv(&std); 1007 if (ret) 1008 return ret; 1009 1010 return alist_calc_index(&std->bootflows, bflow); 1011}