Read the partition file from the vpnor.

This fix reads the file from the partition,
Memory map to it and then copy the asked memory
area to the reserved memory area.

Change-Id: I4b2987e628bc4820edfeb1b0a81e5d1cbb8e7cf1
Signed-off-by: Ratan Gupta <ratagupt@in.ibm.com>
diff --git a/mboxd_flash_virtual.cpp b/mboxd_flash_virtual.cpp
index 4e4e149..c7154d6 100644
--- a/mboxd_flash_virtual.cpp
+++ b/mboxd_flash_virtual.cpp
@@ -31,11 +31,14 @@
 #include "config.h"
 #include "mboxd_flash.h"
 #include "mboxd_pnor_partition_table.h"
+#include "pnor_partition.hpp"
+#include "xyz/openbmc_project/Common/error.hpp"
+#include <phosphor-logging/log.hpp>
+#include <phosphor-logging/elog-errors.hpp>
 
 #include <string>
 #include <exception>
 #include <stdexcept>
-#include <experimental/filesystem>
 
 /*
  * copy_flash() - Copy data from the virtual pnor into a provided buffer
@@ -49,7 +52,10 @@
 int copy_flash(struct mbox_context* context, uint32_t offset, void* mem,
                uint32_t size)
 {
-    namespace fs = std::experimental::filesystem;
+    using namespace phosphor::logging;
+    using namespace sdbusplus::xyz::openbmc_project::Common::Error;
+    using namespace std::string_literals;
+
     int rc = 0;
 
     MSG_DBG("Copy virtual pnor to %p for size 0x%.8x from offset 0x%.8x\n",
@@ -73,42 +79,42 @@
         }
         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);
-            }
+            openpower::virtual_pnor::RORequest roRequest;
+            auto partitionInfo = roRequest.getPartitionInfo(context, offset);
 
-            fs::path partitionFilePath = context->paths.ro_loc;
-            partitionFilePath /= partition->data.name;
+            auto mapped_mem = mmap(NULL, partitionInfo->data.actual,
+                                   PROT_READ, MAP_PRIVATE, roRequest.fd(), 0);
 
-            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);
+                MSG_ERR("Failed to map partition=%s:Error=%s\n",
+                        partitionInfo->data.name, strerror(errno));
+
+                elog<InternalFailure>();
+            }
+
+            // if the asked offset + no of bytes to read is greater
+            // then size of the partition file then throw error.
+
+            uint32_t baseOffset = partitionInfo->data.base << context->block_size_shift;
+
+            if ((offset + size) > (baseOffset + partitionInfo->data.actual))
+            {
+                MSG_ERR("Offset is beyond the partition file length[0x%.8x]\n",
+                        partitionInfo->data.actual);
+                munmap(mapped_mem, partitionInfo->data.actual);
+                elog<InternalFailure>();
             }
 
             //copy to the reserved memory area
-            memcpy(mem, mapped_mem, size);
-            munmap(mapped_mem, size);
-            close(fd);
+            auto diffOffset = offset - baseOffset;
+            memcpy(mem, (char*)mapped_mem + diffOffset , size);
+            munmap(mapped_mem, partitionInfo->data.actual);
         }
     }
-    catch (const std::exception& e)
+    catch (InternalFailure& e)
     {
-        MSG_ERR("%s", e.what());
+        commit<InternalFailure>();
         rc = -1;
     }
     return rc;
diff --git a/pnor_partition.cpp b/pnor_partition.cpp
index 3f4fd02..015a951 100644
--- a/pnor_partition.cpp
+++ b/pnor_partition.cpp
@@ -91,7 +91,6 @@
                                                   uint32_t offset)
 {
     std::string path = getPartitionFilePath(context, offset);
-
     ReturnCode rc = Request::open(path, O_RDONLY);
     if (rc == ReturnCode::SUCCESS)
     {
@@ -111,6 +110,7 @@
     }
 
     MSG_DBG("Couldn't open the file[%s]", path.c_str());
+
     // we don't get the file in the respective partition(RW/PSRV)
     // try to open it from RO location.
 
diff --git a/test/create_read_window_vpnor.cpp b/test/create_read_window_vpnor.cpp
index 8121498..d9bcccc 100644
--- a/test/create_read_window_vpnor.cpp
+++ b/test/create_read_window_vpnor.cpp
@@ -13,7 +13,7 @@
 #include <fstream>
 #include <experimental/filesystem>
 
-constexpr auto line = "partition01=HBB,00000000,00000400,ECC,PRESERVED";
+constexpr auto line = "partition01=HBB,00000000,0001000,ECC,PRESERVED";
 constexpr auto partition = "HBB";
 char tmplt[] = "/tmp/create_read_test.XXXXXX";
 uint8_t data[8] = { 0xaa, 0x55, 0xaa, 0x66, 0x77, 0x88, 0x99, 0xab };
@@ -86,6 +86,10 @@
     rc = memcmp(ctx->mem, data, 6);
     assert(rc == 0);
 
+    //TODO: Add few more test cases for read from multiple partitions(PRSV/RW)
+    //      Read beyond the partition file size.
+    //      openbmc/openbmc#1868
+
     fs::remove_all(fs::path{tmpdir});
     return rc;
 }