blob: 479468b0964a5b58196c81ecbe4e2412224346ea [file] [log] [blame]
/*
* 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;
}