1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright 2021 Google LLC
4 * Written by Simon Glass <sjg@chromium.org>
7 #define LOG_CATEGORY UCLASS_BOOTSTD
14 #include <env_internal.h>
17 #include <dm/device-internal.h>
18 #include <dm/uclass-internal.h>
20 /* error codes used to signal running out of things */
22 BF_NO_MORE_PARTS
= -ESHUTDOWN
,
23 BF_NO_MORE_DEVICES
= -ENODEV
,
26 static const char *const bootflow_img
[BFI_COUNT
- BFI_FIRST
] = {
34 * bootflow_state - name for each state
36 * See enum bootflow_state_t for what each of these means
38 static const char *const bootflow_state
[BOOTFLOWST_COUNT
] = {
47 const char *bootflow_state_get_name(enum bootflow_state_t state
)
49 /* This doesn't need to be a useful name, since it will never occur */
50 if (state
< 0 || state
>= BOOTFLOWST_COUNT
)
53 return bootflow_state
[state
];
56 int bootflow_first_glob(struct bootflow
**bflowp
)
58 struct bootstd_priv
*std
;
61 ret
= bootstd_get_priv(&std
);
65 if (!std
->bootflows
.count
)
68 *bflowp
= alist_getw(&std
->bootflows
, 0, struct bootflow
);
73 int bootflow_next_glob(struct bootflow
**bflowp
)
75 struct bootstd_priv
*std
;
78 ret
= bootstd_get_priv(&std
);
82 *bflowp
= alist_nextw(&std
->bootflows
, *bflowp
);
89 void bootflow_iter_init(struct bootflow_iter
*iter
, int flags
)
91 memset(iter
, '\0', sizeof(*iter
));
92 iter
->first_glob_method
= -1;
95 /* remember the first bootdevs we see */
96 iter
->max_devs
= BOOTFLOW_MAX_USED_DEVS
;
99 void bootflow_iter_uninit(struct bootflow_iter
*iter
)
101 free(iter
->method_order
);
104 int bootflow_iter_drop_bootmeth(struct bootflow_iter
*iter
,
105 const struct udevice
*bmeth
)
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
)
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 *));
122 * bootflow_iter_set_dev() - switch to the next bootdev when iterating
124 * This sets iter->dev, records the device in the dev_used[] list and shows a
125 * message if required
127 * @iter: Iterator to update
128 * @dev: Bootdev to use, or NULL if there are no more
130 static void bootflow_iter_set_dev(struct bootflow_iter
*iter
,
131 struct udevice
*dev
, int method_flags
)
133 struct bootmeth_uc_plat
*ucp
= dev_get_uclass_plat(iter
->method
);
135 log_debug("iter: Setting dev to %s, flags %x\n",
136 dev
? dev
->name
: "(none)", method_flags
);
138 iter
->method_flags
= method_flags
;
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
;
145 if ((iter
->flags
& (BOOTFLOWIF_SHOW
| BOOTFLOWIF_SINGLE_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",
154 printf("No more bootdevs\n");
160 * scan_next_in_uclass() - Scan for the next bootdev in the same media uclass
162 * Move through the following bootdevs until we find another in this media
165 * @devp: On entry, the device to check, on exit the new device, or NULL if
168 static void scan_next_in_uclass(struct udevice
**devp
)
170 struct udevice
*dev
= *devp
;
171 enum uclass_id cur_id
= device_get_uclass_id(dev
->parent
);
174 uclass_find_next_device(&dev
);
175 } while (dev
&& cur_id
!= device_get_uclass_id(dev
->parent
));
181 * iter_incr() - Move to the next item (method, part, bootdev)
183 * Return: 0 if OK, BF_NO_MORE_DEVICES if there are no more bootdevs
185 static int iter_incr(struct bootflow_iter
*iter
)
192 log_debug("entry: err=%d\n", iter
->err
);
193 global
= iter
->doing_global
;
195 if (iter
->err
== BF_NO_MORE_DEVICES
)
196 return BF_NO_MORE_DEVICES
;
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
];
206 * If we have finished scanning the global bootmeths, start the
207 * normal bootdev scan
209 if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL
) && global
) {
210 iter
->num_methods
= iter
->first_glob_method
;
211 iter
->doing_global
= false;
214 * Don't move to the next dev as we haven't tried this
221 if (iter
->flags
& BOOTFLOWIF_SINGLE_PARTITION
)
222 return BF_NO_MORE_DEVICES
;
224 /* No more bootmeths; start at the first one, and... */
225 iter
->cur_method
= 0;
226 iter
->method
= iter
->method_order
[iter
->cur_method
];
228 if (iter
->err
!= BF_NO_MORE_PARTS
) {
229 /* ...select next partition */
230 if (++iter
->part
<= iter
->max_part
)
234 /* No more partitions; start at the first one and... */
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.
244 /* ...select next bootdev */
245 if (iter
->flags
& BOOTFLOWIF_SINGLE_DEV
) {
252 log_debug("inc_dev=%d\n", inc_dev
);
254 ret
= bootdev_setup_iter(iter
, NULL
, &dev
,
256 } else if (IS_ENABLED(CONFIG_BOOTSTD_FULL
) &&
257 (iter
->flags
& BOOTFLOWIF_SINGLE_UCLASS
)) {
258 scan_next_in_uclass(&dev
);
260 log_debug("finished uclass %s\n",
261 dev_get_uclass_name(dev
));
264 } else if (IS_ENABLED(CONFIG_BOOTSTD_FULL
) &&
265 iter
->flags
& BOOTFLOWIF_SINGLE_MEDIA
) {
266 log_debug("next in single\n");
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.
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
) !=
280 log_debug("finished uclass %s\n",
281 dev_get_uclass_name(dev
));
285 log_debug("labels %p\n", iter
->labels
);
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
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",
298 dev
? dev
->name
: "<none>");
303 log_debug("looking at next label\n");
304 ret
= bootdev_next_label(iter
, &dev
,
308 ret
= bootdev_next_prio(iter
, &dev
);
312 log_debug("ret=%d, dev=%p %s\n", ret
, dev
,
313 dev
? dev
->name
: "none");
315 bootflow_iter_set_dev(iter
, NULL
, 0);
318 * Probe the bootdev. This does not probe any attached
319 * block device, since they are siblings
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
);
328 /* if there are no more bootdevs, give up */
330 return log_msg_ret("incr", BF_NO_MORE_DEVICES
);
336 * bootflow_check() - Check if a bootflow can be obtained
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
343 static int bootflow_check(struct bootflow_iter
*iter
, struct bootflow
*bflow
)
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
);
352 return log_msg_ret("glob", ret
);
358 ret
= bootdev_get_bootflow(dev
, iter
, bflow
);
360 /* If we got a valid bootflow, return it */
362 log_debug("Bootdev '%s' part %d method '%s': Found bootflow\n",
363 dev
->name
, iter
->part
, iter
->method
->name
);
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
);
372 * For 'all' we return all bootflows, even
375 if (iter
->flags
& BOOTFLOWIF_ALL
)
376 return log_msg_ret("all", ret
);
379 return log_msg_ret("check", ret
);
382 int bootflow_scan_first(struct udevice
*dev
, const char *label
,
383 struct bootflow_iter
*iter
, int flags
,
384 struct bootflow
*bflow
)
389 flags
|= BOOTFLOWIF_SKIP_GLOBAL
;
390 bootflow_iter_init(iter
, flags
);
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
396 ret
= bootmeth_setup_iter_order(iter
, !(flags
& BOOTFLOWIF_SKIP_GLOBAL
));
398 return log_msg_ret("obmeth", -ENODEV
);
400 /* Find the first bootmeth (there must be at least one!) */
401 iter
->method
= iter
->method_order
[iter
->cur_method
];
403 if (!IS_ENABLED(CONFIG_BOOTMETH_GLOBAL
) || !iter
->doing_global
) {
404 struct udevice
*dev
= NULL
;
407 ret
= bootdev_setup_iter(iter
, label
, &dev
, &method_flags
);
409 return log_msg_ret("obdev", -ENODEV
);
411 bootflow_iter_set_dev(iter
, dev
, method_flags
);
414 ret
= bootflow_check(iter
, bflow
);
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
);
422 ret
= bootflow_scan_next(iter
, bflow
);
424 return log_msg_ret("get", ret
);
430 int bootflow_scan_next(struct bootflow_iter
*iter
, struct bootflow
*bflow
)
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
);
441 ret
= bootflow_check(iter
, bflow
);
442 log_debug("check - ret=%d\n", ret
);
446 if (ret
!= BF_NO_MORE_PARTS
&& ret
!= -ENOSYS
) {
447 if (iter
->flags
& BOOTFLOWIF_ALL
)
448 return log_msg_ret("all", ret
);
451 log_debug("incr failed, err=%d\n", ret
);
458 void bootflow_init(struct bootflow
*bflow
, struct udevice
*bootdev
,
459 struct udevice
*meth
)
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
);
468 void bootflow_free(struct bootflow
*bflow
)
470 struct bootflow_img
*img
;
475 if (!(bflow
->flags
& BOOTFLOWF_STATIC_BUF
))
477 free(bflow
->os_name
);
478 free(bflow
->fdt_fname
);
479 free(bflow
->bootmeth_priv
);
481 alist_for_each(img
, &bflow
->images
)
483 alist_empty(&bflow
->images
);
486 void bootflow_remove(struct bootflow
*bflow
)
488 bootflow_free(bflow
);
491 #if CONFIG_IS_ENABLED(BOOTSTD_FULL)
492 int bootflow_read_all(struct bootflow
*bflow
)
496 if (bflow
->state
!= BOOTFLOWST_READY
)
497 return log_msg_ret("rd", -EPROTO
);
499 ret
= bootmeth_read_all(bflow
->method
, bflow
);
501 return log_msg_ret("rd2", ret
);
505 #endif /* BOOTSTD_FULL */
507 int bootflow_boot(struct bootflow
*bflow
)
511 if (bflow
->state
!= BOOTFLOWST_READY
)
512 return log_msg_ret("load", -EPROTO
);
514 ret
= bootmeth_boot(bflow
->method
, bflow
);
516 return log_msg_ret("boot", ret
);
519 * internal error, should not get here since we should have booted
520 * something or returned an error
523 return log_msg_ret("end", -EFAULT
);
526 int bootflow_run_boot(struct bootflow_iter
*iter
, struct bootflow
*bflow
)
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
);
543 printf("Bootflow not loaded (state '%s')\n",
544 bootflow_state_get_name(bflow
->state
));
547 printf("Boot method '%s' not supported\n", bflow
->method
->name
);
550 /* Disable this bootflow for this iteration */
554 ret2
= bootflow_iter_drop_bootmeth(iter
, bflow
->method
);
556 printf("Boot method '%s' failed and will not be retried\n",
557 bflow
->method
->name
);
563 printf("Boot failed (err=%d)\n", ret
);
570 int bootflow_iter_check_blk(const struct bootflow_iter
*iter
)
572 const struct udevice
*media
= dev_get_parent(iter
->dev
);
573 enum uclass_id id
= device_get_uclass_id(media
);
575 log_debug("uclass %d: %s\n", id
, uclass_get_name(id
));
576 if (id
!= UCLASS_ETH
&& id
!= UCLASS_BOOTSTD
&& id
!= UCLASS_QFW
)
582 int bootflow_iter_check_mmc(const struct bootflow_iter
*iter
)
584 const struct udevice
*media
= dev_get_parent(iter
->dev
);
585 enum uclass_id id
= device_get_uclass_id(media
);
587 log_debug("uclass %d: %s\n", id
, uclass_get_name(id
));
588 if (id
== UCLASS_MMC
)
594 int bootflow_iter_check_sf(const struct bootflow_iter
*iter
)
596 const struct udevice
*media
= dev_get_parent(iter
->dev
);
597 enum uclass_id id
= device_get_uclass_id(media
);
599 log_debug("uclass %d: %s\n", id
, uclass_get_name(id
));
600 if (id
== UCLASS_SPI_FLASH
)
606 int bootflow_iter_check_net(const struct bootflow_iter
*iter
)
608 const struct udevice
*media
= dev_get_parent(iter
->dev
);
609 enum uclass_id id
= device_get_uclass_id(media
);
611 log_debug("uclass %d: %s\n", id
, uclass_get_name(id
));
612 if (id
== UCLASS_ETH
)
618 int bootflow_iter_check_system(const struct bootflow_iter
*iter
)
620 const struct udevice
*media
= dev_get_parent(iter
->dev
);
621 enum uclass_id id
= device_get_uclass_id(media
);
623 log_debug("uclass %d: %s\n", id
, uclass_get_name(id
));
624 if (id
== UCLASS_BOOTSTD
)
631 * bootflow_cmdline_set() - Set the command line for a bootflow
633 * @value: New command-line string
634 * Returns 0 if OK, -ENOENT if no current bootflow, -ENOMEM if out of memory
636 int bootflow_cmdline_set(struct bootflow
*bflow
, const char *value
)
638 char *cmdline
= NULL
;
641 cmdline
= strdup(value
);
646 free(bflow
->cmdline
);
647 bflow
->cmdline
= cmdline
;
652 #ifdef CONFIG_BOOTSTD_FULL
654 * on_bootargs() - Update the cmdline of a bootflow
656 static int on_bootargs(const char *name
, const char *value
, enum env_op op
,
659 struct bootstd_priv
*std
;
660 struct bootflow
*bflow
;
663 ret
= bootstd_get_priv(&std
);
666 bflow
= std
->cur_bootflow
;
672 case env_op_overwrite
:
673 ret
= bootflow_cmdline_set(bflow
, value
);
674 if (ret
&& ret
!= ENOENT
)
678 bootflow_cmdline_set(bflow
, NULL
);
684 U_BOOT_ENV_CALLBACK(bootargs
, on_bootargs
);
688 * copy_in() - Copy a string into a cmdline buffer
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
697 * Returns: Number of chars written to @buf
699 static int copy_in(char *buf
, char *end
, const char *arg
, int len
,
704 /* copy the arg name */
707 memcpy(to
, arg
, len
);
710 if (new_val
== BOOTFLOWCL_EMPTY
) {
713 bool need_quote
= strchr(new_val
, ' ');
714 len
= strlen(new_val
);
716 /* need space for value, equals sign and maybe two quotes */
717 if (to
+ 1 + (need_quote
? 2 : 0) + len
>= end
)
722 memcpy(to
, new_val
, len
);
731 int cmdline_set_arg(char *buf
, int maxlen
, const char *cmdline
,
732 const char *set_arg
, const char *new_val
, int *posp
)
734 bool found_arg
= false;
741 from
= cmdline
?: &empty
;
743 /* check if the value has quotes inside */
744 if (new_val
&& new_val
!= BOOTFLOWCL_EMPTY
&& strchr(new_val
, '"'))
747 set_arg_len
= strlen(set_arg
);
748 for (to
= buf
, end
= buf
+ maxlen
; *from
;) {
749 const char *val
, *arg_end
, *val_end
, *p
;
759 /* find the end of this arg */
764 for (p
= from
;; p
++) {
772 if (*p
== '=' && !arg_end
) {
775 } else if (*p
== '"') {
777 } else if (!*p
|| *p
== ' ') {
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.
795 * arg_end val val_end
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
));
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
)) {
811 bool has_quote
= val_end
[-1] == '"';
814 * exclude any start/end quotes from
819 *posp
= val
- cmdline
+ has_quote
;
820 return val_end
- val
- 2 * has_quote
;
824 /* delete this arg */
825 from
= val_end
+ (*val_end
== ' ');
826 log_debug("delete from: %s\n", from
);
828 to
--; /* drop the space we added */
832 ret
= copy_in(to
, end
, from
, arg_end
- from
, new_val
);
837 /* if not the target arg, copy it unchanged */
841 len
= val_end
- from
;
844 memcpy(to
, from
, len
);
850 /* If we didn't find the arg, add it */
852 /* trying to delete something that is not there */
853 if (!new_val
|| !buf
)
858 /* add a space to separate it from the previous arg */
859 if (to
!= buf
&& to
[-1] != ' ')
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
);
868 /* delete any trailing space */
869 if (to
> buf
&& to
[-1] == ' ')
879 int bootflow_cmdline_set_arg(struct bootflow
*bflow
, const char *set_arg
,
880 const char *new_val
, bool set_env
)
886 ret
= cmdline_set_arg(buf
, sizeof(buf
), bflow
->cmdline
, set_arg
,
891 ret
= bootflow_cmdline_set(bflow
, buf
);
897 free(bflow
->cmdline
);
898 bflow
->cmdline
= cmd
;
901 ret
= env_set("bootargs", bflow
->cmdline
);
909 int cmdline_get_arg(const char *cmdline
, const char *arg
, int *posp
)
913 ret
= cmdline_set_arg(NULL
, 1, cmdline
, arg
, NULL
, posp
);
918 int bootflow_cmdline_get_arg(struct bootflow
*bflow
, const char *arg
,
924 ret
= cmdline_get_arg(bflow
->cmdline
, arg
, &pos
);
927 *val
= bflow
->cmdline
+ pos
;
932 int bootflow_cmdline_auto(struct bootflow
*bflow
, const char *arg
)
934 struct serial_device_info info
;
938 ret
= serial_getinfo(gd
->cur_serial_dev
, &info
);
943 if (!strcmp("earlycon", arg
) && info
.type
== SERIAL_CHIP_16550_COMPATIBLE
) {
944 snprintf(buf
, sizeof(buf
),
945 "uart8250,mmio32,%#lx,%dn8", info
.addr
,
947 } else if (!strcmp("earlycon", arg
) && info
.type
== SERIAL_CHIP_PL01X
) {
948 snprintf(buf
, sizeof(buf
),
949 "pl011,mmio32,%#lx,%dn8", info
.addr
,
951 } else if (!strcmp("console", arg
) && info
.type
== SERIAL_CHIP_16550_COMPATIBLE
) {
952 snprintf(buf
, sizeof(buf
),
953 "ttyS0,%dn8", info
.baudrate
);
957 printf("Unknown param '%s\n", arg
);
961 ret
= bootflow_cmdline_set_arg(bflow
, arg
, buf
, true);
968 const char *bootflow_img_type_name(enum bootflow_img_t type
)
972 if (type
>= BFI_FIRST
&& type
< BFI_COUNT
)
973 name
= bootflow_img
[type
- BFI_FIRST
];
975 name
= genimg_get_type_short_name(type
);
980 struct bootflow_img
*bootflow_img_add(struct bootflow
*bflow
, const char *fname
,
981 enum bootflow_img_t type
, ulong addr
,
984 struct bootflow_img img
, *ptr
;
986 memset(&img
, '\0', sizeof(struct bootflow_img
));
987 img
.fname
= strdup(fname
);
994 ptr
= alist_add(&bflow
->images
, img
);
1001 int bootflow_get_seq(const struct bootflow
*bflow
)
1003 struct bootstd_priv
*std
;
1006 ret
= bootstd_get_priv(&std
);
1010 return alist_calc_index(&std
->bootflows
, bflow
);