bootm: Fix upper bound of FDT overlap checks
[platform/kernel/u-boot.git] / boot / bootmeth_script.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Bootmethod for booting via a U-Boot script
4  *
5  * Copyright 2021 Google LLC
6  * Written by Simon Glass <sjg@chromium.org>
7  */
8
9 #define LOG_CATEGORY UCLASS_BOOTSTD
10
11 #include <common.h>
12 #include <blk.h>
13 #include <bootflow.h>
14 #include <bootmeth.h>
15 #include <bootstd.h>
16 #include <dm.h>
17 #include <env.h>
18 #include <fs.h>
19 #include <image.h>
20 #include <malloc.h>
21 #include <mapmem.h>
22
23 #define SCRIPT_FNAME1   "boot.scr.uimg"
24 #define SCRIPT_FNAME2   "boot.scr"
25
26 static int script_check(struct udevice *dev, struct bootflow_iter *iter)
27 {
28         int ret;
29
30         /* This only works on block devices */
31         ret = bootflow_iter_uses_blk_dev(iter);
32         if (ret)
33                 return log_msg_ret("blk", ret);
34
35         return 0;
36 }
37
38 static int script_read_bootflow(struct udevice *dev, struct bootflow *bflow)
39 {
40         struct blk_desc *desc = NULL;
41         const char *const *prefixes;
42         struct udevice *bootstd;
43         const char *prefix;
44         int ret, i;
45
46         ret = uclass_first_device_err(UCLASS_BOOTSTD, &bootstd);
47         if (ret)
48                 return log_msg_ret("std", ret);
49
50         /* We require a partition table */
51         if (!bflow->part)
52                 return -ENOENT;
53
54         if (bflow->blk)
55                  desc = dev_get_uclass_plat(bflow->blk);
56
57         prefixes = bootstd_get_prefixes(bootstd);
58         i = 0;
59         do {
60                 prefix = prefixes ? prefixes[i] : NULL;
61
62                 ret = bootmeth_try_file(bflow, desc, prefix, SCRIPT_FNAME1);
63                 if (ret)
64                         ret = bootmeth_try_file(bflow, desc, prefix,
65                                                 SCRIPT_FNAME2);
66         } while (ret && prefixes && prefixes[++i]);
67         if (ret)
68                 return log_msg_ret("try", ret);
69
70         bflow->subdir = strdup(prefix ? prefix : "");
71         if (!bflow->subdir)
72                 return log_msg_ret("prefix", -ENOMEM);
73
74         ret = bootmeth_alloc_file(bflow, 0x10000, 1);
75         if (ret)
76                 return log_msg_ret("read", ret);
77
78         return 0;
79 }
80
81 static int script_boot(struct udevice *dev, struct bootflow *bflow)
82 {
83         struct blk_desc *desc = dev_get_uclass_plat(bflow->blk);
84         ulong addr;
85         int ret;
86
87         ret = env_set("devtype", blk_get_devtype(bflow->blk));
88         if (!ret)
89                 ret = env_set_hex("devnum", desc->devnum);
90         if (!ret)
91                 ret = env_set("prefix", bflow->subdir);
92         if (!ret && IS_ENABLED(CONFIG_ARCH_SUNXI) &&
93             !strcmp("mmc", blk_get_devtype(bflow->blk)))
94                 ret = env_set_hex("mmc_bootdev", desc->devnum);
95         if (ret)
96                 return log_msg_ret("env", ret);
97
98         log_debug("devtype: %s\n", env_get("devtype"));
99         log_debug("devnum: %s\n", env_get("devnum"));
100         log_debug("prefix: %s\n", env_get("prefix"));
101         log_debug("mmc_bootdev: %s\n", env_get("mmc_bootdev"));
102
103         addr = map_to_sysmem(bflow->buf);
104         ret = image_source_script(addr, NULL);
105         if (ret)
106                 return log_msg_ret("boot", ret);
107
108         return 0;
109 }
110
111 static int script_bootmeth_bind(struct udevice *dev)
112 {
113         struct bootmeth_uc_plat *plat = dev_get_uclass_plat(dev);
114
115         plat->desc = IS_ENABLED(CONFIG_BOOTSTD_FULL) ?
116                 "Script boot from a block device" : "script";
117
118         return 0;
119 }
120
121 static struct bootmeth_ops script_bootmeth_ops = {
122         .check          = script_check,
123         .read_bootflow  = script_read_bootflow,
124         .read_file      = bootmeth_common_read_file,
125         .boot           = script_boot,
126 };
127
128 static const struct udevice_id script_bootmeth_ids[] = {
129         { .compatible = "u-boot,script" },
130         { }
131 };
132
133 U_BOOT_DRIVER(bootmeth_script) = {
134         .name           = "bootmeth_script",
135         .id             = UCLASS_BOOTMETH,
136         .of_match       = script_bootmeth_ids,
137         .ops            = &script_bootmeth_ops,
138         .bind           = script_bootmeth_bind,
139 };