1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Permission is hereby granted, free of charge, to any person 5 * obtaining a copy of this software and associated documentation 6 * files (the "Software"), to deal in the Software without 7 * restriction, including without limitation the rights to use, copy, 8 * modify, merge, publish, distribute, sublicense, and/or sell copies 9 * of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 */ 24 25 #include <common.h> 26 #include <image.h> 27 #include <android_image.h> 28 #include <malloc.h> 29 #include <mapmem.h> 30 #include <errno.h> 31 #include <command.h> 32 #include <mmc.h> 33 #include <blk.h> 34 #include <part.h> 35 #include <stdio.h> 36 #include <android_avb/avb_ops_user.h> 37 #include <android_avb/libavb_ab.h> 38 #include <android_avb/avb_atx_validate.h> 39 #include <android_avb/avb_atx_types.h> 40 #include <optee_include/OpteeClientInterface.h> 41 #include <optee_include/tee_api_defines.h> 42 #include <android_avb/avb_vbmeta_image.h> 43 #include <android_avb/avb_atx_validate.h> 44 #include <boot_rkimg.h> 45 46 static void byte_to_block(int64_t *offset, 47 size_t *num_bytes, 48 lbaint_t *offset_blk, 49 lbaint_t *blkcnt) 50 { 51 *offset_blk = (lbaint_t)(*offset / 512); 52 if (*num_bytes % 512 == 0) { 53 if (*offset % 512 == 0) 54 *blkcnt = (lbaint_t)(*num_bytes / 512); 55 else 56 *blkcnt = (lbaint_t)(*num_bytes / 512) + 1; 57 } else { 58 if (*offset % 512 == 0) { 59 *blkcnt = (lbaint_t)(*num_bytes / 512) + 1; 60 } else { 61 if ((*offset % 512) + (*num_bytes % 512) < 512 || 62 (*offset % 512) + (*num_bytes % 512) == 512) { 63 *blkcnt = (lbaint_t)(*num_bytes / 512) + 1; 64 } else { 65 *blkcnt = (lbaint_t)(*num_bytes / 512) + 2; 66 } 67 } 68 } 69 } 70 71 static AvbIOResult get_size_of_partition(AvbOps *ops, 72 const char *partition, 73 uint64_t *out_size_in_bytes) 74 { 75 struct blk_desc *dev_desc; 76 disk_partition_t part_info; 77 78 dev_desc = rockchip_get_bootdev(); 79 if (!dev_desc) { 80 printf("%s: Could not find device\n", __func__); 81 return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; 82 } 83 84 if (part_get_info_by_name(dev_desc, partition, &part_info) < 0) 85 return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; 86 87 *out_size_in_bytes = (part_info.size) * 512; 88 return AVB_IO_RESULT_OK; 89 } 90 91 static AvbIOResult read_from_partition(AvbOps *ops, 92 const char *partition, 93 int64_t offset, 94 size_t num_bytes, 95 void *buffer, 96 size_t *out_num_read) 97 { 98 struct blk_desc *dev_desc; 99 lbaint_t offset_blk, blkcnt; 100 disk_partition_t part_info; 101 uint64_t partition_size; 102 103 if (offset < 0) { 104 if (get_size_of_partition(ops, partition, &partition_size)) 105 return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; 106 107 if (-offset > partition_size) 108 return AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION; 109 110 offset = partition_size - (-offset); 111 } 112 113 byte_to_block(&offset, &num_bytes, &offset_blk, &blkcnt); 114 dev_desc = rockchip_get_bootdev(); 115 if (!dev_desc) { 116 printf("%s: Could not find device\n", __func__); 117 return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; 118 } 119 120 if (part_get_info_by_name(dev_desc, partition, &part_info) < 0) { 121 printf("Could not find \"%s\" partition\n", partition); 122 return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; 123 } 124 125 if ((offset % 512 == 0) && (num_bytes % 512 == 0)) { 126 blk_dread(dev_desc, part_info.start + offset_blk, 127 blkcnt, buffer); 128 *out_num_read = blkcnt * 512; 129 } else { 130 char *buffer_temp; 131 132 buffer_temp = malloc(512 * blkcnt); 133 if (!buffer_temp) { 134 printf("malloc error!\n"); 135 return AVB_IO_RESULT_ERROR_OOM; 136 } 137 blk_dread(dev_desc, part_info.start + offset_blk, 138 blkcnt, buffer_temp); 139 memcpy(buffer, buffer_temp + (offset % 512), num_bytes); 140 *out_num_read = num_bytes; 141 free(buffer_temp); 142 } 143 144 return AVB_IO_RESULT_OK; 145 } 146 147 static AvbIOResult write_to_partition(AvbOps *ops, 148 const char *partition, 149 int64_t offset, 150 size_t num_bytes, 151 const void *buffer) 152 { 153 struct blk_desc *dev_desc; 154 char *buffer_temp; 155 disk_partition_t part_info; 156 lbaint_t offset_blk, blkcnt; 157 158 byte_to_block(&offset, &num_bytes, &offset_blk, &blkcnt); 159 buffer_temp = malloc(512 * blkcnt); 160 if (!buffer_temp) { 161 printf("malloc error!\n"); 162 return AVB_IO_RESULT_ERROR_OOM; 163 } 164 memset(buffer_temp, 0, 512 * blkcnt); 165 dev_desc = rockchip_get_bootdev(); 166 if (!dev_desc) { 167 printf("%s: Could not find device\n", __func__); 168 return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; 169 } 170 171 if (part_get_info_by_name(dev_desc, partition, &part_info) < 0) { 172 printf("Could not find \"%s\" partition\n", partition); 173 return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; 174 } 175 176 if ((offset % 512 != 0) && (num_bytes % 512) != 0) 177 blk_dread(dev_desc, part_info.start + offset_blk, 178 blkcnt, buffer_temp); 179 180 memcpy(buffer_temp, buffer + (offset % 512), num_bytes); 181 blk_dwrite(dev_desc, part_info.start + offset_blk, blkcnt, buffer); 182 free(buffer_temp); 183 184 return AVB_IO_RESULT_OK; 185 } 186 187 static AvbIOResult 188 validate_vbmeta_public_key(AvbOps *ops, 189 const uint8_t *public_key_data, 190 size_t public_key_length, 191 const uint8_t *public_key_metadata, 192 size_t public_key_metadata_length, 193 bool *out_is_trusted) 194 { 195 /* remain AVB_VBMETA_PUBLIC_KEY_VALIDATE to compatible legacy code */ 196 #if defined(CONFIG_AVB_VBMETA_PUBLIC_KEY_VALIDATE) || \ 197 defined(AVB_VBMETA_PUBLIC_KEY_VALIDATE) 198 if (out_is_trusted) { 199 avb_atx_validate_vbmeta_public_key(ops, 200 public_key_data, 201 public_key_length, 202 public_key_metadata, 203 public_key_metadata_length, 204 out_is_trusted); 205 } 206 #else 207 if (out_is_trusted) 208 *out_is_trusted = true; 209 #endif 210 return AVB_IO_RESULT_OK; 211 } 212 213 static AvbIOResult read_rollback_index(AvbOps *ops, 214 size_t rollback_index_location, 215 uint64_t *out_rollback_index) 216 { 217 if (out_rollback_index) { 218 #ifdef CONFIG_OPTEE_CLIENT 219 int ret; 220 221 ret = trusty_read_rollback_index(rollback_index_location, 222 out_rollback_index); 223 switch (ret) { 224 case TEE_SUCCESS: 225 ret = AVB_IO_RESULT_OK; 226 break; 227 case TEE_ERROR_GENERIC: 228 case TEE_ERROR_NO_DATA: 229 case TEE_ERROR_ITEM_NOT_FOUND: 230 *out_rollback_index = 0; 231 ret = trusty_write_rollback_index(rollback_index_location, 232 *out_rollback_index); 233 if (ret) { 234 printf("%s: init rollback index error\n", 235 __FILE__); 236 ret = AVB_IO_RESULT_ERROR_IO; 237 } else { 238 ret = 239 trusty_read_rollback_index(rollback_index_location, 240 out_rollback_index); 241 if (ret) 242 ret = AVB_IO_RESULT_ERROR_IO; 243 else 244 ret = AVB_IO_RESULT_OK; 245 } 246 break; 247 default: 248 ret = AVB_IO_RESULT_ERROR_IO; 249 printf("%s: trusty_read_rollback_index failed", 250 __FILE__); 251 } 252 253 return ret; 254 #else 255 *out_rollback_index = 0; 256 257 return AVB_IO_RESULT_OK; 258 #endif 259 } 260 261 return AVB_IO_RESULT_ERROR_IO; 262 } 263 264 static AvbIOResult write_rollback_index(AvbOps *ops, 265 size_t rollback_index_location, 266 uint64_t rollback_index) 267 { 268 #ifdef CONFIG_OPTEE_CLIENT 269 if (trusty_write_rollback_index(rollback_index_location, 270 rollback_index)) { 271 printf("%s: Fail to write rollback index\n", __FILE__); 272 return AVB_IO_RESULT_ERROR_IO; 273 } 274 return AVB_IO_RESULT_OK; 275 #endif 276 return AVB_IO_RESULT_ERROR_IO; 277 } 278 279 static AvbIOResult read_is_device_unlocked(AvbOps *ops, bool *out_is_unlocked) 280 { 281 if (out_is_unlocked) { 282 #ifdef CONFIG_OPTEE_CLIENT 283 uint8_t vboot_flag = 0; 284 int ret; 285 286 ret = trusty_read_lock_state((uint8_t *)out_is_unlocked); 287 switch (ret) { 288 case TEE_SUCCESS: 289 ret = AVB_IO_RESULT_OK; 290 break; 291 case TEE_ERROR_GENERIC: 292 case TEE_ERROR_NO_DATA: 293 case TEE_ERROR_ITEM_NOT_FOUND: 294 if (trusty_read_vbootkey_enable_flag(&vboot_flag)) { 295 printf("Can't read vboot flag\n"); 296 return AVB_IO_RESULT_ERROR_IO; 297 } 298 299 if (vboot_flag) 300 *out_is_unlocked = 0; 301 else 302 *out_is_unlocked = 1; 303 304 if (trusty_write_lock_state(*out_is_unlocked)) { 305 printf("%s: init lock state error\n", __FILE__); 306 ret = AVB_IO_RESULT_ERROR_IO; 307 } else { 308 ret = 309 trusty_read_lock_state((uint8_t *)out_is_unlocked); 310 if (ret == 0) 311 ret = AVB_IO_RESULT_OK; 312 else 313 ret = AVB_IO_RESULT_ERROR_IO; 314 } 315 break; 316 default: 317 ret = AVB_IO_RESULT_ERROR_IO; 318 printf("%s: trusty_read_lock_state failed\n", __FILE__); 319 } 320 return ret; 321 #else 322 *out_is_unlocked = 1; 323 324 return AVB_IO_RESULT_OK; 325 #endif 326 } 327 return AVB_IO_RESULT_ERROR_IO; 328 } 329 330 static AvbIOResult write_is_device_unlocked(AvbOps *ops, bool *out_is_unlocked) 331 { 332 if (out_is_unlocked) { 333 #ifdef CONFIG_OPTEE_CLIENT 334 if (trusty_write_lock_state(*out_is_unlocked)) { 335 printf("%s: Fail to write lock state\n", __FILE__); 336 return AVB_IO_RESULT_ERROR_IO; 337 } 338 return AVB_IO_RESULT_OK; 339 #endif 340 } 341 return AVB_IO_RESULT_ERROR_IO; 342 } 343 344 static AvbIOResult get_unique_guid_for_partition(AvbOps *ops, 345 const char *partition, 346 char *guid_buf, 347 size_t guid_buf_size) 348 { 349 #if CONFIG_IS_ENABLED(PARTITION_UUIDS) 350 struct blk_desc *dev_desc; 351 disk_partition_t part_info; 352 353 dev_desc = rockchip_get_bootdev(); 354 if (!dev_desc) { 355 printf("%s: Could not find device\n", __func__); 356 return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; 357 } 358 359 if (part_get_info_by_name(dev_desc, partition, &part_info) < 0) { 360 printf("Could not find \"%s\" partition\n", partition); 361 return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; 362 } 363 364 if (guid_buf && guid_buf_size > 0) 365 memcpy(guid_buf, part_info.uuid, guid_buf_size); 366 367 return AVB_IO_RESULT_OK; 368 #else 369 printf("WARN: Get partition uuid requires CONFIG_PARTITION_UUIDS enabled\n"); 370 return AVB_IO_RESULT_ERROR_NO_SUCH_VALUE; 371 #endif 372 } 373 374 /* read permanent attributes from rpmb */ 375 AvbIOResult avb_read_perm_attr(AvbAtxOps *atx_ops, 376 AvbAtxPermanentAttributes *attributes) 377 { 378 if (attributes) { 379 #ifdef CONFIG_OPTEE_CLIENT 380 trusty_read_permanent_attributes((uint8_t *)attributes, 381 sizeof(struct AvbAtxPermanentAttributes)); 382 return AVB_IO_RESULT_OK; 383 #endif 384 } 385 386 return -1; 387 } 388 389 /*read permanent attributes hash from efuse */ 390 AvbIOResult avb_read_perm_attr_hash(AvbAtxOps *atx_ops, 391 uint8_t hash[AVB_SHA256_DIGEST_SIZE]) 392 { 393 #ifndef CONFIG_ROCKCHIP_PRELOADER_PUB_KEY 394 #ifdef CONFIG_OPTEE_CLIENT 395 if (trusty_read_attribute_hash((uint32_t *)hash, 396 AVB_SHA256_DIGEST_SIZE / 4)) 397 return -1; 398 #else 399 printf("Please open the macro!\n"); 400 return -1; 401 #endif 402 #endif 403 return AVB_IO_RESULT_OK; 404 } 405 406 static void avb_set_key_version(AvbAtxOps *atx_ops, 407 size_t rollback_index_location, 408 uint64_t key_version) 409 { 410 #ifdef CONFIG_OPTEE_CLIENT 411 uint64_t key_version_temp = 0; 412 413 if (trusty_read_rollback_index(rollback_index_location, &key_version_temp)) 414 printf("%s: Fail to read rollback index\n", __FILE__); 415 if (key_version_temp == key_version) 416 return; 417 if (trusty_write_rollback_index(rollback_index_location, key_version)) 418 printf("%s: Fail to write rollback index\n", __FILE__); 419 #endif 420 } 421 422 AvbIOResult rk_get_random(AvbAtxOps *atx_ops, 423 size_t num_bytes, 424 uint8_t *output) 425 { 426 int i; 427 unsigned int seed; 428 429 seed = (unsigned int)get_timer(0); 430 for (i = 0; i < num_bytes; i++) { 431 srand(seed); 432 output[i] = (uint8_t)(rand()); 433 seed = (unsigned int)(output[i]); 434 } 435 436 return 0; 437 } 438 439 #ifdef CONFIG_ANDROID_BOOT_IMAGE 440 static AvbIOResult get_preloaded_partition(AvbOps* ops, 441 const char* partition, 442 size_t num_bytes, 443 uint8_t** out_pointer, 444 size_t* out_num_bytes_preloaded, 445 int allow_verification_error) 446 { 447 struct preloaded_partition *preload_info = NULL; 448 struct AvbOpsData *data = ops->user_data; 449 struct blk_desc *dev_desc; 450 disk_partition_t part_info; 451 ulong load_addr; 452 AvbIOResult ret; 453 int full_preload = 0; 454 455 dev_desc = rockchip_get_bootdev(); 456 if (!dev_desc) 457 return AVB_IO_RESULT_ERROR_IO; 458 459 if (part_get_info_by_name(dev_desc, partition, &part_info) < 0) { 460 printf("Could not find \"%s\" partition\n", partition); 461 return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; 462 } 463 464 /* Record partition name(either boot or recovery) */ 465 if (!strncmp(partition, ANDROID_PARTITION_BOOT, 4) || 466 !strncmp(partition, ANDROID_PARTITION_RECOVERY, 8)) { 467 data->boot_partition = strdup(partition); 468 #ifdef CONFIG_ANDROID_AB 469 *((char *)data->boot_partition + strlen(partition) - 2) = '\0'; 470 #endif 471 } 472 473 if (!allow_verification_error) { 474 if (!strncmp(partition, ANDROID_PARTITION_BOOT, 4) || 475 !strncmp(partition, ANDROID_PARTITION_RECOVERY, 8)) 476 preload_info = &data->boot; 477 else if (!strncmp(partition, ANDROID_PARTITION_VENDOR_BOOT, 11)) 478 preload_info = &data->vendor_boot; 479 else if (!strncmp(partition, ANDROID_PARTITION_INIT_BOOT, 9)) 480 preload_info = &data->init_boot; 481 else if (!strncmp(partition, ANDROID_PARTITION_RESOURCE, 8)) 482 preload_info = &data->resource; 483 484 if (!preload_info) { 485 printf("Error: unknown full load partition '%s'\n", partition); 486 return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; 487 } 488 489 printf("preloaded(s): %sfull image from '%s' at 0x%08lx - 0x%08lx\n", 490 preload_info->size ? "pre-" : "", partition, 491 (ulong)preload_info->addr, 492 (ulong)preload_info->addr + num_bytes); 493 494 /* If the partition hasn't yet been preloaded, do it now.*/ 495 if (preload_info->size == 0) { 496 ret = ops->read_from_partition(ops, partition, 497 0, num_bytes, 498 preload_info->addr, 499 &preload_info->size); 500 if (ret != AVB_IO_RESULT_OK) 501 return ret; 502 } 503 *out_pointer = preload_info->addr; 504 *out_num_bytes_preloaded = preload_info->size; 505 ret = AVB_IO_RESULT_OK; 506 } else { 507 if (!strncmp(partition, ANDROID_PARTITION_INIT_BOOT, 9) || 508 !strncmp(partition, ANDROID_PARTITION_VENDOR_BOOT, 11) || 509 !strncmp(partition, ANDROID_PARTITION_BOOT, 4) || 510 !strncmp(partition, ANDROID_PARTITION_RECOVERY, 8) || 511 !strncmp(partition, ANDROID_PARTITION_RESOURCE, 8)) { 512 /* If already full preloaded, just use it */ 513 if (!strncmp(partition, ANDROID_PARTITION_BOOT, 4) || 514 !strncmp(partition, ANDROID_PARTITION_RECOVERY, 8)) { 515 preload_info = &data->boot; 516 if (preload_info->size) { 517 *out_pointer = preload_info->addr; 518 *out_num_bytes_preloaded = num_bytes; 519 full_preload = 1; 520 } 521 } 522 printf("preloaded: %s image from '%s\n", 523 full_preload ? "pre-full" : "distribute", partition); 524 } else { 525 printf("Error: unknown preloaded partition '%s'\n", partition); 526 return AVB_IO_RESULT_ERROR_OOM; 527 } 528 529 /* 530 * Already preloaded during boot/recovery loading, 531 * here we just return a dummy buffer. 532 */ 533 if (!strncmp(partition, ANDROID_PARTITION_INIT_BOOT, 9) || 534 !strncmp(partition, ANDROID_PARTITION_VENDOR_BOOT, 11) || 535 !strncmp(partition, ANDROID_PARTITION_RESOURCE, 8)) { 536 *out_pointer = (u8 *)avb_malloc(ARCH_DMA_MINALIGN); 537 *out_num_bytes_preloaded = num_bytes; /* return what it expects */ 538 return AVB_IO_RESULT_OK; 539 } 540 541 /* If already full preloaded, there is nothing to do and just return */ 542 if (full_preload) 543 return AVB_IO_RESULT_OK; 544 545 /* 546 * only boot/recovery partition can reach here 547 * and init/vendor_boot are loaded at this round. 548 */ 549 load_addr = env_get_ulong("kernel_addr_r", 16, 0); 550 if (!load_addr) 551 return AVB_IO_RESULT_ERROR_NO_SUCH_VALUE; 552 553 ret = android_image_load_by_partname(dev_desc, partition, &load_addr); 554 if (!ret) { 555 *out_pointer = (u8 *)load_addr; 556 *out_num_bytes_preloaded = num_bytes; /* return what it expects */ 557 ret = AVB_IO_RESULT_OK; 558 } else { 559 ret = AVB_IO_RESULT_ERROR_IO; 560 } 561 } 562 563 return ret; 564 } 565 #endif 566 567 AvbIOResult validate_public_key_for_partition(AvbOps *ops, 568 const char *partition, 569 const uint8_t *public_key_data, 570 size_t public_key_length, 571 const uint8_t *public_key_metadata, 572 size_t public_key_metadata_length, 573 bool *out_is_trusted, 574 uint32_t *out_rollback_index_location) 575 { 576 /* remain AVB_VBMETA_PUBLIC_KEY_VALIDATE to compatible legacy code */ 577 #if defined(CONFIG_AVB_VBMETA_PUBLIC_KEY_VALIDATE) || \ 578 defined(AVB_VBMETA_PUBLIC_KEY_VALIDATE) 579 if (out_is_trusted) { 580 avb_atx_validate_vbmeta_public_key(ops, 581 public_key_data, 582 public_key_length, 583 public_key_metadata, 584 public_key_metadata_length, 585 out_is_trusted); 586 } 587 #else 588 if (out_is_trusted) 589 *out_is_trusted = true; 590 #endif 591 *out_rollback_index_location = 0; 592 return AVB_IO_RESULT_OK; 593 } 594 595 AvbOps *avb_ops_user_new(void) 596 { 597 AvbOps *ops = NULL; 598 struct AvbOpsData *ops_data = NULL; 599 600 ops = calloc(1, sizeof(AvbOps)); 601 if (!ops) { 602 printf("Error allocating memory for AvbOps.\n"); 603 goto out; 604 } 605 ops->ab_ops = calloc(1, sizeof(AvbABOps)); 606 if (!ops->ab_ops) { 607 printf("Error allocating memory for AvbABOps.\n"); 608 free(ops); 609 goto out; 610 } 611 612 ops->atx_ops = calloc(1, sizeof(AvbAtxOps)); 613 if (!ops->atx_ops) { 614 printf("Error allocating memory for AvbAtxOps.\n"); 615 free(ops->ab_ops); 616 free(ops); 617 goto out; 618 } 619 620 ops_data = calloc(1, sizeof(struct AvbOpsData)); 621 if (!ops_data) { 622 printf("Error allocating memory for AvbOpsData.\n"); 623 free(ops->atx_ops); 624 free(ops->ab_ops); 625 free(ops); 626 goto out; 627 } 628 629 ops->ab_ops->ops = ops; 630 ops->atx_ops->ops = ops; 631 ops_data->ops = ops; 632 ops->user_data = ops_data; 633 634 ops->read_from_partition = read_from_partition; 635 ops->write_to_partition = write_to_partition; 636 ops->validate_vbmeta_public_key = validate_vbmeta_public_key; 637 ops->read_rollback_index = read_rollback_index; 638 ops->write_rollback_index = write_rollback_index; 639 ops->read_is_device_unlocked = read_is_device_unlocked; 640 ops->write_is_device_unlocked = write_is_device_unlocked; 641 ops->get_unique_guid_for_partition = get_unique_guid_for_partition; 642 ops->get_size_of_partition = get_size_of_partition; 643 #ifdef CONFIG_ANDROID_BOOT_IMAGE 644 ops->get_preloaded_partition = get_preloaded_partition; 645 #endif 646 ops->validate_public_key_for_partition = validate_public_key_for_partition; 647 ops->ab_ops->read_ab_metadata = avb_ab_data_read; 648 ops->ab_ops->write_ab_metadata = avb_ab_data_write; 649 ops->atx_ops->read_permanent_attributes = avb_read_perm_attr; 650 ops->atx_ops->read_permanent_attributes_hash = avb_read_perm_attr_hash; 651 ops->atx_ops->set_key_version = avb_set_key_version; 652 ops->atx_ops->get_random = rk_get_random; 653 654 return ops; 655 out: 656 return NULL; 657 } 658 659 void avb_ops_user_free(AvbOps *ops) 660 { 661 free(ops->user_data); 662 free(ops->ab_ops); 663 free(ops->atx_ops); 664 free(ops); 665 } 666