xref: /rk3399_rockchip-uboot/cmd/boot_android.c (revision 4397fdfd14cb55940ebae2015cc9c276de87b475)
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 
17 static int do_boot_android(cmd_tbl_t *cmdtp, int flag, int argc,
18 			   char * const argv[])
19 {
20 	unsigned long load_address;
21 	int ret = CMD_RET_SUCCESS;
22 	char *addr_arg_endp, *addr_str;
23 	struct blk_desc *dev_desc;
24 	disk_partition_t part_info;
25 
26 	if (argc < 4)
27 		return CMD_RET_USAGE;
28 	if (argc > 5)
29 		return CMD_RET_USAGE;
30 
31 	if (argc >= 5) {
32 		load_address = simple_strtoul(argv[4], &addr_arg_endp, 16);
33 		if (addr_arg_endp == argv[4] || *addr_arg_endp != '\0')
34 			return CMD_RET_USAGE;
35 	} else {
36 		addr_str = env_get("loadaddr");
37 		if (addr_str)
38 			load_address = simple_strtoul(addr_str, NULL, 16);
39 		else
40 			load_address = CONFIG_SYS_LOAD_ADDR;
41 	}
42 
43 	if (part_get_info_by_dev_and_name_or_num(argv[1], argv[2],
44 						 &dev_desc, &part_info) < 0) {
45 		return CMD_RET_FAILURE;
46 	}
47 
48 	ret = android_bootloader_boot_flow(dev_desc, &part_info, argv[3],
49 					   load_address);
50 	if (ret < 0) {
51 		printf("Android boot failed, error %d.\n", ret);
52 		return CMD_RET_FAILURE;
53 	}
54 	return CMD_RET_SUCCESS;
55 }
56 
57 U_BOOT_CMD(
58 	boot_android, 5, 0, do_boot_android,
59 	"Execute the Android Bootloader flow.",
60 	"<interface> <dev[:part|;part_name]> <slot> [<kernel_addr>]\n"
61 	"    - Load the Boot Control Block (BCB) from the partition 'part' on\n"
62 	"      device type 'interface' instance 'dev' to determine the boot\n"
63 	"      mode, and load and execute the appropriate kernel.\n"
64 	"      In normal and recovery mode, the kernel will be loaded from\n"
65 	"      the corresponding \"boot\" partition. In bootloader mode, the\n"
66 	"      command defined in the \"fastbootcmd\" variable will be\n"
67 	"      executed.\n"
68 	"      On Android devices with multiple slots, the pass 'slot' is\n"
69 	"      used to load the appropriate kernel. The standard slot names\n"
70 	"      are 'a' and 'b'.\n"
71 	"    - If 'part_name' is passed, preceded with a ; instead of :, the\n"
72 	"      partition name whose label is 'part_name' will be looked up in\n"
73 	"      the partition table. This is commonly the \"misc\" partition.\n"
74 );
75 
76 #ifdef CONFIG_AVB_LIBAVB_USER
77 int do_avb_init_ab_metadata(cmd_tbl_t *cmdtp, int flag,
78 			    int argc, char * const argv[])
79 {
80 	AvbOps *ops;
81 	AvbABData ab_data;
82 
83 	memset(&ab_data, 0, sizeof(AvbABData));
84 	debug("sizeof(AvbABData) = %d\n", sizeof(AvbABData));
85 	if (argc != 1)
86 		return CMD_RET_USAGE;
87 
88 	ops = avb_ops_user_new();
89 	if (ops == NULL) {
90 		printf("avb_ops_user_new() failed!\n");
91 		return CMD_RET_FAILURE;
92 	}
93 
94 	ops->ab_ops->init_ab_metadata(&ab_data);
95 	debug("init");
96 	if (ops->ab_ops->write_ab_metadata(ops->ab_ops, &ab_data) != 0) {
97 		printf("do_avb_init_ab_metadata error!\n");
98 		avb_ops_user_free(ops);
99 		return CMD_RET_FAILURE;
100 	}
101 
102 	avb_ops_user_free(ops);
103 
104 	return CMD_RET_SUCCESS;
105 }
106 
107 int do_avb_version(cmd_tbl_t *cmdtp, int flag, int argc,
108 		   char * const argv[])
109 {
110 	const char *avb_version;
111 
112 	if (argc != 1)
113 		return CMD_RET_USAGE;
114 
115 	avb_version = avb_version_string();
116 	printf("Android avb version is %s.\n", avb_version);
117 
118 	return CMD_RET_SUCCESS;
119 }
120 
121 int do_avb_ab_mark_slot_active(cmd_tbl_t *cmdtp, int flag,
122 			       int argc, char * const argv[])
123 {
124 	AvbOps *ops;
125 	unsigned int slot_number;
126 
127 	if (argc != 2)
128 		return CMD_RET_USAGE;
129 
130 	ops = avb_ops_user_new();
131 	if (ops == NULL) {
132 		printf("avb_ops_user_new() failed!\n");
133 		return CMD_RET_FAILURE;
134 	}
135 
136 	slot_number = simple_strtoul(argv[1], NULL, 16);
137 	if (avb_ab_mark_slot_active(ops->ab_ops, slot_number) != 0) {
138 		printf("avb_ab_mark_slot_active error!\n");
139 		avb_ops_user_free(ops);
140 		return CMD_RET_FAILURE;
141 	}
142 
143 	avb_ops_user_free(ops);
144 
145 	return CMD_RET_SUCCESS;
146 }
147 
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 	avb_ops_user_free(ops);
171 
172 	return CMD_RET_SUCCESS;
173 }
174 
175 int do_avb_ab_mark_slot_successful(cmd_tbl_t *cmdtp, int flag,
176 				   int argc, char * const argv[])
177 {
178 	AvbOps *ops;
179 	unsigned int slot_number;
180 
181 	if (argc != 2)
182 		return CMD_RET_USAGE;
183 
184 	ops = avb_ops_user_new();
185 	if (ops == NULL) {
186 		printf("avb_ops_user_new() failed!\n");
187 		return CMD_RET_FAILURE;
188 	}
189 
190 	slot_number = simple_strtoul(argv[1], NULL, 16);
191 	if (avb_ab_mark_slot_successful(ops->ab_ops, slot_number) != 0) {
192 		printf("do_avb_ab_mark_slot_successful error!\n");
193 		avb_ops_user_free(ops);
194 		return CMD_RET_FAILURE;
195 	}
196 
197 	avb_ops_user_free(ops);
198 
199 	return CMD_RET_SUCCESS;
200 }
201 
202 int do_avb_read_rollback_index(cmd_tbl_t *cmdtp, int flag,
203 			       int argc, char * const argv[])
204 {
205 	AvbOps *ops;
206 	uint64_t out_rollback_index;
207 	size_t rollback_index_location;
208 
209 	if (argc != 2)
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 	rollback_index_location = simple_strtoul(argv[1], NULL, 16);
219 	if (ops->read_rollback_index(ops, rollback_index_location,
220 				     &out_rollback_index) != 0) {
221 		printf("do_avb_read_rollback_index error!\n");
222 		avb_ops_user_free(ops);
223 		return CMD_RET_FAILURE;
224 	}
225 
226 	printf("out_rollback_index = %llx\n", out_rollback_index);
227 	avb_ops_user_free(ops);
228 
229 	return CMD_RET_SUCCESS;
230 }
231 
232 int do_avb_write_rollback_index(cmd_tbl_t *cmdtp, int flag,
233 				int argc, char * const argv[])
234 {
235 	AvbOps *ops;
236 	uint64_t out_rollback_index;
237 	size_t rollback_index_location;
238 
239 	if (argc != 3)
240 		return CMD_RET_USAGE;
241 
242 	rollback_index_location = simple_strtoul(argv[1], NULL, 16);
243 	out_rollback_index = simple_strtoull(argv[2], NULL, 16);
244 	debug("out_rollback_index = %llx\n", out_rollback_index);
245 	ops = avb_ops_user_new();
246 	if (ops == NULL) {
247 		printf("avb_ops_user_new() failed!\n");
248 		return CMD_RET_FAILURE;
249 	}
250 
251 	if (ops->write_rollback_index(ops, rollback_index_location,
252 				      out_rollback_index) != 0) {
253 		printf("do_avb_write_rollback_index error!\n");
254 		avb_ops_user_free(ops);
255 		return CMD_RET_FAILURE;
256 	}
257 
258 	avb_ops_user_free(ops);
259 
260 	return CMD_RET_SUCCESS;
261 }
262 
263 int do_avb_read_is_device_unlocked(cmd_tbl_t *cmdtp, int flag,
264 				   int argc, char * const argv[])
265 {
266 	AvbOps *ops;
267 	bool out_is_unlocked;
268 
269 	if (argc != 1)
270 		return CMD_RET_USAGE;
271 
272 	ops = avb_ops_user_new();
273 	if (ops == NULL) {
274 		printf("avb_ops_user_new() failed!\n");
275 		return CMD_RET_FAILURE;
276 	}
277 
278 	if (ops->read_is_device_unlocked(ops, &out_is_unlocked) != 0) {
279 		printf("do_avb_read_is_device_unlocked error!\n");
280 		avb_ops_user_free(ops);
281 		return CMD_RET_FAILURE;
282 	}
283 
284 	debug("out_is_unlocked = %d\n", out_is_unlocked);
285 	avb_ops_user_free(ops);
286 
287 	return CMD_RET_SUCCESS;
288 }
289 int do_avb_write_is_device_unlocked(cmd_tbl_t *cmdtp, int flag,
290 				    int argc, char * const argv[])
291 {
292 	AvbOps *ops;
293 	bool out_is_unlocked;
294 
295 	if (argc != 2)
296 		return CMD_RET_USAGE;
297 
298 	out_is_unlocked = simple_strtoul(argv[1], NULL, 16);
299 	if ((out_is_unlocked != 0) || (out_is_unlocked != 1))
300 		printf("enter out_is_unlocked value must is '0' or '1'\n");
301 
302 	ops = avb_ops_user_new();
303 	if (ops == NULL) {
304 		printf("avb_ops_user_new() failed!\n");
305 		return CMD_RET_FAILURE;
306 	}
307 
308 	if (ops->write_is_device_unlocked(ops, &out_is_unlocked) != 0) {
309 		printf("do_avb_write_is_device_unlocked error!\n");
310 		avb_ops_user_free(ops);
311 		return CMD_RET_FAILURE;
312 	}
313 
314 	debug("out_is_unlocked = %d\n", out_is_unlocked);
315 	avb_ops_user_free(ops);
316 
317 	return CMD_RET_SUCCESS;
318 }
319 
320 int do_avb_get_size_of_partition(cmd_tbl_t *cmdtp, int flag,
321 				 int argc, char * const argv[])
322 {
323 	AvbOps *ops;
324 	char *requested_partitions;
325 	uint64_t out_size_in_bytes;
326 
327 	if (argc != 2)
328 		return CMD_RET_USAGE;
329 
330 	requested_partitions = argv[1];
331 	ops = avb_ops_user_new();
332 	if (ops == NULL) {
333 		printf("avb_ops_user_new() failed!\n");
334 		return CMD_RET_FAILURE;
335 	}
336 
337 	if (ops->get_size_of_partition(ops, requested_partitions,
338 				       &out_size_in_bytes) != 0) {
339 		printf("do_avb_get_size_of_partition error!\n");
340 		avb_ops_user_free(ops);
341 		return CMD_RET_FAILURE;
342 	}
343 
344 	printf("partition size = %lld\n", out_size_in_bytes);
345 	avb_ops_user_free(ops);
346 
347 	return CMD_RET_SUCCESS;
348 }
349 
350 int do_avb_get_get_unique_guid_for_partition(cmd_tbl_t *cmdtp, int flag,
351 					     int argc, char * const argv[])
352 {
353 	AvbOps *ops;
354 	char *requested_partitions;
355 	size_t guid_buf_size = 37;
356 	char guid_buf[37];
357 
358 	if (argc != 2)
359 		return CMD_RET_USAGE;
360 
361 	requested_partitions = argv[1];
362 	ops = avb_ops_user_new();
363 	if (ops == NULL) {
364 		printf("avb_ops_user_new() failed!\n");
365 		return CMD_RET_FAILURE;
366 	}
367 
368 	if (ops->get_unique_guid_for_partition(ops, requested_partitions,
369 					       guid_buf, guid_buf_size) != 0) {
370 		printf("do_avb_get_get_unique_guid_for_partition error!\n");
371 		avb_ops_user_free(ops);
372 		return CMD_RET_FAILURE;
373 	}
374 
375 	printf("guid = %s\n", guid_buf);
376 	avb_ops_user_free(ops);
377 
378 	return CMD_RET_SUCCESS;
379 }
380 
381 int do_avb_read(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
382 {
383 	AvbOps *ops;
384 	char *requested_partitions;
385 	int64_t offset_blk;
386 	size_t blkcnt;
387 	size_t out_num_read;
388 	int i;
389 	char *buffer;
390 
391 	if (argc != 4)
392 		return CMD_RET_USAGE;
393 
394 	requested_partitions = argv[1];
395 	offset_blk = simple_strtoul(argv[2], NULL, 16);
396 	blkcnt = simple_strtoul(argv[3], NULL, 16);
397 	ops = avb_ops_user_new();
398 	buffer = (char *)malloc(blkcnt * 512);
399 	if (buffer == NULL)
400 		printf("malloc buffer failed!\n");
401 
402 	if (ops == NULL) {
403 		printf("avb_ops_user_new() failed!\n");
404 		return CMD_RET_FAILURE;
405 	}
406 
407 	if (ops->read_from_partition(ops, requested_partitions,
408 				     offset_blk, blkcnt, buffer,
409 				     &out_num_read) != 0) {
410 		printf("do avb read error!\n");
411 		free(buffer);
412 		avb_ops_user_free(ops);
413 		return CMD_RET_FAILURE;
414 	}
415 
416 	for (i = 0; i < 512 * blkcnt; i++)
417 		printf("buffer %d = %d\n", i, buffer[i]);
418 
419 	free(buffer);
420 	avb_ops_user_free(ops);
421 
422 	return CMD_RET_SUCCESS;
423 }
424 
425 int do_avb_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
426 {
427 	AvbOps *ops;
428 	char *requested_partitions;
429 	int64_t offset_blk;
430 	size_t blkcnt;
431 	size_t out_num_read;
432 	char *buffer;
433 
434 	if (argc != 4)
435 		return CMD_RET_USAGE;
436 
437 	requested_partitions = argv[1];
438 	offset_blk = simple_strtoul(argv[2], NULL, 16);
439 	blkcnt = simple_strtoul(argv[3], NULL, 16);
440 	ops = avb_ops_user_new();
441 	buffer = (char *)malloc(blkcnt * 512);
442 	if (buffer == NULL) {
443 		printf("malloc buffer failed!\n");
444 		return CMD_RET_FAILURE;
445 	}
446 
447 	if (ops == NULL) {
448 		printf("avb_ops_user_new() failed!\n");
449 		return CMD_RET_FAILURE;
450 	}
451 	if (ops->read_from_partition(ops, requested_partitions, offset_blk,
452 				     blkcnt, buffer, &out_num_read) != 0) {
453 		printf("do_avb_write error!\n");
454 		free(buffer);
455 		avb_ops_user_free(ops);
456 		return CMD_RET_FAILURE;
457 	}
458 
459 	free(buffer);
460 	avb_ops_user_free(ops);
461 
462 	return CMD_RET_SUCCESS;
463 }
464 
465 int do_avb_load_ab_metadata(cmd_tbl_t *cmdtp, int flag,
466 			    int argc, char * const argv[])
467 {
468 	AvbOps *ops;
469 	AvbABData ab_data, ab_data_orig;
470 	char *data;
471 	int i;
472 
473 	if (argc != 1)
474 		return CMD_RET_USAGE;
475 
476 	ops = avb_ops_user_new();
477 	if (ops == NULL) {
478 		printf("avb_ops_user_new() failed!\n");
479 		return CMD_RET_FAILURE;
480 	}
481 
482 	if (load_metadata(ops->ab_ops, &ab_data, &ab_data_orig) != 0) {
483 		printf("do_avb_write_ab_metadata error!\n");
484 		avb_ops_user_free(ops);
485 		return CMD_RET_FAILURE;
486 	}
487 
488 	data = (char *)&ab_data;
489 	for (i = 0; i < 33; i++)
490 		printf("%d\n", data[i]);
491 
492 	avb_ops_user_free(ops);
493 
494 	return CMD_RET_SUCCESS;
495 }
496 
497 int do_avb_read_ab_metadata(cmd_tbl_t *cmdtp, int flag,
498 			    int argc, char * const argv[])
499 {
500 	AvbOps *ops;
501 	AvbABData ab_data;
502 
503 	if (argc != 1)
504 		return CMD_RET_USAGE;
505 
506 	ops = avb_ops_user_new();
507 	if (ops == NULL) {
508 		printf("avb_ops_user_new() failed!\n");
509 		return CMD_RET_FAILURE;
510 	}
511 
512 	if (ops->ab_ops->read_ab_metadata(ops->ab_ops, &ab_data) != 0) {
513 		printf("do_avb_write_ab_metadata error!\n");
514 		avb_ops_user_free(ops);
515 		return CMD_RET_FAILURE;
516 	}
517 
518 	avb_ops_user_free(ops);
519 
520 	return CMD_RET_SUCCESS;
521 }
522 
523 int do_avb_write_ab_metadata(cmd_tbl_t *cmdtp, int flag,
524 			     int argc, char * const argv[])
525 {
526 	AvbOps *ops;
527 	AvbABData ab_data;
528 
529 	if (argc != 1)
530 		return CMD_RET_USAGE;
531 
532 	ops = avb_ops_user_new();
533 	if (ops == NULL) {
534 		printf("avb_ops_user_new() failed!\n");
535 		return CMD_RET_FAILURE;
536 	}
537 
538 	if (ops->ab_ops->write_ab_metadata(ops->ab_ops, &ab_data) != 0) {
539 		printf("do_avb_write_ab_metadata error!\n");
540 		avb_ops_user_free(ops);
541 		return CMD_RET_FAILURE;
542 	}
543 
544 	avb_ops_user_free(ops);
545 
546 	return CMD_RET_SUCCESS;
547 }
548 
549 int do_avb_verify_partition(cmd_tbl_t *cmdtp, int flag,
550 			    int argc, char * const argv[])
551 {
552 	AvbOps *ops;
553 	const char *requested_partitions[1];
554 	const char * slot_suffixes[2] = {"_a", "_b"};
555 	AvbSlotVerifyFlags flags;
556 	AvbSlotVerifyData *slot_data[2] = {NULL, NULL};
557 	AvbSlotVerifyResult verify_result;
558 	size_t n;
559 
560 	if (argc != 3)
561 		return CMD_RET_USAGE;
562 
563 	requested_partitions[0] = argv[1];
564 	n = simple_strtoul(argv[2], NULL, 16);
565 	ops = avb_ops_user_new();
566 	flags = AVB_SLOT_VERIFY_FLAGS_NONE;
567 	verify_result =
568 		avb_slot_verify(ops,
569 				requested_partitions,
570 				slot_suffixes[n],
571 				flags,
572 				AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
573 				&slot_data[n]);
574 	if (verify_result != 0)
575 		return CMD_RET_FAILURE;
576 
577 	avb_ops_user_free(ops);
578 
579 	return CMD_RET_SUCCESS;
580 }
581 
582 int do_avb_flow(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
583 {
584 	char slot_partition[2][20] = {{0}, {0}};
585 	unsigned long load_address;
586 	AvbOps *ops;
587 	const char *avb_version;
588 	AvbSlotVerifyData *slot_data;
589 	AvbSlotVerifyFlags flags;
590 	const char *requested_partitions[] = {"boot", "system", NULL};
591 	char *command_line;
592 	bool unlocked = true;
593 	const char *mode_cmdline = NULL;
594 	char root_data[70] = "root=PARTUUID=";
595 	mode_cmdline = "skip_initramfs";
596 	size_t guid_buf_size = 37;
597 	char guid_buf[37];
598 	char verify_flag;
599 	char boot_slot_select[5];
600 
601 	if (argc != 2)
602 		return CMD_RET_USAGE;
603 	avb_version = avb_version_string();
604 	printf("Android avb version is %s.\n", avb_version);
605 	ops = avb_ops_user_new();
606 	if (ops == NULL)
607 		printf("avb_ops_user_new() failed!\n");
608 
609 	if (ops->read_is_device_unlocked(ops, &unlocked) != 0)
610 		printf("Error determining whether device is unlocked.\n");
611 
612 	printf("read_is_device_unlocked() ops returned that device is %s\n",
613 	       unlocked ? "UNLOCKED" : "LOCKED");
614 
615 	flags = AVB_SLOT_VERIFY_FLAGS_NONE;
616 	if (unlocked)
617 		flags |= AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR;
618 
619 	verify_flag = argv[1][0];
620 	if (verify_flag == 'v') {
621 		debug("start with verify!\n");
622 		if (avb_ab_flow(ops->ab_ops,
623 			    requested_partitions,
624 			    flags,
625 			    AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
626 			    &slot_data)) {
627 			printf("avb_ab_flow() error!\n");
628 			return CMD_RET_FAILURE;
629 		}
630 
631 		strcat(slot_partition[1], requested_partitions[1]);
632 		strcat(slot_partition[1], slot_data->ab_suffix);
633 		ops->get_unique_guid_for_partition(ops,
634 						   slot_partition[1],
635 						   guid_buf,
636 						   guid_buf_size);
637 		strcat(root_data, guid_buf);
638 		command_line = android_assemble_cmdline(slot_data->ab_suffix,
639 							mode_cmdline);
640 		strcat(root_data, " ");
641 		strcat(root_data, command_line);
642 		env_set("bootargs", root_data);
643 		load_address = CONFIG_SYS_LOAD_ADDR;
644 		memcpy((uint8_t*)load_address,
645 		       slot_data->loaded_partitions->data,
646 		       slot_data->loaded_partitions->data_size);
647 		android_bootloader_boot_kernel(load_address);
648 		avb_slot_verify_data_free(slot_data);
649 		avb_ops_user_free(ops);
650 	} else if (verify_flag == 'n') {
651 		load_address = CONFIG_SYS_LOAD_ADDR;
652 		avb_ab_slot_select(ops->ab_ops, boot_slot_select);
653 		strcat(slot_partition[1], requested_partitions[1]);
654 		strcat(slot_partition[1], boot_slot_select);
655 		printf("%s\n", slot_partition[1]);
656 		ops->get_unique_guid_for_partition(ops,
657 						   slot_partition[1],
658 						   guid_buf,
659 						   guid_buf_size);
660 		strcat(root_data, guid_buf);
661 		command_line = android_assemble_cmdline(boot_slot_select,
662 							mode_cmdline);
663 		strcat(root_data, " ");
664 		strcat(root_data, command_line);
665 		env_set("bootargs", root_data);
666 		android_avb_boot_flow(boot_slot_select, load_address);
667 	} else {
668 		return CMD_RET_USAGE;
669 	}
670 
671 	return CMD_RET_SUCCESS;
672 }
673 
674 static cmd_tbl_t cmd_avb[] = {
675 	U_BOOT_CMD_MKENT(init, 1, 1, do_avb_init_ab_metadata, "", ""),
676 	U_BOOT_CMD_MKENT(version, 1, 1, do_avb_version, "", ""),
677 	U_BOOT_CMD_MKENT(slot_active, 2, 1,
678 			 do_avb_ab_mark_slot_active, "", ""),
679 	U_BOOT_CMD_MKENT(slot_unbootable, 2, 1,
680 			 do_avb_ab_mark_slot_unbootable, "", ""),
681 	U_BOOT_CMD_MKENT(slot_successful, 2, 1,
682 			 do_avb_ab_mark_slot_successful, "", ""),
683 	U_BOOT_CMD_MKENT(read_rollback, 2, 1,
684 			 do_avb_read_rollback_index, "", ""),
685 	U_BOOT_CMD_MKENT(write_rollback, 3, 1,
686 			 do_avb_write_rollback_index, "", ""),
687 	U_BOOT_CMD_MKENT(read_lock_status, 1, 1,
688 			 do_avb_read_is_device_unlocked, "", ""),
689 	U_BOOT_CMD_MKENT(write_lock_status, 2, 1,
690 			 do_avb_write_is_device_unlocked, "", ""),
691 	U_BOOT_CMD_MKENT(part_size, 2, 1,
692 			 do_avb_get_size_of_partition, "", ""),
693 	U_BOOT_CMD_MKENT(part_guid, 2, 1,
694 			 do_avb_get_get_unique_guid_for_partition, "", ""),
695 	U_BOOT_CMD_MKENT(read, 4, 1, do_avb_read, "", ""),
696 	U_BOOT_CMD_MKENT(write, 4, 1, do_avb_write, "", ""),
697 	U_BOOT_CMD_MKENT(loadabmisc, 1, 1, do_avb_load_ab_metadata, "", ""),
698 	U_BOOT_CMD_MKENT(readabmisc, 1, 1, do_avb_read_ab_metadata, "", ""),
699 	U_BOOT_CMD_MKENT(writeabmisc, 1, 1, do_avb_write_ab_metadata, "", ""),
700 	U_BOOT_CMD_MKENT(verify, 3, 1, do_avb_verify_partition, "", ""),
701 	U_BOOT_CMD_MKENT(flow, 2, 1, do_avb_flow, "", "")
702 };
703 
704 static int do_boot_avb(cmd_tbl_t *cmdtp,
705 		       int flag,
706 		       int argc,
707 		       char * const argv[])
708 {
709 	cmd_tbl_t *cp;
710 
711 	cp = find_cmd_tbl(argv[1], cmd_avb, ARRAY_SIZE(cmd_avb));
712 
713 	argc--;
714 	argv++;
715 
716 	if (cp == NULL || argc > cp->maxargs)
717 		return CMD_RET_USAGE;
718 	if (flag == CMD_FLAG_REPEAT && !cp->repeatable)
719 		return CMD_RET_SUCCESS;
720 
721 	return cp->cmd(cmdtp, flag, argc, argv);
722 }
723 
724 U_BOOT_CMD(
725 	bootavb, 29, 1, do_boot_avb,
726 	"Execute the Android avb a/b boot flow.",
727 	"init - initialize the avbabmeta\n"
728 	"bootavb version - display info of bootavb version\n"
729 	"bootavb slot_active cnt\n"
730 	"bootavb slot_unbootable cnt\n"
731 	"bootavb slot_successful cnt\n"
732 	"bootavb read_rollback rollback_index_location\n"
733 	"bootavb write_rollback rollback_index_location out_rollback_index\n"
734 	"bootavb read_lock_status\n"
735 	"bootavb write_lock_status 0 or 1\n"
736 	"bootavb part_size partitions_name\n"
737 	"bootavb part_guid partitions_name\n"
738 	"bootavb read partition offset_blk cnt\n"
739 	"bootavb write partition offset_blk cnt\n"
740 	"bootavb loadabmisc\n"
741 	"bootavb readabmisc\n"
742 	"bootavb writeabmisc\n"
743 	"bootavb verify partition slot_cnt;partion name without '_a' or '_b'\n"
744 	"bootavb flow v/n\n"
745 );
746 #endif
747