137a7bc39SJason Zhu /* 237a7bc39SJason Zhu * Copyright (C) 2017 The Android Open Source Project 337a7bc39SJason Zhu * 437a7bc39SJason Zhu * Permission is hereby granted, free of charge, to any person 537a7bc39SJason Zhu * obtaining a copy of this software and associated documentation 637a7bc39SJason Zhu * files (the "Software"), to deal in the Software without 737a7bc39SJason Zhu * restriction, including without limitation the rights to use, copy, 837a7bc39SJason Zhu * modify, merge, publish, distribute, sublicense, and/or sell copies 937a7bc39SJason Zhu * of the Software, and to permit persons to whom the Software is 1037a7bc39SJason Zhu * furnished to do so, subject to the following conditions: 1137a7bc39SJason Zhu * 1237a7bc39SJason Zhu * The above copyright notice and this permission notice shall be 1337a7bc39SJason Zhu * included in all copies or substantial portions of the Software. 1437a7bc39SJason Zhu * 1537a7bc39SJason Zhu * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 1637a7bc39SJason Zhu * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1737a7bc39SJason Zhu * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 1837a7bc39SJason Zhu * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 1937a7bc39SJason Zhu * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2037a7bc39SJason Zhu * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2137a7bc39SJason Zhu * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 2237a7bc39SJason Zhu * SOFTWARE. 2337a7bc39SJason Zhu */ 2437a7bc39SJason Zhu 2537a7bc39SJason Zhu #include <common.h> 2637a7bc39SJason Zhu #include <image.h> 2737a7bc39SJason Zhu #include <android_image.h> 2837a7bc39SJason Zhu #include <malloc.h> 2937a7bc39SJason Zhu #include <mapmem.h> 3037a7bc39SJason Zhu #include <errno.h> 3137a7bc39SJason Zhu #include <command.h> 3237a7bc39SJason Zhu #include <mmc.h> 3337a7bc39SJason Zhu #include <blk.h> 3437a7bc39SJason Zhu #include <part.h> 3537a7bc39SJason Zhu #include <android_avb/avb_ops_user.h> 3637a7bc39SJason Zhu #include <android_avb/libavb_ab.h> 3737a7bc39SJason Zhu #include <android_avb/avb_atx_validate.h> 3837a7bc39SJason Zhu #include <android_avb/avb_atx_types.h> 3937a7bc39SJason Zhu #include <optee_include/OpteeClientInterface.h> 4037a7bc39SJason Zhu #include <optee_include/tee_api_defines.h> 4137a7bc39SJason Zhu #include <android_avb/avb_vbmeta_image.h> 4237a7bc39SJason Zhu #include <android_avb/avb_atx_validate.h> 43*459bc933SJason Zhu #include <boot_rkimg.h> 4437a7bc39SJason Zhu 4537a7bc39SJason Zhu static void byte_to_block(int64_t *offset, 4637a7bc39SJason Zhu size_t *num_bytes, 4737a7bc39SJason Zhu lbaint_t *offset_blk, 4837a7bc39SJason Zhu lbaint_t *blkcnt) 4937a7bc39SJason Zhu { 5037a7bc39SJason Zhu *offset_blk = (lbaint_t)(*offset / 512); 5137a7bc39SJason Zhu if (*num_bytes % 512 == 0) { 5237a7bc39SJason Zhu if (*offset % 512 == 0) { 5337a7bc39SJason Zhu *blkcnt = (lbaint_t)(*num_bytes / 512); 5437a7bc39SJason Zhu } else { 5537a7bc39SJason Zhu *blkcnt = (lbaint_t)(*num_bytes / 512) + 1; 5637a7bc39SJason Zhu } 5737a7bc39SJason Zhu } else { 5837a7bc39SJason Zhu if (*offset % 512 == 0) { 5937a7bc39SJason Zhu *blkcnt = (lbaint_t)(*num_bytes / 512) + 1; 6037a7bc39SJason Zhu } else { 6137a7bc39SJason Zhu if ((*offset % 512) + (*num_bytes % 512) < 512 || 6237a7bc39SJason Zhu (*offset % 512) + (*num_bytes % 512) == 512) { 6337a7bc39SJason Zhu *blkcnt = (lbaint_t)(*num_bytes / 512) + 1; 6437a7bc39SJason Zhu } else { 6537a7bc39SJason Zhu *blkcnt = (lbaint_t)(*num_bytes / 512) + 2; 6637a7bc39SJason Zhu } 6737a7bc39SJason Zhu } 6837a7bc39SJason Zhu } 6937a7bc39SJason Zhu } 7037a7bc39SJason Zhu 7137a7bc39SJason Zhu static AvbIOResult read_from_partition(AvbOps* ops, 7237a7bc39SJason Zhu const char* partition, 7337a7bc39SJason Zhu int64_t offset, 7437a7bc39SJason Zhu size_t num_bytes, 7537a7bc39SJason Zhu void* buffer, 7637a7bc39SJason Zhu size_t* out_num_read) 7737a7bc39SJason Zhu { 7837a7bc39SJason Zhu struct blk_desc *dev_desc; 7937a7bc39SJason Zhu lbaint_t offset_blk, blkcnt; 8037a7bc39SJason Zhu disk_partition_t part_info; 8137a7bc39SJason Zhu 8237a7bc39SJason Zhu byte_to_block(&offset, &num_bytes, &offset_blk, &blkcnt); 83*459bc933SJason Zhu dev_desc = rockchip_get_bootdev(); 8437a7bc39SJason Zhu if (!dev_desc) { 85*459bc933SJason Zhu printf("%s: Could not find device\n", __func__); 8637a7bc39SJason Zhu return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; 8737a7bc39SJason Zhu } 8837a7bc39SJason Zhu 8937a7bc39SJason Zhu if (part_get_info_by_name(dev_desc, partition, &part_info) < 0) { 9037a7bc39SJason Zhu printf("Could not find \"%s\" partition\n", partition); 9137a7bc39SJason Zhu return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; 9237a7bc39SJason Zhu } 9337a7bc39SJason Zhu 9437a7bc39SJason Zhu if((offset % 512 == 0) && (num_bytes % 512 == 0)) { 9537a7bc39SJason Zhu blk_dread(dev_desc, part_info.start + offset_blk, blkcnt, buffer); 9637a7bc39SJason Zhu *out_num_read = blkcnt * 512; 9737a7bc39SJason Zhu } else { 9837a7bc39SJason Zhu char *buffer_temp; 9937a7bc39SJason Zhu buffer_temp = malloc(512 * blkcnt); 10037a7bc39SJason Zhu if (buffer_temp == NULL) { 10137a7bc39SJason Zhu printf("malloc error!\n"); 10237a7bc39SJason Zhu return AVB_IO_RESULT_ERROR_OOM; 10337a7bc39SJason Zhu } 10437a7bc39SJason Zhu blk_dread(dev_desc, part_info.start + offset_blk, blkcnt, buffer_temp); 10537a7bc39SJason Zhu memcpy(buffer, buffer_temp + (offset % 512), num_bytes); 10637a7bc39SJason Zhu *out_num_read = num_bytes; 10737a7bc39SJason Zhu free(buffer_temp); 10837a7bc39SJason Zhu } 10937a7bc39SJason Zhu 11037a7bc39SJason Zhu return AVB_IO_RESULT_OK; 11137a7bc39SJason Zhu } 11237a7bc39SJason Zhu 11337a7bc39SJason Zhu static AvbIOResult write_to_partition(AvbOps* ops, 11437a7bc39SJason Zhu const char* partition, 11537a7bc39SJason Zhu int64_t offset, 11637a7bc39SJason Zhu size_t num_bytes, 11737a7bc39SJason Zhu const void* buffer) 11837a7bc39SJason Zhu { 11937a7bc39SJason Zhu struct blk_desc *dev_desc; 12037a7bc39SJason Zhu char *buffer_temp; 12137a7bc39SJason Zhu disk_partition_t part_info; 12237a7bc39SJason Zhu lbaint_t offset_blk, blkcnt; 12337a7bc39SJason Zhu 12437a7bc39SJason Zhu byte_to_block(&offset, &num_bytes, &offset_blk, &blkcnt); 12537a7bc39SJason Zhu buffer_temp = malloc(512 * blkcnt); 12637a7bc39SJason Zhu if (buffer_temp == NULL) { 12737a7bc39SJason Zhu printf("malloc error!\n"); 12837a7bc39SJason Zhu return AVB_IO_RESULT_ERROR_OOM; 12937a7bc39SJason Zhu } 13037a7bc39SJason Zhu memset(buffer_temp, 0, 512 * blkcnt); 131*459bc933SJason Zhu dev_desc = rockchip_get_bootdev(); 13237a7bc39SJason Zhu if (!dev_desc) { 133*459bc933SJason Zhu printf("%s: Could not find device\n", __func__); 13437a7bc39SJason Zhu return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; 13537a7bc39SJason Zhu } 13637a7bc39SJason Zhu 13737a7bc39SJason Zhu if (part_get_info_by_name(dev_desc, partition, &part_info) < 0) { 13837a7bc39SJason Zhu printf("Could not find \"%s\" partition\n", partition); 13937a7bc39SJason Zhu return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; 14037a7bc39SJason Zhu } 14137a7bc39SJason Zhu 14237a7bc39SJason Zhu if ((offset % 512 != 0) && (num_bytes % 512) != 0) { 14337a7bc39SJason Zhu blk_dread(dev_desc, part_info.start + offset_blk, blkcnt, buffer_temp); 14437a7bc39SJason Zhu } 14537a7bc39SJason Zhu 14637a7bc39SJason Zhu memcpy(buffer_temp, buffer + (offset % 512), num_bytes); 14737a7bc39SJason Zhu blk_dwrite(dev_desc, part_info.start + offset_blk, blkcnt, buffer); 14837a7bc39SJason Zhu free(buffer_temp); 14937a7bc39SJason Zhu 15037a7bc39SJason Zhu return AVB_IO_RESULT_OK; 15137a7bc39SJason Zhu } 15237a7bc39SJason Zhu 15337a7bc39SJason Zhu static AvbIOResult validate_vbmeta_public_key( 15437a7bc39SJason Zhu AvbOps *ops, 15537a7bc39SJason Zhu const uint8_t *public_key_data, 15637a7bc39SJason Zhu size_t public_key_length, 15737a7bc39SJason Zhu const uint8_t *public_key_metadata, 15837a7bc39SJason Zhu size_t public_key_metadata_length, 15937a7bc39SJason Zhu bool *out_is_trusted) 16037a7bc39SJason Zhu { 16137a7bc39SJason Zhu #ifdef AVB_VBMETA_PUBLIC_KEY_VALIDATE 16237a7bc39SJason Zhu if (out_is_trusted != NULL) { 16337a7bc39SJason Zhu avb_atx_validate_vbmeta_public_key(ops, 16437a7bc39SJason Zhu public_key_data, 16537a7bc39SJason Zhu public_key_length, 16637a7bc39SJason Zhu public_key_metadata, 16737a7bc39SJason Zhu public_key_metadata_length, 16837a7bc39SJason Zhu out_is_trusted); 16937a7bc39SJason Zhu } 17037a7bc39SJason Zhu #else 17137a7bc39SJason Zhu if (out_is_trusted != NULL) { 17237a7bc39SJason Zhu *out_is_trusted = true; 17337a7bc39SJason Zhu } 17437a7bc39SJason Zhu #endif 17537a7bc39SJason Zhu return AVB_IO_RESULT_OK; 17637a7bc39SJason Zhu } 17737a7bc39SJason Zhu 17837a7bc39SJason Zhu static AvbIOResult read_rollback_index(AvbOps *ops, 17937a7bc39SJason Zhu size_t rollback_index_location, 18037a7bc39SJason Zhu uint64_t *out_rollback_index) 18137a7bc39SJason Zhu { 18237a7bc39SJason Zhu if (out_rollback_index != NULL) { 18337a7bc39SJason Zhu #ifdef CONFIG_OPTEE_CLIENT 18437a7bc39SJason Zhu int ret; 18537a7bc39SJason Zhu ret = trusty_read_rollback_index(rollback_index_location, 18637a7bc39SJason Zhu out_rollback_index); 18737a7bc39SJason Zhu if (ret == TEE_ERROR_GENERIC) { 18837a7bc39SJason Zhu *out_rollback_index = 0; 18937a7bc39SJason Zhu ret = trusty_write_rollback_index(rollback_index_location, 19037a7bc39SJason Zhu *out_rollback_index); 19137a7bc39SJason Zhu if (ret != 0) { 19237a7bc39SJason Zhu printf("%s: init rollback index error\n", __FILE__); 19337a7bc39SJason Zhu return AVB_IO_RESULT_ERROR_IO; 19437a7bc39SJason Zhu } 19537a7bc39SJason Zhu ret = trusty_read_rollback_index(rollback_index_location, 19637a7bc39SJason Zhu out_rollback_index); 19737a7bc39SJason Zhu if (ret == 0) 19837a7bc39SJason Zhu return AVB_IO_RESULT_OK; 19937a7bc39SJason Zhu } else if (ret == 0) { 20037a7bc39SJason Zhu return AVB_IO_RESULT_OK; 20137a7bc39SJason Zhu } else { 20237a7bc39SJason Zhu printf("trusty_read_rollback_index ret = %x\n", ret); 20337a7bc39SJason Zhu return AVB_IO_RESULT_ERROR_IO; 20437a7bc39SJason Zhu } 20537a7bc39SJason Zhu #endif 20637a7bc39SJason Zhu } 20737a7bc39SJason Zhu return AVB_IO_RESULT_ERROR_IO; 20837a7bc39SJason Zhu } 20937a7bc39SJason Zhu 21037a7bc39SJason Zhu static AvbIOResult write_rollback_index(AvbOps *ops, 21137a7bc39SJason Zhu size_t rollback_index_location, 21237a7bc39SJason Zhu uint64_t rollback_index) 21337a7bc39SJason Zhu { 21437a7bc39SJason Zhu #ifdef CONFIG_OPTEE_CLIENT 21537a7bc39SJason Zhu if (trusty_write_rollback_index(rollback_index_location, rollback_index)) { 21637a7bc39SJason Zhu printf("%s: Fail to write rollback index\n", __FILE__); 21737a7bc39SJason Zhu return AVB_IO_RESULT_ERROR_IO; 21837a7bc39SJason Zhu } 21937a7bc39SJason Zhu return AVB_IO_RESULT_OK; 22037a7bc39SJason Zhu #endif 22137a7bc39SJason Zhu return AVB_IO_RESULT_ERROR_IO; 22237a7bc39SJason Zhu } 22337a7bc39SJason Zhu 22437a7bc39SJason Zhu static AvbIOResult read_is_device_unlocked(AvbOps *ops, bool *out_is_unlocked) 22537a7bc39SJason Zhu { 22637a7bc39SJason Zhu if (out_is_unlocked != NULL) { 22737a7bc39SJason Zhu #ifdef CONFIG_OPTEE_CLIENT 22837a7bc39SJason Zhu int ret; 22937a7bc39SJason Zhu 23037a7bc39SJason Zhu ret = trusty_read_lock_state((uint8_t *)out_is_unlocked); 23137a7bc39SJason Zhu if (ret == TEE_ERROR_GENERIC) { 23237a7bc39SJason Zhu *out_is_unlocked = 1; 23337a7bc39SJason Zhu if (trusty_write_lock_state(*out_is_unlocked)) { 23437a7bc39SJason Zhu printf("%s: init lock state error\n", __FILE__); 23537a7bc39SJason Zhu return AVB_IO_RESULT_ERROR_IO; 23637a7bc39SJason Zhu } 23737a7bc39SJason Zhu 23837a7bc39SJason Zhu ret = trusty_read_lock_state((uint8_t *)out_is_unlocked); 23937a7bc39SJason Zhu if(ret == 0) 24037a7bc39SJason Zhu return 0; 24137a7bc39SJason Zhu } else if (ret == 0) { 24237a7bc39SJason Zhu return AVB_IO_RESULT_OK; 24337a7bc39SJason Zhu } else { 24437a7bc39SJason Zhu printf("read_is_device_unlocked ret = %x\n", ret); 24537a7bc39SJason Zhu return AVB_IO_RESULT_ERROR_IO; 24637a7bc39SJason Zhu } 24737a7bc39SJason Zhu #endif 24837a7bc39SJason Zhu } 24937a7bc39SJason Zhu return AVB_IO_RESULT_ERROR_IO; 25037a7bc39SJason Zhu } 25137a7bc39SJason Zhu 25237a7bc39SJason Zhu static AvbIOResult write_is_device_unlocked(AvbOps *ops, bool *out_is_unlocked) 25337a7bc39SJason Zhu { 25437a7bc39SJason Zhu if (out_is_unlocked != NULL) { 25537a7bc39SJason Zhu #ifdef CONFIG_OPTEE_CLIENT 25637a7bc39SJason Zhu if (trusty_write_lock_state(*out_is_unlocked)) { 25737a7bc39SJason Zhu printf("%s: Fail to write lock state\n", __FILE__); 25837a7bc39SJason Zhu return AVB_IO_RESULT_ERROR_IO; 25937a7bc39SJason Zhu } 26037a7bc39SJason Zhu return AVB_IO_RESULT_OK; 26137a7bc39SJason Zhu #endif 26237a7bc39SJason Zhu } 26337a7bc39SJason Zhu return AVB_IO_RESULT_ERROR_IO; 26437a7bc39SJason Zhu } 26537a7bc39SJason Zhu 26637a7bc39SJason Zhu static AvbIOResult get_size_of_partition(AvbOps *ops, 26737a7bc39SJason Zhu const char *partition, 26837a7bc39SJason Zhu uint64_t *out_size_in_bytes) 26937a7bc39SJason Zhu { 27037a7bc39SJason Zhu struct blk_desc *dev_desc; 27137a7bc39SJason Zhu disk_partition_t part_info; 27237a7bc39SJason Zhu 273*459bc933SJason Zhu dev_desc = rockchip_get_bootdev(); 27437a7bc39SJason Zhu if (!dev_desc) { 275*459bc933SJason Zhu printf("%s: Could not find device\n", __func__); 27637a7bc39SJason Zhu return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; 27737a7bc39SJason Zhu } 27837a7bc39SJason Zhu 27937a7bc39SJason Zhu if (part_get_info_by_name(dev_desc, partition, &part_info) < 0) { 28037a7bc39SJason Zhu printf("Could not find \"%s\" partition\n", partition); 28137a7bc39SJason Zhu return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; 28237a7bc39SJason Zhu } 28337a7bc39SJason Zhu *out_size_in_bytes = (part_info.size) * 512; 28437a7bc39SJason Zhu return AVB_IO_RESULT_OK; 28537a7bc39SJason Zhu } 28637a7bc39SJason Zhu 28737a7bc39SJason Zhu static AvbIOResult get_unique_guid_for_partition(AvbOps *ops, 28837a7bc39SJason Zhu const char *partition, 28937a7bc39SJason Zhu char *guid_buf, 29037a7bc39SJason Zhu size_t guid_buf_size) 29137a7bc39SJason Zhu { 29237a7bc39SJason Zhu struct blk_desc *dev_desc; 29337a7bc39SJason Zhu disk_partition_t part_info; 294*459bc933SJason Zhu dev_desc = rockchip_get_bootdev(); 29537a7bc39SJason Zhu if (!dev_desc) { 296*459bc933SJason Zhu printf("%s: Could not find device\n", __func__); 29737a7bc39SJason Zhu return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; 29837a7bc39SJason Zhu } 29937a7bc39SJason Zhu 30037a7bc39SJason Zhu if (part_get_info_by_name(dev_desc, partition, &part_info) < 0) { 30137a7bc39SJason Zhu printf("Could not find \"%s\" partition\n", partition); 30237a7bc39SJason Zhu return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; 30337a7bc39SJason Zhu } 30437a7bc39SJason Zhu if (guid_buf != NULL && guid_buf_size > 0) { 30537a7bc39SJason Zhu memcpy(guid_buf, part_info.uuid, guid_buf_size); 30637a7bc39SJason Zhu } 30737a7bc39SJason Zhu return AVB_IO_RESULT_OK; 30837a7bc39SJason Zhu } 30937a7bc39SJason Zhu 31037a7bc39SJason Zhu /* read permanent attributes from rpmb */ 31137a7bc39SJason Zhu AvbIOResult avb_read_perm_attr(AvbAtxOps* atx_ops, 31237a7bc39SJason Zhu AvbAtxPermanentAttributes* attributes) 31337a7bc39SJason Zhu { 31437a7bc39SJason Zhu if (attributes != NULL) { 31537a7bc39SJason Zhu #ifdef CONFIG_OPTEE_CLIENT 31637a7bc39SJason Zhu trusty_read_permanent_attributes((uint8_t *)attributes, 31737a7bc39SJason Zhu sizeof(struct AvbAtxPermanentAttributes)); 31837a7bc39SJason Zhu return AVB_IO_RESULT_OK; 31937a7bc39SJason Zhu #endif 32037a7bc39SJason Zhu } 32137a7bc39SJason Zhu 32237a7bc39SJason Zhu return -1; 32337a7bc39SJason Zhu } 32437a7bc39SJason Zhu 32537a7bc39SJason Zhu /*read permanent attributes hash from efuse */ 32637a7bc39SJason Zhu AvbIOResult avb_read_perm_attr_hash(AvbAtxOps* atx_ops, 32737a7bc39SJason Zhu uint8_t hash[AVB_SHA256_DIGEST_SIZE]) 32837a7bc39SJason Zhu { 32937a7bc39SJason Zhu #ifdef CONFIG_OPTEE_CLIENT 33037a7bc39SJason Zhu if (trusty_read_attribute_hash((uint32_t *)hash, AVB_SHA256_DIGEST_SIZE / 4)) 33137a7bc39SJason Zhu return -1; 33237a7bc39SJason Zhu #else 33337a7bc39SJason Zhu avb_error("Please open the macro!\n"); 33437a7bc39SJason Zhu return -1; 33537a7bc39SJason Zhu #endif 33637a7bc39SJason Zhu return AVB_IO_RESULT_OK; 33737a7bc39SJason Zhu } 33837a7bc39SJason Zhu 33937a7bc39SJason Zhu AvbOps* avb_ops_user_new(void) { 34037a7bc39SJason Zhu AvbOps* ops; 34137a7bc39SJason Zhu 34237a7bc39SJason Zhu ops = calloc(1, sizeof(AvbOps)); 34337a7bc39SJason Zhu if (ops == NULL) { 34437a7bc39SJason Zhu avb_error("Error allocating memory for AvbOps.\n"); 34537a7bc39SJason Zhu goto out; 34637a7bc39SJason Zhu } 34737a7bc39SJason Zhu 34837a7bc39SJason Zhu ops->ab_ops = calloc(1, sizeof(AvbABOps)); 34937a7bc39SJason Zhu if (ops->ab_ops == NULL) { 35037a7bc39SJason Zhu avb_error("Error allocating memory for AvbABOps.\n"); 35137a7bc39SJason Zhu free(ops); 35237a7bc39SJason Zhu goto out; 35337a7bc39SJason Zhu } 35437a7bc39SJason Zhu 35537a7bc39SJason Zhu ops->atx_ops = calloc(1, sizeof(AvbAtxOps)); 35637a7bc39SJason Zhu if (ops->atx_ops == NULL) { 35737a7bc39SJason Zhu avb_error("Error allocating memory for AvbAtxOps.\n"); 35837a7bc39SJason Zhu free(ops->ab_ops); 35937a7bc39SJason Zhu free(ops); 36037a7bc39SJason Zhu goto out; 36137a7bc39SJason Zhu } 36237a7bc39SJason Zhu ops->ab_ops->ops = ops; 36337a7bc39SJason Zhu ops->atx_ops->ops = ops; 36437a7bc39SJason Zhu 36537a7bc39SJason Zhu ops->read_from_partition = read_from_partition; 36637a7bc39SJason Zhu ops->write_to_partition = write_to_partition; 36737a7bc39SJason Zhu ops->validate_vbmeta_public_key = validate_vbmeta_public_key; 36837a7bc39SJason Zhu ops->read_rollback_index = read_rollback_index; 36937a7bc39SJason Zhu ops->write_rollback_index = write_rollback_index; 37037a7bc39SJason Zhu ops->read_is_device_unlocked = read_is_device_unlocked; 37137a7bc39SJason Zhu ops->write_is_device_unlocked = write_is_device_unlocked; 37237a7bc39SJason Zhu ops->get_unique_guid_for_partition = get_unique_guid_for_partition; 37337a7bc39SJason Zhu ops->get_size_of_partition = get_size_of_partition; 37437a7bc39SJason Zhu ops->ab_ops->read_ab_metadata = avb_ab_data_read; 37537a7bc39SJason Zhu ops->ab_ops->write_ab_metadata = avb_ab_data_write; 37637a7bc39SJason Zhu ops->atx_ops->read_permanent_attributes = avb_read_perm_attr; 37737a7bc39SJason Zhu ops->atx_ops->read_permanent_attributes_hash = avb_read_perm_attr_hash; 37837a7bc39SJason Zhu 37937a7bc39SJason Zhu out: 38037a7bc39SJason Zhu return ops; 38137a7bc39SJason Zhu } 38237a7bc39SJason Zhu 38337a7bc39SJason Zhu 38437a7bc39SJason Zhu void avb_ops_user_free(AvbOps* ops) { 38537a7bc39SJason Zhu free(ops->ab_ops); 38637a7bc39SJason Zhu free(ops->atx_ops); 38737a7bc39SJason Zhu free(ops); 38837a7bc39SJason Zhu } 389