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