lpc_aspeed: add mapping implementation

Add mapper implementation for Aspeed.

Change-Id: I4bc1cbaaa6c0bf57424b0c881cb087153d63597c
Signed-off-by: Patrick Venture <venture@google.com>
diff --git a/lpc_aspeed.cpp b/lpc_aspeed.cpp
index df2b13c..63147c4 100644
--- a/lpc_aspeed.cpp
+++ b/lpc_aspeed.cpp
@@ -18,25 +18,82 @@
 
 #include "lpc_interface.hpp"
 
+#include <fcntl.h>
+#include <linux/aspeed-lpc-ctrl.h>
+#include <linux/kernel.h>
+
 #include <cstdint>
+#include <cstring>
 #include <memory>
 #include <utility>
 
 namespace blobs
 {
 
-std::unique_ptr<LpcMapperInterface> LpcMapperAspeed::createAspeedMapper()
+std::unique_ptr<LpcMapperInterface>
+    LpcMapperAspeed::createAspeedMapper(size_t regionSize)
 {
     /* NOTE: considered using a joint factory to create one or the other, for
      * now, separate factories.
      */
-    return std::make_unique<LpcMapperAspeed>();
+    return std::make_unique<LpcMapperAspeed>(regionSize);
 }
 
 std::pair<std::uint32_t, std::uint32_t>
     LpcMapperAspeed::mapWindow(std::uint32_t address, std::uint32_t length)
 {
-    return std::make_pair(0, 0);
+    static const std::uint32_t MASK_64K = 0xFFFFU;
+    const std::uint32_t offset = address & MASK_64K;
+
+    if (offset + length > regionSize)
+    {
+        std::fprintf(stderr,
+                     "requested window size %" PRIu32 ", offset %#" PRIx32
+                     " is too large for mem region"
+                     " of size %zu\n",
+                     length, offset, regionSize);
+        /* TODO: need to throw an exception at this point to store the data to
+         * provide an EBIG response later.
+         */
+        /* *windowSize = regionSize - offset; */
+        return std::make_pair(0, 0);
+    }
+
+    struct aspeed_lpc_ctrl_mapping map = {
+        .window_type = ASPEED_LPC_CTRL_WINDOW_MEMORY,
+        .window_id = 0,
+        .flags = 0,
+        .addr = address & ~MASK_64K,
+        .offset = 0,
+        .size = __ALIGN_KERNEL_MASK(offset + length, MASK_64K),
+    };
+
+    std::fprintf(stderr,
+                 "requesting Aspeed LPC window at %#" PRIx32 " of size %" PRIu32
+                 "\n",
+                 map.addr, map.size);
+
+    static const char lpcControlPath[] = "/dev/aspeed-lpc-ctrl";
+
+    const auto lpcControlFd = sys->open(lpcControlPath, O_RDWR);
+    if (lpcControlFd == -1)
+    {
+        std::fprintf(stderr,
+                     "cannot open Aspeed LPC kernel control dev \"%s\"\n",
+                     lpcControlPath);
+        return std::make_pair(0, 0);
+    }
+
+    if (sys->ioctl(lpcControlFd, ASPEED_LPC_CTRL_IOCTL_MAP, &map) == -1)
+    {
+        std::fprintf(stderr, "Failed to ioctl Aspeed LPC map with error %s\n",
+                     std::strerror(errno));
+        sys->close(lpcControlFd);
+        return std::make_pair(0, 0);
+    }
+
+    sys->close(lpcControlFd);
+    return std::make_pair(offset, length);
 }
 
 } // namespace blobs