1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * (C) Copyright 2020
4 * Sam Protsenko <joe.skb7@gmail.com>
5 */
6
7 #include <android_image.h>
8 #include <command.h>
9 #include <env.h>
10 #include <image.h>
11 #include <mapmem.h>
12
13 #define abootimg_addr() \
14 (_abootimg_addr == -1 ? image_load_addr : _abootimg_addr)
15
16 /* Please use abootimg_addr() macro to obtain the boot image address */
17 static ulong _abootimg_addr = -1;
18 static ulong _ainit_bootimg_addr = -1;
19 static ulong _avendor_bootimg_addr = -1;
20
get_abootimg_addr(void)21 ulong get_abootimg_addr(void)
22 {
23 return (_abootimg_addr == -1 ? image_load_addr : _abootimg_addr);
24 }
25
set_abootimg_addr(ulong addr)26 void set_abootimg_addr(ulong addr)
27 {
28 _abootimg_addr = addr;
29 }
30
get_ainit_bootimg_addr(void)31 ulong get_ainit_bootimg_addr(void)
32 {
33 return _ainit_bootimg_addr;
34 }
35
get_avendor_bootimg_addr(void)36 ulong get_avendor_bootimg_addr(void)
37 {
38 return _avendor_bootimg_addr;
39 }
40
set_avendor_bootimg_addr(ulong addr)41 void set_avendor_bootimg_addr(ulong addr)
42 {
43 _avendor_bootimg_addr = addr;
44 }
45
abootimg_get_ver(int argc,char * const argv[])46 static int abootimg_get_ver(int argc, char *const argv[])
47 {
48 const struct andr_boot_img_hdr_v0 *hdr;
49 int res = CMD_RET_SUCCESS;
50
51 if (argc > 1)
52 return CMD_RET_USAGE;
53
54 hdr = map_sysmem(abootimg_addr(), sizeof(*hdr));
55 if (!is_android_boot_image_header(hdr)) {
56 printf("Error: Boot Image header is incorrect\n");
57 res = CMD_RET_FAILURE;
58 goto exit;
59 }
60
61 if (argc == 0)
62 printf("%u\n", hdr->header_version);
63 else
64 env_set_ulong(argv[0], hdr->header_version);
65
66 exit:
67 unmap_sysmem(hdr);
68 return res;
69 }
70
abootimg_get_recovery_dtbo(int argc,char * const argv[])71 static int abootimg_get_recovery_dtbo(int argc, char *const argv[])
72 {
73 ulong addr;
74 u32 size;
75
76 if (argc > 2)
77 return CMD_RET_USAGE;
78
79 if (!android_image_get_dtbo(abootimg_addr(), &addr, &size))
80 return CMD_RET_FAILURE;
81
82 if (argc == 0) {
83 printf("%lx\n", addr);
84 } else {
85 env_set_hex(argv[0], addr);
86 if (argc == 2)
87 env_set_hex(argv[1], size);
88 }
89
90 return CMD_RET_SUCCESS;
91 }
92
abootimg_get_dtb_load_addr(int argc,char * const argv[])93 static int abootimg_get_dtb_load_addr(int argc, char *const argv[])
94 {
95 if (argc > 1)
96 return CMD_RET_USAGE;
97 struct andr_image_data img_data = {0};
98 const struct andr_boot_img_hdr_v0 *hdr;
99 const struct andr_vnd_boot_img_hdr *vhdr = NULL;
100
101 hdr = map_sysmem(abootimg_addr(), sizeof(*hdr));
102 if (get_avendor_bootimg_addr() != -1)
103 vhdr = map_sysmem(get_avendor_bootimg_addr(), sizeof(*vhdr));
104
105 if (!android_image_get_data(hdr, vhdr, &img_data)) {
106 if (get_avendor_bootimg_addr() != -1)
107 unmap_sysmem(vhdr);
108 unmap_sysmem(hdr);
109 return CMD_RET_FAILURE;
110 }
111
112 if (get_avendor_bootimg_addr() != -1)
113 unmap_sysmem(vhdr);
114 unmap_sysmem(hdr);
115
116 if (img_data.header_version < 2) {
117 printf("Error: header_version must be >= 2 for this\n");
118 return CMD_RET_FAILURE;
119 }
120
121 if (!img_data.dtb_load_addr) {
122 printf("Error: failed to read dtb_load_addr\n");
123 return CMD_RET_FAILURE;
124 }
125
126 if (argc == 0)
127 printf("%lx\n", (ulong)img_data.dtb_load_addr);
128 else
129 env_set_hex(argv[0], (ulong)img_data.dtb_load_addr);
130
131 return CMD_RET_SUCCESS;
132 }
133
abootimg_get_dtb_by_index(int argc,char * const argv[])134 static int abootimg_get_dtb_by_index(int argc, char *const argv[])
135 {
136 const char *index_str;
137 u32 num;
138 char *endp;
139 ulong addr;
140 u32 size;
141
142 if (argc < 1 || argc > 3)
143 return CMD_RET_USAGE;
144
145 index_str = argv[0] + strlen("--index=");
146 if (index_str[0] == '\0') {
147 printf("Error: Wrong index num\n");
148 return CMD_RET_FAILURE;
149 }
150
151 num = simple_strtoul(index_str, &endp, 0);
152 if (*endp != '\0') {
153 printf("Error: Wrong index num\n");
154 return CMD_RET_FAILURE;
155 }
156
157 if (!android_image_get_dtb_by_index(abootimg_addr(),
158 get_avendor_bootimg_addr(), num,
159 &addr, &size)) {
160 return CMD_RET_FAILURE;
161 }
162
163 if (argc == 1) {
164 printf("%lx\n", addr);
165 } else {
166 if (env_set_hex(argv[1], addr)) {
167 printf("Error: Can't set [addr_var]\n");
168 return CMD_RET_FAILURE;
169 }
170
171 if (argc == 3) {
172 if (env_set_hex(argv[2], size)) {
173 printf("Error: Can't set [size_var]\n");
174 return CMD_RET_FAILURE;
175 }
176 }
177 }
178
179 return CMD_RET_SUCCESS;
180 }
181
abootimg_get_dtb(int argc,char * const argv[])182 static int abootimg_get_dtb(int argc, char *const argv[])
183 {
184 if (argc < 1)
185 return CMD_RET_USAGE;
186
187 if (strstr(argv[0], "--index="))
188 return abootimg_get_dtb_by_index(argc, argv);
189
190 return CMD_RET_USAGE;
191 }
192
do_abootimg_addr(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])193 static int do_abootimg_addr(struct cmd_tbl *cmdtp, int flag, int argc,
194 char *const argv[])
195 {
196 char *endp;
197 ulong img_addr;
198
199 if (argc < 2 || argc > 4)
200 return CMD_RET_USAGE;
201
202 img_addr = hextoul(argv[1], &endp);
203 if (*endp != '\0') {
204 printf("Error: Wrong image address\n");
205 return CMD_RET_FAILURE;
206 }
207
208 _abootimg_addr = img_addr;
209
210 if (argc > 2) {
211 img_addr = simple_strtoul(argv[2], &endp, 16);
212 if (*endp != '\0') {
213 printf("Error: Wrong vendor_boot image address\n");
214 return CMD_RET_FAILURE;
215 }
216
217 _avendor_bootimg_addr = img_addr;
218 }
219
220 if (argc == 4) {
221 img_addr = simple_strtoul(argv[3], &endp, 16);
222 if (*endp != '\0') {
223 printf("Error: Wrong init_boot image address\n");
224 return CMD_RET_FAILURE;
225 }
226
227 _ainit_bootimg_addr = img_addr;
228 }
229
230 return CMD_RET_SUCCESS;
231 }
232
do_abootimg_get(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])233 static int do_abootimg_get(struct cmd_tbl *cmdtp, int flag, int argc,
234 char *const argv[])
235 {
236 const char *param;
237
238 if (argc < 2)
239 return CMD_RET_USAGE;
240
241 param = argv[1];
242 argc -= 2;
243 argv += 2;
244 if (!strcmp(param, "ver"))
245 return abootimg_get_ver(argc, argv);
246 else if (!strcmp(param, "recovery_dtbo"))
247 return abootimg_get_recovery_dtbo(argc, argv);
248 else if (!strcmp(param, "dtb_load_addr"))
249 return abootimg_get_dtb_load_addr(argc, argv);
250 else if (!strcmp(param, "dtb"))
251 return abootimg_get_dtb(argc, argv);
252
253 return CMD_RET_USAGE;
254 }
255
do_abootimg_dump(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])256 static int do_abootimg_dump(struct cmd_tbl *cmdtp, int flag, int argc,
257 char *const argv[])
258 {
259 if (argc != 2)
260 return CMD_RET_USAGE;
261
262 if (!strcmp(argv[1], "dtb")) {
263 if (android_image_print_dtb_contents(abootimg_addr()))
264 return CMD_RET_FAILURE;
265 } else {
266 return CMD_RET_USAGE;
267 }
268
269 return CMD_RET_SUCCESS;
270 }
271
272 static struct cmd_tbl cmd_abootimg_sub[] = {
273 U_BOOT_CMD_MKENT(addr, 4, 1, do_abootimg_addr, "", ""),
274 U_BOOT_CMD_MKENT(dump, 2, 1, do_abootimg_dump, "", ""),
275 U_BOOT_CMD_MKENT(get, 5, 1, do_abootimg_get, "", ""),
276 };
277
do_abootimg(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])278 static int do_abootimg(struct cmd_tbl *cmdtp, int flag, int argc,
279 char *const argv[])
280 {
281 struct cmd_tbl *cp;
282
283 cp = find_cmd_tbl(argv[1], cmd_abootimg_sub,
284 ARRAY_SIZE(cmd_abootimg_sub));
285
286 /* Strip off leading 'abootimg' command argument */
287 argc--;
288 argv++;
289
290 if (!cp || argc > cp->maxargs)
291 return CMD_RET_USAGE;
292 if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
293 return CMD_RET_SUCCESS;
294
295 return cp->cmd(cmdtp, flag, argc, argv);
296 }
297
298 U_BOOT_CMD(
299 abootimg, CONFIG_SYS_MAXARGS, 0, do_abootimg,
300 "manipulate Android Boot Image",
301 "addr <boot_img_addr> [<vendor_boot_img_addr> [<init_boot_img_addr>]]\n"
302 " - set the address in RAM where boot image is located\n"
303 " ($loadaddr is used by default)\n"
304 "abootimg dump dtb\n"
305 " - print info for all DT blobs in DTB area\n"
306 "abootimg get ver [varname]\n"
307 " - get header version\n"
308 "abootimg get recovery_dtbo [addr_var [size_var]]\n"
309 " - get address and size (hex) of recovery DTBO area in the image\n"
310 " [addr_var]: variable name to contain DTBO area address\n"
311 " [size_var]: variable name to contain DTBO area size\n"
312 "abootimg get dtb_load_addr [varname]\n"
313 " - get load address (hex) of DTB, from image header\n"
314 "abootimg get dtb --index=<num> [addr_var [size_var]]\n"
315 " - get address and size (hex) of DT blob in the image by index\n"
316 " <num>: index number of desired DT blob in DTB area\n"
317 " [addr_var]: variable name to contain DT blob address\n"
318 " [size_var]: variable name to contain DT blob size"
319 );
320