Load the partitions into virtual pnor

Change-Id: I709c410009fb0047d7e59ddd3a681f25e49341a0
Signed-off-by: Ratan Gupta <ratagupt@in.ibm.com>
diff --git a/mboxd_flash_virtual.cpp b/mboxd_flash_virtual.cpp
index 9aed5fd..4e4e149 100644
--- a/mboxd_flash_virtual.cpp
+++ b/mboxd_flash_virtual.cpp
@@ -17,17 +17,26 @@
  *
  */
 
+#include <fcntl.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <syslog.h>
+#include <sys/mman.h>
+#include <unistd.h>
 
 extern "C" {
 #include "common.h"
 }
 
+#include "config.h"
 #include "mboxd_flash.h"
 #include "mboxd_pnor_partition_table.h"
 
+#include <string>
+#include <exception>
+#include <stdexcept>
+#include <experimental/filesystem>
+
 /*
  * copy_flash() - Copy data from the virtual pnor into a provided buffer
  * @context:    The mbox context pointer
@@ -40,6 +49,7 @@
 int copy_flash(struct mbox_context* context, uint32_t offset, void* mem,
                uint32_t size)
 {
+    namespace fs = std::experimental::filesystem;
     int rc = 0;
 
     MSG_DBG("Copy virtual pnor to %p for size 0x%.8x from offset 0x%.8x\n",
@@ -49,16 +59,57 @@
      * 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)
+    try
     {
-        const struct pnor_partition_table* table =
-            vpnor_get_partition_table(context);
-        memcpy(mem,
-               ((uint8_t*)table) + offset,
-               min_u32(sz - offset, size));
-    }
+        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));
+        }
+        else
+        {
+            /* Copy from virtual pnor into the window buffer */
+            auto partition = vpnor_get_partition(context, offset);
+            if (!partition)
+            {
+                std::string msg = "Couldn't get the partition info for offset " +
+                                  offset;
+                throw std::runtime_error(msg);
+            }
 
+            fs::path partitionFilePath = context->paths.ro_loc;
+            partitionFilePath /= partition->data.name;
+
+            auto fd = open(partitionFilePath.c_str(), O_RDONLY);
+            if (fd == -1)
+            {
+                throw std::runtime_error("Couldn't open the partition file");
+            }
+
+            auto mapped_mem = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
+            if (mem == MAP_FAILED)
+            {
+                std::string msg = "Failed to map" + partitionFilePath.string() + ":"
+                                  + strerror(errno);
+                close(fd);
+                throw std::runtime_error(msg);
+            }
+
+            //copy to the reserved memory area
+            memcpy(mem, mapped_mem, size);
+            munmap(mapped_mem, size);
+            close(fd);
+        }
+    }
+    catch (const std::exception& e)
+    {
+        MSG_ERR("%s", e.what());
+        rc = -1;
+    }
     return rc;
 }