Merge tag 'efi-2022-07-rc4-4' of https://source.denx.de/u-boot/custodians/u-boot-efi
[platform/kernel/u-boot.git] / cmd / adtimg.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2018 Linaro Ltd.
4  * Sam Protsenko <semen.protsenko@linaro.org>
5  * Eugeniu Rosca <rosca.eugeniu@gmail.com>
6  */
7
8 #include <command.h>
9 #include <env.h>
10 #include <image-android-dt.h>
11 #include <common.h>
12
13 #define OPT_INDEX       "--index"
14
15 /*
16  * Current/working DTB/DTBO Android image address.
17  * Similar to 'working_fdt' variable in 'fdt' command.
18  */
19 static ulong working_img;
20
21 static int do_adtimg_addr(struct cmd_tbl *cmdtp, int flag, int argc,
22                           char *const argv[])
23 {
24         char *endp;
25         ulong hdr_addr;
26
27         if (argc != 2)
28                 return CMD_RET_USAGE;
29
30         hdr_addr = hextoul(argv[1], &endp);
31         if (*endp != '\0') {
32                 printf("Error: Wrong image address '%s'\n", argv[1]);
33                 return CMD_RET_FAILURE;
34         }
35
36         /*
37          * Allow users to set an address prior to copying the DTB/DTBO
38          * image to that same address, i.e. skip header verification.
39          */
40
41         working_img = hdr_addr;
42         return CMD_RET_SUCCESS;
43 }
44
45 static int adtimg_check_working_img(void)
46 {
47         if (!working_img) {
48                 printf("Error: Please, call 'adtimg addr <addr>'. Aborting!\n");
49                 return CMD_RET_FAILURE;
50         }
51
52         if (!android_dt_check_header(working_img)) {
53                 printf("Error: Invalid image header at 0x%lx\n", working_img);
54                 return CMD_RET_FAILURE;
55         }
56
57         return CMD_RET_SUCCESS;
58 }
59
60 static int do_adtimg_dump(struct cmd_tbl *cmdtp, int flag, int argc,
61                           char *const argv[])
62 {
63         if (argc != 1)
64                 return CMD_RET_USAGE;
65
66         if (adtimg_check_working_img() != CMD_RET_SUCCESS)
67                 return CMD_RET_FAILURE;
68
69         android_dt_print_contents(working_img);
70
71         return CMD_RET_SUCCESS;
72 }
73
74 static int adtimg_getopt_u32(char * const opt, char * const name, u32 *optval)
75 {
76         char *endp, *str;
77         u32 val;
78
79         if (!opt || !name || !optval)
80                 return CMD_RET_FAILURE;
81
82         str = strchr(opt, '=');
83         if (!str) {
84                 printf("Error: Option '%s' not followed by '='\n", name);
85                 return CMD_RET_FAILURE;
86         }
87
88         if (*++str == '\0') {
89                 printf("Error: Option '%s=' not followed by value\n", name);
90                 return CMD_RET_FAILURE;
91         }
92
93         val = simple_strtoul(str, &endp, 0);
94         if (*endp != '\0') {
95                 printf("Error: Wrong integer value '%s=%s'\n", name, str);
96                 return CMD_RET_FAILURE;
97         }
98
99         *optval = val;
100         return CMD_RET_SUCCESS;
101 }
102
103 static int adtimg_getopt_index(int argc, char *const argv[], u32 *index,
104                                char **avar, char **svar)
105 {
106         int ret;
107
108         if (!argv || !avar || !svar)
109                 return CMD_RET_FAILURE;
110
111         if (argc > 3) {
112                 printf("Error: Unexpected argument '%s'\n", argv[3]);
113                 return CMD_RET_FAILURE;
114         }
115
116         ret = adtimg_getopt_u32(argv[0], OPT_INDEX, index);
117         if (ret != CMD_RET_SUCCESS)
118                 return ret;
119
120         if (argc > 1)
121                 *avar = argv[1];
122         if (argc > 2)
123                 *svar = argv[2];
124
125         return CMD_RET_SUCCESS;
126 }
127
128 static int adtimg_get_dt_by_index(int argc, char *const argv[])
129 {
130         ulong addr;
131         u32 index, size;
132         int ret;
133         char *avar = NULL, *svar = NULL;
134
135         ret = adtimg_getopt_index(argc, argv, &index, &avar, &svar);
136         if (ret != CMD_RET_SUCCESS)
137                 return ret;
138
139         if (!android_dt_get_fdt_by_index(working_img, index, &addr, &size))
140                 return CMD_RET_FAILURE;
141
142         if (avar && svar) {
143                 ret = env_set_hex(avar, addr);
144                 if (ret) {
145                         printf("Error: Can't set '%s' to 0x%lx\n", avar, addr);
146                         return CMD_RET_FAILURE;
147                 }
148                 ret = env_set_hex(svar, size);
149                 if (ret) {
150                         printf("Error: Can't set '%s' to 0x%x\n", svar, size);
151                         return CMD_RET_FAILURE;
152                 }
153         } else if (avar) {
154                 ret = env_set_hex(avar, addr);
155                 if (ret) {
156                         printf("Error: Can't set '%s' to 0x%lx\n", avar, addr);
157                         return CMD_RET_FAILURE;
158                 }
159                 printf("0x%x (%d)\n", size, size);
160         } else {
161                 printf("0x%lx, 0x%x (%d)\n", addr, size, size);
162         }
163
164         return CMD_RET_SUCCESS;
165 }
166
167 static int adtimg_get_dt(int argc, char *const argv[])
168 {
169         if (argc < 2) {
170                 printf("Error: No options passed to '%s'\n", argv[0]);
171                 return CMD_RET_FAILURE;
172         }
173
174         /* Strip off leading 'dt' command argument */
175         argc--;
176         argv++;
177
178         if (!strncmp(argv[0], OPT_INDEX, sizeof(OPT_INDEX) - 1))
179                 return adtimg_get_dt_by_index(argc, argv);
180
181         printf("Error: Option '%s' not supported\n", argv[0]);
182         return CMD_RET_FAILURE;
183 }
184
185 static int do_adtimg_get(struct cmd_tbl *cmdtp, int flag, int argc,
186                          char *const argv[])
187 {
188         if (argc < 2) {
189                 printf("Error: No arguments passed to '%s'\n", argv[0]);
190                 return CMD_RET_FAILURE;
191         }
192
193         if (adtimg_check_working_img() != CMD_RET_SUCCESS)
194                 return CMD_RET_FAILURE;
195
196         /* Strip off leading 'get' command argument */
197         argc--;
198         argv++;
199
200         if (!strcmp(argv[0], "dt"))
201                 return adtimg_get_dt(argc, argv);
202
203         printf("Error: Wrong argument '%s'\n", argv[0]);
204         return CMD_RET_FAILURE;
205 }
206
207 static struct cmd_tbl cmd_adtimg_sub[] = {
208         U_BOOT_CMD_MKENT(addr, CONFIG_SYS_MAXARGS, 1, do_adtimg_addr, "", ""),
209         U_BOOT_CMD_MKENT(dump, CONFIG_SYS_MAXARGS, 1, do_adtimg_dump, "", ""),
210         U_BOOT_CMD_MKENT(get, CONFIG_SYS_MAXARGS, 1, do_adtimg_get, "", ""),
211 };
212
213 static int do_adtimg(struct cmd_tbl *cmdtp, int flag, int argc,
214                      char *const argv[])
215 {
216         struct cmd_tbl *cp;
217
218         cp = find_cmd_tbl(argv[1], cmd_adtimg_sub, ARRAY_SIZE(cmd_adtimg_sub));
219
220         /* Strip off leading 'adtimg' command argument */
221         argc--;
222         argv++;
223
224         if (!cp || argc > cp->maxargs)
225                 return CMD_RET_USAGE;
226         if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
227                 return CMD_RET_SUCCESS;
228
229         return cp->cmd(cmdtp, flag, argc, argv);
230 }
231
232 U_BOOT_CMD(
233         adtimg, CONFIG_SYS_MAXARGS, 0, do_adtimg,
234         "manipulate dtb/dtbo Android image",
235         "addr <addr> - Set image location to <addr>\n"
236         "adtimg dump        - Print out image contents\n"
237         "adtimg get dt --index=<index> [avar [svar]]         - Get DT address/size by index\n"
238         "\n"
239         "Legend:\n"
240         "  - <addr>: DTB/DTBO image address (hex) in RAM\n"
241         "  - <index>: index (hex/dec) of desired DT in the image\n"
242         "  - <avar>: variable name to contain DT address (hex)\n"
243         "  - <svar>: variable name to contain DT size (hex)"
244 );