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> 18d9d5eb74SJason 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 45008aee87SAndy Yan #if defined(CONFIG_ARM64) 463f251879SKever Yang /* ARM64 kernel load addr need to align to 0x80000, and android boot.img 473f251879SKever Yang * have a 2KB header, need to reserve space for it. 483f251879SKever Yang */ 493f251879SKever Yang load_address &= ~0x7ffff; 50008aee87SAndy Yan #endif 51ee465021SJoseph Chen 52891380b5SKever Yang dev_desc = blk_get_dev(argv[1], simple_strtoul(argv[2], NULL, 16)); 53891380b5SKever Yang if (!dev_desc) { 54891380b5SKever Yang printf("Could not get %s %s\n", argv[1], argv[2]); 5506f4a874SAlex Deymo return CMD_RET_FAILURE; 5606f4a874SAlex Deymo } 5706f4a874SAlex Deymo 58891380b5SKever Yang ret = android_bootloader_boot_flow(dev_desc, load_address); 5906f4a874SAlex Deymo if (ret < 0) { 6006f4a874SAlex Deymo printf("Android boot failed, error %d.\n", ret); 6106f4a874SAlex Deymo return CMD_RET_FAILURE; 6206f4a874SAlex Deymo } 6306f4a874SAlex Deymo return CMD_RET_SUCCESS; 6406f4a874SAlex Deymo } 6506f4a874SAlex Deymo 6606f4a874SAlex Deymo U_BOOT_CMD( 6780622240SAlex Deymo boot_android, 5, 0, do_boot_android, 6806f4a874SAlex Deymo "Execute the Android Bootloader flow.", 69df7cce43SAlex Deymo "<interface> <dev[:part|;part_name]> <slot> [<kernel_addr>]\n" 7006f4a874SAlex Deymo " - Load the Boot Control Block (BCB) from the partition 'part' on\n" 7106f4a874SAlex Deymo " device type 'interface' instance 'dev' to determine the boot\n" 7206f4a874SAlex Deymo " mode, and load and execute the appropriate kernel.\n" 7306f4a874SAlex Deymo " In normal and recovery mode, the kernel will be loaded from\n" 7406f4a874SAlex Deymo " the corresponding \"boot\" partition. In bootloader mode, the\n" 7506f4a874SAlex Deymo " command defined in the \"fastbootcmd\" variable will be\n" 7606f4a874SAlex Deymo " executed.\n" 7780622240SAlex Deymo " On Android devices with multiple slots, the pass 'slot' is\n" 7880622240SAlex Deymo " used to load the appropriate kernel. The standard slot names\n" 7980622240SAlex Deymo " are 'a' and 'b'.\n" 8006f4a874SAlex Deymo " - If 'part_name' is passed, preceded with a ; instead of :, the\n" 8106f4a874SAlex Deymo " partition name whose label is 'part_name' will be looked up in\n" 8206f4a874SAlex Deymo " the partition table. This is commonly the \"misc\" partition.\n" 8306f4a874SAlex Deymo ); 84e8e29e8dSJason Zhu 85*6a1e3c91SJason Zhu #ifdef CONFIG_ANDROID_AB 86e8e29e8dSJason Zhu int do_avb_init_ab_metadata(cmd_tbl_t *cmdtp, int flag, 87e8e29e8dSJason Zhu int argc, char * const argv[]) 88e8e29e8dSJason Zhu { 89e8e29e8dSJason Zhu AvbOps *ops; 90e8e29e8dSJason Zhu AvbABData ab_data; 91e8e29e8dSJason Zhu 92e8e29e8dSJason Zhu memset(&ab_data, 0, sizeof(AvbABData)); 93326572eaSJason Zhu debug("sizeof(AvbABData) = %d\n", (int)(size_t)sizeof(AvbABData)); 94e8e29e8dSJason Zhu if (argc != 1) 95e8e29e8dSJason Zhu return CMD_RET_USAGE; 96e8e29e8dSJason Zhu 97e8e29e8dSJason Zhu ops = avb_ops_user_new(); 98e8e29e8dSJason Zhu if (ops == NULL) { 99e8e29e8dSJason Zhu printf("avb_ops_user_new() failed!\n"); 100e8e29e8dSJason Zhu return CMD_RET_FAILURE; 101e8e29e8dSJason Zhu } 102e8e29e8dSJason Zhu 10337a7bc39SJason Zhu avb_ab_data_init(&ab_data); 104e8e29e8dSJason Zhu if (ops->ab_ops->write_ab_metadata(ops->ab_ops, &ab_data) != 0) { 105e8e29e8dSJason Zhu printf("do_avb_init_ab_metadata error!\n"); 106e8e29e8dSJason Zhu avb_ops_user_free(ops); 107e8e29e8dSJason Zhu return CMD_RET_FAILURE; 108e8e29e8dSJason Zhu } 109e8e29e8dSJason Zhu 110cc527546SJason Zhu printf("Initialize ab data to misc partition success.\n"); 111e8e29e8dSJason Zhu avb_ops_user_free(ops); 112e8e29e8dSJason Zhu 113e8e29e8dSJason Zhu return CMD_RET_SUCCESS; 114e8e29e8dSJason Zhu } 115e8e29e8dSJason Zhu 116e8e29e8dSJason Zhu int do_avb_ab_mark_slot_active(cmd_tbl_t *cmdtp, int flag, 117e8e29e8dSJason Zhu int argc, char * const argv[]) 118e8e29e8dSJason Zhu { 119e8e29e8dSJason Zhu AvbOps *ops; 120e8e29e8dSJason Zhu unsigned int slot_number; 121e8e29e8dSJason Zhu 122e8e29e8dSJason Zhu if (argc != 2) 123e8e29e8dSJason Zhu return CMD_RET_USAGE; 124e8e29e8dSJason Zhu 125e8e29e8dSJason Zhu ops = avb_ops_user_new(); 126e8e29e8dSJason Zhu if (ops == NULL) { 127e8e29e8dSJason Zhu printf("avb_ops_user_new() failed!\n"); 128e8e29e8dSJason Zhu return CMD_RET_FAILURE; 129e8e29e8dSJason Zhu } 130e8e29e8dSJason Zhu 131e8e29e8dSJason Zhu slot_number = simple_strtoul(argv[1], NULL, 16); 132e8e29e8dSJason Zhu if (avb_ab_mark_slot_active(ops->ab_ops, slot_number) != 0) { 133e8e29e8dSJason Zhu printf("avb_ab_mark_slot_active error!\n"); 134e8e29e8dSJason Zhu avb_ops_user_free(ops); 135e8e29e8dSJason Zhu return CMD_RET_FAILURE; 136e8e29e8dSJason Zhu } 137e8e29e8dSJason Zhu 138cc527546SJason Zhu printf("Mark slot %d active successfully.\n", slot_number); 139e8e29e8dSJason Zhu avb_ops_user_free(ops); 140e8e29e8dSJason Zhu 141e8e29e8dSJason Zhu return CMD_RET_SUCCESS; 142e8e29e8dSJason Zhu } 143e8e29e8dSJason Zhu 144e8e29e8dSJason Zhu int do_avb_ab_mark_slot_unbootable(cmd_tbl_t *cmdtp, int flag, 145e8e29e8dSJason Zhu int argc, char * const argv[]) 146e8e29e8dSJason Zhu { 147e8e29e8dSJason Zhu AvbOps *ops; 148e8e29e8dSJason Zhu unsigned int slot_number; 149e8e29e8dSJason Zhu 150e8e29e8dSJason Zhu if (argc != 2) 151e8e29e8dSJason Zhu return CMD_RET_USAGE; 152e8e29e8dSJason Zhu 153e8e29e8dSJason Zhu ops = avb_ops_user_new(); 154e8e29e8dSJason Zhu if (ops == NULL) { 155e8e29e8dSJason Zhu printf("avb_ops_user_new() failed!\n"); 156e8e29e8dSJason Zhu return CMD_RET_FAILURE; 157e8e29e8dSJason Zhu } 158e8e29e8dSJason Zhu 159e8e29e8dSJason Zhu slot_number = simple_strtoul(argv[1], NULL, 16); 160e8e29e8dSJason Zhu if (avb_ab_mark_slot_unbootable(ops->ab_ops, slot_number) != 0) { 161e8e29e8dSJason Zhu printf("do_avb_ab_mark_slot_unbootable error!\n"); 162e8e29e8dSJason Zhu avb_ops_user_free(ops); 163e8e29e8dSJason Zhu return CMD_RET_FAILURE; 164e8e29e8dSJason Zhu } 165e8e29e8dSJason Zhu 166cc527546SJason Zhu printf("Mark slot %d unbootable successfully.\n", slot_number); 167e8e29e8dSJason Zhu avb_ops_user_free(ops); 168e8e29e8dSJason Zhu 169e8e29e8dSJason Zhu return CMD_RET_SUCCESS; 170e8e29e8dSJason Zhu } 171e8e29e8dSJason Zhu 172e8e29e8dSJason Zhu int do_avb_ab_mark_slot_successful(cmd_tbl_t *cmdtp, int flag, 173e8e29e8dSJason Zhu int argc, char * const argv[]) 174e8e29e8dSJason Zhu { 175e8e29e8dSJason Zhu AvbOps *ops; 176e8e29e8dSJason Zhu unsigned int slot_number; 177e8e29e8dSJason Zhu 178e8e29e8dSJason Zhu if (argc != 2) 179e8e29e8dSJason Zhu return CMD_RET_USAGE; 180e8e29e8dSJason Zhu 181e8e29e8dSJason Zhu ops = avb_ops_user_new(); 182e8e29e8dSJason Zhu if (ops == NULL) { 183e8e29e8dSJason Zhu printf("avb_ops_user_new() failed!\n"); 184e8e29e8dSJason Zhu return CMD_RET_FAILURE; 185e8e29e8dSJason Zhu } 186e8e29e8dSJason Zhu 187e8e29e8dSJason Zhu slot_number = simple_strtoul(argv[1], NULL, 16); 188e8e29e8dSJason Zhu if (avb_ab_mark_slot_successful(ops->ab_ops, slot_number) != 0) { 189e8e29e8dSJason Zhu printf("do_avb_ab_mark_slot_successful error!\n"); 190e8e29e8dSJason Zhu avb_ops_user_free(ops); 191e8e29e8dSJason Zhu return CMD_RET_FAILURE; 192e8e29e8dSJason Zhu } 193e8e29e8dSJason Zhu 194e8e29e8dSJason Zhu avb_ops_user_free(ops); 195e8e29e8dSJason Zhu 196e8e29e8dSJason Zhu return CMD_RET_SUCCESS; 197e8e29e8dSJason Zhu } 198e8e29e8dSJason Zhu 199*6a1e3c91SJason Zhu int do_avb_read_ab_metadata(cmd_tbl_t *cmdtp, int flag, 200*6a1e3c91SJason Zhu int argc, char * const argv[]) 201*6a1e3c91SJason Zhu { 202*6a1e3c91SJason Zhu AvbOps *ops; 203*6a1e3c91SJason Zhu AvbABData ab_data; 204*6a1e3c91SJason Zhu 205*6a1e3c91SJason Zhu if (argc != 1) 206*6a1e3c91SJason Zhu return CMD_RET_USAGE; 207*6a1e3c91SJason Zhu 208*6a1e3c91SJason Zhu ops = avb_ops_user_new(); 209*6a1e3c91SJason Zhu if (ops == NULL) { 210*6a1e3c91SJason Zhu printf("avb_ops_user_new() failed!\n"); 211*6a1e3c91SJason Zhu return CMD_RET_FAILURE; 212*6a1e3c91SJason Zhu } 213*6a1e3c91SJason Zhu 214*6a1e3c91SJason Zhu if (ops->ab_ops->read_ab_metadata(ops->ab_ops, &ab_data) != 0) { 215*6a1e3c91SJason Zhu printf("do_avb_write_ab_metadata error!\n"); 216*6a1e3c91SJason Zhu avb_ops_user_free(ops); 217*6a1e3c91SJason Zhu return CMD_RET_FAILURE; 218*6a1e3c91SJason Zhu } 219*6a1e3c91SJason Zhu 220*6a1e3c91SJason Zhu printf("Slot A information:\n"); 221*6a1e3c91SJason Zhu printf("slot A: priority = %d, tries_remaining = %d,\ 222*6a1e3c91SJason Zhu successful_boot = %d\n", 223*6a1e3c91SJason Zhu ab_data.slots[0].priority, 224*6a1e3c91SJason Zhu ab_data.slots[0].tries_remaining, 225*6a1e3c91SJason Zhu ab_data.slots[0].successful_boot); 226*6a1e3c91SJason Zhu printf("Slot B information:\n"); 227*6a1e3c91SJason Zhu printf("slot B: priority = %d, tries_remaining = %d,\ 228*6a1e3c91SJason Zhu successful_boot = %d\n", 229*6a1e3c91SJason Zhu ab_data.slots[1].priority, 230*6a1e3c91SJason Zhu ab_data.slots[1].tries_remaining, 231*6a1e3c91SJason Zhu ab_data.slots[1].successful_boot); 232*6a1e3c91SJason Zhu avb_ops_user_free(ops); 233*6a1e3c91SJason Zhu 234*6a1e3c91SJason Zhu return CMD_RET_SUCCESS; 235*6a1e3c91SJason Zhu } 236*6a1e3c91SJason Zhu 237*6a1e3c91SJason Zhu int do_avb_write_ab_metadata(cmd_tbl_t *cmdtp, int flag, 238*6a1e3c91SJason Zhu int argc, char * const argv[]) 239*6a1e3c91SJason Zhu { 240*6a1e3c91SJason Zhu AvbOps *ops; 241*6a1e3c91SJason Zhu AvbABData ab_data; 242*6a1e3c91SJason Zhu 243*6a1e3c91SJason Zhu if (argc != 1) 244*6a1e3c91SJason Zhu return CMD_RET_USAGE; 245*6a1e3c91SJason Zhu 246*6a1e3c91SJason Zhu ops = avb_ops_user_new(); 247*6a1e3c91SJason Zhu if (ops == NULL) { 248*6a1e3c91SJason Zhu printf("avb_ops_user_new() failed!\n"); 249*6a1e3c91SJason Zhu return CMD_RET_FAILURE; 250*6a1e3c91SJason Zhu } 251*6a1e3c91SJason Zhu 252*6a1e3c91SJason Zhu if (ops->ab_ops->write_ab_metadata(ops->ab_ops, &ab_data) != 0) { 253*6a1e3c91SJason Zhu printf("do_avb_write_ab_metadata error!\n"); 254*6a1e3c91SJason Zhu avb_ops_user_free(ops); 255*6a1e3c91SJason Zhu return CMD_RET_FAILURE; 256*6a1e3c91SJason Zhu } 257*6a1e3c91SJason Zhu 258*6a1e3c91SJason Zhu avb_ops_user_free(ops); 259*6a1e3c91SJason Zhu 260*6a1e3c91SJason Zhu return CMD_RET_SUCCESS; 261*6a1e3c91SJason Zhu } 262*6a1e3c91SJason Zhu #endif 263*6a1e3c91SJason Zhu 264*6a1e3c91SJason Zhu #ifdef CONFIG_ANDROID_AVB 265*6a1e3c91SJason Zhu int do_avb_version(cmd_tbl_t *cmdtp, int flag, int argc, 266*6a1e3c91SJason Zhu char * const argv[]) 267*6a1e3c91SJason Zhu { 268*6a1e3c91SJason Zhu const char *avb_version; 269*6a1e3c91SJason Zhu 270*6a1e3c91SJason Zhu if (argc != 1) 271*6a1e3c91SJason Zhu return CMD_RET_USAGE; 272*6a1e3c91SJason Zhu 273*6a1e3c91SJason Zhu avb_version = avb_version_string(); 274*6a1e3c91SJason Zhu printf("Android avb version is %s.\n", avb_version); 275*6a1e3c91SJason Zhu 276*6a1e3c91SJason Zhu return CMD_RET_SUCCESS; 277*6a1e3c91SJason Zhu } 278*6a1e3c91SJason Zhu 279e8e29e8dSJason Zhu int do_avb_read_rollback_index(cmd_tbl_t *cmdtp, int flag, 280e8e29e8dSJason Zhu int argc, char * const argv[]) 281e8e29e8dSJason Zhu { 282e8e29e8dSJason Zhu AvbOps *ops; 283e8e29e8dSJason Zhu uint64_t out_rollback_index; 284e8e29e8dSJason Zhu size_t rollback_index_location; 285e8e29e8dSJason Zhu 286e8e29e8dSJason Zhu if (argc != 2) 287e8e29e8dSJason Zhu return CMD_RET_USAGE; 288e8e29e8dSJason Zhu 289e8e29e8dSJason Zhu ops = avb_ops_user_new(); 290e8e29e8dSJason Zhu if (ops == NULL) { 291e8e29e8dSJason Zhu printf("avb_ops_user_new() failed!\n"); 292e8e29e8dSJason Zhu return CMD_RET_FAILURE; 293e8e29e8dSJason Zhu } 294e8e29e8dSJason Zhu 295e8e29e8dSJason Zhu rollback_index_location = simple_strtoul(argv[1], NULL, 16); 296e8e29e8dSJason Zhu if (ops->read_rollback_index(ops, rollback_index_location, 297e8e29e8dSJason Zhu &out_rollback_index) != 0) { 298e8e29e8dSJason Zhu printf("do_avb_read_rollback_index error!\n"); 299e8e29e8dSJason Zhu avb_ops_user_free(ops); 300e8e29e8dSJason Zhu return CMD_RET_FAILURE; 301e8e29e8dSJason Zhu } 302e8e29e8dSJason Zhu 303cc527546SJason Zhu printf("\nout_rollback_index = %llx\n", out_rollback_index); 304e8e29e8dSJason Zhu avb_ops_user_free(ops); 305e8e29e8dSJason Zhu 306e8e29e8dSJason Zhu return CMD_RET_SUCCESS; 307e8e29e8dSJason Zhu } 308e8e29e8dSJason Zhu 309e8e29e8dSJason Zhu int do_avb_write_rollback_index(cmd_tbl_t *cmdtp, int flag, 310e8e29e8dSJason Zhu int argc, char * const argv[]) 311e8e29e8dSJason Zhu { 312e8e29e8dSJason Zhu AvbOps *ops; 313e8e29e8dSJason Zhu uint64_t out_rollback_index; 314e8e29e8dSJason Zhu size_t rollback_index_location; 315e8e29e8dSJason Zhu 316e8e29e8dSJason Zhu if (argc != 3) 317e8e29e8dSJason Zhu return CMD_RET_USAGE; 318e8e29e8dSJason Zhu 319e8e29e8dSJason Zhu rollback_index_location = simple_strtoul(argv[1], NULL, 16); 320e8e29e8dSJason Zhu out_rollback_index = simple_strtoull(argv[2], NULL, 16); 321e8e29e8dSJason Zhu debug("out_rollback_index = %llx\n", out_rollback_index); 322e8e29e8dSJason Zhu ops = avb_ops_user_new(); 323e8e29e8dSJason Zhu if (ops == NULL) { 324e8e29e8dSJason Zhu printf("avb_ops_user_new() failed!\n"); 325e8e29e8dSJason Zhu return CMD_RET_FAILURE; 326e8e29e8dSJason Zhu } 327e8e29e8dSJason Zhu 328e8e29e8dSJason Zhu if (ops->write_rollback_index(ops, rollback_index_location, 329e8e29e8dSJason Zhu out_rollback_index) != 0) { 330e8e29e8dSJason Zhu printf("do_avb_write_rollback_index error!\n"); 331e8e29e8dSJason Zhu avb_ops_user_free(ops); 332e8e29e8dSJason Zhu return CMD_RET_FAILURE; 333e8e29e8dSJason Zhu } 334e8e29e8dSJason Zhu 335cc527546SJason Zhu printf("\nWrite rollback index successfully.\n"); 336e8e29e8dSJason Zhu avb_ops_user_free(ops); 337e8e29e8dSJason Zhu 338e8e29e8dSJason Zhu return CMD_RET_SUCCESS; 339e8e29e8dSJason Zhu } 340e8e29e8dSJason Zhu 341e8e29e8dSJason Zhu int do_avb_read_is_device_unlocked(cmd_tbl_t *cmdtp, int flag, 342e8e29e8dSJason Zhu int argc, char * const argv[]) 343e8e29e8dSJason Zhu { 344e8e29e8dSJason Zhu AvbOps *ops; 345e8e29e8dSJason Zhu bool out_is_unlocked; 346e8e29e8dSJason Zhu 347e8e29e8dSJason Zhu if (argc != 1) 348e8e29e8dSJason Zhu return CMD_RET_USAGE; 349e8e29e8dSJason Zhu 350e8e29e8dSJason Zhu ops = avb_ops_user_new(); 351e8e29e8dSJason Zhu if (ops == NULL) { 352e8e29e8dSJason Zhu printf("avb_ops_user_new() failed!\n"); 353e8e29e8dSJason Zhu return CMD_RET_FAILURE; 354e8e29e8dSJason Zhu } 355e8e29e8dSJason Zhu 356e8e29e8dSJason Zhu if (ops->read_is_device_unlocked(ops, &out_is_unlocked) != 0) { 357e8e29e8dSJason Zhu printf("do_avb_read_is_device_unlocked error!\n"); 358e8e29e8dSJason Zhu avb_ops_user_free(ops); 359e8e29e8dSJason Zhu return CMD_RET_FAILURE; 360e8e29e8dSJason Zhu } 361e8e29e8dSJason Zhu 362cc527546SJason Zhu printf("\n The device is %s\n", 363cc527546SJason Zhu out_is_unlocked ? "UNLOCKED" : "LOCKED"); 364e8e29e8dSJason Zhu avb_ops_user_free(ops); 365e8e29e8dSJason Zhu 366e8e29e8dSJason Zhu return CMD_RET_SUCCESS; 367e8e29e8dSJason Zhu } 368e8e29e8dSJason Zhu int do_avb_write_is_device_unlocked(cmd_tbl_t *cmdtp, int flag, 369e8e29e8dSJason Zhu int argc, char * const argv[]) 370e8e29e8dSJason Zhu { 371e8e29e8dSJason Zhu AvbOps *ops; 372e8e29e8dSJason Zhu bool out_is_unlocked; 373e8e29e8dSJason Zhu 374e8e29e8dSJason Zhu if (argc != 2) 375e8e29e8dSJason Zhu return CMD_RET_USAGE; 376e8e29e8dSJason Zhu 377e8e29e8dSJason Zhu out_is_unlocked = simple_strtoul(argv[1], NULL, 16); 378e8e29e8dSJason Zhu if ((out_is_unlocked != 0) || (out_is_unlocked != 1)) 379e8e29e8dSJason Zhu printf("enter out_is_unlocked value must is '0' or '1'\n"); 380e8e29e8dSJason Zhu 381e8e29e8dSJason Zhu ops = avb_ops_user_new(); 382e8e29e8dSJason Zhu if (ops == NULL) { 383e8e29e8dSJason Zhu printf("avb_ops_user_new() failed!\n"); 384e8e29e8dSJason Zhu return CMD_RET_FAILURE; 385e8e29e8dSJason Zhu } 386e8e29e8dSJason Zhu 387e8e29e8dSJason Zhu if (ops->write_is_device_unlocked(ops, &out_is_unlocked) != 0) { 388e8e29e8dSJason Zhu printf("do_avb_write_is_device_unlocked error!\n"); 389e8e29e8dSJason Zhu avb_ops_user_free(ops); 390e8e29e8dSJason Zhu return CMD_RET_FAILURE; 391e8e29e8dSJason Zhu } 392e8e29e8dSJason Zhu 393e8e29e8dSJason Zhu debug("out_is_unlocked = %d\n", out_is_unlocked); 394e8e29e8dSJason Zhu avb_ops_user_free(ops); 395e8e29e8dSJason Zhu 396e8e29e8dSJason Zhu return CMD_RET_SUCCESS; 397e8e29e8dSJason Zhu } 398e8e29e8dSJason Zhu 399e8e29e8dSJason Zhu int do_avb_get_size_of_partition(cmd_tbl_t *cmdtp, int flag, 400e8e29e8dSJason Zhu int argc, char * const argv[]) 401e8e29e8dSJason Zhu { 402e8e29e8dSJason Zhu AvbOps *ops; 403e8e29e8dSJason Zhu char *requested_partitions; 404e8e29e8dSJason Zhu uint64_t out_size_in_bytes; 405e8e29e8dSJason Zhu 406e8e29e8dSJason Zhu if (argc != 2) 407e8e29e8dSJason Zhu return CMD_RET_USAGE; 408e8e29e8dSJason Zhu 409e8e29e8dSJason Zhu requested_partitions = argv[1]; 410e8e29e8dSJason Zhu ops = avb_ops_user_new(); 411e8e29e8dSJason Zhu if (ops == NULL) { 412e8e29e8dSJason Zhu printf("avb_ops_user_new() failed!\n"); 413e8e29e8dSJason Zhu return CMD_RET_FAILURE; 414e8e29e8dSJason Zhu } 415e8e29e8dSJason Zhu 416e8e29e8dSJason Zhu if (ops->get_size_of_partition(ops, requested_partitions, 417e8e29e8dSJason Zhu &out_size_in_bytes) != 0) { 418cc527546SJason Zhu printf("Can not get %s partition size!\n", requested_partitions); 419e8e29e8dSJason Zhu avb_ops_user_free(ops); 420e8e29e8dSJason Zhu return CMD_RET_FAILURE; 421e8e29e8dSJason Zhu } 422e8e29e8dSJason Zhu 423cc527546SJason Zhu printf("%s partition size = 0x%llx\n", requested_partitions, 424cc527546SJason Zhu out_size_in_bytes); 425e8e29e8dSJason Zhu avb_ops_user_free(ops); 426e8e29e8dSJason Zhu 427e8e29e8dSJason Zhu return CMD_RET_SUCCESS; 428e8e29e8dSJason Zhu } 429e8e29e8dSJason Zhu 430e8e29e8dSJason Zhu int do_avb_get_get_unique_guid_for_partition(cmd_tbl_t *cmdtp, int flag, 431e8e29e8dSJason Zhu int argc, char * const argv[]) 432e8e29e8dSJason Zhu { 433e8e29e8dSJason Zhu AvbOps *ops; 434e8e29e8dSJason Zhu char *requested_partitions; 435e8e29e8dSJason Zhu size_t guid_buf_size = 37; 436e8e29e8dSJason Zhu char guid_buf[37]; 437e8e29e8dSJason Zhu 438e8e29e8dSJason Zhu if (argc != 2) 439e8e29e8dSJason Zhu return CMD_RET_USAGE; 440e8e29e8dSJason Zhu 441e8e29e8dSJason Zhu requested_partitions = argv[1]; 442e8e29e8dSJason Zhu ops = avb_ops_user_new(); 443e8e29e8dSJason Zhu if (ops == NULL) { 444e8e29e8dSJason Zhu printf("avb_ops_user_new() failed!\n"); 445e8e29e8dSJason Zhu return CMD_RET_FAILURE; 446e8e29e8dSJason Zhu } 447e8e29e8dSJason Zhu 448e8e29e8dSJason Zhu if (ops->get_unique_guid_for_partition(ops, requested_partitions, 449e8e29e8dSJason Zhu guid_buf, guid_buf_size) != 0) { 450cc527546SJason Zhu printf("Can not get %s partition UUID!\n", 451cc527546SJason Zhu requested_partitions); 452e8e29e8dSJason Zhu avb_ops_user_free(ops); 453e8e29e8dSJason Zhu return CMD_RET_FAILURE; 454e8e29e8dSJason Zhu } 455e8e29e8dSJason Zhu 456cc527546SJason Zhu printf("%s partition UUID is %s\n", requested_partitions, guid_buf); 457e8e29e8dSJason Zhu avb_ops_user_free(ops); 458e8e29e8dSJason Zhu 459e8e29e8dSJason Zhu return CMD_RET_SUCCESS; 460e8e29e8dSJason Zhu } 461e8e29e8dSJason Zhu 462e8e29e8dSJason Zhu int do_avb_read(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 463e8e29e8dSJason Zhu { 464e8e29e8dSJason Zhu AvbOps *ops; 465e8e29e8dSJason Zhu char *requested_partitions; 466e8e29e8dSJason Zhu int64_t offset_blk; 467e8e29e8dSJason Zhu size_t blkcnt; 468e8e29e8dSJason Zhu size_t out_num_read; 469e8e29e8dSJason Zhu int i; 470e8e29e8dSJason Zhu char *buffer; 471e8e29e8dSJason Zhu 472e8e29e8dSJason Zhu if (argc != 4) 473e8e29e8dSJason Zhu return CMD_RET_USAGE; 474e8e29e8dSJason Zhu 475e8e29e8dSJason Zhu requested_partitions = argv[1]; 476e8e29e8dSJason Zhu offset_blk = simple_strtoul(argv[2], NULL, 16); 477e8e29e8dSJason Zhu blkcnt = simple_strtoul(argv[3], NULL, 16); 478e8e29e8dSJason Zhu ops = avb_ops_user_new(); 479e8e29e8dSJason Zhu buffer = (char *)malloc(blkcnt * 512); 480e8e29e8dSJason Zhu if (buffer == NULL) 481e8e29e8dSJason Zhu printf("malloc buffer failed!\n"); 482e8e29e8dSJason Zhu 483e8e29e8dSJason Zhu if (ops == NULL) { 484e8e29e8dSJason Zhu printf("avb_ops_user_new() failed!\n"); 485e8e29e8dSJason Zhu return CMD_RET_FAILURE; 486e8e29e8dSJason Zhu } 487e8e29e8dSJason Zhu 488e8e29e8dSJason Zhu if (ops->read_from_partition(ops, requested_partitions, 489e8e29e8dSJason Zhu offset_blk, blkcnt, buffer, 490e8e29e8dSJason Zhu &out_num_read) != 0) { 491e8e29e8dSJason Zhu printf("do avb read error!\n"); 492e8e29e8dSJason Zhu free(buffer); 493e8e29e8dSJason Zhu avb_ops_user_free(ops); 494e8e29e8dSJason Zhu return CMD_RET_FAILURE; 495e8e29e8dSJason Zhu } 496e8e29e8dSJason Zhu 497cc527546SJason Zhu for (i = 0; i < 512 * blkcnt; i++) { 498cc527546SJason Zhu printf("buffer %d = %x", i, buffer[i]); 499cc527546SJason Zhu if ((i + 1) % 4 == 0) 500cc527546SJason Zhu printf("\n"); 501e8e29e8dSJason Zhu } 502e8e29e8dSJason Zhu 503e8e29e8dSJason Zhu free(buffer); 504e8e29e8dSJason Zhu avb_ops_user_free(ops); 505e8e29e8dSJason Zhu 506e8e29e8dSJason Zhu return CMD_RET_SUCCESS; 507e8e29e8dSJason Zhu } 508e8e29e8dSJason Zhu 509d9d5eb74SJason Zhu int do_perm_attr_test(cmd_tbl_t *cmdtp, int flag, 510d9d5eb74SJason Zhu int argc, char * const argv[]) 511d9d5eb74SJason Zhu { 512d9d5eb74SJason Zhu AvbOps *ops; 513d9d5eb74SJason Zhu int i; 514d9d5eb74SJason Zhu uint8_t hash[AVB_SHA256_DIGEST_SIZE]; 515d9d5eb74SJason Zhu 516d9d5eb74SJason Zhu if (argc != 1) 517d9d5eb74SJason Zhu return CMD_RET_USAGE; 518d9d5eb74SJason Zhu 519d9d5eb74SJason Zhu ops = avb_ops_user_new(); 520d9d5eb74SJason Zhu if (ops == NULL) { 521d9d5eb74SJason Zhu printf("avb_ops_user_new() failed!\n"); 522d9d5eb74SJason Zhu return CMD_RET_FAILURE; 523d9d5eb74SJason Zhu } 524d9d5eb74SJason Zhu 525d9d5eb74SJason Zhu if (ops->atx_ops->read_permanent_attributes_hash(ops->atx_ops, hash) != 0) { 526d9d5eb74SJason Zhu printf("read_permanent_attributes_hash error!\n"); 527d9d5eb74SJason Zhu avb_ops_user_free(ops); 528d9d5eb74SJason Zhu return CMD_RET_FAILURE; 529d9d5eb74SJason Zhu } 530d9d5eb74SJason Zhu 531d9d5eb74SJason Zhu for (i = 0; i < AVB_SHA256_DIGEST_SIZE; i++) { 532d9d5eb74SJason Zhu if (i % 4 == 0) 533d9d5eb74SJason Zhu printf("\n"); 534d9d5eb74SJason Zhu printf("0x%x ", hash[i]); 535d9d5eb74SJason Zhu } 536d9d5eb74SJason Zhu 537d9d5eb74SJason Zhu avb_ops_user_free(ops); 538d9d5eb74SJason Zhu 539d9d5eb74SJason Zhu return CMD_RET_SUCCESS; 540d9d5eb74SJason Zhu } 541d9d5eb74SJason Zhu 542e8e29e8dSJason Zhu int do_avb_verify_partition(cmd_tbl_t *cmdtp, int flag, 543e8e29e8dSJason Zhu int argc, char * const argv[]) 544e8e29e8dSJason Zhu { 545e8e29e8dSJason Zhu AvbOps *ops; 546e8e29e8dSJason Zhu const char *requested_partitions[1]; 547e8e29e8dSJason Zhu const char * slot_suffixes[2] = {"_a", "_b"}; 548e8e29e8dSJason Zhu AvbSlotVerifyFlags flags; 549e8e29e8dSJason Zhu AvbSlotVerifyData *slot_data[2] = {NULL, NULL}; 550e8e29e8dSJason Zhu AvbSlotVerifyResult verify_result; 551e8e29e8dSJason Zhu size_t n; 552e8e29e8dSJason Zhu 553e8e29e8dSJason Zhu if (argc != 3) 554e8e29e8dSJason Zhu return CMD_RET_USAGE; 555e8e29e8dSJason Zhu 556e8e29e8dSJason Zhu requested_partitions[0] = argv[1]; 557e8e29e8dSJason Zhu n = simple_strtoul(argv[2], NULL, 16); 558e8e29e8dSJason Zhu ops = avb_ops_user_new(); 559e8e29e8dSJason Zhu flags = AVB_SLOT_VERIFY_FLAGS_NONE; 560e8e29e8dSJason Zhu verify_result = 561e8e29e8dSJason Zhu avb_slot_verify(ops, 562e8e29e8dSJason Zhu requested_partitions, 563e8e29e8dSJason Zhu slot_suffixes[n], 564e8e29e8dSJason Zhu flags, 565e8e29e8dSJason Zhu AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, 566e8e29e8dSJason Zhu &slot_data[n]); 567e8e29e8dSJason Zhu if (verify_result != 0) 568e8e29e8dSJason Zhu return CMD_RET_FAILURE; 569e8e29e8dSJason Zhu 570e8e29e8dSJason Zhu avb_ops_user_free(ops); 571e8e29e8dSJason Zhu 572e8e29e8dSJason Zhu return CMD_RET_SUCCESS; 573e8e29e8dSJason Zhu } 574*6a1e3c91SJason Zhu #endif 575e8e29e8dSJason Zhu 576e8e29e8dSJason Zhu static cmd_tbl_t cmd_avb[] = { 577*6a1e3c91SJason Zhu #ifdef CONFIG_ANDROID_AB 578e8e29e8dSJason Zhu U_BOOT_CMD_MKENT(init, 1, 1, do_avb_init_ab_metadata, "", ""), 579e8e29e8dSJason Zhu U_BOOT_CMD_MKENT(slot_active, 2, 1, 580e8e29e8dSJason Zhu do_avb_ab_mark_slot_active, "", ""), 581e8e29e8dSJason Zhu U_BOOT_CMD_MKENT(slot_unbootable, 2, 1, 582e8e29e8dSJason Zhu do_avb_ab_mark_slot_unbootable, "", ""), 583e8e29e8dSJason Zhu U_BOOT_CMD_MKENT(slot_successful, 2, 1, 584e8e29e8dSJason Zhu do_avb_ab_mark_slot_successful, "", ""), 585*6a1e3c91SJason Zhu U_BOOT_CMD_MKENT(readabmisc, 1, 1, do_avb_read_ab_metadata, "", ""), 586*6a1e3c91SJason Zhu #endif 587*6a1e3c91SJason Zhu #ifdef CONFIG_ANDROID_AVB 588*6a1e3c91SJason Zhu U_BOOT_CMD_MKENT(version, 1, 1, do_avb_version, "", ""), 589e8e29e8dSJason Zhu U_BOOT_CMD_MKENT(read_rollback, 2, 1, 590e8e29e8dSJason Zhu do_avb_read_rollback_index, "", ""), 591e8e29e8dSJason Zhu U_BOOT_CMD_MKENT(write_rollback, 3, 1, 592e8e29e8dSJason Zhu do_avb_write_rollback_index, "", ""), 593e8e29e8dSJason Zhu U_BOOT_CMD_MKENT(read_lock_status, 1, 1, 594e8e29e8dSJason Zhu do_avb_read_is_device_unlocked, "", ""), 595e8e29e8dSJason Zhu U_BOOT_CMD_MKENT(write_lock_status, 2, 1, 596e8e29e8dSJason Zhu do_avb_write_is_device_unlocked, "", ""), 597e8e29e8dSJason Zhu U_BOOT_CMD_MKENT(part_size, 2, 1, 598e8e29e8dSJason Zhu do_avb_get_size_of_partition, "", ""), 599e8e29e8dSJason Zhu U_BOOT_CMD_MKENT(part_guid, 2, 1, 600e8e29e8dSJason Zhu do_avb_get_get_unique_guid_for_partition, "", ""), 601e8e29e8dSJason Zhu U_BOOT_CMD_MKENT(read, 4, 1, do_avb_read, "", ""), 602d9d5eb74SJason Zhu U_BOOT_CMD_MKENT(perm_attr_test, 1, 1, do_perm_attr_test, "", ""), 603e8e29e8dSJason Zhu U_BOOT_CMD_MKENT(verify, 3, 1, do_avb_verify_partition, "", ""), 604*6a1e3c91SJason Zhu #endif 605e8e29e8dSJason Zhu }; 606e8e29e8dSJason Zhu 607e8e29e8dSJason Zhu static int do_boot_avb(cmd_tbl_t *cmdtp, 608e8e29e8dSJason Zhu int flag, 609e8e29e8dSJason Zhu int argc, 610e8e29e8dSJason Zhu char * const argv[]) 611e8e29e8dSJason Zhu { 612e8e29e8dSJason Zhu cmd_tbl_t *cp; 613e8e29e8dSJason Zhu 614e8e29e8dSJason Zhu cp = find_cmd_tbl(argv[1], cmd_avb, ARRAY_SIZE(cmd_avb)); 615e8e29e8dSJason Zhu 616e8e29e8dSJason Zhu argc--; 617e8e29e8dSJason Zhu argv++; 618e8e29e8dSJason Zhu 619e8e29e8dSJason Zhu if (cp == NULL || argc > cp->maxargs) 620e8e29e8dSJason Zhu return CMD_RET_USAGE; 621e8e29e8dSJason Zhu if (flag == CMD_FLAG_REPEAT && !cp->repeatable) 622e8e29e8dSJason Zhu return CMD_RET_SUCCESS; 623e8e29e8dSJason Zhu 624e8e29e8dSJason Zhu return cp->cmd(cmdtp, flag, argc, argv); 625e8e29e8dSJason Zhu } 626e8e29e8dSJason Zhu 627e8e29e8dSJason Zhu U_BOOT_CMD( 628e8e29e8dSJason Zhu bootavb, 29, 1, do_boot_avb, 629e8e29e8dSJason Zhu "Execute the Android avb a/b boot flow.", 630e8e29e8dSJason Zhu "init - initialize the avbabmeta\n" 631e8e29e8dSJason Zhu "bootavb version - display info of bootavb version\n" 632e8e29e8dSJason Zhu "bootavb slot_active cnt\n" 633e8e29e8dSJason Zhu "bootavb slot_unbootable cnt\n" 634e8e29e8dSJason Zhu "bootavb slot_successful cnt\n" 635e8e29e8dSJason Zhu "bootavb read_rollback rollback_index_location\n" 636cc527546SJason Zhu "bootavb write_rollback rollback_index_location rollback_index\n" 637e8e29e8dSJason Zhu "bootavb read_lock_status\n" 638e8e29e8dSJason Zhu "bootavb write_lock_status 0 or 1\n" 639e8e29e8dSJason Zhu "bootavb part_size partitions_name\n" 640e8e29e8dSJason Zhu "bootavb part_guid partitions_name\n" 641e8e29e8dSJason Zhu "bootavb read partition offset_blk cnt\n" 642e8e29e8dSJason Zhu "bootavb readabmisc\n" 643d9d5eb74SJason Zhu "bootavb perm_attr_test\n" 644e8e29e8dSJason Zhu "bootavb verify partition slot_cnt;partion name without '_a' or '_b'\n" 645e8e29e8dSJason Zhu ); 646