arm: smh: Allow semihosting trap calls to be inlined
[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_init(struct bootflow *bflow, struct udevice *bootdev,
343                    struct udevice *meth)
344 {
345         memset(bflow, '\0', sizeof(*bflow));
346         bflow->dev = bootdev;
347         bflow->method = meth;
348         bflow->state = BOOTFLOWST_BASE;
349 }
350
351 void bootflow_free(struct bootflow *bflow)
352 {
353         free(bflow->name);
354         free(bflow->subdir);
355         free(bflow->fname);
356         free(bflow->buf);
357 }
358
359 void bootflow_remove(struct bootflow *bflow)
360 {
361         if (bflow->dev)
362                 list_del(&bflow->bm_node);
363         list_del(&bflow->glob_node);
364
365         bootflow_free(bflow);
366         free(bflow);
367 }
368
369 int bootflow_boot(struct bootflow *bflow)
370 {
371         int ret;
372
373         if (bflow->state != BOOTFLOWST_READY)
374                 return log_msg_ret("load", -EPROTO);
375
376         ret = bootmeth_boot(bflow->method, bflow);
377         if (ret)
378                 return log_msg_ret("boot", ret);
379
380         /*
381          * internal error, should not get here since we should have booted
382          * something or returned an error
383          */
384
385         return log_msg_ret("end", -EFAULT);
386 }
387
388 int bootflow_run_boot(struct bootflow_iter *iter, struct bootflow *bflow)
389 {
390         int ret;
391
392         printf("** Booting bootflow '%s' with %s\n", bflow->name,
393                bflow->method->name);
394         ret = bootflow_boot(bflow);
395         if (!IS_ENABLED(CONFIG_BOOTSTD_FULL)) {
396                 printf("Boot failed (err=%d)\n", ret);
397                 return ret;
398         }
399
400         switch (ret) {
401         case -EPROTO:
402                 printf("Bootflow not loaded (state '%s')\n",
403                        bootflow_state_get_name(bflow->state));
404                 break;
405         case -ENOSYS:
406                 printf("Boot method '%s' not supported\n", bflow->method->name);
407                 break;
408         case -ENOTSUPP:
409                 /* Disable this bootflow for this iteration */
410                 if (iter) {
411                         int ret2;
412
413                         ret2 = bootflow_iter_drop_bootmeth(iter, bflow->method);
414                         if (!ret2) {
415                                 printf("Boot method '%s' failed and will not be retried\n",
416                                        bflow->method->name);
417                         }
418                 }
419
420                 break;
421         default:
422                 printf("Boot failed (err=%d)\n", ret);
423                 break;
424         }
425
426         return ret;
427 }
428
429 int bootflow_iter_uses_blk_dev(const struct bootflow_iter *iter)
430 {
431         const struct udevice *media = dev_get_parent(iter->dev);
432         enum uclass_id id = device_get_uclass_id(media);
433
434         log_debug("uclass %d: %s\n", id, uclass_get_name(id));
435         if (id != UCLASS_ETH && id != UCLASS_BOOTSTD)
436                 return 0;
437
438         return -ENOTSUPP;
439 }
440
441 int bootflow_iter_uses_network(const struct bootflow_iter *iter)
442 {
443         const struct udevice *media = dev_get_parent(iter->dev);
444         enum uclass_id id = device_get_uclass_id(media);
445
446         log_debug("uclass %d: %s\n", id, uclass_get_name(id));
447         if (id == UCLASS_ETH)
448                 return 0;
449
450         return -ENOTSUPP;
451 }
452
453 int bootflow_iter_uses_system(const struct bootflow_iter *iter)
454 {
455         const struct udevice *media = dev_get_parent(iter->dev);
456         enum uclass_id id = device_get_uclass_id(media);
457
458         log_debug("uclass %d: %s\n", id, uclass_get_name(id));
459         if (id == UCLASS_BOOTSTD)
460                 return 0;
461
462         return -ENOTSUPP;
463 }