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