--- /dev/null
+/*
+ * (C) Copyright 2018, Linaro Limited
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <avb_verify.h>
+#include <fastboot.h>
+#include <image.h>
+#include <malloc.h>
+#include <part.h>
+
+const unsigned char avb_root_pub[1032] = {
+ 0x0, 0x0, 0x10, 0x0, 0x55, 0xd9, 0x4, 0xad, 0xd8, 0x4,
+ 0xaf, 0xe3, 0xd3, 0x84, 0x6c, 0x7e, 0xd, 0x89, 0x3d, 0xc2,
+ 0x8c, 0xd3, 0x12, 0x55, 0xe9, 0x62, 0xc9, 0xf1, 0xf, 0x5e,
+ 0xcc, 0x16, 0x72, 0xab, 0x44, 0x7c, 0x2c, 0x65, 0x4a, 0x94,
+ 0xb5, 0x16, 0x2b, 0x0, 0xbb, 0x6, 0xef, 0x13, 0x7, 0x53,
+ 0x4c, 0xf9, 0x64, 0xb9, 0x28, 0x7a, 0x1b, 0x84, 0x98, 0x88,
+ 0xd8, 0x67, 0xa4, 0x23, 0xf9, 0xa7, 0x4b, 0xdc, 0x4a, 0xf,
+ 0xf7, 0x3a, 0x18, 0xae, 0x54, 0xa8, 0x15, 0xfe, 0xb0, 0xad,
+ 0xac, 0x35, 0xda, 0x3b, 0xad, 0x27, 0xbc, 0xaf, 0xe8, 0xd3,
+ 0x2f, 0x37, 0x34, 0xd6, 0x51, 0x2b, 0x6c, 0x5a, 0x27, 0xd7,
+ 0x96, 0x6, 0xaf, 0x6b, 0xb8, 0x80, 0xca, 0xfa, 0x30, 0xb4,
+ 0xb1, 0x85, 0xb3, 0x4d, 0xaa, 0xaa, 0xc3, 0x16, 0x34, 0x1a,
+ 0xb8, 0xe7, 0xc7, 0xfa, 0xf9, 0x9, 0x77, 0xab, 0x97, 0x93,
+ 0xeb, 0x44, 0xae, 0xcf, 0x20, 0xbc, 0xf0, 0x80, 0x11, 0xdb,
+ 0x23, 0xc, 0x47, 0x71, 0xb9, 0x6d, 0xd6, 0x7b, 0x60, 0x47,
+ 0x87, 0x16, 0x56, 0x93, 0xb7, 0xc2, 0x2a, 0x9a, 0xb0, 0x4c,
+ 0x1, 0xc, 0x30, 0xd8, 0x93, 0x87, 0xf0, 0xed, 0x6e, 0x8b,
+ 0xbe, 0x30, 0x5b, 0xf6, 0xa6, 0xaf, 0xdd, 0x80, 0x7c, 0x45,
+ 0x5e, 0x8f, 0x91, 0x93, 0x5e, 0x44, 0xfe, 0xb8, 0x82, 0x7,
+ 0xee, 0x79, 0xca, 0xbf, 0x31, 0x73, 0x62, 0x58, 0xe3, 0xcd,
+ 0xc4, 0xbc, 0xc2, 0x11, 0x1d, 0xa1, 0x4a, 0xbf, 0xfe, 0x27,
+ 0x7d, 0xa1, 0xf6, 0x35, 0xa3, 0x5e, 0xca, 0xdc, 0x57, 0x2f,
+ 0x3e, 0xf0, 0xc9, 0x5d, 0x86, 0x6a, 0xf8, 0xaf, 0x66, 0xa7,
+ 0xed, 0xcd, 0xb8, 0xed, 0xa1, 0x5f, 0xba, 0x9b, 0x85, 0x1a,
+ 0xd5, 0x9, 0xae, 0x94, 0x4e, 0x3b, 0xcf, 0xcb, 0x5c, 0xc9,
+ 0x79, 0x80, 0xf7, 0xcc, 0xa6, 0x4a, 0xa8, 0x6a, 0xd8, 0xd3,
+ 0x31, 0x11, 0xf9, 0xf6, 0x2, 0x63, 0x2a, 0x1a, 0x2d, 0xd1,
+ 0x1a, 0x66, 0x1b, 0x16, 0x41, 0xbd, 0xbd, 0xf7, 0x4d, 0xc0,
+ 0x4a, 0xe5, 0x27, 0x49, 0x5f, 0x7f, 0x58, 0xe3, 0x27, 0x2d,
+ 0xe5, 0xc9, 0x66, 0xe, 0x52, 0x38, 0x16, 0x38, 0xfb, 0x16,
+ 0xeb, 0x53, 0x3f, 0xe6, 0xfd, 0xe9, 0xa2, 0x5e, 0x25, 0x59,
+ 0xd8, 0x79, 0x45, 0xff, 0x3, 0x4c, 0x26, 0xa2, 0x0, 0x5a,
+ 0x8e, 0xc2, 0x51, 0xa1, 0x15, 0xf9, 0x7b, 0xf4, 0x5c, 0x81,
+ 0x9b, 0x18, 0x47, 0x35, 0xd8, 0x2d, 0x5, 0xe9, 0xad, 0xf,
+ 0x35, 0x74, 0x15, 0xa3, 0x8e, 0x8b, 0xcc, 0x27, 0xda, 0x7c,
+ 0x5d, 0xe4, 0xfa, 0x4, 0xd3, 0x5, 0xb, 0xba, 0x3a, 0xb2,
+ 0x49, 0x45, 0x2f, 0x47, 0xc7, 0xd, 0x41, 0x3f, 0x97, 0x80,
+ 0x4d, 0x3f, 0xc1, 0xb5, 0xbb, 0x70, 0x5f, 0xa7, 0x37, 0xaf,
+ 0x48, 0x22, 0x12, 0x45, 0x2e, 0xf5, 0xf, 0x87, 0x92, 0xe2,
+ 0x84, 0x1, 0xf9, 0x12, 0xf, 0x14, 0x15, 0x24, 0xce, 0x89,
+ 0x99, 0xee, 0xb9, 0xc4, 0x17, 0x70, 0x70, 0x15, 0xea, 0xbe,
+ 0xc6, 0x6c, 0x1f, 0x62, 0xb3, 0xf4, 0x2d, 0x16, 0x87, 0xfb,
+ 0x56, 0x1e, 0x45, 0xab, 0xae, 0x32, 0xe4, 0x5e, 0x91, 0xed,
+ 0x53, 0x66, 0x5e, 0xbd, 0xed, 0xad, 0xe6, 0x12, 0x39, 0xd,
+ 0x83, 0xc9, 0xe8, 0x6b, 0x6c, 0x2d, 0xa5, 0xee, 0xc4, 0x5a,
+ 0x66, 0xae, 0x8c, 0x97, 0xd7, 0xd, 0x6c, 0x49, 0xc7, 0xf5,
+ 0xc4, 0x92, 0x31, 0x8b, 0x9, 0xee, 0x33, 0xda, 0xa9, 0x37,
+ 0xb6, 0x49, 0x18, 0xf8, 0xe, 0x60, 0x45, 0xc8, 0x33, 0x91,
+ 0xef, 0x20, 0x57, 0x10, 0xbe, 0x78, 0x2d, 0x83, 0x26, 0xd6,
+ 0xca, 0x61, 0xf9, 0x2f, 0xe0, 0xbf, 0x5, 0x30, 0x52, 0x5a,
+ 0x12, 0x1c, 0x0, 0xa7, 0x5d, 0xcc, 0x7c, 0x2e, 0xc5, 0x95,
+ 0x8b, 0xa3, 0x3b, 0xf0, 0x43, 0x2e, 0x5e, 0xdd, 0x0, 0xdb,
+ 0xd, 0xb3, 0x37, 0x99, 0xa9, 0xcd, 0x9c, 0xb7, 0x43, 0xf7,
+ 0x35, 0x44, 0x21, 0xc2, 0x82, 0x71, 0xab, 0x8d, 0xaa, 0xb4,
+ 0x41, 0x11, 0xec, 0x1e, 0x8d, 0xfc, 0x14, 0x82, 0x92, 0x4e,
+ 0x83, 0x6a, 0xa, 0x6b, 0x35, 0x5e, 0x5d, 0xe9, 0x5c, 0xcc,
+ 0x8c, 0xde, 0x39, 0xd1, 0x4a, 0x5b, 0x5f, 0x63, 0xa9, 0x64,
+ 0xe0, 0xa, 0xcb, 0xb, 0xb8, 0x5a, 0x7c, 0xc3, 0xb, 0xe6,
+ 0xbe, 0xfe, 0x8b, 0xf, 0x7d, 0x34, 0x8e, 0x2, 0x66, 0x74,
+ 0x1, 0x6c, 0xca, 0x76, 0xac, 0x7c, 0x67, 0x8, 0x2f, 0x3f,
+ 0x1a, 0xa6, 0x2c, 0x60, 0xb3, 0xff, 0xda, 0x8d, 0xb8, 0x12,
+ 0xc, 0x0, 0x7f, 0xcc, 0x50, 0xa1, 0x5c, 0x64, 0xa1, 0xe2,
+ 0x5f, 0x32, 0x65, 0xc9, 0x9c, 0xbe, 0xd6, 0xa, 0x13, 0x87,
+ 0x3c, 0x2a, 0x45, 0x47, 0xc, 0xca, 0x42, 0x82, 0xfa, 0x89,
+ 0x65, 0xe7, 0x89, 0xb4, 0x8f, 0xf7, 0x1e, 0xe6, 0x23, 0xa5,
+ 0xd0, 0x59, 0x37, 0x79, 0x92, 0xd7, 0xce, 0x3d, 0xfd, 0xe3,
+ 0xa1, 0xb, 0xcf, 0x6c, 0x85, 0xa0, 0x65, 0xf3, 0x5c, 0xc6,
+ 0x4a, 0x63, 0x5f, 0x6e, 0x3a, 0x3a, 0x2a, 0x8b, 0x6a, 0xb6,
+ 0x2f, 0xbb, 0xf8, 0xb2, 0x4b, 0x62, 0xbc, 0x1a, 0x91, 0x25,
+ 0x66, 0xe3, 0x69, 0xca, 0x60, 0x49, 0xb, 0xf6, 0x8a, 0xbe,
+ 0x3e, 0x76, 0x53, 0xc2, 0x7a, 0xa8, 0x4, 0x17, 0x75, 0xf1,
+ 0xf3, 0x3, 0x62, 0x1b, 0x85, 0xb2, 0xb0, 0xef, 0x80, 0x15,
+ 0xb6, 0xd4, 0x4e, 0xdf, 0x71, 0xac, 0xdb, 0x2a, 0x4, 0xd4,
+ 0xb4, 0x21, 0xba, 0x65, 0x56, 0x57, 0xe8, 0xfa, 0x84, 0xa2,
+ 0x7d, 0x13, 0xe, 0xaf, 0xd7, 0x9a, 0x58, 0x2a, 0xa3, 0x81,
+ 0x84, 0x8d, 0x9, 0xa0, 0x6a, 0xc1, 0xbb, 0xd9, 0xf5, 0x86,
+ 0xac, 0xbd, 0x75, 0x61, 0x9, 0xe6, 0x8c, 0x3d, 0x77, 0xb2,
+ 0xed, 0x30, 0x20, 0xe4, 0x0, 0x1d, 0x97, 0xe8, 0xbf, 0xc7,
+ 0x0, 0x1b, 0x21, 0xb1, 0x16, 0xe7, 0x41, 0x67, 0x2e, 0xec,
+ 0x38, 0xbc, 0xe5, 0x1b, 0xb4, 0x6, 0x23, 0x31, 0x71, 0x1c,
+ 0x49, 0xcd, 0x76, 0x4a, 0x76, 0x36, 0x8d, 0xa3, 0x89, 0x8b,
+ 0x4a, 0x7a, 0xf4, 0x87, 0xc8, 0x15, 0xf, 0x37, 0x39, 0xf6,
+ 0x6d, 0x80, 0x19, 0xef, 0x5c, 0xa8, 0x66, 0xce, 0x1b, 0x16,
+ 0x79, 0x21, 0xdf, 0xd7, 0x31, 0x30, 0xc4, 0x21, 0xdd, 0x34,
+ 0x5b, 0xd2, 0x1a, 0x2b, 0x3e, 0x5d, 0xf7, 0xea, 0xca, 0x5,
+ 0x8e, 0xb7, 0xcb, 0x49, 0x2e, 0xa0, 0xe3, 0xf4, 0xa7, 0x48,
+ 0x19, 0x10, 0x9c, 0x4, 0xa7, 0xf4, 0x28, 0x74, 0xc8, 0x6f,
+ 0x63, 0x20, 0x2b, 0x46, 0x24, 0x26, 0x19, 0x1d, 0xd1, 0x2c,
+ 0x31, 0x6d, 0x5a, 0x29, 0xa2, 0x6, 0xa6, 0xb2, 0x41, 0xcc,
+ 0xa, 0x27, 0x96, 0x9, 0x96, 0xac, 0x47, 0x65, 0x78, 0x68,
+ 0x51, 0x98, 0xd6, 0xd8, 0xa6, 0x2d, 0xa0, 0xcf, 0xec, 0xe2,
+ 0x74, 0xf2, 0x82, 0xe3, 0x97, 0xd9, 0x7e, 0xd4, 0xf8, 0xb,
+ 0x70, 0x43, 0x3d, 0xb1, 0x7b, 0x97, 0x80, 0xd6, 0xcb, 0xd7,
+ 0x19, 0xbc, 0x63, 0xb, 0xfd, 0x4d, 0x88, 0xfe, 0x67, 0xac,
+ 0xb8, 0xcc, 0x50, 0xb7, 0x68, 0xb3, 0x5b, 0xd6, 0x1e, 0x25,
+ 0xfc, 0x5f, 0x3c, 0x8d, 0xb1, 0x33, 0x7c, 0xb3, 0x49, 0x1,
+ 0x3f, 0x71, 0x55, 0xe, 0x51, 0xba, 0x61, 0x26, 0xfa, 0xea,
+ 0xe5, 0xb5, 0xe8, 0xaa, 0xcf, 0xcd, 0x96, 0x9f, 0xd6, 0xc1,
+ 0x5f, 0x53, 0x91, 0xad, 0x5, 0xde, 0x20, 0xe7, 0x51, 0xda,
+ 0x5b, 0x95, 0x67, 0xed, 0xf4, 0xee, 0x42, 0x65, 0x70, 0x13,
+ 0xb, 0x70, 0x14, 0x1c, 0xc9, 0xe0, 0x19, 0xca, 0x5f, 0xf5,
+ 0x1d, 0x70, 0x4b, 0x6c, 0x6, 0x74, 0xec, 0xb5, 0x2e, 0x77,
+ 0xe1, 0x74, 0xa1, 0xa3, 0x99, 0xa0, 0x85, 0x9e, 0xf1, 0xac,
+ 0xd8, 0x7e,
+};
+
+/**
+ * ============================================================================
+ * IO(mmc) auxiliary functions
+ * ============================================================================
+ */
+static unsigned long mmc_read_and_flush(struct mmc_part *part,
+ lbaint_t start,
+ lbaint_t sectors,
+ void *buffer)
+{
+ unsigned long blks;
+ void *tmp_buf;
+ size_t buf_size;
+ bool unaligned = is_buf_unaligned(buffer);
+
+ if (start < part->info.start) {
+ printf("%s: partition start out of bounds\n", __func__);
+ return 0;
+ }
+ if ((start + sectors) > (part->info.start + part->info.size)) {
+ sectors = part->info.start + part->info.size - start;
+ printf("%s: read sector aligned to partition bounds (%ld)\n",
+ __func__, sectors);
+ }
+
+ /*
+ * Reading fails on unaligned buffers, so we have to
+ * use aligned temporary buffer and then copy to destination
+ */
+
+ if (unaligned) {
+ printf("Handling unaligned read buffer..\n");
+ tmp_buf = get_sector_buf();
+ buf_size = get_sector_buf_size();
+ if (sectors > buf_size / part->info.blksz)
+ sectors = buf_size / part->info.blksz;
+ } else {
+ tmp_buf = buffer;
+ }
+
+ blks = part->mmc->block_dev.block_read(part->mmc_blk,
+ start, sectors, tmp_buf);
+ /* flush cache after read */
+ flush_cache((ulong)tmp_buf, sectors * part->info.blksz);
+
+ if (unaligned)
+ memcpy(buffer, tmp_buf, sectors * part->info.blksz);
+
+ return blks;
+}
+
+static unsigned long mmc_write(struct mmc_part *part, lbaint_t start,
+ lbaint_t sectors, void *buffer)
+{
+ void *tmp_buf;
+ size_t buf_size;
+ bool unaligned = is_buf_unaligned(buffer);
+
+ if (start < part->info.start) {
+ printf("%s: partition start out of bounds\n", __func__);
+ return 0;
+ }
+ if ((start + sectors) > (part->info.start + part->info.size)) {
+ sectors = part->info.start + part->info.size - start;
+ printf("%s: sector aligned to partition bounds (%ld)\n",
+ __func__, sectors);
+ }
+ if (unaligned) {
+ tmp_buf = get_sector_buf();
+ buf_size = get_sector_buf_size();
+ printf("Handling unaligned wrire buffer..\n");
+ if (sectors > buf_size / part->info.blksz)
+ sectors = buf_size / part->info.blksz;
+
+ memcpy(tmp_buf, buffer, sectors * part->info.blksz);
+ } else {
+ tmp_buf = buffer;
+ }
+
+ return part->mmc->block_dev.block_write(part->mmc_blk,
+ start, sectors, tmp_buf);
+}
+
+static struct mmc_part *get_partition(AvbOps *ops, const char *partition)
+{
+ int ret;
+ u8 dev_num;
+ int part_num = 0;
+ struct mmc_part *part;
+ struct blk_desc *mmc_blk;
+
+ part = malloc(sizeof(struct mmc_part));
+ if (!part)
+ return NULL;
+
+ dev_num = get_boot_device(ops);
+ part->mmc = find_mmc_device(dev_num);
+ if (!part->mmc) {
+ printf("No MMC device at slot %x\n", dev_num);
+ return NULL;
+ }
+
+ if (mmc_init(part->mmc)) {
+ printf("MMC initialization failed\n");
+ return NULL;
+ }
+
+ ret = mmc_switch_part(part->mmc, part_num);
+ if (ret)
+ return NULL;
+
+ mmc_blk = mmc_get_blk_desc(part->mmc);
+ if (!mmc_blk) {
+ printf("Error - failed to obtain block descriptor\n");
+ return NULL;
+ }
+
+ ret = part_get_info_by_name(mmc_blk, partition, &part->info);
+ if (!ret) {
+ printf("Can't find partition '%s'\n", partition);
+ return NULL;
+ }
+
+ part->dev_num = dev_num;
+ part->mmc_blk = mmc_blk;
+
+ return part;
+}
+
+static AvbIOResult mmc_byte_io(AvbOps *ops,
+ const char *partition,
+ s64 offset,
+ size_t num_bytes,
+ void *buffer,
+ size_t *out_num_read,
+ enum mmc_io_type io_type)
+{
+ ulong ret;
+ struct mmc_part *part;
+ u64 start_offset, start_sector, sectors, residue;
+ u8 *tmp_buf;
+ size_t io_cnt = 0;
+
+ if (!partition || !buffer || io_type > IO_WRITE)
+ return AVB_IO_RESULT_ERROR_IO;
+
+ part = get_partition(ops, partition);
+ if (!part)
+ return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
+
+ start_offset = calc_offset(part, offset);
+ while (num_bytes) {
+ start_sector = start_offset / part->info.blksz;
+ sectors = num_bytes / part->info.blksz;
+ /* handle non block-aligned reads */
+ if (start_offset % part->info.blksz ||
+ num_bytes < part->info.blksz) {
+ tmp_buf = get_sector_buf();
+ if (start_offset % part->info.blksz) {
+ residue = part->info.blksz -
+ (start_offset % part->info.blksz);
+ if (residue > num_bytes)
+ residue = num_bytes;
+ } else {
+ residue = num_bytes;
+ }
+
+ if (io_type == IO_READ) {
+ ret = mmc_read_and_flush(part,
+ part->info.start +
+ start_sector,
+ 1, tmp_buf);
+
+ if (ret != 1) {
+ printf("%s: read error (%ld, %lld)\n",
+ __func__, ret, start_sector);
+ return AVB_IO_RESULT_ERROR_IO;
+ }
+ /*
+ * if this is not aligned at sector start,
+ * we have to adjust the tmp buffer
+ */
+ tmp_buf += (start_offset % part->info.blksz);
+ memcpy(buffer, (void *)tmp_buf, residue);
+ } else {
+ ret = mmc_read_and_flush(part,
+ part->info.start +
+ start_sector,
+ 1, tmp_buf);
+
+ if (ret != 1) {
+ printf("%s: read error (%ld, %lld)\n",
+ __func__, ret, start_sector);
+ return AVB_IO_RESULT_ERROR_IO;
+ }
+ memcpy((void *)tmp_buf +
+ start_offset % part->info.blksz,
+ buffer, residue);
+
+ ret = mmc_write(part, part->info.start +
+ start_sector, 1, tmp_buf);
+ if (ret != 1) {
+ printf("%s: write error (%ld, %lld)\n",
+ __func__, ret, start_sector);
+ return AVB_IO_RESULT_ERROR_IO;
+ }
+ }
+
+ io_cnt += residue;
+ buffer += residue;
+ start_offset += residue;
+ num_bytes -= residue;
+ continue;
+ }
+
+ if (sectors) {
+ if (io_type == IO_READ) {
+ ret = mmc_read_and_flush(part,
+ part->info.start +
+ start_sector,
+ sectors, buffer);
+ } else {
+ ret = mmc_write(part,
+ part->info.start +
+ start_sector,
+ sectors, buffer);
+ }
+
+ if (!ret) {
+ printf("%s: sector read error\n", __func__);
+ return AVB_IO_RESULT_ERROR_IO;
+ }
+
+ io_cnt += ret * part->info.blksz;
+ buffer += ret * part->info.blksz;
+ start_offset += ret * part->info.blksz;
+ num_bytes -= ret * part->info.blksz;
+ }
+ }
+
+ /* Set counter for read operation */
+ if (io_type == IO_READ && out_num_read)
+ *out_num_read = io_cnt;
+
+ return AVB_IO_RESULT_OK;
+}
+
+/**
+ * ============================================================================
+ * AVB 2.0 operations
+ * ============================================================================
+ */
+
+/**
+ * read_from_partition() - reads @num_bytes from @offset from partition
+ * identified by a string name
+ *
+ * @ops: contains AVB ops handlers
+ * @partition_name: partition name, NUL-terminated UTF-8 string
+ * @offset: offset from the beginning of partition
+ * @num_bytes: amount of bytes to read
+ * @buffer: destination buffer to store data
+ * @out_num_read:
+ *
+ * @return:
+ * AVB_IO_RESULT_OK, if partition was found and read operation succeed
+ * AVB_IO_RESULT_ERROR_IO, if i/o error occurred from the underlying i/o
+ * subsystem
+ * AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION, if there is no partition with
+ * the given name
+ */
+static AvbIOResult read_from_partition(AvbOps *ops,
+ const char *partition_name,
+ s64 offset_from_partition,
+ size_t num_bytes,
+ void *buffer,
+ size_t *out_num_read)
+{
+ return mmc_byte_io(ops, partition_name, offset_from_partition,
+ num_bytes, buffer, out_num_read, IO_READ);
+}
+
+/**
+ * write_to_partition() - writes N bytes to a partition identified by a string
+ * name
+ *
+ * @ops: AvbOps, contains AVB ops handlers
+ * @partition_name: partition name
+ * @offset_from_partition: offset from the beginning of partition
+ * @num_bytes: amount of bytes to write
+ * @buf: data to write
+ * @out_num_read:
+ *
+ * @return:
+ * AVB_IO_RESULT_OK, if partition was found and read operation succeed
+ * AVB_IO_RESULT_ERROR_IO, if input/output error occurred
+ * AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION, if partition, specified in
+ * @partition_name was not found
+ */
+static AvbIOResult write_to_partition(AvbOps *ops,
+ const char *partition_name,
+ s64 offset_from_partition,
+ size_t num_bytes,
+ const void *buffer)
+{
+ return mmc_byte_io(ops, partition_name, offset_from_partition,
+ num_bytes, (void *)buffer, NULL, IO_WRITE);
+}
+
+/**
+ * validate_vmbeta_public_key() - checks if the given public key used to sign
+ * the vbmeta partition is trusted
+ *
+ * @ops: AvbOps, contains AVB ops handlers
+ * @public_key_data: public key for verifying vbmeta partition signature
+ * @public_key_length: length of public key
+ * @public_key_metadata:
+ * @public_key_metadata_length:
+ * @out_key_is_trusted:
+ *
+ * @return:
+ * AVB_IO_RESULT_OK, if partition was found and read operation succeed
+ */
+static AvbIOResult validate_vbmeta_public_key(AvbOps *ops,
+ const u8 *public_key_data,
+ size_t public_key_length,
+ const u8
+ *public_key_metadata,
+ size_t
+ public_key_metadata_length,
+ bool *out_key_is_trusted)
+{
+ if (!public_key_length || !public_key_data || !out_key_is_trusted)
+ return AVB_IO_RESULT_ERROR_IO;
+
+ *out_key_is_trusted = false;
+ if (public_key_length != sizeof(avb_root_pub))
+ return AVB_IO_RESULT_ERROR_IO;
+
+ if (memcmp(avb_root_pub, public_key_data, public_key_length) == 0)
+ *out_key_is_trusted = true;
+
+ return AVB_IO_RESULT_OK;
+}
+
+/**
+ * read_rollback_index() - gets the rollback index corresponding to the
+ * location of given by @out_rollback_index.
+ *
+ * @ops: contains AvbOps handlers
+ * @rollback_index_slot:
+ * @out_rollback_index: used to write a retrieved rollback index.
+ *
+ * @return
+ * AVB_IO_RESULT_OK, if the roolback index was retrieved
+ */
+static AvbIOResult read_rollback_index(AvbOps *ops,
+ size_t rollback_index_slot,
+ u64 *out_rollback_index)
+{
+ /* For now we always return 0 as the stored rollback index. */
+ printf("TODO: implement %s.\n", __func__);
+
+ if (out_rollback_index)
+ *out_rollback_index = 0;
+
+ return AVB_IO_RESULT_OK;
+}
+
+/**
+ * write_rollback_index() - sets the rollback index corresponding to the
+ * location of given by @out_rollback_index.
+ *
+ * @ops: contains AvbOps handlers
+ * @rollback_index_slot:
+ * @rollback_index: rollback index to write.
+ *
+ * @return
+ * AVB_IO_RESULT_OK, if the roolback index was retrieved
+ */
+static AvbIOResult write_rollback_index(AvbOps *ops,
+ size_t rollback_index_slot,
+ u64 rollback_index)
+{
+ /* For now this is a no-op. */
+ printf("TODO: implement %s.\n", __func__);
+
+ return AVB_IO_RESULT_OK;
+}
+
+/**
+ * read_is_device_unlocked() - gets whether the device is unlocked
+ *
+ * @ops: contains AVB ops handlers
+ * @out_is_unlocked: device unlock state is stored here, true if unlocked,
+ * false otherwise
+ *
+ * @return:
+ * AVB_IO_RESULT_OK: state is retrieved successfully
+ * AVB_IO_RESULT_ERROR_IO: an error occurred
+ */
+static AvbIOResult read_is_device_unlocked(AvbOps *ops, bool *out_is_unlocked)
+{
+ /* For now we always return that the device is unlocked. */
+
+ printf("TODO: implement %s.\n", __func__);
+
+ *out_is_unlocked = true;
+
+ return AVB_IO_RESULT_OK;
+}
+
+/**
+ * get_unique_guid_for_partition() - gets the GUID for a partition identified
+ * by a string name
+ *
+ * @ops: contains AVB ops handlers
+ * @partition: partition name (NUL-terminated UTF-8 string)
+ * @guid_buf: buf, used to copy in GUID string. Example of value:
+ * 527c1c6d-6361-4593-8842-3c78fcd39219
+ * @guid_buf_size: @guid_buf buffer size
+ *
+ * @return:
+ * AVB_IO_RESULT_OK, on success (GUID found)
+ * AVB_IO_RESULT_ERROR_IO, if incorrect buffer size (@guid_buf_size) was
+ * provided
+ * AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION, if partition was not found
+ */
+static AvbIOResult get_unique_guid_for_partition(AvbOps *ops,
+ const char *partition,
+ char *guid_buf,
+ size_t guid_buf_size)
+{
+ struct mmc_part *part;
+ size_t uuid_size;
+
+ part = get_partition(ops, partition);
+ if (!part)
+ return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
+
+ uuid_size = sizeof(part->info.uuid);
+ if (uuid_size > guid_buf_size)
+ return AVB_IO_RESULT_ERROR_IO;
+
+ memcpy(guid_buf, part->info.uuid, uuid_size);
+ guid_buf[uuid_size - 1] = 0;
+
+ return AVB_IO_RESULT_OK;
+}
+
+/**
+ * ============================================================================
+ * AVB2.0 AvbOps alloc/initialisation/free
+ * ============================================================================
+ */
+AvbOps *avb_ops_alloc(int boot_device)
+{
+ struct AvbOpsData *ops_data;
+
+ ops_data = avb_calloc(sizeof(struct AvbOpsData));
+ if (!ops_data)
+ return NULL;
+
+ ops_data->ops.user_data = ops_data;
+
+ ops_data->ops.read_from_partition = read_from_partition;
+ ops_data->ops.write_to_partition = write_to_partition;
+ ops_data->ops.validate_vbmeta_public_key = validate_vbmeta_public_key;
+ ops_data->ops.read_rollback_index = read_rollback_index;
+ ops_data->ops.write_rollback_index = write_rollback_index;
+ ops_data->ops.read_is_device_unlocked = read_is_device_unlocked;
+ ops_data->ops.get_unique_guid_for_partition =
+ get_unique_guid_for_partition;
+
+ ops_data->mmc_dev = boot_device;
+
+ return &ops_data->ops;
+}
+
+void avb_ops_free(AvbOps *ops)
+{
+ struct AvbOpsData *ops_data;
+
+ if (ops)
+ return;
+
+ ops_data = ops->user_data;
+
+ if (ops_data)
+ avb_free(ops_data);
+}