Merge tag 'u-boot-at91-fixes-2023.01-a' of https://source.denx.de/u-boot/custodians...
[platform/kernel/u-boot.git] / boot / bootflow.c
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 <common.h>
10 #include <bootdev.h>
11 #include <bootflow.h>
12 #include <bootmeth.h>
13 #include <bootstd.h>
14 #include <dm.h>
15 #include <malloc.h>
16 #include <dm/device-internal.h>
17 #include <dm/uclass-internal.h>
18
19 /* error codes used to signal running out of things */
20 enum {
21         BF_NO_MORE_PARTS        = -ESHUTDOWN,
22         BF_NO_MORE_DEVICES      = -ENODEV,
23 };
24
25 /**
26  * bootflow_state - name for each state
27  *
28  * See enum bootflow_state_t for what each of these means
29  */
30 static const char *const bootflow_state[BOOTFLOWST_COUNT] = {
31         "base",
32         "media",
33         "part",
34         "fs",
35         "file",
36         "ready",
37 };
38
39 const char *bootflow_state_get_name(enum bootflow_state_t state)
40 {
41         /* This doesn't need to be a useful name, since it will never occur */
42         if (state < 0 || state >= BOOTFLOWST_COUNT)
43                 return "?";
44
45         return bootflow_state[state];
46 }
47
48 int bootflow_first_glob(struct bootflow **bflowp)
49 {
50         struct bootstd_priv *std;
51         int ret;
52
53         ret = bootstd_get_priv(&std);
54         if (ret)
55                 return ret;
56
57         if (list_empty(&std->glob_head))
58                 return -ENOENT;
59
60         *bflowp = list_first_entry(&std->glob_head, struct bootflow,
61                                    glob_node);
62
63         return 0;
64 }
65
66 int bootflow_next_glob(struct bootflow **bflowp)
67 {
68         struct bootstd_priv *std;
69         struct bootflow *bflow = *bflowp;
70         int ret;
71
72         ret = bootstd_get_priv(&std);
73         if (ret)
74                 return ret;
75
76         *bflowp = NULL;
77
78         if (list_is_last(&bflow->glob_node, &std->glob_head))
79                 return -ENOENT;
80
81         *bflowp = list_entry(bflow->glob_node.next, struct bootflow, glob_node);
82
83         return 0;
84 }
85
86 void bootflow_iter_init(struct bootflow_iter *iter, int flags)
87 {
88         memset(iter, '\0', sizeof(*iter));
89         iter->first_glob_method = -1;
90         iter->flags = flags;
91 }
92
93 void bootflow_iter_uninit(struct bootflow_iter *iter)
94 {
95         free(iter->dev_order);
96         free(iter->method_order);
97 }
98
99 int bootflow_iter_drop_bootmeth(struct bootflow_iter *iter,
100                                 const struct udevice *bmeth)
101 {
102         /* We only support disabling the current bootmeth */
103         if (bmeth != iter->method || iter->cur_method >= iter->num_methods ||
104             iter->method_order[iter->cur_method] != bmeth)
105                 return -EINVAL;
106
107         memmove(&iter->method_order[iter->cur_method],
108                 &iter->method_order[iter->cur_method + 1],
109                 (iter->num_methods - iter->cur_method - 1) * sizeof(void *));
110
111         iter->num_methods--;
112
113         return 0;
114 }
115
116 static void bootflow_iter_set_dev(struct bootflow_iter *iter,
117                                   struct udevice *dev)
118 {
119         struct bootmeth_uc_plat *ucp = dev_get_uclass_plat(iter->method);
120
121         iter->dev = dev;
122         if ((iter->flags & (BOOTFLOWF_SHOW | BOOTFLOWF_SINGLE_DEV)) ==
123             BOOTFLOWF_SHOW) {
124                 if (dev)
125                         printf("Scanning bootdev '%s':\n", dev->name);
126                 else if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) &&
127                          ucp->flags & BOOTMETHF_GLOBAL)
128                         printf("Scanning global bootmeth '%s':\n",
129                                iter->method->name);
130                 else
131                         printf("No more bootdevs\n");
132         }
133 }
134
135 /**
136  * iter_incr() - Move to the next item (method, part, bootdev)
137  *
138  * Return: 0 if OK, BF_NO_MORE_DEVICES if there are no more bootdevs
139  */
140 static int iter_incr(struct bootflow_iter *iter)
141 {
142         struct udevice *dev;
143         bool inc_dev = true;
144         bool global;
145         int ret;
146
147         global = iter->doing_global;
148
149         if (iter->err == BF_NO_MORE_DEVICES)
150                 return BF_NO_MORE_DEVICES;
151
152         if (iter->err != BF_NO_MORE_PARTS) {
153                 /* Get the next boothmethod */
154                 if (++iter->cur_method < iter->num_methods) {
155                         iter->method = iter->method_order[iter->cur_method];
156                         return 0;
157                 }
158
159                 /*
160                  * If we have finished scanning the global bootmeths, start the
161                  * normal bootdev scan
162                  */
163                 if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && global) {
164                         iter->num_methods = iter->first_glob_method;
165                         iter->doing_global = false;
166
167                         /*
168                          * Don't move to the next dev as we haven't tried this
169                          * one yet!
170                          */
171                         inc_dev = false;
172                 }
173         }
174
175         /* No more bootmeths; start at the first one, and... */
176         iter->cur_method = 0;
177         iter->method = iter->method_order[iter->cur_method];
178
179         if (iter->err != BF_NO_MORE_PARTS) {
180                 /* ...select next partition  */
181                 if (++iter->part <= iter->max_part)
182                         return 0;
183         }
184
185         /* No more partitions; start at the first one and...*/
186         iter->part = 0;
187
188         /*
189          * Note: as far as we know, there is no partition table on the next
190          * bootdev, so set max_part to 0 until we discover otherwise. See
191          * bootdev_find_in_blk() for where this is set.
192          */
193         iter->max_part = 0;
194
195         /* ...select next bootdev */
196         if (iter->flags & BOOTFLOWF_SINGLE_DEV) {
197                 ret = -ENOENT;
198         } else {
199                 if (inc_dev)
200                         iter->cur_dev++;
201                 if (iter->cur_dev == iter->num_devs) {
202                         ret = -ENOENT;
203                         bootflow_iter_set_dev(iter, NULL);
204                 } else {
205                         dev = iter->dev_order[iter->cur_dev];
206                         ret = device_probe(dev);
207                         if (!log_msg_ret("probe", ret))
208                                 bootflow_iter_set_dev(iter, dev);
209                 }
210         }
211
212         /* if there are no more bootdevs, give up */
213         if (ret)
214                 return log_msg_ret("incr", BF_NO_MORE_DEVICES);
215
216         return 0;
217 }
218
219 /**
220  * bootflow_check() - Check if a bootflow can be obtained
221  *
222  * @iter: Provides part, bootmeth to use
223  * @bflow: Bootflow to update on success
224  * Return: 0 if OK, -ENOSYS if there is no bootflow support on this device,
225  *      BF_NO_MORE_PARTS if there are no more partitions on bootdev
226  */
227 static int bootflow_check(struct bootflow_iter *iter, struct bootflow *bflow)
228 {
229         struct udevice *dev;
230         int ret;
231
232         if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && iter->doing_global) {
233                 bootflow_iter_set_dev(iter, NULL);
234                 ret = bootmeth_get_bootflow(iter->method, bflow);
235                 if (ret)
236                         return log_msg_ret("glob", ret);
237
238                 return 0;
239         }
240
241         dev = iter->dev;
242         ret = bootdev_get_bootflow(dev, iter, bflow);
243
244         /* If we got a valid bootflow, return it */
245         if (!ret) {
246                 log_debug("Bootdevice '%s' part %d method '%s': Found bootflow\n",
247                           dev->name, iter->part, iter->method->name);
248                 return 0;
249         }
250
251         /* Unless there is nothing more to try, move to the next device */
252         else if (ret != BF_NO_MORE_PARTS && ret != -ENOSYS) {
253                 log_debug("Bootdevice '%s' part %d method '%s': Error %d\n",
254                           dev->name, iter->part, iter->method->name, ret);
255                 /*
256                  * For 'all' we return all bootflows, even
257                  * those with errors
258                  */
259                 if (iter->flags & BOOTFLOWF_ALL)
260                         return log_msg_ret("all", ret);
261         }
262         if (ret)
263                 return log_msg_ret("check", ret);
264
265         return 0;
266 }
267
268 int bootflow_scan_bootdev(struct udevice *dev, struct bootflow_iter *iter,
269                           int flags, struct bootflow *bflow)
270 {
271         int ret;
272
273         if (dev)
274                 flags |= BOOTFLOWF_SKIP_GLOBAL;
275         bootflow_iter_init(iter, flags);
276
277         ret = bootdev_setup_iter_order(iter, &dev);
278         if (ret)
279                 return log_msg_ret("obdev", -ENODEV);
280
281         ret = bootmeth_setup_iter_order(iter, !(flags & BOOTFLOWF_SKIP_GLOBAL));
282         if (ret)
283                 return log_msg_ret("obmeth", -ENODEV);
284
285         /* Find the first bootmeth (there must be at least one!) */
286         iter->method = iter->method_order[iter->cur_method];
287         if (!IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) || !iter->doing_global)
288                 bootflow_iter_set_dev(iter, dev);
289
290         ret = bootflow_check(iter, bflow);
291         if (ret) {
292                 if (ret != BF_NO_MORE_PARTS && ret != -ENOSYS) {
293                         if (iter->flags & BOOTFLOWF_ALL)
294                                 return log_msg_ret("all", ret);
295                 }
296                 iter->err = ret;
297                 ret = bootflow_scan_next(iter, bflow);
298                 if (ret)
299                         return log_msg_ret("get", ret);
300         }
301
302         return 0;
303 }
304
305 int bootflow_scan_first(struct bootflow_iter *iter, int flags,
306                         struct bootflow *bflow)
307 {
308         int ret;
309
310         ret = bootflow_scan_bootdev(NULL, iter, flags, bflow);
311         if (ret)
312                 return log_msg_ret("start", ret);
313
314         return 0;
315 }
316
317 int bootflow_scan_next(struct bootflow_iter *iter, struct bootflow *bflow)
318 {
319         int ret;
320
321         do {
322                 ret = iter_incr(iter);
323                 if (ret == BF_NO_MORE_DEVICES)
324                         return log_msg_ret("done", ret);
325
326                 if (!ret) {
327                         ret = bootflow_check(iter, bflow);
328                         if (!ret)
329                                 return 0;
330                         iter->err = ret;
331                         if (ret != BF_NO_MORE_PARTS && ret != -ENOSYS) {
332                                 if (iter->flags & BOOTFLOWF_ALL)
333                                         return log_msg_ret("all", ret);
334                         }
335                 } else {
336                         iter->err = ret;
337                 }
338
339         } while (1);
340 }
341
342 void bootflow_free(struct bootflow *bflow)
343 {
344         free(bflow->name);
345         free(bflow->subdir);
346         free(bflow->fname);
347         free(bflow->buf);
348 }
349
350 void bootflow_remove(struct bootflow *bflow)
351 {
352         if (bflow->dev)
353                 list_del(&bflow->bm_node);
354         list_del(&bflow->glob_node);
355
356         bootflow_free(bflow);
357         free(bflow);
358 }
359
360 int bootflow_boot(struct bootflow *bflow)
361 {
362         int ret;
363
364         if (bflow->state != BOOTFLOWST_READY)
365                 return log_msg_ret("load", -EPROTO);
366
367         ret = bootmeth_boot(bflow->method, bflow);
368         if (ret)
369                 return log_msg_ret("boot", ret);
370
371         /*
372          * internal error, should not get here since we should have booted
373          * something or returned an error
374          */
375
376         return log_msg_ret("end", -EFAULT);
377 }
378
379 int bootflow_run_boot(struct bootflow_iter *iter, struct bootflow *bflow)
380 {
381         int ret;
382
383         printf("** Booting bootflow '%s' with %s\n", bflow->name,
384                bflow->method->name);
385         ret = bootflow_boot(bflow);
386         if (!IS_ENABLED(CONFIG_BOOTSTD_FULL)) {
387                 printf("Boot failed (err=%d)\n", ret);
388                 return ret;
389         }
390
391         switch (ret) {
392         case -EPROTO:
393                 printf("Bootflow not loaded (state '%s')\n",
394                        bootflow_state_get_name(bflow->state));
395                 break;
396         case -ENOSYS:
397                 printf("Boot method '%s' not supported\n", bflow->method->name);
398                 break;
399         case -ENOTSUPP:
400                 /* Disable this bootflow for this iteration */
401                 if (iter) {
402                         int ret2;
403
404                         ret2 = bootflow_iter_drop_bootmeth(iter, bflow->method);
405                         if (!ret2) {
406                                 printf("Boot method '%s' failed and will not be retried\n",
407                                        bflow->method->name);
408                         }
409                 }
410
411                 break;
412         default:
413                 printf("Boot failed (err=%d)\n", ret);
414                 break;
415         }
416
417         return ret;
418 }
419
420 int bootflow_iter_uses_blk_dev(const struct bootflow_iter *iter)
421 {
422         const struct udevice *media = dev_get_parent(iter->dev);
423         enum uclass_id id = device_get_uclass_id(media);
424
425         log_debug("uclass %d: %s\n", id, uclass_get_name(id));
426         if (id != UCLASS_ETH && id != UCLASS_BOOTSTD)
427                 return 0;
428
429         return -ENOTSUPP;
430 }
431
432 int bootflow_iter_uses_network(const struct bootflow_iter *iter)
433 {
434         const struct udevice *media = dev_get_parent(iter->dev);
435         enum uclass_id id = device_get_uclass_id(media);
436
437         log_debug("uclass %d: %s\n", id, uclass_get_name(id));
438         if (id == UCLASS_ETH)
439                 return 0;
440
441         return -ENOTSUPP;
442 }
443
444 int bootflow_iter_uses_system(const struct bootflow_iter *iter)
445 {
446         const struct udevice *media = dev_get_parent(iter->dev);
447         enum uclass_id id = device_get_uclass_id(media);
448
449         log_debug("uclass %d: %s\n", id, uclass_get_name(id));
450         if (id == UCLASS_BOOTSTD)
451                 return 0;
452
453         return -ENOTSUPP;
454 }