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