pci_handler: add support for opening, mapping, closing

Add support for opening, mapping, closing the aspeed-p2a-ctrl.

Signed-off-by: Patrick Venture <venture@google.com>
Change-Id: I8a9361d69af0218365ab752ea69f9276bd0e767a
diff --git a/main.cpp b/main.cpp
index a0716ef..e9de21c 100644
--- a/main.cpp
+++ b/main.cpp
@@ -54,7 +54,7 @@
 
 #ifdef ENABLE_PCI_BRIDGE
 #if defined(ASPEED_P2A)
-PciDataHandler pciDataHandler(MAPPED_ADDRESS);
+PciDataHandler pciDataHandler(MAPPED_ADDRESS, memoryRegionSize);
 #else
 #error "You must specify a hardware implementation."
 #endif
diff --git a/pci_handler.cpp b/pci_handler.cpp
index b82d16a..51a2ca5 100644
--- a/pci_handler.cpp
+++ b/pci_handler.cpp
@@ -16,6 +16,9 @@
 
 #include "pci_handler.hpp"
 
+#include <fcntl.h>
+#include <linux/aspeed-p2a-ctrl.h>
+
 #include <cstdint>
 #include <cstring>
 #include <string>
@@ -28,17 +31,69 @@
 
 bool PciDataHandler::open()
 {
-    /* TODO: For the ASPEED P2A driver, this method will enable the memory
-     * region to use.
+    mappedFd = sys->open(p2aControlPath.c_str(), O_RDWR);
+    if (mappedFd == -1)
+    {
+        return false;
+    }
+
+    struct aspeed_p2a_ctrl_mapping map;
+    map.addr = regionAddress;
+    map.length = memoryRegionSize;
+    map.flags = ASPEED_P2A_CTRL_READWRITE;
+
+    if (sys->ioctl(mappedFd, ASPEED_P2A_CTRL_IOCTL_SET_WINDOW, &map))
+    {
+        sys->close(mappedFd);
+        mappedFd = -1;
+
+        return false;
+    }
+
+    if (sys->ioctl(mappedFd, ASPEED_P2A_CTRL_IOCTL_GET_MEMORY_CONFIG, &map))
+    {
+        sys->close(mappedFd);
+        mappedFd = -1;
+
+        return false;
+    }
+
+    /* The length of the region reserved is reported, and it's important
+     * because the offset + memory region could be beyond that reserved
+     * region.
      */
-    return false;
+    std::uint64_t offset = regionAddress - map.addr;
+
+    mapped = reinterpret_cast<std::uint8_t*>(
+        mmap(0, memoryRegionSize, PROT_READ, MAP_SHARED, mappedFd, offset));
+    if (mapped == MAP_FAILED)
+    {
+        sys->close(mappedFd);
+        mappedFd = -1;
+
+        return false;
+    }
+
+    return true;
 }
 
 bool PciDataHandler::close()
 {
     /* TODO: Turn off the P2A bridge and region to disable host-side access.
      */
-    return false;
+    if (mapped)
+    {
+        sys->munmap(mapped, memoryRegionSize);
+        mapped = nullptr;
+    }
+
+    if (mappedFd != -1)
+    {
+        sys->close(mappedFd);
+        mappedFd = -1;
+    }
+
+    return true;
 }
 
 std::vector<std::uint8_t> PciDataHandler::copyFrom(std::uint32_t length)
diff --git a/pci_handler.hpp b/pci_handler.hpp
index f99a811..f3ae798 100644
--- a/pci_handler.hpp
+++ b/pci_handler.hpp
@@ -24,10 +24,10 @@
 class PciDataHandler : public DataInterface
 {
   public:
-    PciDataHandler(std::uint32_t regionAddress,
+    PciDataHandler(std::uint32_t regionAddress, std::size_t regionSize,
                    const internal::Sys* sys = &internal::sys_impl) :
         regionAddress(regionAddress),
-        sys(sys){};
+        memoryRegionSize(regionSize), sys(sys){};
 
     bool open() override;
     bool close() override;
@@ -37,7 +37,11 @@
 
   private:
     std::uint32_t regionAddress;
+    std::uint32_t memoryRegionSize;
     const internal::Sys* sys;
+
+    int mappedFd = -1;
+    std::uint8_t* mapped = nullptr;
     static const std::string p2aControlPath;
 };