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