xref: /rk3399_rockchip-uboot/cmd/boot_android.c (revision 36c449fe1f667af7b034680940bb8694b94b7e89)
106f4a874SAlex Deymo /*
206f4a874SAlex Deymo  * Copyright (C) 2016 The Android Open Source Project
306f4a874SAlex Deymo  *
406f4a874SAlex Deymo  * SPDX-License-Identifier: BSD-2-Clause
506f4a874SAlex Deymo  */
606f4a874SAlex Deymo 
706f4a874SAlex Deymo #include <android_bootloader.h>
8e8e29e8dSJason Zhu #include <android_avb/avb_version.h>
9e8e29e8dSJason Zhu #include <android_avb/avb_ab_flow.h>
10e8e29e8dSJason Zhu #include <android_avb/avb_ops_user.h>
11180cc7c6SAlex Deymo #include <android_cmds.h>
12e8e29e8dSJason Zhu #include <malloc.h>
1306f4a874SAlex Deymo #include <common.h>
14e8e29e8dSJason Zhu #include <bootm.h>
1506f4a874SAlex Deymo #include <command.h>
16*36c449feSJoseph Chen #include <mp_boot.h>
1782ee22d4SJason Zhu #include <android_bootloader_message.h>
1837a7bc39SJason Zhu #include <android_avb/rk_avb_ops_user.h>
19d9d5eb74SJason Zhu #include <android_avb/avb_atx_ops.h>
2006f4a874SAlex Deymo 
do_boot_android(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])2106f4a874SAlex Deymo static int do_boot_android(cmd_tbl_t *cmdtp, int flag, int argc,
2206f4a874SAlex Deymo 			   char * const argv[])
2306f4a874SAlex Deymo {
2406f4a874SAlex Deymo 	unsigned long load_address;
2506f4a874SAlex Deymo 	int ret = CMD_RET_SUCCESS;
2606f4a874SAlex Deymo 	char *addr_arg_endp, *addr_str;
2706f4a874SAlex Deymo 	struct blk_desc *dev_desc;
2806f4a874SAlex Deymo 
29891380b5SKever Yang 	if (argc < 3)
3006f4a874SAlex Deymo 		return CMD_RET_USAGE;
3180622240SAlex Deymo 	if (argc > 5)
3206f4a874SAlex Deymo 		return CMD_RET_USAGE;
3306f4a874SAlex Deymo 
34*36c449feSJoseph Chen #ifdef CONFIG_MP_BOOT_BOOTM
35*36c449feSJoseph Chen 	mpb_post(5);
36*36c449feSJoseph Chen #endif
3780622240SAlex Deymo 	if (argc >= 5) {
3880622240SAlex Deymo 		load_address = simple_strtoul(argv[4], &addr_arg_endp, 16);
3980622240SAlex Deymo 		if (addr_arg_endp == argv[4] || *addr_arg_endp != '\0')
4006f4a874SAlex Deymo 			return CMD_RET_USAGE;
4106f4a874SAlex Deymo 	} else {
42891380b5SKever Yang 		addr_str = env_get("kernel_addr_r");
4306f4a874SAlex Deymo 		if (addr_str)
4406f4a874SAlex Deymo 			load_address = simple_strtoul(addr_str, NULL, 16);
4506f4a874SAlex Deymo 		else
4606f4a874SAlex Deymo 			load_address = CONFIG_SYS_LOAD_ADDR;
4706f4a874SAlex Deymo 	}
4806f4a874SAlex Deymo 
49008aee87SAndy Yan #if defined(CONFIG_ARM64)
503f251879SKever Yang 	/* ARM64 kernel load addr need to align to 0x80000, and android boot.img
513f251879SKever Yang 	 * have a 2KB header, need to reserve space for it.
523f251879SKever Yang 	 */
533f251879SKever Yang 	load_address &= ~0x7ffff;
54008aee87SAndy Yan #endif
55ee465021SJoseph Chen 
56891380b5SKever Yang 	dev_desc = blk_get_dev(argv[1], simple_strtoul(argv[2], NULL, 16));
57891380b5SKever Yang 	if (!dev_desc) {
58891380b5SKever Yang 		printf("Could not get %s %s\n", argv[1], argv[2]);
5906f4a874SAlex Deymo 		return CMD_RET_FAILURE;
6006f4a874SAlex Deymo 	}
6106f4a874SAlex Deymo 
62891380b5SKever Yang 	ret = android_bootloader_boot_flow(dev_desc, load_address);
6306f4a874SAlex Deymo 	if (ret < 0) {
6406f4a874SAlex Deymo 		printf("Android boot failed, error %d.\n", ret);
6506f4a874SAlex Deymo 		return CMD_RET_FAILURE;
6606f4a874SAlex Deymo 	}
6706f4a874SAlex Deymo 	return CMD_RET_SUCCESS;
6806f4a874SAlex Deymo }
6906f4a874SAlex Deymo 
7006f4a874SAlex Deymo U_BOOT_CMD(
7180622240SAlex Deymo 	boot_android, 5, 0, do_boot_android,
7206f4a874SAlex Deymo 	"Execute the Android Bootloader flow.",
73df7cce43SAlex Deymo 	"<interface> <dev[:part|;part_name]> <slot> [<kernel_addr>]\n"
7406f4a874SAlex Deymo 	"    - Load the Boot Control Block (BCB) from the partition 'part' on\n"
7506f4a874SAlex Deymo 	"      device type 'interface' instance 'dev' to determine the boot\n"
7606f4a874SAlex Deymo 	"      mode, and load and execute the appropriate kernel.\n"
7706f4a874SAlex Deymo 	"      In normal and recovery mode, the kernel will be loaded from\n"
7806f4a874SAlex Deymo 	"      the corresponding \"boot\" partition. In bootloader mode, the\n"
7906f4a874SAlex Deymo 	"      command defined in the \"fastbootcmd\" variable will be\n"
8006f4a874SAlex Deymo 	"      executed.\n"
8180622240SAlex Deymo 	"      On Android devices with multiple slots, the pass 'slot' is\n"
8280622240SAlex Deymo 	"      used to load the appropriate kernel. The standard slot names\n"
8380622240SAlex Deymo 	"      are 'a' and 'b'.\n"
8406f4a874SAlex Deymo 	"    - If 'part_name' is passed, preceded with a ; instead of :, the\n"
8506f4a874SAlex Deymo 	"      partition name whose label is 'part_name' will be looked up in\n"
8606f4a874SAlex Deymo 	"      the partition table. This is commonly the \"misc\" partition.\n"
8706f4a874SAlex Deymo );
88e8e29e8dSJason Zhu 
896a1e3c91SJason Zhu #ifdef CONFIG_ANDROID_AB
do_avb_init_ab_metadata(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])90e8e29e8dSJason Zhu int do_avb_init_ab_metadata(cmd_tbl_t *cmdtp, int flag,
91e8e29e8dSJason Zhu 			    int argc, char * const argv[])
92e8e29e8dSJason Zhu {
93e8e29e8dSJason Zhu 	AvbOps *ops;
94e8e29e8dSJason Zhu 	AvbABData ab_data;
95e8e29e8dSJason Zhu 
96e8e29e8dSJason Zhu 	memset(&ab_data, 0, sizeof(AvbABData));
97326572eaSJason Zhu 	debug("sizeof(AvbABData) = %d\n", (int)(size_t)sizeof(AvbABData));
98e8e29e8dSJason Zhu 	if (argc != 1)
99e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
100e8e29e8dSJason Zhu 
101e8e29e8dSJason Zhu 	ops = avb_ops_user_new();
102e8e29e8dSJason Zhu 	if (ops == NULL) {
103e8e29e8dSJason Zhu 		printf("avb_ops_user_new() failed!\n");
104e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
105e8e29e8dSJason Zhu 	}
106e8e29e8dSJason Zhu 
10737a7bc39SJason Zhu 	avb_ab_data_init(&ab_data);
108e8e29e8dSJason Zhu 	if (ops->ab_ops->write_ab_metadata(ops->ab_ops, &ab_data) != 0) {
109e8e29e8dSJason Zhu 		printf("do_avb_init_ab_metadata error!\n");
110e8e29e8dSJason Zhu 		avb_ops_user_free(ops);
111e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
112e8e29e8dSJason Zhu 	}
113e8e29e8dSJason Zhu 
114cc527546SJason Zhu 	printf("Initialize ab data to misc partition success.\n");
115e8e29e8dSJason Zhu 	avb_ops_user_free(ops);
116e8e29e8dSJason Zhu 
117e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
118e8e29e8dSJason Zhu }
119e8e29e8dSJason Zhu 
do_avb_ab_mark_slot_active(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])120e8e29e8dSJason Zhu int do_avb_ab_mark_slot_active(cmd_tbl_t *cmdtp, int flag,
121e8e29e8dSJason Zhu 			       int argc, char * const argv[])
122e8e29e8dSJason Zhu {
123e8e29e8dSJason Zhu 	AvbOps *ops;
124e8e29e8dSJason Zhu 	unsigned int slot_number;
125e8e29e8dSJason Zhu 
126e8e29e8dSJason Zhu 	if (argc != 2)
127e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
128e8e29e8dSJason Zhu 
129e8e29e8dSJason Zhu 	ops = avb_ops_user_new();
130e8e29e8dSJason Zhu 	if (ops == NULL) {
131e8e29e8dSJason Zhu 		printf("avb_ops_user_new() failed!\n");
132e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
133e8e29e8dSJason Zhu 	}
134e8e29e8dSJason Zhu 
135e8e29e8dSJason Zhu 	slot_number = simple_strtoul(argv[1], NULL, 16);
136e8e29e8dSJason Zhu 	if (avb_ab_mark_slot_active(ops->ab_ops, slot_number) != 0) {
137e8e29e8dSJason Zhu 		printf("avb_ab_mark_slot_active error!\n");
138e8e29e8dSJason Zhu 		avb_ops_user_free(ops);
139e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
140e8e29e8dSJason Zhu 	}
141e8e29e8dSJason Zhu 
142cc527546SJason Zhu 	printf("Mark slot %d active successfully.\n", slot_number);
143e8e29e8dSJason Zhu 	avb_ops_user_free(ops);
144e8e29e8dSJason Zhu 
145e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
146e8e29e8dSJason Zhu }
147e8e29e8dSJason Zhu 
do_avb_ab_mark_slot_unbootable(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])148e8e29e8dSJason Zhu int do_avb_ab_mark_slot_unbootable(cmd_tbl_t *cmdtp, int flag,
149e8e29e8dSJason Zhu 				   int argc, char * const argv[])
150e8e29e8dSJason Zhu {
151e8e29e8dSJason Zhu 	AvbOps *ops;
152e8e29e8dSJason Zhu 	unsigned int slot_number;
153e8e29e8dSJason Zhu 
154e8e29e8dSJason Zhu 	if (argc != 2)
155e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
156e8e29e8dSJason Zhu 
157e8e29e8dSJason Zhu 	ops = avb_ops_user_new();
158e8e29e8dSJason Zhu 	if (ops == NULL) {
159e8e29e8dSJason Zhu 		printf("avb_ops_user_new() failed!\n");
160e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
161e8e29e8dSJason Zhu 	}
162e8e29e8dSJason Zhu 
163e8e29e8dSJason Zhu 	slot_number = simple_strtoul(argv[1], NULL, 16);
164e8e29e8dSJason Zhu 	if (avb_ab_mark_slot_unbootable(ops->ab_ops, slot_number) != 0) {
165e8e29e8dSJason Zhu 		printf("do_avb_ab_mark_slot_unbootable error!\n");
166e8e29e8dSJason Zhu 		avb_ops_user_free(ops);
167e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
168e8e29e8dSJason Zhu 	}
169e8e29e8dSJason Zhu 
170cc527546SJason Zhu 	printf("Mark slot %d unbootable successfully.\n", slot_number);
171e8e29e8dSJason Zhu 	avb_ops_user_free(ops);
172e8e29e8dSJason Zhu 
173e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
174e8e29e8dSJason Zhu }
175e8e29e8dSJason Zhu 
do_avb_ab_mark_slot_successful(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])176e8e29e8dSJason Zhu int do_avb_ab_mark_slot_successful(cmd_tbl_t *cmdtp, int flag,
177e8e29e8dSJason Zhu 				   int argc, char * const argv[])
178e8e29e8dSJason Zhu {
179e8e29e8dSJason Zhu 	AvbOps *ops;
180e8e29e8dSJason Zhu 	unsigned int slot_number;
181e8e29e8dSJason Zhu 
182e8e29e8dSJason Zhu 	if (argc != 2)
183e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
184e8e29e8dSJason Zhu 
185e8e29e8dSJason Zhu 	ops = avb_ops_user_new();
186e8e29e8dSJason Zhu 	if (ops == NULL) {
187e8e29e8dSJason Zhu 		printf("avb_ops_user_new() failed!\n");
188e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
189e8e29e8dSJason Zhu 	}
190e8e29e8dSJason Zhu 
191e8e29e8dSJason Zhu 	slot_number = simple_strtoul(argv[1], NULL, 16);
192e8e29e8dSJason Zhu 	if (avb_ab_mark_slot_successful(ops->ab_ops, slot_number) != 0) {
193e8e29e8dSJason Zhu 		printf("do_avb_ab_mark_slot_successful error!\n");
194e8e29e8dSJason Zhu 		avb_ops_user_free(ops);
195e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
196e8e29e8dSJason Zhu 	}
197e8e29e8dSJason Zhu 
198e8e29e8dSJason Zhu 	avb_ops_user_free(ops);
199e8e29e8dSJason Zhu 
200e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
201e8e29e8dSJason Zhu }
202e8e29e8dSJason Zhu 
do_avb_read_ab_metadata(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])2036a1e3c91SJason Zhu int do_avb_read_ab_metadata(cmd_tbl_t *cmdtp, int flag,
2046a1e3c91SJason Zhu 			    int argc, char * const argv[])
2056a1e3c91SJason Zhu {
2066a1e3c91SJason Zhu 	AvbOps *ops;
2076a1e3c91SJason Zhu 	AvbABData ab_data;
2086a1e3c91SJason Zhu 
2096a1e3c91SJason Zhu 	if (argc != 1)
2106a1e3c91SJason Zhu 		return CMD_RET_USAGE;
2116a1e3c91SJason Zhu 
2126a1e3c91SJason Zhu 	ops = avb_ops_user_new();
2136a1e3c91SJason Zhu 	if (ops == NULL) {
2146a1e3c91SJason Zhu 		printf("avb_ops_user_new() failed!\n");
2156a1e3c91SJason Zhu 		return CMD_RET_FAILURE;
2166a1e3c91SJason Zhu 	}
2176a1e3c91SJason Zhu 
2186a1e3c91SJason Zhu 	if (ops->ab_ops->read_ab_metadata(ops->ab_ops, &ab_data) != 0) {
2196a1e3c91SJason Zhu 		printf("do_avb_write_ab_metadata error!\n");
2206a1e3c91SJason Zhu 		avb_ops_user_free(ops);
2216a1e3c91SJason Zhu 		return CMD_RET_FAILURE;
2226a1e3c91SJason Zhu 	}
2236a1e3c91SJason Zhu 
2246a1e3c91SJason Zhu 	printf("Slot A information:\n");
2256a1e3c91SJason Zhu 	printf("slot A: priority = %d, tries_remaining = %d,\
2266a1e3c91SJason Zhu 	       successful_boot = %d\n",
2276a1e3c91SJason Zhu 	       ab_data.slots[0].priority,
2286a1e3c91SJason Zhu 	       ab_data.slots[0].tries_remaining,
2296a1e3c91SJason Zhu 	       ab_data.slots[0].successful_boot);
2306a1e3c91SJason Zhu 	printf("Slot B information:\n");
2316a1e3c91SJason Zhu 	printf("slot B: priority = %d, tries_remaining = %d,\
2326a1e3c91SJason Zhu 	       successful_boot = %d\n",
2336a1e3c91SJason Zhu 	       ab_data.slots[1].priority,
2346a1e3c91SJason Zhu 	       ab_data.slots[1].tries_remaining,
2356a1e3c91SJason Zhu 	       ab_data.slots[1].successful_boot);
2366a1e3c91SJason Zhu 	avb_ops_user_free(ops);
2376a1e3c91SJason Zhu 
2386a1e3c91SJason Zhu 	return CMD_RET_SUCCESS;
2396a1e3c91SJason Zhu }
2406a1e3c91SJason Zhu 
do_avb_write_ab_metadata(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])2416a1e3c91SJason Zhu int do_avb_write_ab_metadata(cmd_tbl_t *cmdtp, int flag,
2426a1e3c91SJason Zhu 			     int argc, char * const argv[])
2436a1e3c91SJason Zhu {
2446a1e3c91SJason Zhu 	AvbOps *ops;
2456a1e3c91SJason Zhu 	AvbABData ab_data;
2466a1e3c91SJason Zhu 
2476a1e3c91SJason Zhu 	if (argc != 1)
2486a1e3c91SJason Zhu 		return CMD_RET_USAGE;
2496a1e3c91SJason Zhu 
2506a1e3c91SJason Zhu 	ops = avb_ops_user_new();
2516a1e3c91SJason Zhu 	if (ops == NULL) {
2526a1e3c91SJason Zhu 		printf("avb_ops_user_new() failed!\n");
2536a1e3c91SJason Zhu 		return CMD_RET_FAILURE;
2546a1e3c91SJason Zhu 	}
2556a1e3c91SJason Zhu 
2566a1e3c91SJason Zhu 	if (ops->ab_ops->write_ab_metadata(ops->ab_ops, &ab_data) != 0) {
2576a1e3c91SJason Zhu 		printf("do_avb_write_ab_metadata error!\n");
2586a1e3c91SJason Zhu 		avb_ops_user_free(ops);
2596a1e3c91SJason Zhu 		return CMD_RET_FAILURE;
2606a1e3c91SJason Zhu 	}
2616a1e3c91SJason Zhu 
2626a1e3c91SJason Zhu 	avb_ops_user_free(ops);
2636a1e3c91SJason Zhu 
2646a1e3c91SJason Zhu 	return CMD_RET_SUCCESS;
2656a1e3c91SJason Zhu }
2666a1e3c91SJason Zhu #endif
2676a1e3c91SJason Zhu 
2686a1e3c91SJason Zhu #ifdef CONFIG_ANDROID_AVB
do_avb_version(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])2696a1e3c91SJason Zhu int do_avb_version(cmd_tbl_t *cmdtp, int flag, int argc,
2706a1e3c91SJason Zhu 		   char * const argv[])
2716a1e3c91SJason Zhu {
2726a1e3c91SJason Zhu 	const char *avb_version;
2736a1e3c91SJason Zhu 
2746a1e3c91SJason Zhu 	if (argc != 1)
2756a1e3c91SJason Zhu 		return CMD_RET_USAGE;
2766a1e3c91SJason Zhu 
2776a1e3c91SJason Zhu 	avb_version = avb_version_string();
2786a1e3c91SJason Zhu 	printf("Android avb version is %s.\n", avb_version);
2796a1e3c91SJason Zhu 
2806a1e3c91SJason Zhu 	return CMD_RET_SUCCESS;
2816a1e3c91SJason Zhu }
2826a1e3c91SJason Zhu 
do_avb_read_rollback_index(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])283e8e29e8dSJason Zhu int do_avb_read_rollback_index(cmd_tbl_t *cmdtp, int flag,
284e8e29e8dSJason Zhu 			       int argc, char * const argv[])
285e8e29e8dSJason Zhu {
286e8e29e8dSJason Zhu 	AvbOps *ops;
287e8e29e8dSJason Zhu 	uint64_t out_rollback_index;
288e8e29e8dSJason Zhu 	size_t rollback_index_location;
289e8e29e8dSJason Zhu 
290e8e29e8dSJason Zhu 	if (argc != 2)
291e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
292e8e29e8dSJason Zhu 
293e8e29e8dSJason Zhu 	ops = avb_ops_user_new();
294e8e29e8dSJason Zhu 	if (ops == NULL) {
295e8e29e8dSJason Zhu 		printf("avb_ops_user_new() failed!\n");
296e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
297e8e29e8dSJason Zhu 	}
298e8e29e8dSJason Zhu 
299e8e29e8dSJason Zhu 	rollback_index_location = simple_strtoul(argv[1], NULL, 16);
300e8e29e8dSJason Zhu 	if (ops->read_rollback_index(ops, rollback_index_location,
301e8e29e8dSJason Zhu 				     &out_rollback_index) != 0) {
302e8e29e8dSJason Zhu 		printf("do_avb_read_rollback_index error!\n");
303e8e29e8dSJason Zhu 		avb_ops_user_free(ops);
304e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
305e8e29e8dSJason Zhu 	}
306e8e29e8dSJason Zhu 
307cc527546SJason Zhu 	printf("\nout_rollback_index = %llx\n", out_rollback_index);
308e8e29e8dSJason Zhu 	avb_ops_user_free(ops);
309e8e29e8dSJason Zhu 
310e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
311e8e29e8dSJason Zhu }
312e8e29e8dSJason Zhu 
do_avb_write_rollback_index(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])313e8e29e8dSJason Zhu int do_avb_write_rollback_index(cmd_tbl_t *cmdtp, int flag,
314e8e29e8dSJason Zhu 				int argc, char * const argv[])
315e8e29e8dSJason Zhu {
316e8e29e8dSJason Zhu 	AvbOps *ops;
317e8e29e8dSJason Zhu 	uint64_t out_rollback_index;
318e8e29e8dSJason Zhu 	size_t rollback_index_location;
319e8e29e8dSJason Zhu 
320e8e29e8dSJason Zhu 	if (argc != 3)
321e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
322e8e29e8dSJason Zhu 
323e8e29e8dSJason Zhu 	rollback_index_location = simple_strtoul(argv[1], NULL, 16);
324e8e29e8dSJason Zhu 	out_rollback_index = simple_strtoull(argv[2], NULL, 16);
325e8e29e8dSJason Zhu 	debug("out_rollback_index = %llx\n", out_rollback_index);
326e8e29e8dSJason Zhu 	ops = avb_ops_user_new();
327e8e29e8dSJason Zhu 	if (ops == NULL) {
328e8e29e8dSJason Zhu 		printf("avb_ops_user_new() failed!\n");
329e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
330e8e29e8dSJason Zhu 	}
331e8e29e8dSJason Zhu 
332e8e29e8dSJason Zhu 	if (ops->write_rollback_index(ops, rollback_index_location,
333e8e29e8dSJason Zhu 				      out_rollback_index) != 0) {
334e8e29e8dSJason Zhu 		printf("do_avb_write_rollback_index error!\n");
335e8e29e8dSJason Zhu 		avb_ops_user_free(ops);
336e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
337e8e29e8dSJason Zhu 	}
338e8e29e8dSJason Zhu 
339cc527546SJason Zhu 	printf("\nWrite  rollback index successfully.\n");
340e8e29e8dSJason Zhu 	avb_ops_user_free(ops);
341e8e29e8dSJason Zhu 
342e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
343e8e29e8dSJason Zhu }
344e8e29e8dSJason Zhu 
do_avb_read_is_device_unlocked(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])345e8e29e8dSJason Zhu int do_avb_read_is_device_unlocked(cmd_tbl_t *cmdtp, int flag,
346e8e29e8dSJason Zhu 				   int argc, char * const argv[])
347e8e29e8dSJason Zhu {
348e8e29e8dSJason Zhu 	AvbOps *ops;
349e8e29e8dSJason Zhu 	bool out_is_unlocked;
350e8e29e8dSJason Zhu 
351e8e29e8dSJason Zhu 	if (argc != 1)
352e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
353e8e29e8dSJason Zhu 
354e8e29e8dSJason Zhu 	ops = avb_ops_user_new();
355e8e29e8dSJason Zhu 	if (ops == NULL) {
356e8e29e8dSJason Zhu 		printf("avb_ops_user_new() failed!\n");
357e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
358e8e29e8dSJason Zhu 	}
359e8e29e8dSJason Zhu 
360e8e29e8dSJason Zhu 	if (ops->read_is_device_unlocked(ops, &out_is_unlocked) != 0) {
361e8e29e8dSJason Zhu 		printf("do_avb_read_is_device_unlocked error!\n");
362e8e29e8dSJason Zhu 		avb_ops_user_free(ops);
363e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
364e8e29e8dSJason Zhu 	}
365e8e29e8dSJason Zhu 
366cc527546SJason Zhu 	printf("\n The device is %s\n",
367cc527546SJason Zhu 		out_is_unlocked ? "UNLOCKED" : "LOCKED");
368e8e29e8dSJason Zhu 	avb_ops_user_free(ops);
369e8e29e8dSJason Zhu 
370e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
371e8e29e8dSJason Zhu }
do_avb_write_is_device_unlocked(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])372e8e29e8dSJason Zhu int do_avb_write_is_device_unlocked(cmd_tbl_t *cmdtp, int flag,
373e8e29e8dSJason Zhu 				    int argc, char * const argv[])
374e8e29e8dSJason Zhu {
375e8e29e8dSJason Zhu 	AvbOps *ops;
376e8e29e8dSJason Zhu 	bool out_is_unlocked;
377e8e29e8dSJason Zhu 
378e8e29e8dSJason Zhu 	if (argc != 2)
379e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
380e8e29e8dSJason Zhu 
381e8e29e8dSJason Zhu 	out_is_unlocked = simple_strtoul(argv[1], NULL, 16);
3824061badaSBian Jin chen 	if ((out_is_unlocked != 0) && (out_is_unlocked != 1))
383e8e29e8dSJason Zhu 		printf("enter out_is_unlocked value must is '0' or '1'\n");
384e8e29e8dSJason Zhu 
385e8e29e8dSJason Zhu 	ops = avb_ops_user_new();
386e8e29e8dSJason Zhu 	if (ops == NULL) {
387e8e29e8dSJason Zhu 		printf("avb_ops_user_new() failed!\n");
388e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
389e8e29e8dSJason Zhu 	}
390e8e29e8dSJason Zhu 
391e8e29e8dSJason Zhu 	if (ops->write_is_device_unlocked(ops, &out_is_unlocked) != 0) {
392e8e29e8dSJason Zhu 		printf("do_avb_write_is_device_unlocked error!\n");
393e8e29e8dSJason Zhu 		avb_ops_user_free(ops);
394e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
395e8e29e8dSJason Zhu 	}
396e8e29e8dSJason Zhu 
397e8e29e8dSJason Zhu 	debug("out_is_unlocked = %d\n", out_is_unlocked);
398e8e29e8dSJason Zhu 	avb_ops_user_free(ops);
399e8e29e8dSJason Zhu 
400e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
401e8e29e8dSJason Zhu }
402e8e29e8dSJason Zhu 
do_avb_get_size_of_partition(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])403e8e29e8dSJason Zhu int do_avb_get_size_of_partition(cmd_tbl_t *cmdtp, int flag,
404e8e29e8dSJason Zhu 				 int argc, char * const argv[])
405e8e29e8dSJason Zhu {
406e8e29e8dSJason Zhu 	AvbOps *ops;
407e8e29e8dSJason Zhu 	char *requested_partitions;
408e8e29e8dSJason Zhu 	uint64_t out_size_in_bytes;
409e8e29e8dSJason Zhu 
410e8e29e8dSJason Zhu 	if (argc != 2)
411e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
412e8e29e8dSJason Zhu 
413e8e29e8dSJason Zhu 	requested_partitions = argv[1];
414e8e29e8dSJason Zhu 	ops = avb_ops_user_new();
415e8e29e8dSJason Zhu 	if (ops == NULL) {
416e8e29e8dSJason Zhu 		printf("avb_ops_user_new() failed!\n");
417e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
418e8e29e8dSJason Zhu 	}
419e8e29e8dSJason Zhu 
420e8e29e8dSJason Zhu 	if (ops->get_size_of_partition(ops, requested_partitions,
421e8e29e8dSJason Zhu 				       &out_size_in_bytes) != 0) {
422cc527546SJason Zhu 		printf("Can not get %s partition size!\n", requested_partitions);
423e8e29e8dSJason Zhu 		avb_ops_user_free(ops);
424e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
425e8e29e8dSJason Zhu 	}
426e8e29e8dSJason Zhu 
427cc527546SJason Zhu 	printf("%s partition size = 0x%llx\n", requested_partitions,
428cc527546SJason Zhu 	       out_size_in_bytes);
429e8e29e8dSJason Zhu 	avb_ops_user_free(ops);
430e8e29e8dSJason Zhu 
431e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
432e8e29e8dSJason Zhu }
433e8e29e8dSJason Zhu 
do_avb_get_get_unique_guid_for_partition(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])434e8e29e8dSJason Zhu int do_avb_get_get_unique_guid_for_partition(cmd_tbl_t *cmdtp, int flag,
435e8e29e8dSJason Zhu 					     int argc, char * const argv[])
436e8e29e8dSJason Zhu {
437e8e29e8dSJason Zhu 	AvbOps *ops;
438e8e29e8dSJason Zhu 	char *requested_partitions;
439e8e29e8dSJason Zhu 	size_t guid_buf_size = 37;
440e8e29e8dSJason Zhu 	char guid_buf[37];
441e8e29e8dSJason Zhu 
442e8e29e8dSJason Zhu 	if (argc != 2)
443e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
444e8e29e8dSJason Zhu 
445e8e29e8dSJason Zhu 	requested_partitions = argv[1];
446e8e29e8dSJason Zhu 	ops = avb_ops_user_new();
447e8e29e8dSJason Zhu 	if (ops == NULL) {
448e8e29e8dSJason Zhu 		printf("avb_ops_user_new() failed!\n");
449e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
450e8e29e8dSJason Zhu 	}
451e8e29e8dSJason Zhu 
452e8e29e8dSJason Zhu 	if (ops->get_unique_guid_for_partition(ops, requested_partitions,
453e8e29e8dSJason Zhu 					       guid_buf, guid_buf_size) != 0) {
454cc527546SJason Zhu 		printf("Can not get %s partition UUID!\n",
455cc527546SJason Zhu 		       requested_partitions);
456e8e29e8dSJason Zhu 		avb_ops_user_free(ops);
457e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
458e8e29e8dSJason Zhu 	}
459e8e29e8dSJason Zhu 
460cc527546SJason Zhu 	printf("%s partition UUID is %s\n", requested_partitions, guid_buf);
461e8e29e8dSJason Zhu 	avb_ops_user_free(ops);
462e8e29e8dSJason Zhu 
463e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
464e8e29e8dSJason Zhu }
465e8e29e8dSJason Zhu 
do_avb_read(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])466e8e29e8dSJason Zhu int do_avb_read(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
467e8e29e8dSJason Zhu {
468e8e29e8dSJason Zhu 	AvbOps *ops;
469e8e29e8dSJason Zhu 	char *requested_partitions;
470e8e29e8dSJason Zhu 	int64_t offset_blk;
471e8e29e8dSJason Zhu 	size_t blkcnt;
472e8e29e8dSJason Zhu 	size_t out_num_read;
473e8e29e8dSJason Zhu 	int i;
474e8e29e8dSJason Zhu 	char *buffer;
475e8e29e8dSJason Zhu 
476e8e29e8dSJason Zhu 	if (argc != 4)
477e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
478e8e29e8dSJason Zhu 
479e8e29e8dSJason Zhu 	requested_partitions = argv[1];
480e8e29e8dSJason Zhu 	offset_blk = simple_strtoul(argv[2], NULL, 16);
481e8e29e8dSJason Zhu 	blkcnt = simple_strtoul(argv[3], NULL, 16);
482e8e29e8dSJason Zhu 	ops = avb_ops_user_new();
483e8e29e8dSJason Zhu 	buffer = (char *)malloc(blkcnt * 512);
484e8e29e8dSJason Zhu 	if (buffer == NULL)
485e8e29e8dSJason Zhu 		printf("malloc buffer failed!\n");
486e8e29e8dSJason Zhu 
487e8e29e8dSJason Zhu 	if (ops == NULL) {
488e8e29e8dSJason Zhu 		printf("avb_ops_user_new() failed!\n");
489e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
490e8e29e8dSJason Zhu 	}
491e8e29e8dSJason Zhu 
492e8e29e8dSJason Zhu 	if (ops->read_from_partition(ops, requested_partitions,
493e8e29e8dSJason Zhu 				     offset_blk, blkcnt, buffer,
494e8e29e8dSJason Zhu 				     &out_num_read) != 0) {
495e8e29e8dSJason Zhu 		printf("do avb read error!\n");
496e8e29e8dSJason Zhu 		free(buffer);
497e8e29e8dSJason Zhu 		avb_ops_user_free(ops);
498e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
499e8e29e8dSJason Zhu 	}
500e8e29e8dSJason Zhu 
501cc527546SJason Zhu 	for (i = 0; i < 512 * blkcnt; i++) {
502cc527546SJason Zhu 		printf("buffer %d = %x", i, buffer[i]);
503cc527546SJason Zhu 		if ((i + 1) % 4 == 0)
504cc527546SJason Zhu 			printf("\n");
505e8e29e8dSJason Zhu 	}
506e8e29e8dSJason Zhu 
507e8e29e8dSJason Zhu 	free(buffer);
508e8e29e8dSJason Zhu 	avb_ops_user_free(ops);
509e8e29e8dSJason Zhu 
510e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
511e8e29e8dSJason Zhu }
512e8e29e8dSJason Zhu 
do_perm_attr_test(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])513d9d5eb74SJason Zhu int do_perm_attr_test(cmd_tbl_t *cmdtp, int flag,
514d9d5eb74SJason Zhu 		      int argc, char * const argv[])
515d9d5eb74SJason Zhu {
516d9d5eb74SJason Zhu 	AvbOps *ops;
517d9d5eb74SJason Zhu 	int i;
518d9d5eb74SJason Zhu 	uint8_t hash[AVB_SHA256_DIGEST_SIZE];
519d9d5eb74SJason Zhu 
520d9d5eb74SJason Zhu 	if (argc != 1)
521d9d5eb74SJason Zhu 		return CMD_RET_USAGE;
522d9d5eb74SJason Zhu 
523d9d5eb74SJason Zhu 	ops = avb_ops_user_new();
524d9d5eb74SJason Zhu 	if (ops == NULL) {
525d9d5eb74SJason Zhu 		printf("avb_ops_user_new() failed!\n");
526d9d5eb74SJason Zhu 		return CMD_RET_FAILURE;
527d9d5eb74SJason Zhu 	}
528d9d5eb74SJason Zhu 
529d9d5eb74SJason Zhu 	if (ops->atx_ops->read_permanent_attributes_hash(ops->atx_ops, hash) != 0) {
530d9d5eb74SJason Zhu 		printf("read_permanent_attributes_hash error!\n");
531d9d5eb74SJason Zhu 		avb_ops_user_free(ops);
532d9d5eb74SJason Zhu 		return CMD_RET_FAILURE;
533d9d5eb74SJason Zhu 	}
534d9d5eb74SJason Zhu 
535d9d5eb74SJason Zhu 	for (i = 0; i < AVB_SHA256_DIGEST_SIZE; i++) {
536d9d5eb74SJason Zhu 		if (i % 4 == 0)
537d9d5eb74SJason Zhu 			printf("\n");
538d9d5eb74SJason Zhu 		printf("0x%x  ", hash[i]);
539d9d5eb74SJason Zhu 	}
540d9d5eb74SJason Zhu 
541d9d5eb74SJason Zhu 	avb_ops_user_free(ops);
542d9d5eb74SJason Zhu 
543d9d5eb74SJason Zhu 	return CMD_RET_SUCCESS;
544d9d5eb74SJason Zhu }
545d9d5eb74SJason Zhu 
do_avb_verify_partition(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])546e8e29e8dSJason Zhu int do_avb_verify_partition(cmd_tbl_t *cmdtp, int flag,
547e8e29e8dSJason Zhu 			    int argc, char * const argv[])
548e8e29e8dSJason Zhu {
549e8e29e8dSJason Zhu 	AvbOps *ops;
550e8e29e8dSJason Zhu 	const char *requested_partitions[1];
551e8e29e8dSJason Zhu 	const char * slot_suffixes[2] = {"_a", "_b"};
552e8e29e8dSJason Zhu 	AvbSlotVerifyFlags flags;
553e8e29e8dSJason Zhu 	AvbSlotVerifyData *slot_data[2] = {NULL, NULL};
554e8e29e8dSJason Zhu 	AvbSlotVerifyResult verify_result;
555e8e29e8dSJason Zhu 	size_t n;
556e8e29e8dSJason Zhu 
557e8e29e8dSJason Zhu 	if (argc != 3)
558e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
559e8e29e8dSJason Zhu 
560e8e29e8dSJason Zhu 	requested_partitions[0] = argv[1];
561e8e29e8dSJason Zhu 	n = simple_strtoul(argv[2], NULL, 16);
562e8e29e8dSJason Zhu 	ops = avb_ops_user_new();
563e8e29e8dSJason Zhu 	flags = AVB_SLOT_VERIFY_FLAGS_NONE;
564e8e29e8dSJason Zhu 	verify_result =
565e8e29e8dSJason Zhu 		avb_slot_verify(ops,
566e8e29e8dSJason Zhu 				requested_partitions,
567e8e29e8dSJason Zhu 				slot_suffixes[n],
568e8e29e8dSJason Zhu 				flags,
569e8e29e8dSJason Zhu 				AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
570e8e29e8dSJason Zhu 				&slot_data[n]);
571e8e29e8dSJason Zhu 	if (verify_result != 0)
572e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
573e8e29e8dSJason Zhu 
574e8e29e8dSJason Zhu 	avb_ops_user_free(ops);
575e8e29e8dSJason Zhu 
576e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
577e8e29e8dSJason Zhu }
5786a1e3c91SJason Zhu #endif
579e8e29e8dSJason Zhu 
580e8e29e8dSJason Zhu static cmd_tbl_t cmd_avb[] = {
5816a1e3c91SJason Zhu #ifdef CONFIG_ANDROID_AB
582e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(init, 1, 1, do_avb_init_ab_metadata, "", ""),
583e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(slot_active, 2, 1,
584e8e29e8dSJason Zhu 			 do_avb_ab_mark_slot_active, "", ""),
585e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(slot_unbootable, 2, 1,
586e8e29e8dSJason Zhu 			 do_avb_ab_mark_slot_unbootable, "", ""),
587e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(slot_successful, 2, 1,
588e8e29e8dSJason Zhu 			 do_avb_ab_mark_slot_successful, "", ""),
5896a1e3c91SJason Zhu 	U_BOOT_CMD_MKENT(readabmisc, 1, 1, do_avb_read_ab_metadata, "", ""),
5906a1e3c91SJason Zhu #endif
5916a1e3c91SJason Zhu #ifdef CONFIG_ANDROID_AVB
5926a1e3c91SJason Zhu 	U_BOOT_CMD_MKENT(version, 1, 1, do_avb_version, "", ""),
593e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(read_rollback, 2, 1,
594e8e29e8dSJason Zhu 			 do_avb_read_rollback_index, "", ""),
595e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(write_rollback, 3, 1,
596e8e29e8dSJason Zhu 			 do_avb_write_rollback_index, "", ""),
597e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(read_lock_status, 1, 1,
598e8e29e8dSJason Zhu 			 do_avb_read_is_device_unlocked, "", ""),
599e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(write_lock_status, 2, 1,
600e8e29e8dSJason Zhu 			 do_avb_write_is_device_unlocked, "", ""),
601e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(part_size, 2, 1,
602e8e29e8dSJason Zhu 			 do_avb_get_size_of_partition, "", ""),
603e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(part_guid, 2, 1,
604e8e29e8dSJason Zhu 			 do_avb_get_get_unique_guid_for_partition, "", ""),
605e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(read, 4, 1, do_avb_read, "", ""),
606d9d5eb74SJason Zhu 	U_BOOT_CMD_MKENT(perm_attr_test, 1, 1, do_perm_attr_test, "", ""),
607e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(verify, 3, 1, do_avb_verify_partition, "", ""),
6086a1e3c91SJason Zhu #endif
609e8e29e8dSJason Zhu };
610e8e29e8dSJason Zhu 
do_boot_avb(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])611e8e29e8dSJason Zhu static int do_boot_avb(cmd_tbl_t *cmdtp,
612e8e29e8dSJason Zhu 		       int flag,
613e8e29e8dSJason Zhu 		       int argc,
614e8e29e8dSJason Zhu 		       char * const argv[])
615e8e29e8dSJason Zhu {
616e8e29e8dSJason Zhu 	cmd_tbl_t *cp;
617e8e29e8dSJason Zhu 
618e8e29e8dSJason Zhu 	cp = find_cmd_tbl(argv[1], cmd_avb, ARRAY_SIZE(cmd_avb));
619e8e29e8dSJason Zhu 
620e8e29e8dSJason Zhu 	argc--;
621e8e29e8dSJason Zhu 	argv++;
622e8e29e8dSJason Zhu 
623e8e29e8dSJason Zhu 	if (cp == NULL || argc > cp->maxargs)
624e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
625e8e29e8dSJason Zhu 	if (flag == CMD_FLAG_REPEAT && !cp->repeatable)
626e8e29e8dSJason Zhu 		return CMD_RET_SUCCESS;
627e8e29e8dSJason Zhu 
628e8e29e8dSJason Zhu 	return cp->cmd(cmdtp, flag, argc, argv);
629e8e29e8dSJason Zhu }
630e8e29e8dSJason Zhu 
631e8e29e8dSJason Zhu U_BOOT_CMD(
632e8e29e8dSJason Zhu 	bootavb, 29, 1, do_boot_avb,
633e8e29e8dSJason Zhu 	"Execute the Android avb a/b boot flow.",
634e8e29e8dSJason Zhu 	"init - initialize the avbabmeta\n"
635e8e29e8dSJason Zhu 	"bootavb version - display info of bootavb version\n"
636e8e29e8dSJason Zhu 	"bootavb slot_active cnt\n"
637e8e29e8dSJason Zhu 	"bootavb slot_unbootable cnt\n"
638e8e29e8dSJason Zhu 	"bootavb slot_successful cnt\n"
639e8e29e8dSJason Zhu 	"bootavb read_rollback rollback_index_location\n"
640cc527546SJason Zhu 	"bootavb write_rollback rollback_index_location rollback_index\n"
641e8e29e8dSJason Zhu 	"bootavb read_lock_status\n"
642e8e29e8dSJason Zhu 	"bootavb write_lock_status 0 or 1\n"
643e8e29e8dSJason Zhu 	"bootavb part_size partitions_name\n"
644e8e29e8dSJason Zhu 	"bootavb part_guid partitions_name\n"
645e8e29e8dSJason Zhu 	"bootavb read partition offset_blk cnt\n"
646e8e29e8dSJason Zhu 	"bootavb readabmisc\n"
647d9d5eb74SJason Zhu 	"bootavb perm_attr_test\n"
648e8e29e8dSJason Zhu 	"bootavb verify partition slot_cnt;partion name without '_a' or '_b'\n"
649e8e29e8dSJason Zhu );
650