xref: /rk3399_rockchip-uboot/cmd/boot_android.c (revision d9d5eb74015ce2cc22d948e91369c74ce77ccf1b)
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>
1682ee22d4SJason Zhu #include <android_bootloader_message.h>
1737a7bc39SJason Zhu #include <android_avb/rk_avb_ops_user.h>
18*d9d5eb74SJason Zhu #include <android_avb/avb_atx_ops.h>
1906f4a874SAlex Deymo 
2006f4a874SAlex Deymo static int do_boot_android(cmd_tbl_t *cmdtp, int flag, int argc,
2106f4a874SAlex Deymo 			   char * const argv[])
2206f4a874SAlex Deymo {
2306f4a874SAlex Deymo 	unsigned long load_address;
2406f4a874SAlex Deymo 	int ret = CMD_RET_SUCCESS;
2506f4a874SAlex Deymo 	char *addr_arg_endp, *addr_str;
2606f4a874SAlex Deymo 	struct blk_desc *dev_desc;
2706f4a874SAlex Deymo 
28891380b5SKever Yang 	if (argc < 3)
2906f4a874SAlex Deymo 		return CMD_RET_USAGE;
3080622240SAlex Deymo 	if (argc > 5)
3106f4a874SAlex Deymo 		return CMD_RET_USAGE;
3206f4a874SAlex Deymo 
3380622240SAlex Deymo 	if (argc >= 5) {
3480622240SAlex Deymo 		load_address = simple_strtoul(argv[4], &addr_arg_endp, 16);
3580622240SAlex Deymo 		if (addr_arg_endp == argv[4] || *addr_arg_endp != '\0')
3606f4a874SAlex Deymo 			return CMD_RET_USAGE;
3706f4a874SAlex Deymo 	} else {
38891380b5SKever Yang 		addr_str = env_get("kernel_addr_r");
3906f4a874SAlex Deymo 		if (addr_str)
4006f4a874SAlex Deymo 			load_address = simple_strtoul(addr_str, NULL, 16);
4106f4a874SAlex Deymo 		else
4206f4a874SAlex Deymo 			load_address = CONFIG_SYS_LOAD_ADDR;
4306f4a874SAlex Deymo 	}
4406f4a874SAlex Deymo 
453f251879SKever Yang 	/* ARM64 kernel load addr need to align to 0x80000, and android boot.img
463f251879SKever Yang 	 * have a 2KB header, need to reserve space for it.
473f251879SKever Yang 	 */
483f251879SKever Yang 	load_address &= ~0x7ffff;
493f251879SKever Yang 	load_address -= 0x800; /* default page size for boot header */
50891380b5SKever Yang 	dev_desc = blk_get_dev(argv[1], simple_strtoul(argv[2], NULL, 16));
51891380b5SKever Yang 	if (!dev_desc) {
52891380b5SKever Yang 		printf("Could not get %s %s\n", argv[1], argv[2]);
5306f4a874SAlex Deymo 		return CMD_RET_FAILURE;
5406f4a874SAlex Deymo 	}
5506f4a874SAlex Deymo 
56891380b5SKever Yang 	ret = android_bootloader_boot_flow(dev_desc, load_address);
5706f4a874SAlex Deymo 	if (ret < 0) {
5806f4a874SAlex Deymo 		printf("Android boot failed, error %d.\n", ret);
5906f4a874SAlex Deymo 		return CMD_RET_FAILURE;
6006f4a874SAlex Deymo 	}
6106f4a874SAlex Deymo 	return CMD_RET_SUCCESS;
6206f4a874SAlex Deymo }
6306f4a874SAlex Deymo 
6406f4a874SAlex Deymo U_BOOT_CMD(
6580622240SAlex Deymo 	boot_android, 5, 0, do_boot_android,
6606f4a874SAlex Deymo 	"Execute the Android Bootloader flow.",
67df7cce43SAlex Deymo 	"<interface> <dev[:part|;part_name]> <slot> [<kernel_addr>]\n"
6806f4a874SAlex Deymo 	"    - Load the Boot Control Block (BCB) from the partition 'part' on\n"
6906f4a874SAlex Deymo 	"      device type 'interface' instance 'dev' to determine the boot\n"
7006f4a874SAlex Deymo 	"      mode, and load and execute the appropriate kernel.\n"
7106f4a874SAlex Deymo 	"      In normal and recovery mode, the kernel will be loaded from\n"
7206f4a874SAlex Deymo 	"      the corresponding \"boot\" partition. In bootloader mode, the\n"
7306f4a874SAlex Deymo 	"      command defined in the \"fastbootcmd\" variable will be\n"
7406f4a874SAlex Deymo 	"      executed.\n"
7580622240SAlex Deymo 	"      On Android devices with multiple slots, the pass 'slot' is\n"
7680622240SAlex Deymo 	"      used to load the appropriate kernel. The standard slot names\n"
7780622240SAlex Deymo 	"      are 'a' and 'b'.\n"
7806f4a874SAlex Deymo 	"    - If 'part_name' is passed, preceded with a ; instead of :, the\n"
7906f4a874SAlex Deymo 	"      partition name whose label is 'part_name' will be looked up in\n"
8006f4a874SAlex Deymo 	"      the partition table. This is commonly the \"misc\" partition.\n"
8106f4a874SAlex Deymo );
82e8e29e8dSJason Zhu 
8337a7bc39SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
8482ee22d4SJason Zhu static int bootloader_message_read(struct android_bootloader_message *data)
8582ee22d4SJason Zhu {
8682ee22d4SJason Zhu 	AvbOps *ops;
8782ee22d4SJason Zhu 	char requested_partitions[] = "misc";
8882ee22d4SJason Zhu 	size_t out_num_read;
8982ee22d4SJason Zhu 	char *buffer;
9082ee22d4SJason Zhu 
9182ee22d4SJason Zhu 	ops = avb_ops_user_new();
9282ee22d4SJason Zhu 	buffer = (char *)data;
9382ee22d4SJason Zhu 
9482ee22d4SJason Zhu 	if (ops == NULL) {
9582ee22d4SJason Zhu 		printf("avb_ops_user_new() failed!\n");
9682ee22d4SJason Zhu 		return CMD_RET_FAILURE;
9782ee22d4SJason Zhu 	}
9882ee22d4SJason Zhu 
9982ee22d4SJason Zhu 	if (ops->read_from_partition(ops, requested_partitions,
10082ee22d4SJason Zhu 				     0, 2048, buffer,
10182ee22d4SJason Zhu 				     &out_num_read) != 0) {
10282ee22d4SJason Zhu 		printf("do avb read error!\n");
10382ee22d4SJason Zhu 		avb_ops_user_free(ops);
10482ee22d4SJason Zhu 		return CMD_RET_FAILURE;
10582ee22d4SJason Zhu 	}
10682ee22d4SJason Zhu 
10782ee22d4SJason Zhu 	avb_ops_user_free(ops);
10882ee22d4SJason Zhu 
10982ee22d4SJason Zhu 	return CMD_RET_SUCCESS;
11082ee22d4SJason Zhu }
11182ee22d4SJason Zhu 
11282ee22d4SJason Zhu static int bootloader_message_write(struct android_bootloader_message *data)
11382ee22d4SJason Zhu {
11482ee22d4SJason Zhu 	AvbOps *ops;
11582ee22d4SJason Zhu 	char requested_partitions[] = "misc";
11682ee22d4SJason Zhu 	char *buffer;
11782ee22d4SJason Zhu 
11882ee22d4SJason Zhu 	ops = avb_ops_user_new();
11982ee22d4SJason Zhu 	buffer = (char *)data;
12082ee22d4SJason Zhu 
12182ee22d4SJason Zhu 	if (ops == NULL) {
12282ee22d4SJason Zhu 		printf("avb_ops_user_new() failed!\n");
12382ee22d4SJason Zhu 		return CMD_RET_FAILURE;
12482ee22d4SJason Zhu 	}
12582ee22d4SJason Zhu 
12682ee22d4SJason Zhu 	if (ops->write_to_partition(ops, requested_partitions,
12782ee22d4SJason Zhu 				     0, 2048, buffer) != 0) {
12882ee22d4SJason Zhu 		printf("do avb write error!\n");
12982ee22d4SJason Zhu 		avb_ops_user_free(ops);
13082ee22d4SJason Zhu 		return CMD_RET_FAILURE;
13182ee22d4SJason Zhu 	}
13282ee22d4SJason Zhu 
13382ee22d4SJason Zhu 	avb_ops_user_free(ops);
13482ee22d4SJason Zhu 
13582ee22d4SJason Zhu 	return CMD_RET_SUCCESS;
13682ee22d4SJason Zhu }
13782ee22d4SJason Zhu 
138e8e29e8dSJason Zhu int do_avb_init_ab_metadata(cmd_tbl_t *cmdtp, int flag,
139e8e29e8dSJason Zhu 			    int argc, char * const argv[])
140e8e29e8dSJason Zhu {
141e8e29e8dSJason Zhu 	AvbOps *ops;
142e8e29e8dSJason Zhu 	AvbABData ab_data;
143e8e29e8dSJason Zhu 
144e8e29e8dSJason Zhu 	memset(&ab_data, 0, sizeof(AvbABData));
145326572eaSJason Zhu 	debug("sizeof(AvbABData) = %d\n", (int)(size_t)sizeof(AvbABData));
146e8e29e8dSJason Zhu 	if (argc != 1)
147e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
148e8e29e8dSJason Zhu 
149e8e29e8dSJason Zhu 	ops = avb_ops_user_new();
150e8e29e8dSJason Zhu 	if (ops == NULL) {
151e8e29e8dSJason Zhu 		printf("avb_ops_user_new() failed!\n");
152e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
153e8e29e8dSJason Zhu 	}
154e8e29e8dSJason Zhu 
15537a7bc39SJason Zhu 	avb_ab_data_init(&ab_data);
156e8e29e8dSJason Zhu 	if (ops->ab_ops->write_ab_metadata(ops->ab_ops, &ab_data) != 0) {
157e8e29e8dSJason Zhu 		printf("do_avb_init_ab_metadata error!\n");
158e8e29e8dSJason Zhu 		avb_ops_user_free(ops);
159e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
160e8e29e8dSJason Zhu 	}
161e8e29e8dSJason Zhu 
162e8e29e8dSJason Zhu 	avb_ops_user_free(ops);
163e8e29e8dSJason Zhu 
164e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
165e8e29e8dSJason Zhu }
166e8e29e8dSJason Zhu 
167e8e29e8dSJason Zhu int do_avb_version(cmd_tbl_t *cmdtp, int flag, int argc,
168e8e29e8dSJason Zhu 		   char * const argv[])
169e8e29e8dSJason Zhu {
170e8e29e8dSJason Zhu 	const char *avb_version;
171e8e29e8dSJason Zhu 
172e8e29e8dSJason Zhu 	if (argc != 1)
173e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
174e8e29e8dSJason Zhu 
175e8e29e8dSJason Zhu 	avb_version = avb_version_string();
176e8e29e8dSJason Zhu 	printf("Android avb version is %s.\n", avb_version);
177e8e29e8dSJason Zhu 
178e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
179e8e29e8dSJason Zhu }
180e8e29e8dSJason Zhu 
181e8e29e8dSJason Zhu int do_avb_ab_mark_slot_active(cmd_tbl_t *cmdtp, int flag,
182e8e29e8dSJason Zhu 			       int argc, char * const argv[])
183e8e29e8dSJason Zhu {
184e8e29e8dSJason Zhu 	AvbOps *ops;
185e8e29e8dSJason Zhu 	unsigned int slot_number;
186e8e29e8dSJason Zhu 
187e8e29e8dSJason Zhu 	if (argc != 2)
188e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
189e8e29e8dSJason Zhu 
190e8e29e8dSJason Zhu 	ops = avb_ops_user_new();
191e8e29e8dSJason Zhu 	if (ops == NULL) {
192e8e29e8dSJason Zhu 		printf("avb_ops_user_new() failed!\n");
193e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
194e8e29e8dSJason Zhu 	}
195e8e29e8dSJason Zhu 
196e8e29e8dSJason Zhu 	slot_number = simple_strtoul(argv[1], NULL, 16);
197e8e29e8dSJason Zhu 	if (avb_ab_mark_slot_active(ops->ab_ops, slot_number) != 0) {
198e8e29e8dSJason Zhu 		printf("avb_ab_mark_slot_active error!\n");
199e8e29e8dSJason Zhu 		avb_ops_user_free(ops);
200e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
201e8e29e8dSJason Zhu 	}
202e8e29e8dSJason Zhu 
203e8e29e8dSJason Zhu 	avb_ops_user_free(ops);
204e8e29e8dSJason Zhu 
205e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
206e8e29e8dSJason Zhu }
207e8e29e8dSJason Zhu 
208e8e29e8dSJason Zhu int do_avb_ab_mark_slot_unbootable(cmd_tbl_t *cmdtp, int flag,
209e8e29e8dSJason Zhu 				   int argc, char * const argv[])
210e8e29e8dSJason Zhu {
211e8e29e8dSJason Zhu 	AvbOps *ops;
212e8e29e8dSJason Zhu 	unsigned int slot_number;
213e8e29e8dSJason Zhu 
214e8e29e8dSJason Zhu 	if (argc != 2)
215e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
216e8e29e8dSJason Zhu 
217e8e29e8dSJason Zhu 	ops = avb_ops_user_new();
218e8e29e8dSJason Zhu 	if (ops == NULL) {
219e8e29e8dSJason Zhu 		printf("avb_ops_user_new() failed!\n");
220e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
221e8e29e8dSJason Zhu 	}
222e8e29e8dSJason Zhu 
223e8e29e8dSJason Zhu 	slot_number = simple_strtoul(argv[1], NULL, 16);
224e8e29e8dSJason Zhu 	if (avb_ab_mark_slot_unbootable(ops->ab_ops, slot_number) != 0) {
225e8e29e8dSJason Zhu 		printf("do_avb_ab_mark_slot_unbootable error!\n");
226e8e29e8dSJason Zhu 		avb_ops_user_free(ops);
227e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
228e8e29e8dSJason Zhu 	}
229e8e29e8dSJason Zhu 
230e8e29e8dSJason Zhu 	avb_ops_user_free(ops);
231e8e29e8dSJason Zhu 
232e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
233e8e29e8dSJason Zhu }
234e8e29e8dSJason Zhu 
235e8e29e8dSJason Zhu int do_avb_ab_mark_slot_successful(cmd_tbl_t *cmdtp, int flag,
236e8e29e8dSJason Zhu 				   int argc, char * const argv[])
237e8e29e8dSJason Zhu {
238e8e29e8dSJason Zhu 	AvbOps *ops;
239e8e29e8dSJason Zhu 	unsigned int slot_number;
240e8e29e8dSJason Zhu 
241e8e29e8dSJason Zhu 	if (argc != 2)
242e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
243e8e29e8dSJason Zhu 
244e8e29e8dSJason Zhu 	ops = avb_ops_user_new();
245e8e29e8dSJason Zhu 	if (ops == NULL) {
246e8e29e8dSJason Zhu 		printf("avb_ops_user_new() failed!\n");
247e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
248e8e29e8dSJason Zhu 	}
249e8e29e8dSJason Zhu 
250e8e29e8dSJason Zhu 	slot_number = simple_strtoul(argv[1], NULL, 16);
251e8e29e8dSJason Zhu 	if (avb_ab_mark_slot_successful(ops->ab_ops, slot_number) != 0) {
252e8e29e8dSJason Zhu 		printf("do_avb_ab_mark_slot_successful error!\n");
253e8e29e8dSJason Zhu 		avb_ops_user_free(ops);
254e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
255e8e29e8dSJason Zhu 	}
256e8e29e8dSJason Zhu 
257e8e29e8dSJason Zhu 	avb_ops_user_free(ops);
258e8e29e8dSJason Zhu 
259e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
260e8e29e8dSJason Zhu }
261e8e29e8dSJason Zhu 
262e8e29e8dSJason Zhu int do_avb_read_rollback_index(cmd_tbl_t *cmdtp, int flag,
263e8e29e8dSJason Zhu 			       int argc, char * const argv[])
264e8e29e8dSJason Zhu {
265e8e29e8dSJason Zhu 	AvbOps *ops;
266e8e29e8dSJason Zhu 	uint64_t out_rollback_index;
267e8e29e8dSJason Zhu 	size_t rollback_index_location;
268e8e29e8dSJason Zhu 
269e8e29e8dSJason Zhu 	if (argc != 2)
270e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
271e8e29e8dSJason Zhu 
272e8e29e8dSJason Zhu 	ops = avb_ops_user_new();
273e8e29e8dSJason Zhu 	if (ops == NULL) {
274e8e29e8dSJason Zhu 		printf("avb_ops_user_new() failed!\n");
275e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
276e8e29e8dSJason Zhu 	}
277e8e29e8dSJason Zhu 
278e8e29e8dSJason Zhu 	rollback_index_location = simple_strtoul(argv[1], NULL, 16);
279e8e29e8dSJason Zhu 	if (ops->read_rollback_index(ops, rollback_index_location,
280e8e29e8dSJason Zhu 				     &out_rollback_index) != 0) {
281e8e29e8dSJason Zhu 		printf("do_avb_read_rollback_index error!\n");
282e8e29e8dSJason Zhu 		avb_ops_user_free(ops);
283e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
284e8e29e8dSJason Zhu 	}
285e8e29e8dSJason Zhu 
286e8e29e8dSJason Zhu 	printf("out_rollback_index = %llx\n", out_rollback_index);
287e8e29e8dSJason Zhu 	avb_ops_user_free(ops);
288e8e29e8dSJason Zhu 
289e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
290e8e29e8dSJason Zhu }
291e8e29e8dSJason Zhu 
292e8e29e8dSJason Zhu int do_avb_write_rollback_index(cmd_tbl_t *cmdtp, int flag,
293e8e29e8dSJason Zhu 				int argc, char * const argv[])
294e8e29e8dSJason Zhu {
295e8e29e8dSJason Zhu 	AvbOps *ops;
296e8e29e8dSJason Zhu 	uint64_t out_rollback_index;
297e8e29e8dSJason Zhu 	size_t rollback_index_location;
298e8e29e8dSJason Zhu 
299e8e29e8dSJason Zhu 	if (argc != 3)
300e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
301e8e29e8dSJason Zhu 
302e8e29e8dSJason Zhu 	rollback_index_location = simple_strtoul(argv[1], NULL, 16);
303e8e29e8dSJason Zhu 	out_rollback_index = simple_strtoull(argv[2], NULL, 16);
304e8e29e8dSJason Zhu 	debug("out_rollback_index = %llx\n", out_rollback_index);
305e8e29e8dSJason Zhu 	ops = avb_ops_user_new();
306e8e29e8dSJason Zhu 	if (ops == NULL) {
307e8e29e8dSJason Zhu 		printf("avb_ops_user_new() failed!\n");
308e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
309e8e29e8dSJason Zhu 	}
310e8e29e8dSJason Zhu 
311e8e29e8dSJason Zhu 	if (ops->write_rollback_index(ops, rollback_index_location,
312e8e29e8dSJason Zhu 				      out_rollback_index) != 0) {
313e8e29e8dSJason Zhu 		printf("do_avb_write_rollback_index error!\n");
314e8e29e8dSJason Zhu 		avb_ops_user_free(ops);
315e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
316e8e29e8dSJason Zhu 	}
317e8e29e8dSJason Zhu 
318e8e29e8dSJason Zhu 	avb_ops_user_free(ops);
319e8e29e8dSJason Zhu 
320e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
321e8e29e8dSJason Zhu }
322e8e29e8dSJason Zhu 
323e8e29e8dSJason Zhu int do_avb_read_is_device_unlocked(cmd_tbl_t *cmdtp, int flag,
324e8e29e8dSJason Zhu 				   int argc, char * const argv[])
325e8e29e8dSJason Zhu {
326e8e29e8dSJason Zhu 	AvbOps *ops;
327e8e29e8dSJason Zhu 	bool out_is_unlocked;
328e8e29e8dSJason Zhu 
329e8e29e8dSJason Zhu 	if (argc != 1)
330e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
331e8e29e8dSJason Zhu 
332e8e29e8dSJason Zhu 	ops = avb_ops_user_new();
333e8e29e8dSJason Zhu 	if (ops == NULL) {
334e8e29e8dSJason Zhu 		printf("avb_ops_user_new() failed!\n");
335e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
336e8e29e8dSJason Zhu 	}
337e8e29e8dSJason Zhu 
338e8e29e8dSJason Zhu 	if (ops->read_is_device_unlocked(ops, &out_is_unlocked) != 0) {
339e8e29e8dSJason Zhu 		printf("do_avb_read_is_device_unlocked error!\n");
340e8e29e8dSJason Zhu 		avb_ops_user_free(ops);
341e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
342e8e29e8dSJason Zhu 	}
343e8e29e8dSJason Zhu 
344*d9d5eb74SJason Zhu 	printf("out_is_unlocked = %d\n", out_is_unlocked);
345e8e29e8dSJason Zhu 	avb_ops_user_free(ops);
346e8e29e8dSJason Zhu 
347e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
348e8e29e8dSJason Zhu }
349e8e29e8dSJason Zhu int do_avb_write_is_device_unlocked(cmd_tbl_t *cmdtp, int flag,
350e8e29e8dSJason Zhu 				    int argc, char * const argv[])
351e8e29e8dSJason Zhu {
352e8e29e8dSJason Zhu 	AvbOps *ops;
353e8e29e8dSJason Zhu 	bool out_is_unlocked;
354e8e29e8dSJason Zhu 
355e8e29e8dSJason Zhu 	if (argc != 2)
356e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
357e8e29e8dSJason Zhu 
358e8e29e8dSJason Zhu 	out_is_unlocked = simple_strtoul(argv[1], NULL, 16);
359e8e29e8dSJason Zhu 	if ((out_is_unlocked != 0) || (out_is_unlocked != 1))
360e8e29e8dSJason Zhu 		printf("enter out_is_unlocked value must is '0' or '1'\n");
361e8e29e8dSJason Zhu 
362e8e29e8dSJason Zhu 	ops = avb_ops_user_new();
363e8e29e8dSJason Zhu 	if (ops == NULL) {
364e8e29e8dSJason Zhu 		printf("avb_ops_user_new() failed!\n");
365e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
366e8e29e8dSJason Zhu 	}
367e8e29e8dSJason Zhu 
368e8e29e8dSJason Zhu 	if (ops->write_is_device_unlocked(ops, &out_is_unlocked) != 0) {
369e8e29e8dSJason Zhu 		printf("do_avb_write_is_device_unlocked error!\n");
370e8e29e8dSJason Zhu 		avb_ops_user_free(ops);
371e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
372e8e29e8dSJason Zhu 	}
373e8e29e8dSJason Zhu 
374e8e29e8dSJason Zhu 	debug("out_is_unlocked = %d\n", out_is_unlocked);
375e8e29e8dSJason Zhu 	avb_ops_user_free(ops);
376e8e29e8dSJason Zhu 
377e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
378e8e29e8dSJason Zhu }
379e8e29e8dSJason Zhu 
380e8e29e8dSJason Zhu int do_avb_get_size_of_partition(cmd_tbl_t *cmdtp, int flag,
381e8e29e8dSJason Zhu 				 int argc, char * const argv[])
382e8e29e8dSJason Zhu {
383e8e29e8dSJason Zhu 	AvbOps *ops;
384e8e29e8dSJason Zhu 	char *requested_partitions;
385e8e29e8dSJason Zhu 	uint64_t out_size_in_bytes;
386e8e29e8dSJason Zhu 
387e8e29e8dSJason Zhu 	if (argc != 2)
388e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
389e8e29e8dSJason Zhu 
390e8e29e8dSJason Zhu 	requested_partitions = argv[1];
391e8e29e8dSJason Zhu 	ops = avb_ops_user_new();
392e8e29e8dSJason Zhu 	if (ops == NULL) {
393e8e29e8dSJason Zhu 		printf("avb_ops_user_new() failed!\n");
394e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
395e8e29e8dSJason Zhu 	}
396e8e29e8dSJason Zhu 
397e8e29e8dSJason Zhu 	if (ops->get_size_of_partition(ops, requested_partitions,
398e8e29e8dSJason Zhu 				       &out_size_in_bytes) != 0) {
399e8e29e8dSJason Zhu 		printf("do_avb_get_size_of_partition error!\n");
400e8e29e8dSJason Zhu 		avb_ops_user_free(ops);
401e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
402e8e29e8dSJason Zhu 	}
403e8e29e8dSJason Zhu 
404e8e29e8dSJason Zhu 	printf("partition size = %lld\n", out_size_in_bytes);
405e8e29e8dSJason Zhu 	avb_ops_user_free(ops);
406e8e29e8dSJason Zhu 
407e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
408e8e29e8dSJason Zhu }
409e8e29e8dSJason Zhu 
410e8e29e8dSJason Zhu int do_avb_get_get_unique_guid_for_partition(cmd_tbl_t *cmdtp, int flag,
411e8e29e8dSJason Zhu 					     int argc, char * const argv[])
412e8e29e8dSJason Zhu {
413e8e29e8dSJason Zhu 	AvbOps *ops;
414e8e29e8dSJason Zhu 	char *requested_partitions;
415e8e29e8dSJason Zhu 	size_t guid_buf_size = 37;
416e8e29e8dSJason Zhu 	char guid_buf[37];
417e8e29e8dSJason Zhu 
418e8e29e8dSJason Zhu 	if (argc != 2)
419e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
420e8e29e8dSJason Zhu 
421e8e29e8dSJason Zhu 	requested_partitions = argv[1];
422e8e29e8dSJason Zhu 	ops = avb_ops_user_new();
423e8e29e8dSJason Zhu 	if (ops == NULL) {
424e8e29e8dSJason Zhu 		printf("avb_ops_user_new() failed!\n");
425e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
426e8e29e8dSJason Zhu 	}
427e8e29e8dSJason Zhu 
428e8e29e8dSJason Zhu 	if (ops->get_unique_guid_for_partition(ops, requested_partitions,
429e8e29e8dSJason Zhu 					       guid_buf, guid_buf_size) != 0) {
430e8e29e8dSJason Zhu 		printf("do_avb_get_get_unique_guid_for_partition error!\n");
431e8e29e8dSJason Zhu 		avb_ops_user_free(ops);
432e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
433e8e29e8dSJason Zhu 	}
434e8e29e8dSJason Zhu 
435e8e29e8dSJason Zhu 	printf("guid = %s\n", guid_buf);
436e8e29e8dSJason Zhu 	avb_ops_user_free(ops);
437e8e29e8dSJason Zhu 
438e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
439e8e29e8dSJason Zhu }
440e8e29e8dSJason Zhu 
441e8e29e8dSJason Zhu int do_avb_read(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
442e8e29e8dSJason Zhu {
443e8e29e8dSJason Zhu 	AvbOps *ops;
444e8e29e8dSJason Zhu 	char *requested_partitions;
445e8e29e8dSJason Zhu 	int64_t offset_blk;
446e8e29e8dSJason Zhu 	size_t blkcnt;
447e8e29e8dSJason Zhu 	size_t out_num_read;
448e8e29e8dSJason Zhu 	int i;
449e8e29e8dSJason Zhu 	char *buffer;
450e8e29e8dSJason Zhu 
451e8e29e8dSJason Zhu 	if (argc != 4)
452e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
453e8e29e8dSJason Zhu 
454e8e29e8dSJason Zhu 	requested_partitions = argv[1];
455e8e29e8dSJason Zhu 	offset_blk = simple_strtoul(argv[2], NULL, 16);
456e8e29e8dSJason Zhu 	blkcnt = simple_strtoul(argv[3], NULL, 16);
457e8e29e8dSJason Zhu 	ops = avb_ops_user_new();
458e8e29e8dSJason Zhu 	buffer = (char *)malloc(blkcnt * 512);
459e8e29e8dSJason Zhu 	if (buffer == NULL)
460e8e29e8dSJason Zhu 		printf("malloc buffer failed!\n");
461e8e29e8dSJason Zhu 
462e8e29e8dSJason Zhu 	if (ops == NULL) {
463e8e29e8dSJason Zhu 		printf("avb_ops_user_new() failed!\n");
464e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
465e8e29e8dSJason Zhu 	}
466e8e29e8dSJason Zhu 
467e8e29e8dSJason Zhu 	if (ops->read_from_partition(ops, requested_partitions,
468e8e29e8dSJason Zhu 				     offset_blk, blkcnt, buffer,
469e8e29e8dSJason Zhu 				     &out_num_read) != 0) {
470e8e29e8dSJason Zhu 		printf("do avb read error!\n");
471e8e29e8dSJason Zhu 		free(buffer);
472e8e29e8dSJason Zhu 		avb_ops_user_free(ops);
473e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
474e8e29e8dSJason Zhu 	}
475e8e29e8dSJason Zhu 
476e8e29e8dSJason Zhu 	for (i = 0; i < 512 * blkcnt; i++)
477e8e29e8dSJason Zhu 		printf("buffer %d = %d\n", i, buffer[i]);
478e8e29e8dSJason Zhu 
479e8e29e8dSJason Zhu 	free(buffer);
480e8e29e8dSJason Zhu 	avb_ops_user_free(ops);
481e8e29e8dSJason Zhu 
482e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
483e8e29e8dSJason Zhu }
484e8e29e8dSJason Zhu 
485e8e29e8dSJason Zhu int do_avb_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
486e8e29e8dSJason Zhu {
487e8e29e8dSJason Zhu 	AvbOps *ops;
488e8e29e8dSJason Zhu 	char *requested_partitions;
489e8e29e8dSJason Zhu 	int64_t offset_blk;
490e8e29e8dSJason Zhu 	size_t blkcnt;
491e8e29e8dSJason Zhu 	size_t out_num_read;
492e8e29e8dSJason Zhu 	char *buffer;
493e8e29e8dSJason Zhu 
494e8e29e8dSJason Zhu 	if (argc != 4)
495e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
496e8e29e8dSJason Zhu 
497e8e29e8dSJason Zhu 	requested_partitions = argv[1];
498e8e29e8dSJason Zhu 	offset_blk = simple_strtoul(argv[2], NULL, 16);
499e8e29e8dSJason Zhu 	blkcnt = simple_strtoul(argv[3], NULL, 16);
500e8e29e8dSJason Zhu 	ops = avb_ops_user_new();
501e8e29e8dSJason Zhu 	buffer = (char *)malloc(blkcnt * 512);
502e8e29e8dSJason Zhu 	if (buffer == NULL) {
503e8e29e8dSJason Zhu 		printf("malloc buffer failed!\n");
504e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
505e8e29e8dSJason Zhu 	}
506e8e29e8dSJason Zhu 
507e8e29e8dSJason Zhu 	if (ops == NULL) {
508e8e29e8dSJason Zhu 		printf("avb_ops_user_new() failed!\n");
509e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
510e8e29e8dSJason Zhu 	}
511e8e29e8dSJason Zhu 	if (ops->read_from_partition(ops, requested_partitions, offset_blk,
512e8e29e8dSJason Zhu 				     blkcnt, buffer, &out_num_read) != 0) {
513e8e29e8dSJason Zhu 		printf("do_avb_write error!\n");
514e8e29e8dSJason Zhu 		free(buffer);
515e8e29e8dSJason Zhu 		avb_ops_user_free(ops);
516e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
517e8e29e8dSJason Zhu 	}
518e8e29e8dSJason Zhu 
519e8e29e8dSJason Zhu 	free(buffer);
520e8e29e8dSJason Zhu 	avb_ops_user_free(ops);
521e8e29e8dSJason Zhu 
522e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
523e8e29e8dSJason Zhu }
524e8e29e8dSJason Zhu 
525e8e29e8dSJason Zhu int do_avb_read_ab_metadata(cmd_tbl_t *cmdtp, int flag,
526e8e29e8dSJason Zhu 			    int argc, char * const argv[])
527e8e29e8dSJason Zhu {
528e8e29e8dSJason Zhu 	AvbOps *ops;
529e8e29e8dSJason Zhu 	AvbABData ab_data;
530e8e29e8dSJason Zhu 
531e8e29e8dSJason Zhu 	if (argc != 1)
532e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
533e8e29e8dSJason Zhu 
534e8e29e8dSJason Zhu 	ops = avb_ops_user_new();
535e8e29e8dSJason Zhu 	if (ops == NULL) {
536e8e29e8dSJason Zhu 		printf("avb_ops_user_new() failed!\n");
537e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
538e8e29e8dSJason Zhu 	}
539e8e29e8dSJason Zhu 
540e8e29e8dSJason Zhu 	if (ops->ab_ops->read_ab_metadata(ops->ab_ops, &ab_data) != 0) {
541e8e29e8dSJason Zhu 		printf("do_avb_write_ab_metadata error!\n");
542e8e29e8dSJason Zhu 		avb_ops_user_free(ops);
543e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
544e8e29e8dSJason Zhu 	}
545e8e29e8dSJason Zhu 
546e8e29e8dSJason Zhu 	avb_ops_user_free(ops);
547e8e29e8dSJason Zhu 
548e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
549e8e29e8dSJason Zhu }
550e8e29e8dSJason Zhu 
551e8e29e8dSJason Zhu int do_avb_write_ab_metadata(cmd_tbl_t *cmdtp, int flag,
552e8e29e8dSJason Zhu 			     int argc, char * const argv[])
553e8e29e8dSJason Zhu {
554e8e29e8dSJason Zhu 	AvbOps *ops;
555e8e29e8dSJason Zhu 	AvbABData ab_data;
556e8e29e8dSJason Zhu 
557e8e29e8dSJason Zhu 	if (argc != 1)
558e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
559e8e29e8dSJason Zhu 
560e8e29e8dSJason Zhu 	ops = avb_ops_user_new();
561e8e29e8dSJason Zhu 	if (ops == NULL) {
562e8e29e8dSJason Zhu 		printf("avb_ops_user_new() failed!\n");
563e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
564e8e29e8dSJason Zhu 	}
565e8e29e8dSJason Zhu 
566e8e29e8dSJason Zhu 	if (ops->ab_ops->write_ab_metadata(ops->ab_ops, &ab_data) != 0) {
567e8e29e8dSJason Zhu 		printf("do_avb_write_ab_metadata error!\n");
568e8e29e8dSJason Zhu 		avb_ops_user_free(ops);
569e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
570e8e29e8dSJason Zhu 	}
571e8e29e8dSJason Zhu 
572e8e29e8dSJason Zhu 	avb_ops_user_free(ops);
573e8e29e8dSJason Zhu 
574e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
575e8e29e8dSJason Zhu }
576e8e29e8dSJason Zhu 
577*d9d5eb74SJason Zhu int do_perm_attr_test(cmd_tbl_t *cmdtp, int flag,
578*d9d5eb74SJason Zhu 		      int argc, char * const argv[])
579*d9d5eb74SJason Zhu {
580*d9d5eb74SJason Zhu 	AvbOps *ops;
581*d9d5eb74SJason Zhu 	int i;
582*d9d5eb74SJason Zhu 	uint8_t hash[AVB_SHA256_DIGEST_SIZE];
583*d9d5eb74SJason Zhu 
584*d9d5eb74SJason Zhu 	if (argc != 1)
585*d9d5eb74SJason Zhu 		return CMD_RET_USAGE;
586*d9d5eb74SJason Zhu 
587*d9d5eb74SJason Zhu 	ops = avb_ops_user_new();
588*d9d5eb74SJason Zhu 	if (ops == NULL) {
589*d9d5eb74SJason Zhu 		printf("avb_ops_user_new() failed!\n");
590*d9d5eb74SJason Zhu 		return CMD_RET_FAILURE;
591*d9d5eb74SJason Zhu 	}
592*d9d5eb74SJason Zhu 
593*d9d5eb74SJason Zhu 	if (ops->atx_ops->read_permanent_attributes_hash(ops->atx_ops, hash) != 0) {
594*d9d5eb74SJason Zhu 		printf("read_permanent_attributes_hash error!\n");
595*d9d5eb74SJason Zhu 		avb_ops_user_free(ops);
596*d9d5eb74SJason Zhu 		return CMD_RET_FAILURE;
597*d9d5eb74SJason Zhu 	}
598*d9d5eb74SJason Zhu 
599*d9d5eb74SJason Zhu 	for (i = 0; i < AVB_SHA256_DIGEST_SIZE; i++) {
600*d9d5eb74SJason Zhu 		if (i % 4 == 0)
601*d9d5eb74SJason Zhu 			printf("\n");
602*d9d5eb74SJason Zhu 		printf("0x%x  ", hash[i]);
603*d9d5eb74SJason Zhu 	}
604*d9d5eb74SJason Zhu 
605*d9d5eb74SJason Zhu 	avb_ops_user_free(ops);
606*d9d5eb74SJason Zhu 
607*d9d5eb74SJason Zhu 	return CMD_RET_SUCCESS;
608*d9d5eb74SJason Zhu }
609*d9d5eb74SJason Zhu 
610e8e29e8dSJason Zhu int do_avb_verify_partition(cmd_tbl_t *cmdtp, int flag,
611e8e29e8dSJason Zhu 			    int argc, char * const argv[])
612e8e29e8dSJason Zhu {
613e8e29e8dSJason Zhu 	AvbOps *ops;
614e8e29e8dSJason Zhu 	const char *requested_partitions[1];
615e8e29e8dSJason Zhu 	const char * slot_suffixes[2] = {"_a", "_b"};
616e8e29e8dSJason Zhu 	AvbSlotVerifyFlags flags;
617e8e29e8dSJason Zhu 	AvbSlotVerifyData *slot_data[2] = {NULL, NULL};
618e8e29e8dSJason Zhu 	AvbSlotVerifyResult verify_result;
619e8e29e8dSJason Zhu 	size_t n;
620e8e29e8dSJason Zhu 
621e8e29e8dSJason Zhu 	if (argc != 3)
622e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
623e8e29e8dSJason Zhu 
624e8e29e8dSJason Zhu 	requested_partitions[0] = argv[1];
625e8e29e8dSJason Zhu 	n = simple_strtoul(argv[2], NULL, 16);
626e8e29e8dSJason Zhu 	ops = avb_ops_user_new();
627e8e29e8dSJason Zhu 	flags = AVB_SLOT_VERIFY_FLAGS_NONE;
628e8e29e8dSJason Zhu 	verify_result =
629e8e29e8dSJason Zhu 		avb_slot_verify(ops,
630e8e29e8dSJason Zhu 				requested_partitions,
631e8e29e8dSJason Zhu 				slot_suffixes[n],
632e8e29e8dSJason Zhu 				flags,
633e8e29e8dSJason Zhu 				AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
634e8e29e8dSJason Zhu 				&slot_data[n]);
635e8e29e8dSJason Zhu 	if (verify_result != 0)
636e8e29e8dSJason Zhu 		return CMD_RET_FAILURE;
637e8e29e8dSJason Zhu 
638e8e29e8dSJason Zhu 	avb_ops_user_free(ops);
639e8e29e8dSJason Zhu 
640e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
641e8e29e8dSJason Zhu }
642e8e29e8dSJason Zhu 
643e8e29e8dSJason Zhu int do_avb_flow(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
644e8e29e8dSJason Zhu {
645f0864c7fSJason Zhu 	char slot_partition[2][20] = {{0}, {0}};
646e8e29e8dSJason Zhu 	unsigned long load_address;
647e8e29e8dSJason Zhu 	AvbOps *ops;
648e8e29e8dSJason Zhu 	const char *avb_version;
649e8e29e8dSJason Zhu 	AvbSlotVerifyData *slot_data;
650e8e29e8dSJason Zhu 	AvbSlotVerifyFlags flags;
651e8e29e8dSJason Zhu 	const char *requested_partitions[] = {"boot", "system", NULL};
652e8e29e8dSJason Zhu 	char *command_line;
65337a7bc39SJason Zhu 	bool unlocked;
654e8e29e8dSJason Zhu 	const char *mode_cmdline = NULL;
655e8e29e8dSJason Zhu 	char root_data[70] = "root=PARTUUID=";
65637a7bc39SJason Zhu 	char *vboot_state = "androidboot.verifiedbootstate=";
6579aed1a13SJason Zhu 	char avb_root_data[2000] = {0};
658e8e29e8dSJason Zhu 	size_t guid_buf_size = 37;
659e8e29e8dSJason Zhu 	char guid_buf[37];
660e8e29e8dSJason Zhu 	char verify_flag;
661e8e29e8dSJason Zhu 	char boot_slot_select[5];
66282ee22d4SJason Zhu 	struct android_bootloader_message data;
66382ee22d4SJason Zhu 	const char *fastboot_cmd = env_get("fastbootcmd");
66437a7bc39SJason Zhu 	AvbABFlowResult ab_result;
665e8e29e8dSJason Zhu 
666e8e29e8dSJason Zhu 	if (argc != 2)
667e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
66882ee22d4SJason Zhu 
66982ee22d4SJason Zhu 	bootloader_message_read(&data);
67082ee22d4SJason Zhu 	if (!strcmp("bootonce-bootloader", data.command)) {
67182ee22d4SJason Zhu 		memset(data.command, 0, sizeof(data.command));
67282ee22d4SJason Zhu 		bootloader_message_write(&data);
67382ee22d4SJason Zhu 		if (fastboot_cmd) {
67482ee22d4SJason Zhu 			printf("bootonce-bootloader!\n");
67582ee22d4SJason Zhu 			return run_command(fastboot_cmd, CMD_FLAG_ENV);
67682ee22d4SJason Zhu 		} else {
67782ee22d4SJason Zhu 			printf("The fastbootcmd is NULL!\n");
67837a7bc39SJason Zhu 			goto fail;
67982ee22d4SJason Zhu 		}
68082ee22d4SJason Zhu 	} else if (!strcmp("boot-recovery", data.command)) {
68182ee22d4SJason Zhu 		printf("Enter boot-recovery!\n");
68282ee22d4SJason Zhu 	} else if(!strcmp("boot-normal", data.command)) {
68382ee22d4SJason Zhu 		printf("Enter boot-normal!\n");
68482ee22d4SJason Zhu 		mode_cmdline = "skip_initramfs";
68582ee22d4SJason Zhu 	} else {
6869f7ea89dSWenping Zhang 		/*
6879f7ea89dSWenping Zhang 		 * Firstly, confirm if there is a command in misc partition in
6889f7ea89dSWenping Zhang 		 * previous cases, and then we need to confirm whether user has
6899f7ea89dSWenping Zhang 		 * requested to enter recovery mode by entering "reboot recovery"
6909f7ea89dSWenping Zhang 		 * command through adb or serial console.
6919f7ea89dSWenping Zhang 		 */
6929f7ea89dSWenping Zhang 		char *env_rebootmode = env_get("reboot_mode");
6939f7ea89dSWenping Zhang 
6949f7ea89dSWenping Zhang 		if (env_rebootmode && !strcmp("recovery", env_rebootmode))
6959f7ea89dSWenping Zhang 			printf("Enter recovery mode by command 'reboot recovery'!\n");
6969f7ea89dSWenping Zhang 		else
69782ee22d4SJason Zhu 			mode_cmdline = "skip_initramfs";
69882ee22d4SJason Zhu 	}
69982ee22d4SJason Zhu 
700e8e29e8dSJason Zhu 	avb_version = avb_version_string();
701e8e29e8dSJason Zhu 	printf("Android avb version is %s.\n", avb_version);
702e8e29e8dSJason Zhu 	ops = avb_ops_user_new();
70337a7bc39SJason Zhu 	if (ops == NULL) {
704e8e29e8dSJason Zhu 		printf("avb_ops_user_new() failed!\n");
70537a7bc39SJason Zhu 		goto fail;
70637a7bc39SJason Zhu 	}
707e8e29e8dSJason Zhu 
70837a7bc39SJason Zhu 	if (ops->read_is_device_unlocked(ops, &unlocked) != 0) {
709e8e29e8dSJason Zhu 		printf("Error determining whether device is unlocked.\n");
71037a7bc39SJason Zhu 		unlocked = ANDROID_VBOOT_UNLOCK;
71137a7bc39SJason Zhu 		if (ops->write_is_device_unlocked(ops, &unlocked) != 0) {
71237a7bc39SJason Zhu 			printf("Can not write lock state!\n");
71337a7bc39SJason Zhu 			unlocked = ANDROID_VBOOT_LOCK;
71437a7bc39SJason Zhu 		}
71537a7bc39SJason Zhu 		if (ops->read_is_device_unlocked(ops, &unlocked) != 0) {
71637a7bc39SJason Zhu 			printf("Can not read lock state!\n");
71737a7bc39SJason Zhu 			unlocked = ANDROID_VBOOT_LOCK;
71837a7bc39SJason Zhu 		}
71937a7bc39SJason Zhu 	}
720e8e29e8dSJason Zhu 
721e8e29e8dSJason Zhu 	printf("read_is_device_unlocked() ops returned that device is %s\n",
722e8e29e8dSJason Zhu 	       unlocked ? "UNLOCKED" : "LOCKED");
723e8e29e8dSJason Zhu 
724e8e29e8dSJason Zhu 	flags = AVB_SLOT_VERIFY_FLAGS_NONE;
725e8e29e8dSJason Zhu 	if (unlocked)
726e8e29e8dSJason Zhu 		flags |= AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR;
727e8e29e8dSJason Zhu 
728e8e29e8dSJason Zhu 	verify_flag = argv[1][0];
729e8e29e8dSJason Zhu 	if (verify_flag == 'v') {
730e8e29e8dSJason Zhu 		debug("start with verify!\n");
73137a7bc39SJason Zhu 		ab_result =
73237a7bc39SJason Zhu 		    avb_ab_flow(ops->ab_ops,
733e8e29e8dSJason Zhu 				requested_partitions,
734e8e29e8dSJason Zhu 				flags,
735e8e29e8dSJason Zhu 				AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
73637a7bc39SJason Zhu 				&slot_data);
73737a7bc39SJason Zhu 		if ((ab_result != AVB_AB_FLOW_RESULT_OK) &&
73837a7bc39SJason Zhu 		    (ab_result !=
73937a7bc39SJason Zhu 		    AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR)) {
7404397fdfdSJason Zhu 			printf("avb_ab_flow() error!\n");
74137a7bc39SJason Zhu 			avb_ops_user_free(ops);
74237a7bc39SJason Zhu 			goto fail;
74337a7bc39SJason Zhu 		}
74437a7bc39SJason Zhu 
74537a7bc39SJason Zhu 		if (ab_result ==\
74637a7bc39SJason Zhu 		    AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR) {
74737a7bc39SJason Zhu 			strcat(avb_root_data, vboot_state);
74837a7bc39SJason Zhu 			strcat(avb_root_data, "orange");
74937a7bc39SJason Zhu 		} else if (ab_result == AVB_AB_FLOW_RESULT_OK) {
75037a7bc39SJason Zhu 			strcat(avb_root_data, vboot_state);
75137a7bc39SJason Zhu 			strcat(avb_root_data, "green");
7524397fdfdSJason Zhu 		}
7534397fdfdSJason Zhu 
754e8e29e8dSJason Zhu 		command_line = android_assemble_cmdline(slot_data->ab_suffix,
755e8e29e8dSJason Zhu 							mode_cmdline);
7569aed1a13SJason Zhu 		strcat(avb_root_data, " ");
7579aed1a13SJason Zhu 		strcat(avb_root_data, command_line);
7589aed1a13SJason Zhu 		strcat(avb_root_data, " ");
7599aed1a13SJason Zhu 		strcat(avb_root_data, slot_data->cmdline);
7609aed1a13SJason Zhu 		env_set("bootargs", avb_root_data);
761e8e29e8dSJason Zhu 		load_address = CONFIG_SYS_LOAD_ADDR;
76237a7bc39SJason Zhu 		if (rk_avb_close_optee_client())
763708de143SJason Zhu 			printf("Can not close optee client!\n");
764708de143SJason Zhu 
765e8e29e8dSJason Zhu 		memcpy((uint8_t*)load_address,
766e8e29e8dSJason Zhu 		       slot_data->loaded_partitions->data,
767e8e29e8dSJason Zhu 		       slot_data->loaded_partitions->data_size);
768e8e29e8dSJason Zhu 		android_bootloader_boot_kernel(load_address);
76937a7bc39SJason Zhu 		avb_ops_user_free(ops);
770e8e29e8dSJason Zhu 	} else if (verify_flag == 'n') {
771e8e29e8dSJason Zhu 		load_address = CONFIG_SYS_LOAD_ADDR;
77237a7bc39SJason Zhu 		rk_avb_ab_slot_select(ops->ab_ops, boot_slot_select);
773e8e29e8dSJason Zhu 		strcat(slot_partition[1], requested_partitions[1]);
774e8e29e8dSJason Zhu 		strcat(slot_partition[1], boot_slot_select);
775e8e29e8dSJason Zhu 		printf("%s\n", slot_partition[1]);
776e8e29e8dSJason Zhu 		ops->get_unique_guid_for_partition(ops,
777e8e29e8dSJason Zhu 						   slot_partition[1],
778e8e29e8dSJason Zhu 						   guid_buf,
779e8e29e8dSJason Zhu 						   guid_buf_size);
780e8e29e8dSJason Zhu 		strcat(root_data, guid_buf);
781e8e29e8dSJason Zhu 		command_line = android_assemble_cmdline(boot_slot_select,
782e8e29e8dSJason Zhu 							mode_cmdline);
783e8e29e8dSJason Zhu 		strcat(root_data, " ");
784e8e29e8dSJason Zhu 		strcat(root_data, command_line);
785e8e29e8dSJason Zhu 		env_set("bootargs", root_data);
78637a7bc39SJason Zhu 		if (android_avb_boot_flow(boot_slot_select, load_address)) {
78737a7bc39SJason Zhu 			printf("Cannot boot the system, goto the fastboot!\n");
78837a7bc39SJason Zhu 			avb_ops_user_free(ops);
78937a7bc39SJason Zhu 			goto fail;
79037a7bc39SJason Zhu 		}
79137a7bc39SJason Zhu 		avb_ops_user_free(ops);
792bf17c627SJason Zhu 	} else if (verify_flag == 'o') {
793bf17c627SJason Zhu 		load_address = CONFIG_SYS_LOAD_ADDR;
794bf17c627SJason Zhu 		strcat(slot_partition[1], requested_partitions[1]);
795bf17c627SJason Zhu 		ops->get_unique_guid_for_partition(ops,
796bf17c627SJason Zhu 						   slot_partition[1],
797bf17c627SJason Zhu 						   guid_buf,
798bf17c627SJason Zhu 						   guid_buf_size);
799bf17c627SJason Zhu 		strcat(root_data, guid_buf);
800bf17c627SJason Zhu 		command_line = android_assemble_cmdline(boot_slot_select,
801bf17c627SJason Zhu 							mode_cmdline);
802bf17c627SJason Zhu 		strcat(root_data, " ");
803bf17c627SJason Zhu 		strcat(root_data, command_line);
804bf17c627SJason Zhu 		env_set("bootargs", root_data);
80537a7bc39SJason Zhu 		if (android_boot_flow(load_address)) {
80637a7bc39SJason Zhu 			printf("Cannot boot the system, goto the fastboot!\n");
80737a7bc39SJason Zhu 			avb_ops_user_free(ops);
80837a7bc39SJason Zhu 			goto fail;
80937a7bc39SJason Zhu 		}
81037a7bc39SJason Zhu 		avb_ops_user_free(ops);
811e8e29e8dSJason Zhu 	} else {
812e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
813e8e29e8dSJason Zhu 	}
814e8e29e8dSJason Zhu 
815e8e29e8dSJason Zhu 	return CMD_RET_SUCCESS;
81637a7bc39SJason Zhu fail:
81737a7bc39SJason Zhu 	if (fastboot_cmd == NULL) {
81837a7bc39SJason Zhu 		printf("fastboot_cmd is null, run default fastboot_cmd!\n");
81937a7bc39SJason Zhu 		fastboot_cmd = "fastboot usb 0";
82037a7bc39SJason Zhu 	}
82137a7bc39SJason Zhu 
82237a7bc39SJason Zhu 	return run_command(fastboot_cmd, CMD_FLAG_ENV);
823e8e29e8dSJason Zhu }
824e8e29e8dSJason Zhu 
825e8e29e8dSJason Zhu static cmd_tbl_t cmd_avb[] = {
826e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(init, 1, 1, do_avb_init_ab_metadata, "", ""),
827e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(version, 1, 1, do_avb_version, "", ""),
828e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(slot_active, 2, 1,
829e8e29e8dSJason Zhu 			 do_avb_ab_mark_slot_active, "", ""),
830e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(slot_unbootable, 2, 1,
831e8e29e8dSJason Zhu 			 do_avb_ab_mark_slot_unbootable, "", ""),
832e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(slot_successful, 2, 1,
833e8e29e8dSJason Zhu 			 do_avb_ab_mark_slot_successful, "", ""),
834e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(read_rollback, 2, 1,
835e8e29e8dSJason Zhu 			 do_avb_read_rollback_index, "", ""),
836e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(write_rollback, 3, 1,
837e8e29e8dSJason Zhu 			 do_avb_write_rollback_index, "", ""),
838e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(read_lock_status, 1, 1,
839e8e29e8dSJason Zhu 			 do_avb_read_is_device_unlocked, "", ""),
840e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(write_lock_status, 2, 1,
841e8e29e8dSJason Zhu 			 do_avb_write_is_device_unlocked, "", ""),
842e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(part_size, 2, 1,
843e8e29e8dSJason Zhu 			 do_avb_get_size_of_partition, "", ""),
844e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(part_guid, 2, 1,
845e8e29e8dSJason Zhu 			 do_avb_get_get_unique_guid_for_partition, "", ""),
846e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(read, 4, 1, do_avb_read, "", ""),
847e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(write, 4, 1, do_avb_write, "", ""),
848e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(readabmisc, 1, 1, do_avb_read_ab_metadata, "", ""),
849e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(writeabmisc, 1, 1, do_avb_write_ab_metadata, "", ""),
850*d9d5eb74SJason Zhu 	U_BOOT_CMD_MKENT(perm_attr_test, 1, 1, do_perm_attr_test, "", ""),
851e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(verify, 3, 1, do_avb_verify_partition, "", ""),
852e8e29e8dSJason Zhu 	U_BOOT_CMD_MKENT(flow, 2, 1, do_avb_flow, "", "")
853e8e29e8dSJason Zhu };
854e8e29e8dSJason Zhu 
855e8e29e8dSJason Zhu static int do_boot_avb(cmd_tbl_t *cmdtp,
856e8e29e8dSJason Zhu 		       int flag,
857e8e29e8dSJason Zhu 		       int argc,
858e8e29e8dSJason Zhu 		       char * const argv[])
859e8e29e8dSJason Zhu {
860e8e29e8dSJason Zhu 	cmd_tbl_t *cp;
861e8e29e8dSJason Zhu 
862e8e29e8dSJason Zhu 	cp = find_cmd_tbl(argv[1], cmd_avb, ARRAY_SIZE(cmd_avb));
863e8e29e8dSJason Zhu 
864e8e29e8dSJason Zhu 	argc--;
865e8e29e8dSJason Zhu 	argv++;
866e8e29e8dSJason Zhu 
867e8e29e8dSJason Zhu 	if (cp == NULL || argc > cp->maxargs)
868e8e29e8dSJason Zhu 		return CMD_RET_USAGE;
869e8e29e8dSJason Zhu 	if (flag == CMD_FLAG_REPEAT && !cp->repeatable)
870e8e29e8dSJason Zhu 		return CMD_RET_SUCCESS;
871e8e29e8dSJason Zhu 
872e8e29e8dSJason Zhu 	return cp->cmd(cmdtp, flag, argc, argv);
873e8e29e8dSJason Zhu }
874e8e29e8dSJason Zhu 
875e8e29e8dSJason Zhu U_BOOT_CMD(
876e8e29e8dSJason Zhu 	bootavb, 29, 1, do_boot_avb,
877e8e29e8dSJason Zhu 	"Execute the Android avb a/b boot flow.",
878e8e29e8dSJason Zhu 	"init - initialize the avbabmeta\n"
879e8e29e8dSJason Zhu 	"bootavb version - display info of bootavb version\n"
880e8e29e8dSJason Zhu 	"bootavb slot_active cnt\n"
881e8e29e8dSJason Zhu 	"bootavb slot_unbootable cnt\n"
882e8e29e8dSJason Zhu 	"bootavb slot_successful cnt\n"
883e8e29e8dSJason Zhu 	"bootavb read_rollback rollback_index_location\n"
884e8e29e8dSJason Zhu 	"bootavb write_rollback rollback_index_location out_rollback_index\n"
885e8e29e8dSJason Zhu 	"bootavb read_lock_status\n"
886e8e29e8dSJason Zhu 	"bootavb write_lock_status 0 or 1\n"
887e8e29e8dSJason Zhu 	"bootavb part_size partitions_name\n"
888e8e29e8dSJason Zhu 	"bootavb part_guid partitions_name\n"
889e8e29e8dSJason Zhu 	"bootavb read partition offset_blk cnt\n"
890e8e29e8dSJason Zhu 	"bootavb write partition offset_blk cnt\n"
891e8e29e8dSJason Zhu 	"bootavb readabmisc\n"
892e8e29e8dSJason Zhu 	"bootavb writeabmisc\n"
893*d9d5eb74SJason Zhu 	"bootavb perm_attr_test\n"
894e8e29e8dSJason Zhu 	"bootavb verify partition slot_cnt;partion name without '_a' or '_b'\n"
895e8e29e8dSJason Zhu 	"bootavb flow v/n\n"
896e8e29e8dSJason Zhu );
897e8e29e8dSJason Zhu #endif
898