add lpc mapping interface and stubs

Add an lpc mapping interface to allow for multiple mapping
implementations, such as one for Aspeed and one for Nuvoton.

Add empty implementations for Aspeed and Nuvoton.
Add configuration options to enable aspeed or nuvoton lpc.

Change-Id: I3fd2b1e437db6366c7656f294d138224c25d4e81
Signed-off-by: Patrick Venture <venture@google.com>
diff --git a/configure.ac b/configure.ac
index b7b972e..0dd8799 100644
--- a/configure.ac
+++ b/configure.ac
@@ -46,6 +46,27 @@
     AX_APPEND_COMPILE_FLAGS([-DENABLE_LPC_BRIDGE], [CXXFLAGS])
 ])
 
+AC_ARG_ENABLE([aspeed-lpc],
+    AS_HELP_STRING([--enable-aspeed-lpc],
+                   [Enable external transfers using Aspeed LPC]))
+AS_IF([test "x$enable_aspeed_lpc" = "xyes"], [
+    AC_CHECK_HEADER(linux/aspeed-lpc-ctrl.h,
+                    [HAVE_UAPI_LINUX_LPC_CTRL_H=""],
+                    [HAVE_UAPI_LINUX_LPC_CTRL_H="-I linux/aspeed-lpc-ctrl.h"])
+    AS_IF([test "$HAVE_UAPI_LINUX_LPC_CTRL_H" != ""],
+        AC_MSG_WARN([Could not find linux/aspeed-lpc-ctrl.h: Attempting to download locally for building from openbmc/linux/+dev-4.18])
+        AC_SUBST([BT_BMC_DL],
+                 [`mkdir -p linux;wget https://raw.githubusercontent.com/openbmc/linux/dev-4.18/include/uapi/linux/aspeed-lpc-ctrl.h -O linux/aspeed-lpc-ctrl.h`])
+    )
+    AX_APPEND_COMPILE_FLAGS([-DASPEED_LPC], [CXXFLAGS])
+])
+AC_ARG_ENABLE([nuvoton-lpc],
+    AS_HELP_STRING([--enable-nuvoton-lpc],
+                   [Enable external transfers using Nuvoton LPC SHM]))
+AS_IF([test "x$enable_nuvoton_lpc" = "xyes"], [
+    AX_APPEND_COMPILE_FLAGS([-DNUVOTON_LPC], [CXXFLAGS])
+])
+
 # Check/set gtest specific functions.
 PKG_CHECK_MODULES([GTEST], [gtest], [], [AC_MSG_NOTICE([gtest not found, tests will not build])])
 PKG_CHECK_MODULES([GMOCK], [gmock], [], [AC_MSG_NOTICE([gmock not found, tests will not build])])
@@ -85,7 +106,6 @@
 AS_IF([test "x$STATIC_HANDLER_STAGED_NAME" == "x"], [STATIC_HANDLER_STAGED_NAME="/run/initramfs/bmc-image"])
 AC_DEFINE_UNQUOTED([STATIC_HANDLER_STAGED_NAME], ["$STATIC_HANDLER_STAGED_NAME"], [The file to use for staging the firmware update.])
 
-
 # Create configured output
 AC_CONFIG_FILES([Makefile test/Makefile])
 AC_OUTPUT
diff --git a/lpc_aspeed.cpp b/lpc_aspeed.cpp
new file mode 100644
index 0000000..677a9fd
--- /dev/null
+++ b/lpc_aspeed.cpp
@@ -0,0 +1,26 @@
+#include "lpc_aspeed.hpp"
+
+#include "lpc_interface.hpp"
+
+#include <cstdint>
+#include <memory>
+#include <utility>
+
+namespace blobs
+{
+
+std::unique_ptr<LpcMapperInterface> LpcMapperAspeed::createAspeedMapper()
+{
+    /* NOTE: considered using a joint factory to create one or the other, for
+     * now, separate factories.
+     */
+    return std::make_unique<LpcMapperAspeed>();
+}
+
+std::pair<std::uint32_t, std::uint32_t>
+    LpcMapperAspeed::mapWindow(std::uint32_t address, std::uint32_t length)
+{
+    return std::make_pair(0, 0);
+}
+
+} // namespace blobs
diff --git a/lpc_aspeed.hpp b/lpc_aspeed.hpp
new file mode 100644
index 0000000..1d5f4ac
--- /dev/null
+++ b/lpc_aspeed.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "lpc_interface.hpp"
+
+namespace blobs
+{
+
+class LpcMapperAspeed : public LpcMapperInterface
+{
+  public:
+    static std::unique_ptr<LpcMapperInterface> createAspeedMapper();
+
+    /* TODO: Needs reserved memory region's physical address and size. */
+    LpcMapperAspeed() = default;
+
+    std::pair<std::uint32_t, std::uint32_t>
+        mapWindow(std::uint32_t address, std::uint32_t length) override;
+};
+
+} // namespace blobs
diff --git a/lpc_handler.hpp b/lpc_handler.hpp
index c60b782..91c976b 100644
--- a/lpc_handler.hpp
+++ b/lpc_handler.hpp
@@ -1,8 +1,10 @@
 #pragma once
 
 #include "data_handler.hpp"
+#include "lpc_interface.hpp"
 
 #include <cstdint>
+#include <memory>
 #include <vector>
 
 namespace blobs
@@ -24,13 +26,24 @@
 class LpcDataHandler : public DataInterface
 {
   public:
-    LpcDataHandler() = default;
+    /**
+     * Create an LpcDataHandler.
+     *
+     * @param[in] mapper - pointer to a mapper implementation to use.
+     */
+    explicit LpcDataHandler(std::unique_ptr<LpcMapperInterface> mapper) :
+        mapper(std::move(mapper))
+    {
+    }
 
     bool open() override;
     bool close() override;
     std::vector<std::uint8_t> copyFrom(std::uint32_t length) override;
     bool write(const std::vector<std::uint8_t>& configuration) override;
     std::vector<std::uint8_t> read() override;
+
+  private:
+    std::unique_ptr<LpcMapperInterface> mapper;
 };
 
 } // namespace blobs
diff --git a/lpc_interface.hpp b/lpc_interface.hpp
new file mode 100644
index 0000000..c5573b6
--- /dev/null
+++ b/lpc_interface.hpp
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <cstdint>
+#include <utility>
+
+namespace blobs
+{
+
+/**
+ * Different LPC memory map implementations may require different mechanisms for
+ * specific tasks such as mapping the memory window.
+ */
+class LpcMapperInterface
+{
+  public:
+    virtual ~LpcMapperInterface() = default;
+
+    /**
+     * Returns a windowOffset and windowSize if the requested window was mapped.
+     *
+     * TODO: If the length requested is too large, windowSize will be written
+     * with the max size that the BMC can map and returns false.
+     *
+     * @param[in] address - The address for mapping (passed to LPC window)
+     * @param[in] length - The length of the region
+     * @return windowOffset, windowSize - The offset into the window and
+     * length of the region.  On failure, length is set to 0.
+     */
+    virtual std::pair<std::uint32_t, std::uint32_t>
+        mapWindow(std::uint32_t address, std::uint32_t length) = 0;
+};
+
+} // namespace blobs
diff --git a/lpc_nuvoton.cpp b/lpc_nuvoton.cpp
new file mode 100644
index 0000000..5869ab9
--- /dev/null
+++ b/lpc_nuvoton.cpp
@@ -0,0 +1,24 @@
+#include "lpc_nuvoton.hpp"
+
+#include "lpc_interface.hpp"
+
+#include <cstdint>
+#include <memory>
+#include <utility>
+
+namespace blobs
+{
+
+std::unique_ptr<LpcMapperInterface> LpcMapperNuvoton::createNuvotonMapper()
+{
+    /* NOTE: Considered making one factory for both types. */
+    return std::make_unique<LpcMapperNuvoton>();
+}
+
+std::pair<std::uint32_t, std::uint32_t>
+    LpcMapperNuvoton::mapWindow(std::uint32_t address, std::uint32_t length)
+{
+    return std::make_pair(0, 0);
+}
+
+} // namespace blobs
diff --git a/lpc_nuvoton.hpp b/lpc_nuvoton.hpp
new file mode 100644
index 0000000..c44874d
--- /dev/null
+++ b/lpc_nuvoton.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "lpc_interface.hpp"
+
+namespace blobs
+{
+
+class LpcMapperNuvoton : public LpcMapperInterface
+{
+  public:
+    static std::unique_ptr<LpcMapperInterface> createNuvotonMapper();
+
+    /* TODO: Needs reserved memory region's physical address and size. */
+    LpcMapperNuvoton() = default;
+
+    std::pair<std::uint32_t, std::uint32_t>
+        mapWindow(std::uint32_t address, std::uint32_t length) override;
+};
+
+} // namespace blobs
diff --git a/main.cpp b/main.cpp
index 8d94dca..0a43b96 100644
--- a/main.cpp
+++ b/main.cpp
@@ -18,7 +18,17 @@
 {
 HashFileHandler hashHandler;
 StaticLayoutHandler staticLayoutHandler(STATIC_HANDLER_STAGED_NAME);
-LpcDataHandler lpcDataHandler;
+
+#ifdef ENABLE_LPC_BRIDGE
+#if defined(ASPEED_LPC)
+LpcDataHandler lpcDataHandler(LpcMapperAspeed::createAspeedMapper());
+#elif defined(NUVOTON_LPC)
+LpcDataHandler lpcDataHandler(LpcMapperNuvoton::createNuvotonMapper());
+#else
+#error "You must specify a hardware implementation."
+#endif
+#endif
+
 PciDataHandler pciDataHandler(PCI_PHYSICAL_ADDRESS);
 
 std::vector<HandlerPack> supportedFirmware = {
diff --git a/test/lpc_mapper_mock.hpp b/test/lpc_mapper_mock.hpp
new file mode 100644
index 0000000..7d84a8a
--- /dev/null
+++ b/test/lpc_mapper_mock.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "lpc_interface.hpp"
+
+#include <gmock/gmock.h>
+
+namespace blobs
+{
+
+class LpcInterfaceMock : public LpcMapperInterface
+{
+  public:
+    virtual ~LpcInterfaceMock() = default;
+
+    MOCK_METHOD2(mapWindow,
+                 std::pair<std::uint32_t, std::uint32_t>(std::uint32_t,
+                                                         std::uint32_t));
+};
+
+} // namespace blobs