avb2.0: implement AVB ops
authorIgor Opaniuk <igor.opaniuk@linaro.org>
Sun, 3 Jun 2018 18:56:38 +0000 (21:56 +0300)
committerTom Rini <trini@konsulko.com>
Mon, 18 Jun 2018 17:55:13 +0000 (13:55 -0400)
Implement AVB ops on top of existing mmc subsystem API. Currently there
is a full implementation of such operations, defined by [1]
AVB2.0 specification:

.read_from_partition() - reads N bytes from a partition identified by
a name.
.write_to_partition() - Writes N bytes to a partition identified by a name.
.validate_vbmeta_public_key() - checks if the given public ‘vbmeta’
partition is trusted.
.get_unique_guid_for_partition() - Gets the GUID for a partition identified
by a string name.

As [1] specification recommends to use tamper-evident storage for storing
rollback indexes and device state (LOCKED/UNLOCKED),
currently are only stubs instead of full implementation for these ops:
.read_rollback_index() - Gets the rollback index for a given index location
.write_rollback_index() - Sets the rollback index to a given location
.read_is_device_unlocked() - Gets where the device is unlocked

[1] https://android.googlesource.com/platform/external/avb/+/master/README.md

Signed-off-by: Igor Opaniuk <igor.opaniuk@linaro.org>
common/Makefile
common/avb_verify.c [new file with mode: 0644]
include/avb_verify.h [new file with mode: 0644]

index b3da72ebb2c94ee3ca23a104cb8d79a1be51f5eb..66584f8f48be554a2afe662433d8e05503724982 100644 (file)
@@ -120,3 +120,5 @@ obj-$(CONFIG_$(SPL_)LOG) += log.o
 obj-$(CONFIG_$(SPL_)LOG_CONSOLE) += log_console.o
 obj-y += s_record.o
 obj-y += xyzModem.o
+
+obj-$(CONFIG_LIBAVB) += avb_verify.o
diff --git a/common/avb_verify.c b/common/avb_verify.c
new file mode 100644 (file)
index 0000000..a4de168
--- /dev/null
@@ -0,0 +1,610 @@
+/*
+ * (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);
+}
diff --git a/include/avb_verify.h b/include/avb_verify.h
new file mode 100644 (file)
index 0000000..428c69a
--- /dev/null
@@ -0,0 +1,79 @@
+
+/*
+ * (C) Copyright 2018, Linaro Limited
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef        _AVB_VERIFY_H
+#define _AVB_VERIFY_H
+
+#include <../lib/libavb/libavb.h>
+#include <mmc.h>
+
+#define ALLOWED_BUF_ALIGN      8
+
+struct AvbOpsData {
+       struct AvbOps ops;
+       int mmc_dev;
+};
+
+struct mmc_part {
+       int dev_num;
+       struct mmc *mmc;
+       struct blk_desc *mmc_blk;
+       disk_partition_t info;
+};
+
+enum mmc_io_type {
+       IO_READ,
+       IO_WRITE
+};
+
+AvbOps *avb_ops_alloc(int boot_device);
+void avb_ops_free(AvbOps *ops);
+
+/**
+ * ============================================================================
+ * I/O helper inline functions
+ * ============================================================================
+ */
+static inline uint64_t calc_offset(struct mmc_part *part, int64_t offset)
+{
+       u64 part_size = part->info.size * part->info.blksz;
+
+       if (offset < 0)
+               return part_size + offset;
+
+       return offset;
+}
+
+static inline size_t get_sector_buf_size(void)
+{
+       return (size_t)CONFIG_FASTBOOT_BUF_SIZE;
+}
+
+static inline void *get_sector_buf(void)
+{
+       return (void *)CONFIG_FASTBOOT_BUF_ADDR;
+}
+
+static inline bool is_buf_unaligned(void *buffer)
+{
+       return (bool)((uintptr_t)buffer % ALLOWED_BUF_ALIGN);
+}
+
+static inline int get_boot_device(AvbOps *ops)
+{
+       struct AvbOpsData *data;
+
+       if (ops) {
+               data = ops->user_data;
+               if (data)
+                       return data->mmc_dev;
+       }
+
+       return -1;
+}
+
+#endif /* _AVB_VERIFY_H */