[v2,3/8] avb2.0: implement AVB ops

Message ID 1528052203-29689-4-git-send-email-igor.opaniuk@linaro.org
State New
Headers show
Series
  • Initial integration of AVB2.0
Related show

Commit Message

Igor Opaniuk June 3, 2018, 6:56 p.m.
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      |   2 +
 common/avb_verify.c  | 610 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/avb_verify.h |  79 +++++++
 3 files changed, 691 insertions(+)
 create mode 100644 common/avb_verify.c
 create mode 100644 include/avb_verify.h

Patch

diff --git a/common/Makefile b/common/Makefile
index 7011dad..8ba0b79 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -136,3 +136,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
index 0000000..a4de168
--- /dev/null
+++ b/common/avb_verify.c
@@ -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
index 0000000..428c69a
--- /dev/null
+++ b/include/avb_verify.h
@@ -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 */