| /* |
| * Copyright (c) 2019 The Fuchsia Authors |
| * |
| * SPDX-License-Identifier: BSD-3-Clause |
| */ |
| |
| #include <asm/arch/bl31_apis.h> |
| #include <asm/arch/efuse.h> |
| #include <common.h> |
| #include <libavb/libavb.h> |
| #include <libavb_atx/libavb_atx.h> |
| #include <u-boot/sha256.h> |
| |
| #ifdef CONFIG_DEV_BUILD |
| #include "avb_dev_attrs/atx_permanent_attrs.h" |
| #elif defined(CONFIG_DOGFOOD_BUILD) |
| #include "avb_dogfood_attrs/atx_permanent_attrs.h" |
| #elif defined(CONFIG_PROD_BUILD) |
| #include "avb_prod_attrs/atx_permanent_attrs.h" |
| #else |
| #error "Unknown build config" |
| #endif |
| |
| #define ROLLBACK_INDEX_BYTES 8 |
| #define MAX_ROLLBACK_INDEX 8 * ROLLBACK_INDEX_BYTES |
| |
| #define AVB_ATX_PIK_VERSION_LOCATION_MAX 63 |
| #define AVB_ATX_PIK_VERSION_LOCATION_MASK \ |
| ((1ULL << AVB_ATX_PIK_VERSION_LOCATION_MAX) - 1) |
| |
| /* Make sure we agree with BL31 on the sizes of the perm attrs and hashes. */ |
| _Static_assert(sizeof(AvbAtxPermanentAttributes) == PERMANENT_ATTRIBUTES_SIZE, |
| "Permanent attribute size mismatch"); |
| _Static_assert(sizeof(avb_atx_permanent_attributes_hash) == |
| PERMANENT_ATTRIBUTES_HASH_SIZE, |
| "Permanent attribute hash size mismatch"); |
| _Static_assert(sizeof(avb_atx_permanent_attributes_hash) == |
| AVB_SHA256_DIGEST_SIZE, |
| "AVB digest size mismatch"); |
| |
| AvbIOResult avb_read_permanent_attributes(AvbAtxOps *atx_ops, |
| AvbAtxPermanentAttributes *attributes) |
| { |
| int result = bl31_get_permanent_attributes( |
| avb_atx_permanent_attributes_hash, attributes); |
| return (result == 0) ? AVB_IO_RESULT_OK : AVB_IO_RESULT_ERROR_IO; |
| } |
| |
| AvbIOResult |
| avb_read_permanent_attributes_hash(AvbAtxOps *atx_ops, |
| uint8_t hash[AVB_SHA256_DIGEST_SIZE]) |
| { |
| memcpy(hash, avb_atx_permanent_attributes_hash, AVB_SHA256_DIGEST_SIZE); |
| return AVB_IO_RESULT_OK; |
| } |
| |
| /* Reads rollback index from user data area of OTP. */ |
| AvbIOResult avb_read_rollback_index(AvbOps *ops, size_t rollback_index_location, |
| uint64_t *out_rollback_index) |
| { |
| #ifdef CONFIG_USE_ROLLBACK_IN_FUSE |
| char buf[ROLLBACK_INDEX_BYTES]; |
| uint64_t *fuse_bits; |
| ssize_t ret; |
| |
| if ((rollback_index_location > |
| AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS) && |
| (rollback_index_location != AVB_ATX_PIK_VERSION_LOCATION) && |
| (rollback_index_location != AVB_ATX_PSK_VERSION_LOCATION)) { |
| return AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION; |
| } |
| |
| loff_t offset = rollback_index_location * ROLLBACK_INDEX_BYTES; |
| |
| ret = efuse_read_usr(buf, ROLLBACK_INDEX_BYTES, &offset); |
| if (ret != ROLLBACK_INDEX_BYTES) { |
| return AVB_SLOT_VERIFY_RESULT_ERROR_IO; |
| } |
| fuse_bits = (uint64_t *)buf; |
| |
| if (rollback_index_location == AVB_ATX_PIK_VERSION_LOCATION) { |
| *fuse_bits &= AVB_ATX_PIK_VERSION_LOCATION_MASK; |
| } |
| |
| *out_rollback_index = __builtin_popcountl(*fuse_bits); |
| #else |
| *out_rollback_index = 0; |
| #endif |
| return AVB_IO_RESULT_OK; |
| } |
| |
| /* Writes rollback index to user data area of OTP. If the rollback_index is |
| * less than the current rollback index, the function does nothing and |
| * returns with no error. |
| */ |
| AvbIOResult avb_write_rollback_index(AvbOps *ops, |
| size_t rollback_index_location, |
| uint64_t rollback_index) |
| { |
| #ifdef CONFIG_USE_ROLLBACK_IN_FUSE |
| uint64_t cur_index; |
| |
| if (rollback_index > MAX_ROLLBACK_INDEX) { |
| return AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE; |
| } |
| // read_rollback_index() performs bounds check on the index location. |
| AvbIOResult ret = avb_read_rollback_index(ops, rollback_index_location, |
| &cur_index); |
| if (ret != AVB_IO_RESULT_OK) { |
| return ret; |
| } |
| if (rollback_index <= cur_index) { |
| return AVB_IO_RESULT_OK; |
| } |
| |
| if ((rollback_index_location == AVB_ATX_PIK_VERSION_LOCATION) && |
| (rollback_index > AVB_ATX_PIK_VERSION_LOCATION_MAX)) { |
| return AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX; |
| } |
| |
| loff_t offset = rollback_index_location * ROLLBACK_INDEX_BYTES; |
| uint64_t fuse_bits = (1 << rollback_index) - 1; |
| ssize_t bytes_written = efuse_write_usr((char *)&fuse_bits, |
| ROLLBACK_INDEX_BYTES, &offset); |
| if (bytes_written != ROLLBACK_INDEX_BYTES) { |
| return AVB_SLOT_VERIFY_RESULT_ERROR_IO; |
| } |
| #endif |
| return AVB_IO_RESULT_OK; |
| } |