sandbox: Add a way to specify the sandbox executable
[platform/kernel/u-boot.git] / boot / bootmeth-uclass.c
index c040d5f..25552dd 100644 (file)
 
 DECLARE_GLOBAL_DATA_PTR;
 
+int bootmeth_get_state_desc(struct udevice *dev, char *buf, int maxsize)
+{
+       const struct bootmeth_ops *ops = bootmeth_get_ops(dev);
+
+       if (!ops->get_state_desc)
+               return -ENOSYS;
+
+       return ops->get_state_desc(dev, buf, maxsize);
+}
+
 int bootmeth_check(struct udevice *dev, struct bootflow_iter *iter)
 {
        const struct bootmeth_ops *ops = bootmeth_get_ops(dev);
@@ -61,18 +71,18 @@ int bootmeth_read_file(struct udevice *dev, struct bootflow *bflow,
        return ops->read_file(dev, bflow, file_path, addr, sizep);
 }
 
-/**
- * bootmeth_setup_iter_order() - Set up the ordering of bootmeths to scan
- *
- * This sets up the ordering information in @iter, based on the selected
- * ordering of the bootmethds in bootstd_priv->bootmeth_order. If there is no
- * ordering there, then all bootmethods are added
- *
- * @iter: Iterator to update with the order
- * Return: 0 if OK, -ENOENT if no bootdevs, -ENOMEM if out of memory, other -ve
- *     on other error
- */
-int bootmeth_setup_iter_order(struct bootflow_iter *iter)
+int bootmeth_get_bootflow(struct udevice *dev, struct bootflow *bflow)
+{
+       const struct bootmeth_ops *ops = bootmeth_get_ops(dev);
+
+       if (!ops->read_bootflow)
+               return -ENOSYS;
+       bootflow_init(bflow, NULL, dev);
+
+       return ops->read_bootflow(dev, bflow);
+}
+
+int bootmeth_setup_iter_order(struct bootflow_iter *iter, bool include_global)
 {
        struct bootstd_priv *std;
        struct udevice **order;
@@ -95,29 +105,77 @@ int bootmeth_setup_iter_order(struct bootflow_iter *iter)
 
        /* If we have an ordering, copy it */
        if (IS_ENABLED(CONFIG_BOOTSTD_FULL) && std->bootmeth_count) {
+               int i;
+
+               /*
+                * We don't support skipping global bootmeths. Instead, the user
+                * should omit them from the ordering
+                */
+               if (!include_global)
+                       return log_msg_ret("glob", -EPERM);
                memcpy(order, std->bootmeth_order,
                       count * sizeof(struct bootmeth *));
+
+               if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL)) {
+                       for (i = 0; i < count; i++) {
+                               struct udevice *dev = order[i];
+                               struct bootmeth_uc_plat *ucp;
+                               bool is_global;
+
+                               ucp = dev_get_uclass_plat(dev);
+                               is_global = ucp->flags &
+                                       BOOTMETHF_GLOBAL;
+                               if (is_global) {
+                                       iter->first_glob_method = i;
+                                       break;
+                               }
+                       }
+               }
        } else {
                struct udevice *dev;
-               int i, upto;
+               int i, upto, pass;
 
                /*
-                * Get a list of bootmethods, in seq order (i.e. using aliases).
-                * There may be gaps so try to count up high enough to find them
-                * all.
+                * Do two passes, one to find the normal bootmeths and another
+                * to find the global ones, if required, The global ones go at
+                * the end.
                 */
-               for (i = 0, upto = 0; upto < count && i < 20 + count * 2; i++) {
-                       ret = uclass_get_device_by_seq(UCLASS_BOOTMETH, i,
-                                                      &dev);
-                       if (!ret)
-                               order[upto++] = dev;
+               for (pass = 0, upto = 0; pass < 1 + include_global; pass++) {
+                       if (pass)
+                               iter->first_glob_method = upto;
+                       /*
+                        * Get a list of bootmethods, in seq order (i.e. using
+                        * aliases). There may be gaps so try to count up high
+                        * enough to find them all.
+                        */
+                       for (i = 0; upto < count && i < 20 + count * 2; i++) {
+                               struct bootmeth_uc_plat *ucp;
+                               bool is_global;
+
+                               ret = uclass_get_device_by_seq(UCLASS_BOOTMETH,
+                                                              i, &dev);
+                               if (ret)
+                                       continue;
+                               ucp = dev_get_uclass_plat(dev);
+                               is_global =
+                                       IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) &&
+                                       (ucp->flags & BOOTMETHF_GLOBAL);
+                               if (pass ? is_global : !is_global)
+                                       order[upto++] = dev;
+                       }
                }
                count = upto;
        }
+       if (!count)
+               return log_msg_ret("count2", -ENOENT);
 
+       if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && include_global &&
+           iter->first_glob_method != -1 && iter->first_glob_method != count) {
+               iter->cur_method = iter->first_glob_method;
+               iter->doing_global = true;
+       }
        iter->method_order = order;
        iter->num_methods = count;
-       iter->cur_method = 0;
 
        return 0;
 }