vboot_reference: Support MTD devices in dump_kernel_config

This CL implements a read function that works with MTD devices in
dump_kernel_config.

BUG=chromium:457862
BRANCH=none
TEST=make runtests
TEST=try on storm_nand

Change-Id: Id784d422de64e7918b163005c0b426d727d2115e
Reviewed-on: https://chromium-review.googlesource.com/249271
Reviewed-by: Nam Nguyen <namnguyen@chromium.org>
Commit-Queue: Nam Nguyen <namnguyen@chromium.org>
Trybot-Ready: Nam Nguyen <namnguyen@chromium.org>
Tested-by: Nam Nguyen <namnguyen@chromium.org>
diff --git a/Makefile b/Makefile
index 574e961..0804972 100644
--- a/Makefile
+++ b/Makefile
@@ -164,6 +164,11 @@
 CFLAGS += -DPD_SYNC
 endif
 
+ifneq (${USE_MTD},)
+CFLAGS += -DUSE_MTD
+LDLIBS += -lmtdutils
+endif
+
 # NOTE: We don't use these files but they are useful for other packages to
 # query about required compiling/linking flags.
 PC_IN_FILES = vboot_host.pc.in
diff --git a/futility/dump_kernel_config_lib.c b/futility/dump_kernel_config_lib.c
index 1baa2d5..c2d5943 100644
--- a/futility/dump_kernel_config_lib.c
+++ b/futility/dump_kernel_config_lib.c
@@ -18,6 +18,12 @@
 #include "vboot_api.h"
 #include "vboot_host.h"
 
+#ifdef USE_MTD
+#include <linux/major.h>
+#include <mtd/mtd-user.h>
+#include <mtdutils.h>
+#endif
+
 typedef ssize_t (*ReadFullyFn)(void *ctx, void *buf, size_t count);
 
 static ssize_t ReadFullyWithRead(void *ctx, void *buf, size_t count)
@@ -37,6 +43,14 @@
 	return nr_read;
 }
 
+#ifdef USE_MTD
+static ssize_t ReadFullyWithMtdRead(void *ctx, void *buf, size_t count)
+{
+	MtdReadContext *mtd_ctx = (MtdReadContext*)ctx;
+	return mtd_read_data(mtd_ctx, buf, count);
+}
+#endif
+
 /* Skip the stream by calling |read_fn| many times. Return 0 on success. */
 static int SkipWithRead(void *ctx, ReadFullyFn read_fn, size_t count)
 {
@@ -130,9 +144,32 @@
 	void *ctx = &fd;
 	ReadFullyFn read_fn = ReadFullyWithRead;
 
+#ifdef USE_MTD
+	struct stat stat_buf;
+	if (fstat(fd, &stat_buf)) {
+		VbExError("Cannot stat %s\n", infile);
+		return NULL;
+	}
+
+	int is_mtd = (major(stat_buf.st_rdev) == MTD_CHAR_MAJOR);
+	if (is_mtd) {
+		ctx = mtd_read_descriptor(fd, infile);
+		if (!ctx) {
+			VbExError("Cannot read from MTD device %s\n", infile);
+			return NULL;
+		}
+		read_fn = ReadFullyWithMtdRead;
+	}
+#endif
+
 	newstr = FindKernelConfigFromStream(ctx, read_fn,
 					    kernel_body_load_address);
 
+#ifdef USE_MTD
+	if (is_mtd) {
+		mtd_read_close(ctx);
+	}
+#endif
 	close(fd);
 
 	return newstr;