mboxd: Add a backend abstraction layer to mboxd.

Introduce a backend abstraction, enabling multiple implementations to be
compiled in at once. This change formally abstracts the two existing
backends, mtd and vpnor.

With the backend abstraction in place, subsequent backends are easier to
implement.

This change is based of Evan's work and he retains authorship credit. I
(AJ) have reworked the patch to pass the vpnor tests, refactored some
parts to enable broader use of const structures and others to clarify
the initialisation sequences.

Due to the existing lack of abstraction the patch has unfortunately
wide-ranging impacts. I've whittled it down as much as I consider
reasonable.

Change-Id: I29984a36dae4ea86ec00b853d2a756f0b9afb3ec
Signed-off-by: Evan Lojewski <github@meklort.com>
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
diff --git a/test/Makefile.am.include b/test/Makefile.am.include
index 195e451..2b7ba75 100644
--- a/test/Makefile.am.include
+++ b/test/Makefile.am.include
@@ -2,20 +2,23 @@
 
 test_flash_copy_SOURCES = \
 	%reldir%/flash_copy.c \
-	flash.c \
+	mtd/backend.c \
+	lpc.c \
 	common.c mtd.c \
 	%reldir%/tmpf.c \
 	%reldir%/system.c
 
 test_flash_erase_SOURCES = \
 	%reldir%/flash_erase.c \
-	flash.c \
+	mtd/backend.c \
+	lpc.c \
 	common.c \
 	%reldir%/tmpf.c
 
 test_flash_write_SOURCES = \
 	%reldir%/flash_write.c \
-	flash.c \
+	mtd/backend.c \
+	lpc.c \
 	common.c \
 	%reldir%/tmpf.c
 
@@ -23,12 +26,16 @@
 	transport_mbox.c \
 	windows.c \
 	lpc.c \
-	lpc_reset.c \
 	common.c \
-	flash.c \
 	protocol.c
 
-TEST_MOCK_SRCS = %reldir%/tmpf.c %reldir%/mbox.c %reldir%/system.c
+TEST_MOCK_CORE = \
+	%reldir%/tmpf.c \
+	mtd/backend.c \
+	%reldir%/mbox.c \
+	%reldir%/system.c
+
+TEST_MOCK_SRCS = %reldir%/backend.c $(TEST_MOCK_CORE)
 
 test_get_mbox_info_v2_SOURCES = %reldir%/get_mbox_info_v2.c \
 				$(TEST_MBOX_SRCS) $(TEST_MOCK_SRCS)
diff --git a/test/backend.c b/test/backend.c
new file mode 100644
index 0000000..7b9fec8
--- /dev/null
+++ b/test/backend.c
@@ -0,0 +1,11 @@
+#include "backend.h"
+#include "mboxd.h"
+
+#include <errno.h>
+
+struct backend backend_get_vpnor(void)
+{
+	struct backend be = {0};
+
+	return be;
+}
diff --git a/test/flash_copy.c b/test/flash_copy.c
index 3b88b76..472315b 100644
--- a/test/flash_copy.c
+++ b/test/flash_copy.c
@@ -11,7 +11,7 @@
 
 #include "common.h"
 #include "mboxd.h"
-#include "flash.h"
+#include "backend.h"
 
 #include "test/system.h"
 #include "test/tmpf.h"
@@ -69,12 +69,15 @@
 		goto free;
 	}
 
-	context.fds[MTD_FD].fd = tmp.fd;
+	assert(!backend_probe_mtd(&context.backend, tmp.path));
 
 	flash_copy(&context, 0, dst, TEST_SIZE);
 	assert(0 == memcmp(src, dst, TEST_SIZE));
 
+	backend_free(&context.backend);
+
 free:
+
 	free(src);
 	free(dst);
 
diff --git a/test/flash_erase.c b/test/flash_erase.c
index 3d299dd..ad4e535 100644
--- a/test/flash_erase.c
+++ b/test/flash_erase.c
@@ -13,7 +13,7 @@
 
 #include "common.h"
 #include "mboxd.h"
-#include "flash.h"
+#include "backend.h"
 
 #include "test/tmpf.h"
 
@@ -32,7 +32,7 @@
 	if (rc < 0)
 		return NULL;
 
-	return strdup(mtd.path);
+	return mtd.path;
 }
 
 struct erase_info_user *recorded;
@@ -98,10 +98,13 @@
 
 int main(void)
 {
-	struct mbox_context context;
+	struct mbox_context context = {0};
+	struct backend *backend;
 	char data[MEM_SIZE];
 	int rc;
 
+	backend = &context.backend;
+
 	rc = atexit(cleanup_mtd);
 	if (rc)
 		return rc;
@@ -111,7 +114,7 @@
 	n_ioctls = 0;
 	recorded = NULL;
 
-	flash_dev_init(&context);
+	assert(!backend_probe_mtd(backend, get_dev_mtd()));
 
 	/* Erase from an unknown state */
 	rc = flash_erase(&context, 0, sizeof(data));
@@ -206,7 +209,7 @@
 	recorded = NULL;
 	n_ioctls = 0;
 
-	flash_dev_free(&context);
+	backend_free(backend);
 
 	return rc;
 }
diff --git a/test/flash_write.c b/test/flash_write.c
index 1b55dbe..168b2aa 100644
--- a/test/flash_write.c
+++ b/test/flash_write.c
@@ -12,7 +12,7 @@
 
 #include "common.h"
 #include "mboxd.h"
-#include "flash.h"
+#include "backend.h"
 
 #include "test/tmpf.h"
 
@@ -31,7 +31,7 @@
 	if (rc < 0)
 		return NULL;
 
-	return strdup(tmp->path);
+	return tmp->path;
 }
 
 #define MEM_SIZE 3
@@ -58,6 +58,7 @@
 int main(void)
 {
 	struct mbox_context _context, *context = &_context;
+	struct backend *backend = &context->backend;
 	char src[MEM_SIZE];
 	uint8_t *map;
 	int rc;
@@ -66,7 +67,7 @@
 
 	mbox_vlog = &mbox_log_console;
 
-	rc = flash_dev_init(context);
+	rc = backend_probe_mtd(backend, get_dev_mtd());
 	assert(rc == 0);
 
 	map = mmap(NULL, MEM_SIZE, PROT_READ, MAP_PRIVATE, tmp->fd, 0);
@@ -102,7 +103,7 @@
 	rc = memcmp(src, map, sizeof(src));
 	assert(rc == 0);
 
-	flash_dev_free(context);
+	backend_free(backend);
 
 	return rc;
 }
diff --git a/test/implicit_flush.c b/test/implicit_flush.c
index 74275e4..f186d19 100644
--- a/test/implicit_flush.c
+++ b/test/implicit_flush.c
@@ -5,6 +5,7 @@
 #include <sys/mman.h>
 
 #include "mboxd.h"
+#include "mtd/backend.h"
 #include "transport_mbox.h"
 
 #include "test/mbox.h"
@@ -92,7 +93,7 @@
 	assert(rc == 0);
 
 	map = mmap(NULL, MEM_SIZE, PROT_READ, MAP_PRIVATE,
-			ctx->fds[MTD_FD].fd, 0);
+			((struct mtd_data *)ctx->backend.priv)->fd, 0);
 	assert(map != MAP_FAILED);
 
 	rc = memcmp(finish_data, map, sizeof(finish_data));
@@ -124,7 +125,7 @@
 	assert(rc == 0);
 
 	map = mmap(NULL, MEM_SIZE, PROT_READ, MAP_PRIVATE,
-			ctx->fds[MTD_FD].fd, 0);
+			((struct mtd_data *)ctx->backend.priv)->fd, 0);
 	assert(map != MAP_FAILED);
 
 	rc = memcmp(finish_data, map, sizeof(finish_data));
diff --git a/test/mark_write_erased_v2.c b/test/mark_write_erased_v2.c
index 9c0f172..95cff4b 100644
--- a/test/mark_write_erased_v2.c
+++ b/test/mark_write_erased_v2.c
@@ -5,6 +5,7 @@
 #include <sys/mman.h>
 
 #include "mboxd.h"
+#include "mtd/backend.h"
 #include "transport_mbox.h"
 
 #include "test/mbox.h"
@@ -74,7 +75,7 @@
 	assert(rc == 0);
 
 	map = mmap(NULL, MEM_SIZE, PROT_READ, MAP_PRIVATE,
-			ctx->fds[MTD_FD].fd, 0);
+			((struct mtd_data *)ctx->backend.priv)->fd, 0);
 	assert(map != MAP_FAILED);
 
 	rc = memcmp(start_data, map, sizeof(start_data));
diff --git a/test/mbox.c b/test/mbox.c
index a351250..55af00c 100644
--- a/test/mbox.c
+++ b/test/mbox.c
@@ -8,13 +8,15 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/ioctl.h>
 #include <sys/mman.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 
+#include "config.h"
 #include "mboxd.h"
-#include "flash.h"
+#include "backend.h"
 #include "lpc.h"
 #include "transport_mbox.h"
 #include "windows.h"
@@ -212,8 +214,9 @@
 int __transport_mbox_init(struct mbox_context *context, const char *path);
 int __lpc_dev_init(struct mbox_context *context, const char *path);
 
-struct mbox_context *mbox_create_test_context(int n_windows, size_t len)
+struct mbox_context *mbox_create_frontend_context(int n_windows, size_t len)
 {
+	struct mtd_info_user mtd_info;
 	int rc;
 
 	mbox_vlog = &mbox_log_console;
@@ -224,9 +227,6 @@
 	rc = tmpf_init(&test.mbox, "mbox-store.XXXXXX");
 	assert(rc == 0);
 
-	rc = tmpf_init(&test.flash, "flash-store.XXXXXX");
-	assert(rc == 0);
-
 	rc = tmpf_init(&test.lpc, "lpc-store.XXXXXX");
 	assert(rc == 0);
 
@@ -247,12 +247,18 @@
 	assert(rc == 0);
 	test.context.fds[MBOX_FD].fd = test.mbox.fd;
 
-	rc = flash_dev_init(&test.context);
+	/* Instantiate the mtd backend */
+	rc = tmpf_init(&test.flash, "flash-store.XXXXXX");
 	assert(rc == 0);
 
-	rc = fallocate(test.flash.fd, 0, 0, test.context.mtd_info.size);
+	rc = ioctl(test.flash.fd, MEMGETINFO, &mtd_info);
 	assert(rc == 0);
 
+	rc = fallocate(test.flash.fd, 0, 0, mtd_info.size);
+	assert(rc == 0);
+
+	test.context.backend.flash_size = mtd_info.size;
+
 	rc = __lpc_dev_init(&test.context, test.lpc.path);
 	assert(rc == 0);
 
@@ -265,6 +271,20 @@
 	return rc ? NULL : &test.context;
 }
 
+struct mbox_context *mbox_create_test_context(int n_windows, size_t len)
+{
+	struct mbox_context *ctx;
+	int rc;
+
+	ctx = mbox_create_frontend_context(n_windows, len);
+	assert(ctx);
+
+	rc = backend_probe_mtd(&ctx->backend, test.flash.path);
+	assert(rc == 0);
+
+	return ctx;
+}
+
 /* From ccan's container_of module, CC0 license */
 #define container_of(member_ptr, containing_type, member)		\
 	 ((containing_type *)						\
@@ -295,13 +315,13 @@
 	/* Sanity check */
 	arg = container_of(context, struct mbox_test_context, context);
 	assert(&test == arg);
-	assert(len <= test.context.flash_size);
+	assert(len <= test.context.backend.flash_size);
 
-	map = mmap(NULL, test.context.mtd_info.size, PROT_WRITE, MAP_SHARED,
-			test.flash.fd, 0);
+	map = mmap(NULL, test.context.backend.flash_size,
+		   PROT_WRITE, MAP_SHARED, test.flash.fd, 0);
 	assert(map != MAP_FAILED);
 	memcpy(map, data, len);
-	munmap(map, test.context.mtd_info.size);
+	munmap(map, test.context.backend.flash_size);
 
 	return 0;
 }
diff --git a/test/mbox.h b/test/mbox.h
index 8c1bff9..a030b7d 100644
--- a/test/mbox.h
+++ b/test/mbox.h
@@ -14,6 +14,7 @@
 #include "tmpf.h"
 
 struct mbox_context *mbox_create_test_context(int n_windows, size_t len);
+struct mbox_context *mbox_create_frontend_context(int n_windows, size_t len);
 
 int mbox_set_mtd_data(struct mbox_context *context, const void *data,
 		size_t len);
diff --git a/test/write_flush_v2.c b/test/write_flush_v2.c
index fafa7d0..b53550d 100644
--- a/test/write_flush_v2.c
+++ b/test/write_flush_v2.c
@@ -5,6 +5,7 @@
 #include <sys/mman.h>
 
 #include "mboxd.h"
+#include "mtd/backend.h"
 #include "transport_mbox.h"
 
 #include "test/mbox.h"
@@ -95,7 +96,7 @@
 	assert(rc == 0);
 
 	map = mmap(NULL, MEM_SIZE, PROT_READ, MAP_PRIVATE,
-			ctx->fds[MTD_FD].fd, 0);
+			((struct mtd_data *)ctx->backend.priv)->fd, 0);
 	assert(map != MAP_FAILED);
 
 	rc = memcmp(flush_middle_data, map, sizeof(flush_middle_data));
diff --git a/test/write_window_dirty_erase.c b/test/write_window_dirty_erase.c
index e839890..15f0bc3 100644
--- a/test/write_window_dirty_erase.c
+++ b/test/write_window_dirty_erase.c
@@ -5,6 +5,7 @@
 #include <sys/mman.h>
 
 #include "mboxd.h"
+#include "mtd/backend.h"
 #include "transport_mbox.h"
 
 #include "test/mbox.h"
@@ -114,7 +115,7 @@
 	assert(rc == 0);
 
 	map = mmap(NULL, MEM_SIZE, PROT_READ, MAP_PRIVATE,
-			ctx->fds[MTD_FD].fd, 0);
+			((struct mtd_data *)ctx->backend.priv)->fd, 0);
 	assert(map != MAP_FAILED);
 
 	rc = memcmp(flush_dirty_erased_dirty_data, map,