p2a: add initial p2a support (empty)

Add initial pci-to-ahb host-side support, by just listing the aspeed pci
devices.

Tested: This dumped the aspeed PCI device listed on my test platform.
Change-Id: I6dc4aeb3b38ec2f95bfd716bda2d8eb4786328ab
Signed-off-by: Patrick Venture <venture@google.com>
diff --git a/tools/Makefile.am b/tools/Makefile.am
index d86d365..7d07434 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -12,4 +12,6 @@
 	bt.cpp \
 	lpc.cpp \
 	io.cpp \
+	pci.cpp \
+	p2a.cpp \
 	../internal/sys.cpp
diff --git a/tools/main.cpp b/tools/main.cpp
index f676f6a..3b9760c 100644
--- a/tools/main.cpp
+++ b/tools/main.cpp
@@ -17,6 +17,8 @@
 #include "bt.hpp"
 #include "io.hpp"
 #include "lpc.hpp"
+#include "p2a.hpp"
+#include "pci.hpp"
 #include "tool_errors.hpp"
 #include "updater.hpp"
 
@@ -34,11 +36,12 @@
 #include <vector>
 
 #define IPMILPC "ipmilpc"
+#define IPMIPCI "ipmipci"
 #define IPMIBT "ipmibt"
 
 namespace
 {
-const std::vector<std::string> interfaceList = {IPMIBT, IPMILPC};
+const std::vector<std::string> interfaceList = {IPMIBT, IPMILPC, IPMIPCI};
 }
 
 void usage(const char* program)
@@ -140,6 +143,7 @@
         ipmiblob::IpmiHandler ipmi;
         ipmiblob::BlobHandler blob(&ipmi);
         host_tool::DevMemDevice devmem;
+        host_tool::PciUtilImpl pci;
 
         std::unique_ptr<host_tool::DataInterface> handler;
 
@@ -153,6 +157,11 @@
             handler =
                 std::make_unique<host_tool::LpcDataHandler>(&blob, &devmem);
         }
+        else if (interface == IPMIPCI)
+        {
+            handler = std::make_unique<host_tool::P2aDataHandler>(
+                &blob, &devmem, &pci);
+        }
 
         if (!handler)
         {
diff --git a/tools/p2a.cpp b/tools/p2a.cpp
new file mode 100644
index 0000000..6d0ab37
--- /dev/null
+++ b/tools/p2a.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "p2a.hpp"
+
+#include "pci.hpp"
+
+namespace host_tool
+{
+
+bool P2aDataHandler::sendContents(const std::string& input,
+                                  std::uint16_t session)
+{
+    PciUtilImpl pci;
+    PciFilter filter;
+
+    filter.vid = aspeedVendorId;
+    filter.did = aspeedDeviceId;
+
+    auto output = pci.getPciDevices(filter);
+    for (const auto& d : output)
+    {
+        std::fprintf(stderr, "0x%x", d.vid);
+    }
+
+    return false;
+}
+
+} // namespace host_tool
diff --git a/tools/p2a.hpp b/tools/p2a.hpp
new file mode 100644
index 0000000..4c02107
--- /dev/null
+++ b/tools/p2a.hpp
@@ -0,0 +1,38 @@
+#pragma once
+
+#include "interface.hpp"
+#include "io.hpp"
+#include "pci.hpp"
+
+#include <cstdint>
+#include <ipmiblob/blob_interface.hpp>
+
+constexpr std::uint16_t aspeedVendorId = 0x1a03;
+constexpr std::uint16_t aspeedDeviceId = 0x2000;
+
+namespace host_tool
+{
+
+class P2aDataHandler : public DataInterface
+{
+  public:
+    P2aDataHandler(ipmiblob::BlobInterface* blob, HostIoInterface* io,
+                   PciUtilInterface* pci) :
+        blob(blob),
+        io(io), pci(pci)
+    {
+    }
+
+    bool sendContents(const std::string& input, std::uint16_t session) override;
+    blobs::FirmwareBlobHandler::UpdateFlags supportedType() const override
+    {
+        return blobs::FirmwareBlobHandler::UpdateFlags::p2a;
+    }
+
+  private:
+    ipmiblob::BlobInterface* blob;
+    HostIoInterface* io;
+    PciUtilInterface* pci;
+};
+
+} // namespace host_tool
diff --git a/tools/pci.cpp b/tools/pci.cpp
new file mode 100644
index 0000000..2f283e6
--- /dev/null
+++ b/tools/pci.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "pci.hpp"
+
+extern "C" {
+#include <pci/pci.h>
+} // extern "C"
+
+#include <optional>
+#include <vector>
+
+namespace host_tool
+{
+
+std::vector<PciDevice>
+    PciUtilImpl::getPciDevices(std::optional<PciFilter> filter)
+{
+    PciFilter test;
+    bool check = false;
+    std::vector<PciDevice> results;
+
+    if (filter.has_value())
+    {
+        test = filter.value();
+        check = true;
+    }
+
+    pci_scan_bus(pacc);
+    struct pci_dev* dev;
+
+    for (dev = pacc->devices; dev; dev = dev->next)
+    {
+        PciDevice item;
+
+        pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS);
+
+        item.bus = dev->bus;
+        item.dev = dev->dev;
+        item.func = dev->func;
+        item.vid = dev->vendor_id;
+        item.did = dev->device_id;
+
+        if (check)
+        {
+            if (test.vid == dev->vendor_id && test.did == dev->device_id)
+            {
+                results.push_back(item);
+            }
+        }
+        else
+        {
+            results.push_back(item);
+        }
+    }
+
+    return results;
+}
+
+} // namespace host_tool
diff --git a/tools/pci.hpp b/tools/pci.hpp
new file mode 100644
index 0000000..96f1ea4
--- /dev/null
+++ b/tools/pci.hpp
@@ -0,0 +1,73 @@
+#pragma once
+
+extern "C" {
+#include <pci/pci.h>
+} // extern "C"
+
+#include <optional>
+#include <vector>
+
+namespace host_tool
+{
+
+/* The ASPEED AST2400 & AST2500 have the same VIDDID. */
+
+/**
+ * The PciDevice structure is a copy of the information to uniquely identify a
+ * PCI device.
+ */
+struct PciDevice
+{
+    int vid;
+    int did;
+    int bus;
+    int dev;
+    int func;
+};
+
+/**
+ * The PciFilter structure is a simple mechanism for filtering devices by their
+ * vendor and/or device ids.
+ */
+struct PciFilter
+{
+    int vid;
+    int did;
+};
+
+class PciUtilInterface
+{
+  public:
+    virtual ~PciUtilInterface() = default;
+
+    /**
+     * Get a list of PCI devices from a system.
+     *
+     * @param[in] filter - optional filter for the list.
+     * @return the list of devices.
+     */
+    virtual std::vector<PciDevice>
+        getPciDevices(std::optional<PciFilter> filter = std::nullopt) = 0;
+};
+
+class PciUtilImpl : public PciUtilInterface
+{
+  public:
+    PciUtilImpl()
+    {
+        pacc = pci_alloc();
+        pci_init(pacc);
+    }
+    ~PciUtilImpl()
+    {
+        pci_cleanup(pacc);
+    }
+
+    std::vector<PciDevice>
+        getPciDevices(std::optional<PciFilter> filter = std::nullopt) override;
+
+  private:
+    struct pci_access* pacc;
+};
+
+} // namespace host_tool