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