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