msg: handle partition table read request

Map host's request to read the flash at offset less than the partition
table length as a request to read the pnor partition table.

Resolves openbmc/openbmc#1439.

Change-Id: I0f5b98f073d983b0d4749b0aba84b37d7f42f884
Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
diff --git a/Makefile.am b/Makefile.am
index 8c779f8..78aeffa 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -14,8 +14,10 @@
 mboxd_CFLAGS = $(LIBSYSTEMD_CFLAGS)
 
 if VIRTUAL_PNOR_ENABLED
-mboxd_SOURCES += pnor_partition_table.cpp mboxd_pnor_partition_table.cpp
+mboxd_SOURCES += pnor_partition_table.cpp mboxd_pnor_partition_table.cpp mboxd_flash_virtual.cpp
 mboxd_LDFLAGS += -lstdc++fs
+else
+mboxd_SOURCES += mboxd_flash_physical.c
 endif
 
 mboxctl_SOURCES = mboxctl.c
@@ -31,13 +33,13 @@
 
 test_sanity_SOURCES = test/sanity.c
 
-test_copy_flash_SOURCES = test/copy_flash.c mboxd_flash.c common.c mtd.c test/tmpf.c
+test_copy_flash_SOURCES = test/copy_flash.c mboxd_flash.c mboxd_flash_physical.c common.c mtd.c test/tmpf.c
 
 test_erase_flash_SOURCES = test/erase_flash.c mboxd_flash.c common.c test/tmpf.c
 
 test_write_flash_SOURCES = test/write_flash.c mboxd_flash.c common.c test/tmpf.c
 
-TEST_MBOX_SRCS = mboxd_msg.c mboxd_windows.c mboxd_lpc.c mboxd_flash.c common.c
+TEST_MBOX_SRCS = mboxd_msg.c mboxd_windows.c mboxd_lpc.c mboxd_flash.c common.c mboxd_flash_physical.c
 TEST_MOCK_SRCS = test/tmpf.c test/mbox.c test/system.c
 
 test_get_mbox_info_v2_SOURCES = test/get_mbox_info_v2.c \
diff --git a/mboxd.c b/mboxd.c
index 5f851df..c418543 100644
--- a/mboxd.c
+++ b/mboxd.c
@@ -51,6 +51,7 @@
 #include "mboxd_lpc.h"
 #include "mboxd_msg.h"
 #include "mboxd_windows.h"
+#include "mboxd_pnor_partition_table.h"
 
 #define USAGE \
 "\nUsage: %s [-V | --version] [-h | --help] [-v[v] | --verbose] [-s | --syslog]\n" \
@@ -311,6 +312,10 @@
 
 	MSG_INFO("Starting Daemon\n");
 
+#ifdef VIRTUAL_PNOR_ENABLED
+	vpnor_create_partition_table(context);
+#endif
+
 	rc = init_signals(context, &set);
 	if (rc) {
 		goto finish;
@@ -367,6 +372,9 @@
 	free_lpc_dev(context);
 	free_mbox_dev(context);
 	free_windows(context);
+#ifdef VIRTUAL_PNOR_ENABLED
+	vpnor_destroy_partition_table(context);
+#endif
 	free(context);
 
 	return rc;
diff --git a/mboxd_flash.c b/mboxd_flash.c
index 1e1b7a0..240c660 100644
--- a/mboxd_flash.c
+++ b/mboxd_flash.c
@@ -120,46 +120,6 @@
 
 /* Flash Functions */
 
-#define CHUNKSIZE (64 * 1024)
-
-/*
- * copy_flash() - Copy data from the flash device into a provided buffer
- * @context:	The mbox context pointer
- * @offset:	The flash offset to copy from (bytes)
- * @mem:	The buffer to copy into (must be of atleast size)
- * @size:	The number of bytes to copy
- *
- * Return:	0 on success otherwise negative error code
- */
-int copy_flash(struct mbox_context *context, uint32_t offset, void *mem,
-	       uint32_t size)
-{
-	int32_t size_read;
-
-	MSG_DBG("Copy flash to %p for size 0x%.8x from offset 0x%.8x\n",
-		mem, size, offset);
-	if (lseek(context->fds[MTD_FD].fd, offset, SEEK_SET) != offset) {
-		MSG_ERR("Couldn't seek flash at pos: %u %s\n", offset,
-			strerror(errno));
-		return -MBOX_R_SYSTEM_ERROR;
-	}
-
-	do {
-		size_read = read(context->fds[MTD_FD].fd, mem,
-					  min_u32(CHUNKSIZE, size));
-		if (size_read < 0) {
-			MSG_ERR("Couldn't copy mtd into ram: %s\n",
-				strerror(errno));
-			return -MBOX_R_SYSTEM_ERROR;
-		}
-
-		size -= size_read;
-		mem += size_read;
-	} while (size && size_read);
-
-	return size ? -MBOX_R_SYSTEM_ERROR : 0;
-}
-
 /*
  * flash_is_erased() - Check if an offset into flash is erased
  * @context:	The mbox context pointer
diff --git a/mboxd_flash.h b/mboxd_flash.h
index af9757b..d8b0d0d 100644
--- a/mboxd_flash.h
+++ b/mboxd_flash.h
@@ -23,6 +23,10 @@
 
 #include "mbox.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 int init_flash_dev(struct mbox_context *context);
 void free_flash_dev(struct mbox_context *context);
 int copy_flash(struct mbox_context *context, uint32_t offset, void *mem,
@@ -33,4 +37,7 @@
 int write_flash(struct mbox_context *context, uint32_t offset, void *buf,
 		uint32_t count);
 
+#ifdef __cplusplus
+}
+#endif
 #endif /* MBOXD_FLASH_H */
diff --git a/mboxd_flash_physical.c b/mboxd_flash_physical.c
new file mode 100644
index 0000000..92c70e7
--- /dev/null
+++ b/mboxd_flash_physical.c
@@ -0,0 +1,71 @@
+/*
+ * Mailbox Daemon Flash Helpers
+ *
+ * Copyright 2017 IBM
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#define _GNU_SOURCE
+#include <stdint.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <mtd/mtd-abi.h>
+
+#include "mbox.h"
+#include "common.h"
+#include "mboxd_flash.h"
+
+#define CHUNKSIZE (64 * 1024)
+
+/*
+ * copy_flash() - Copy data from the flash device into a provided buffer
+ * @context:	The mbox context pointer
+ * @offset:	The flash offset to copy from (bytes)
+ * @mem:	The buffer to copy into (must be of atleast 'size' bytes)
+ * @size:	The number of bytes to copy
+ *
+ * Return:	0 on success otherwise negative error code
+ */
+int copy_flash(struct mbox_context *context, uint32_t offset, void *mem,
+	       uint32_t size)
+{
+	int32_t size_read;
+
+	MSG_DBG("Copy flash to %p for size 0x%.8x from offset 0x%.8x\n",
+		mem, size, offset);
+	if (lseek(context->fds[MTD_FD].fd, offset, SEEK_SET) != offset) {
+		MSG_ERR("Couldn't seek flash at pos: %u %s\n", offset,
+			strerror(errno));
+		return -MBOX_R_SYSTEM_ERROR;
+	}
+
+	do {
+		size_read = read(context->fds[MTD_FD].fd, mem,
+					  min_u32(CHUNKSIZE, size));
+		if (size_read < 0) {
+			MSG_ERR("Couldn't copy mtd into ram: %s\n",
+				strerror(errno));
+			return -MBOX_R_SYSTEM_ERROR;
+		}
+
+		size -= size_read;
+		mem += size_read;
+	} while (size && size_read);
+
+	return size ? -MBOX_R_SYSTEM_ERROR : 0;
+}
diff --git a/mboxd_flash_virtual.cpp b/mboxd_flash_virtual.cpp
new file mode 100644
index 0000000..9aed5fd
--- /dev/null
+++ b/mboxd_flash_virtual.cpp
@@ -0,0 +1,64 @@
+/*
+ * Mailbox Daemon Window Helpers
+ *
+ * Copyright 2017 IBM
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <syslog.h>
+
+extern "C" {
+#include "common.h"
+}
+
+#include "mboxd_flash.h"
+#include "mboxd_pnor_partition_table.h"
+
+/*
+ * copy_flash() - Copy data from the virtual pnor into a provided buffer
+ * @context:    The mbox context pointer
+ * @offset:     The pnor offset to copy from (bytes)
+ * @mem:        The buffer to copy into (must be of atleast 'size' bytes)
+ * @size:       The number of bytes to copy
+ *
+ * Return:      0 on success otherwise negative error code
+ */
+int copy_flash(struct mbox_context* context, uint32_t offset, void* mem,
+               uint32_t size)
+{
+    int rc = 0;
+
+    MSG_DBG("Copy virtual pnor to %p for size 0x%.8x from offset 0x%.8x\n",
+            mem, size, offset);
+
+    /* The virtual PNOR partition table starts at offset 0 in the virtual
+     * pnor image. Check if host asked for an offset that lies within the
+     * partition table.
+     */
+    size_t sz =
+        vpnor_get_partition_table_size(context) << context->block_size_shift;
+    if (offset < sz)
+    {
+        const struct pnor_partition_table* table =
+            vpnor_get_partition_table(context);
+        memcpy(mem,
+               ((uint8_t*)table) + offset,
+               min_u32(sz - offset, size));
+    }
+
+    return rc;
+}