xref: /OK3568_Linux_fs/u-boot/cmd/boot_android.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  */
6 
7 #include <android_bootloader.h>
8 #include <android_avb/avb_version.h>
9 #include <android_avb/avb_ab_flow.h>
10 #include <android_avb/avb_ops_user.h>
11 #include <android_cmds.h>
12 #include <malloc.h>
13 #include <common.h>
14 #include <bootm.h>
15 #include <command.h>
16 #include <mp_boot.h>
17 #include <android_bootloader_message.h>
18 #include <android_avb/rk_avb_ops_user.h>
19 #include <android_avb/avb_atx_ops.h>
20 
do_boot_android(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])21 static int do_boot_android(cmd_tbl_t *cmdtp, int flag, int argc,
22 			   char * const argv[])
23 {
24 	unsigned long load_address;
25 	int ret = CMD_RET_SUCCESS;
26 	char *addr_arg_endp, *addr_str;
27 	struct blk_desc *dev_desc;
28 
29 	if (argc < 3)
30 		return CMD_RET_USAGE;
31 	if (argc > 5)
32 		return CMD_RET_USAGE;
33 
34 #ifdef CONFIG_MP_BOOT_BOOTM
35 	mpb_post(5);
36 #endif
37 	if (argc >= 5) {
38 		load_address = simple_strtoul(argv[4], &addr_arg_endp, 16);
39 		if (addr_arg_endp == argv[4] || *addr_arg_endp != '\0')
40 			return CMD_RET_USAGE;
41 	} else {
42 		addr_str = env_get("kernel_addr_r");
43 		if (addr_str)
44 			load_address = simple_strtoul(addr_str, NULL, 16);
45 		else
46 			load_address = CONFIG_SYS_LOAD_ADDR;
47 	}
48 
49 #if defined(CONFIG_ARM64)
50 	/* ARM64 kernel load addr need to align to 0x80000, and android boot.img
51 	 * have a 2KB header, need to reserve space for it.
52 	 */
53 	load_address &= ~0x7ffff;
54 #endif
55 
56 	dev_desc = blk_get_dev(argv[1], simple_strtoul(argv[2], NULL, 16));
57 	if (!dev_desc) {
58 		printf("Could not get %s %s\n", argv[1], argv[2]);
59 		return CMD_RET_FAILURE;
60 	}
61 
62 	ret = android_bootloader_boot_flow(dev_desc, load_address);
63 	if (ret < 0) {
64 		printf("Android boot failed, error %d.\n", ret);
65 		return CMD_RET_FAILURE;
66 	}
67 	return CMD_RET_SUCCESS;
68 }
69 
70 U_BOOT_CMD(
71 	boot_android, 5, 0, do_boot_android,
72 	"Execute the Android Bootloader flow.",
73 	"<interface> <dev[:part|;part_name]> <slot> [<kernel_addr>]\n"
74 	"    - Load the Boot Control Block (BCB) from the partition 'part' on\n"
75 	"      device type 'interface' instance 'dev' to determine the boot\n"
76 	"      mode, and load and execute the appropriate kernel.\n"
77 	"      In normal and recovery mode, the kernel will be loaded from\n"
78 	"      the corresponding \"boot\" partition. In bootloader mode, the\n"
79 	"      command defined in the \"fastbootcmd\" variable will be\n"
80 	"      executed.\n"
81 	"      On Android devices with multiple slots, the pass 'slot' is\n"
82 	"      used to load the appropriate kernel. The standard slot names\n"
83 	"      are 'a' and 'b'.\n"
84 	"    - If 'part_name' is passed, preceded with a ; instead of :, the\n"
85 	"      partition name whose label is 'part_name' will be looked up in\n"
86 	"      the partition table. This is commonly the \"misc\" partition.\n"
87 );
88 
89 #ifdef CONFIG_ANDROID_AB
do_avb_init_ab_metadata(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])90 int do_avb_init_ab_metadata(cmd_tbl_t *cmdtp, int flag,
91 			    int argc, char * const argv[])
92 {
93 	AvbOps *ops;
94 	AvbABData ab_data;
95 
96 	memset(&ab_data, 0, sizeof(AvbABData));
97 	debug("sizeof(AvbABData) = %d\n", (int)(size_t)sizeof(AvbABData));
98 	if (argc != 1)
99 		return CMD_RET_USAGE;
100 
101 	ops = avb_ops_user_new();
102 	if (ops == NULL) {
103 		printf("avb_ops_user_new() failed!\n");
104 		return CMD_RET_FAILURE;
105 	}
106 
107 	avb_ab_data_init(&ab_data);
108 	if (ops->ab_ops->write_ab_metadata(ops->ab_ops, &ab_data) != 0) {
109 		printf("do_avb_init_ab_metadata error!\n");
110 		avb_ops_user_free(ops);
111 		return CMD_RET_FAILURE;
112 	}
113 
114 	printf("Initialize ab data to misc partition success.\n");
115 	avb_ops_user_free(ops);
116 
117 	return CMD_RET_SUCCESS;
118 }
119 
do_avb_ab_mark_slot_active(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])120 int do_avb_ab_mark_slot_active(cmd_tbl_t *cmdtp, int flag,
121 			       int argc, char * const argv[])
122 {
123 	AvbOps *ops;
124 	unsigned int slot_number;
125 
126 	if (argc != 2)
127 		return CMD_RET_USAGE;
128 
129 	ops = avb_ops_user_new();
130 	if (ops == NULL) {
131 		printf("avb_ops_user_new() failed!\n");
132 		return CMD_RET_FAILURE;
133 	}
134 
135 	slot_number = simple_strtoul(argv[1], NULL, 16);
136 	if (avb_ab_mark_slot_active(ops->ab_ops, slot_number) != 0) {
137 		printf("avb_ab_mark_slot_active error!\n");
138 		avb_ops_user_free(ops);
139 		return CMD_RET_FAILURE;
140 	}
141 
142 	printf("Mark slot %d active successfully.\n", slot_number);
143 	avb_ops_user_free(ops);
144 
145 	return CMD_RET_SUCCESS;
146 }
147 
do_avb_ab_mark_slot_unbootable(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])148 int do_avb_ab_mark_slot_unbootable(cmd_tbl_t *cmdtp, int flag,
149 				   int argc, char * const argv[])
150 {
151 	AvbOps *ops;
152 	unsigned int slot_number;
153 
154 	if (argc != 2)
155 		return CMD_RET_USAGE;
156 
157 	ops = avb_ops_user_new();
158 	if (ops == NULL) {
159 		printf("avb_ops_user_new() failed!\n");
160 		return CMD_RET_FAILURE;
161 	}
162 
163 	slot_number = simple_strtoul(argv[1], NULL, 16);
164 	if (avb_ab_mark_slot_unbootable(ops->ab_ops, slot_number) != 0) {
165 		printf("do_avb_ab_mark_slot_unbootable error!\n");
166 		avb_ops_user_free(ops);
167 		return CMD_RET_FAILURE;
168 	}
169 
170 	printf("Mark slot %d unbootable successfully.\n", slot_number);
171 	avb_ops_user_free(ops);
172 
173 	return CMD_RET_SUCCESS;
174 }
175 
do_avb_ab_mark_slot_successful(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])176 int do_avb_ab_mark_slot_successful(cmd_tbl_t *cmdtp, int flag,
177 				   int argc, char * const argv[])
178 {
179 	AvbOps *ops;
180 	unsigned int slot_number;
181 
182 	if (argc != 2)
183 		return CMD_RET_USAGE;
184 
185 	ops = avb_ops_user_new();
186 	if (ops == NULL) {
187 		printf("avb_ops_user_new() failed!\n");
188 		return CMD_RET_FAILURE;
189 	}
190 
191 	slot_number = simple_strtoul(argv[1], NULL, 16);
192 	if (avb_ab_mark_slot_successful(ops->ab_ops, slot_number) != 0) {
193 		printf("do_avb_ab_mark_slot_successful error!\n");
194 		avb_ops_user_free(ops);
195 		return CMD_RET_FAILURE;
196 	}
197 
198 	avb_ops_user_free(ops);
199 
200 	return CMD_RET_SUCCESS;
201 }
202 
do_avb_read_ab_metadata(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])203 int do_avb_read_ab_metadata(cmd_tbl_t *cmdtp, int flag,
204 			    int argc, char * const argv[])
205 {
206 	AvbOps *ops;
207 	AvbABData ab_data;
208 
209 	if (argc != 1)
210 		return CMD_RET_USAGE;
211 
212 	ops = avb_ops_user_new();
213 	if (ops == NULL) {
214 		printf("avb_ops_user_new() failed!\n");
215 		return CMD_RET_FAILURE;
216 	}
217 
218 	if (ops->ab_ops->read_ab_metadata(ops->ab_ops, &ab_data) != 0) {
219 		printf("do_avb_write_ab_metadata error!\n");
220 		avb_ops_user_free(ops);
221 		return CMD_RET_FAILURE;
222 	}
223 
224 	printf("Slot A information:\n");
225 	printf("slot A: priority = %d, tries_remaining = %d,\
226 	       successful_boot = %d\n",
227 	       ab_data.slots[0].priority,
228 	       ab_data.slots[0].tries_remaining,
229 	       ab_data.slots[0].successful_boot);
230 	printf("Slot B information:\n");
231 	printf("slot B: priority = %d, tries_remaining = %d,\
232 	       successful_boot = %d\n",
233 	       ab_data.slots[1].priority,
234 	       ab_data.slots[1].tries_remaining,
235 	       ab_data.slots[1].successful_boot);
236 	avb_ops_user_free(ops);
237 
238 	return CMD_RET_SUCCESS;
239 }
240 
do_avb_write_ab_metadata(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])241 int do_avb_write_ab_metadata(cmd_tbl_t *cmdtp, int flag,
242 			     int argc, char * const argv[])
243 {
244 	AvbOps *ops;
245 	AvbABData ab_data;
246 
247 	if (argc != 1)
248 		return CMD_RET_USAGE;
249 
250 	ops = avb_ops_user_new();
251 	if (ops == NULL) {
252 		printf("avb_ops_user_new() failed!\n");
253 		return CMD_RET_FAILURE;
254 	}
255 
256 	if (ops->ab_ops->write_ab_metadata(ops->ab_ops, &ab_data) != 0) {
257 		printf("do_avb_write_ab_metadata error!\n");
258 		avb_ops_user_free(ops);
259 		return CMD_RET_FAILURE;
260 	}
261 
262 	avb_ops_user_free(ops);
263 
264 	return CMD_RET_SUCCESS;
265 }
266 #endif
267 
268 #ifdef CONFIG_ANDROID_AVB
do_avb_version(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])269 int do_avb_version(cmd_tbl_t *cmdtp, int flag, int argc,
270 		   char * const argv[])
271 {
272 	const char *avb_version;
273 
274 	if (argc != 1)
275 		return CMD_RET_USAGE;
276 
277 	avb_version = avb_version_string();
278 	printf("Android avb version is %s.\n", avb_version);
279 
280 	return CMD_RET_SUCCESS;
281 }
282 
do_avb_read_rollback_index(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])283 int do_avb_read_rollback_index(cmd_tbl_t *cmdtp, int flag,
284 			       int argc, char * const argv[])
285 {
286 	AvbOps *ops;
287 	uint64_t out_rollback_index;
288 	size_t rollback_index_location;
289 
290 	if (argc != 2)
291 		return CMD_RET_USAGE;
292 
293 	ops = avb_ops_user_new();
294 	if (ops == NULL) {
295 		printf("avb_ops_user_new() failed!\n");
296 		return CMD_RET_FAILURE;
297 	}
298 
299 	rollback_index_location = simple_strtoul(argv[1], NULL, 16);
300 	if (ops->read_rollback_index(ops, rollback_index_location,
301 				     &out_rollback_index) != 0) {
302 		printf("do_avb_read_rollback_index error!\n");
303 		avb_ops_user_free(ops);
304 		return CMD_RET_FAILURE;
305 	}
306 
307 	printf("\nout_rollback_index = %llx\n", out_rollback_index);
308 	avb_ops_user_free(ops);
309 
310 	return CMD_RET_SUCCESS;
311 }
312 
do_avb_write_rollback_index(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])313 int do_avb_write_rollback_index(cmd_tbl_t *cmdtp, int flag,
314 				int argc, char * const argv[])
315 {
316 	AvbOps *ops;
317 	uint64_t out_rollback_index;
318 	size_t rollback_index_location;
319 
320 	if (argc != 3)
321 		return CMD_RET_USAGE;
322 
323 	rollback_index_location = simple_strtoul(argv[1], NULL, 16);
324 	out_rollback_index = simple_strtoull(argv[2], NULL, 16);
325 	debug("out_rollback_index = %llx\n", out_rollback_index);
326 	ops = avb_ops_user_new();
327 	if (ops == NULL) {
328 		printf("avb_ops_user_new() failed!\n");
329 		return CMD_RET_FAILURE;
330 	}
331 
332 	if (ops->write_rollback_index(ops, rollback_index_location,
333 				      out_rollback_index) != 0) {
334 		printf("do_avb_write_rollback_index error!\n");
335 		avb_ops_user_free(ops);
336 		return CMD_RET_FAILURE;
337 	}
338 
339 	printf("\nWrite  rollback index successfully.\n");
340 	avb_ops_user_free(ops);
341 
342 	return CMD_RET_SUCCESS;
343 }
344 
do_avb_read_is_device_unlocked(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])345 int do_avb_read_is_device_unlocked(cmd_tbl_t *cmdtp, int flag,
346 				   int argc, char * const argv[])
347 {
348 	AvbOps *ops;
349 	bool out_is_unlocked;
350 
351 	if (argc != 1)
352 		return CMD_RET_USAGE;
353 
354 	ops = avb_ops_user_new();
355 	if (ops == NULL) {
356 		printf("avb_ops_user_new() failed!\n");
357 		return CMD_RET_FAILURE;
358 	}
359 
360 	if (ops->read_is_device_unlocked(ops, &out_is_unlocked) != 0) {
361 		printf("do_avb_read_is_device_unlocked error!\n");
362 		avb_ops_user_free(ops);
363 		return CMD_RET_FAILURE;
364 	}
365 
366 	printf("\n The device is %s\n",
367 		out_is_unlocked ? "UNLOCKED" : "LOCKED");
368 	avb_ops_user_free(ops);
369 
370 	return CMD_RET_SUCCESS;
371 }
do_avb_write_is_device_unlocked(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])372 int do_avb_write_is_device_unlocked(cmd_tbl_t *cmdtp, int flag,
373 				    int argc, char * const argv[])
374 {
375 	AvbOps *ops;
376 	bool out_is_unlocked;
377 
378 	if (argc != 2)
379 		return CMD_RET_USAGE;
380 
381 	out_is_unlocked = simple_strtoul(argv[1], NULL, 16);
382 	if ((out_is_unlocked != 0) && (out_is_unlocked != 1))
383 		printf("enter out_is_unlocked value must is '0' or '1'\n");
384 
385 	ops = avb_ops_user_new();
386 	if (ops == NULL) {
387 		printf("avb_ops_user_new() failed!\n");
388 		return CMD_RET_FAILURE;
389 	}
390 
391 	if (ops->write_is_device_unlocked(ops, &out_is_unlocked) != 0) {
392 		printf("do_avb_write_is_device_unlocked error!\n");
393 		avb_ops_user_free(ops);
394 		return CMD_RET_FAILURE;
395 	}
396 
397 	debug("out_is_unlocked = %d\n", out_is_unlocked);
398 	avb_ops_user_free(ops);
399 
400 	return CMD_RET_SUCCESS;
401 }
402 
do_avb_get_size_of_partition(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])403 int do_avb_get_size_of_partition(cmd_tbl_t *cmdtp, int flag,
404 				 int argc, char * const argv[])
405 {
406 	AvbOps *ops;
407 	char *requested_partitions;
408 	uint64_t out_size_in_bytes;
409 
410 	if (argc != 2)
411 		return CMD_RET_USAGE;
412 
413 	requested_partitions = argv[1];
414 	ops = avb_ops_user_new();
415 	if (ops == NULL) {
416 		printf("avb_ops_user_new() failed!\n");
417 		return CMD_RET_FAILURE;
418 	}
419 
420 	if (ops->get_size_of_partition(ops, requested_partitions,
421 				       &out_size_in_bytes) != 0) {
422 		printf("Can not get %s partition size!\n", requested_partitions);
423 		avb_ops_user_free(ops);
424 		return CMD_RET_FAILURE;
425 	}
426 
427 	printf("%s partition size = 0x%llx\n", requested_partitions,
428 	       out_size_in_bytes);
429 	avb_ops_user_free(ops);
430 
431 	return CMD_RET_SUCCESS;
432 }
433 
do_avb_get_get_unique_guid_for_partition(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])434 int do_avb_get_get_unique_guid_for_partition(cmd_tbl_t *cmdtp, int flag,
435 					     int argc, char * const argv[])
436 {
437 	AvbOps *ops;
438 	char *requested_partitions;
439 	size_t guid_buf_size = 37;
440 	char guid_buf[37];
441 
442 	if (argc != 2)
443 		return CMD_RET_USAGE;
444 
445 	requested_partitions = argv[1];
446 	ops = avb_ops_user_new();
447 	if (ops == NULL) {
448 		printf("avb_ops_user_new() failed!\n");
449 		return CMD_RET_FAILURE;
450 	}
451 
452 	if (ops->get_unique_guid_for_partition(ops, requested_partitions,
453 					       guid_buf, guid_buf_size) != 0) {
454 		printf("Can not get %s partition UUID!\n",
455 		       requested_partitions);
456 		avb_ops_user_free(ops);
457 		return CMD_RET_FAILURE;
458 	}
459 
460 	printf("%s partition UUID is %s\n", requested_partitions, guid_buf);
461 	avb_ops_user_free(ops);
462 
463 	return CMD_RET_SUCCESS;
464 }
465 
do_avb_read(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])466 int do_avb_read(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
467 {
468 	AvbOps *ops;
469 	char *requested_partitions;
470 	int64_t offset_blk;
471 	size_t blkcnt;
472 	size_t out_num_read;
473 	int i;
474 	char *buffer;
475 
476 	if (argc != 4)
477 		return CMD_RET_USAGE;
478 
479 	requested_partitions = argv[1];
480 	offset_blk = simple_strtoul(argv[2], NULL, 16);
481 	blkcnt = simple_strtoul(argv[3], NULL, 16);
482 	ops = avb_ops_user_new();
483 	buffer = (char *)malloc(blkcnt * 512);
484 	if (buffer == NULL)
485 		printf("malloc buffer failed!\n");
486 
487 	if (ops == NULL) {
488 		printf("avb_ops_user_new() failed!\n");
489 		return CMD_RET_FAILURE;
490 	}
491 
492 	if (ops->read_from_partition(ops, requested_partitions,
493 				     offset_blk, blkcnt, buffer,
494 				     &out_num_read) != 0) {
495 		printf("do avb read error!\n");
496 		free(buffer);
497 		avb_ops_user_free(ops);
498 		return CMD_RET_FAILURE;
499 	}
500 
501 	for (i = 0; i < 512 * blkcnt; i++) {
502 		printf("buffer %d = %x", i, buffer[i]);
503 		if ((i + 1) % 4 == 0)
504 			printf("\n");
505 	}
506 
507 	free(buffer);
508 	avb_ops_user_free(ops);
509 
510 	return CMD_RET_SUCCESS;
511 }
512 
do_perm_attr_test(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])513 int do_perm_attr_test(cmd_tbl_t *cmdtp, int flag,
514 		      int argc, char * const argv[])
515 {
516 	AvbOps *ops;
517 	int i;
518 	uint8_t hash[AVB_SHA256_DIGEST_SIZE];
519 
520 	if (argc != 1)
521 		return CMD_RET_USAGE;
522 
523 	ops = avb_ops_user_new();
524 	if (ops == NULL) {
525 		printf("avb_ops_user_new() failed!\n");
526 		return CMD_RET_FAILURE;
527 	}
528 
529 	if (ops->atx_ops->read_permanent_attributes_hash(ops->atx_ops, hash) != 0) {
530 		printf("read_permanent_attributes_hash error!\n");
531 		avb_ops_user_free(ops);
532 		return CMD_RET_FAILURE;
533 	}
534 
535 	for (i = 0; i < AVB_SHA256_DIGEST_SIZE; i++) {
536 		if (i % 4 == 0)
537 			printf("\n");
538 		printf("0x%x  ", hash[i]);
539 	}
540 
541 	avb_ops_user_free(ops);
542 
543 	return CMD_RET_SUCCESS;
544 }
545 
do_avb_verify_partition(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])546 int do_avb_verify_partition(cmd_tbl_t *cmdtp, int flag,
547 			    int argc, char * const argv[])
548 {
549 	AvbOps *ops;
550 	const char *requested_partitions[1];
551 	const char * slot_suffixes[2] = {"_a", "_b"};
552 	AvbSlotVerifyFlags flags;
553 	AvbSlotVerifyData *slot_data[2] = {NULL, NULL};
554 	AvbSlotVerifyResult verify_result;
555 	size_t n;
556 
557 	if (argc != 3)
558 		return CMD_RET_USAGE;
559 
560 	requested_partitions[0] = argv[1];
561 	n = simple_strtoul(argv[2], NULL, 16);
562 	ops = avb_ops_user_new();
563 	flags = AVB_SLOT_VERIFY_FLAGS_NONE;
564 	verify_result =
565 		avb_slot_verify(ops,
566 				requested_partitions,
567 				slot_suffixes[n],
568 				flags,
569 				AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
570 				&slot_data[n]);
571 	if (verify_result != 0)
572 		return CMD_RET_FAILURE;
573 
574 	avb_ops_user_free(ops);
575 
576 	return CMD_RET_SUCCESS;
577 }
578 #endif
579 
580 static cmd_tbl_t cmd_avb[] = {
581 #ifdef CONFIG_ANDROID_AB
582 	U_BOOT_CMD_MKENT(init, 1, 1, do_avb_init_ab_metadata, "", ""),
583 	U_BOOT_CMD_MKENT(slot_active, 2, 1,
584 			 do_avb_ab_mark_slot_active, "", ""),
585 	U_BOOT_CMD_MKENT(slot_unbootable, 2, 1,
586 			 do_avb_ab_mark_slot_unbootable, "", ""),
587 	U_BOOT_CMD_MKENT(slot_successful, 2, 1,
588 			 do_avb_ab_mark_slot_successful, "", ""),
589 	U_BOOT_CMD_MKENT(readabmisc, 1, 1, do_avb_read_ab_metadata, "", ""),
590 #endif
591 #ifdef CONFIG_ANDROID_AVB
592 	U_BOOT_CMD_MKENT(version, 1, 1, do_avb_version, "", ""),
593 	U_BOOT_CMD_MKENT(read_rollback, 2, 1,
594 			 do_avb_read_rollback_index, "", ""),
595 	U_BOOT_CMD_MKENT(write_rollback, 3, 1,
596 			 do_avb_write_rollback_index, "", ""),
597 	U_BOOT_CMD_MKENT(read_lock_status, 1, 1,
598 			 do_avb_read_is_device_unlocked, "", ""),
599 	U_BOOT_CMD_MKENT(write_lock_status, 2, 1,
600 			 do_avb_write_is_device_unlocked, "", ""),
601 	U_BOOT_CMD_MKENT(part_size, 2, 1,
602 			 do_avb_get_size_of_partition, "", ""),
603 	U_BOOT_CMD_MKENT(part_guid, 2, 1,
604 			 do_avb_get_get_unique_guid_for_partition, "", ""),
605 	U_BOOT_CMD_MKENT(read, 4, 1, do_avb_read, "", ""),
606 	U_BOOT_CMD_MKENT(perm_attr_test, 1, 1, do_perm_attr_test, "", ""),
607 	U_BOOT_CMD_MKENT(verify, 3, 1, do_avb_verify_partition, "", ""),
608 #endif
609 };
610 
do_boot_avb(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])611 static int do_boot_avb(cmd_tbl_t *cmdtp,
612 		       int flag,
613 		       int argc,
614 		       char * const argv[])
615 {
616 	cmd_tbl_t *cp;
617 
618 	cp = find_cmd_tbl(argv[1], cmd_avb, ARRAY_SIZE(cmd_avb));
619 
620 	argc--;
621 	argv++;
622 
623 	if (cp == NULL || argc > cp->maxargs)
624 		return CMD_RET_USAGE;
625 	if (flag == CMD_FLAG_REPEAT && !cp->repeatable)
626 		return CMD_RET_SUCCESS;
627 
628 	return cp->cmd(cmdtp, flag, argc, argv);
629 }
630 
631 U_BOOT_CMD(
632 	bootavb, 29, 1, do_boot_avb,
633 	"Execute the Android avb a/b boot flow.",
634 	"init - initialize the avbabmeta\n"
635 	"bootavb version - display info of bootavb version\n"
636 	"bootavb slot_active cnt\n"
637 	"bootavb slot_unbootable cnt\n"
638 	"bootavb slot_successful cnt\n"
639 	"bootavb read_rollback rollback_index_location\n"
640 	"bootavb write_rollback rollback_index_location rollback_index\n"
641 	"bootavb read_lock_status\n"
642 	"bootavb write_lock_status 0 or 1\n"
643 	"bootavb part_size partitions_name\n"
644 	"bootavb part_guid partitions_name\n"
645 	"bootavb read partition offset_blk cnt\n"
646 	"bootavb readabmisc\n"
647 	"bootavb perm_attr_test\n"
648 	"bootavb verify partition slot_cnt;partion name without '_a' or '_b'\n"
649 );
650