pci: implement sending firmware image over p2a
Implement sending firmware image over p2a via the aspeed-p2a-ctrl
driver.
Test configuration:
# Image is static, uses the PCI bridge, and requires the ASPEED
# PCI-to-AHB hardware implementation.
EXTRA_OECONF_append_quanta-q71l = " --enable-static-layout"
EXTRA_OECONF_append_quanta-q71l = " --enable-pci-bridge"
EXTRA_OECONF_append_quanta-q71l = " --enable-aspeed-p2a"
EXTRA_OECONF_append_quanta-q71l = " MAPPED_ADDRESS=0x47FF0000"
Tested: Verified via md5sum the image-bmc file sent from the host via
this tool matches the hash of /run/initramfs/bmc-image. This code can
be used to send any file down, but was only tested with a "static"
layout build.
Signed-off-by: Patrick Venture <venture@google.com>
Change-Id: I430bc7444f06f4f93a63e3bf2646bd195eaa2e52
diff --git a/pci_handler.cpp b/pci_handler.cpp
index 51a2ca5..56016c7 100644
--- a/pci_handler.cpp
+++ b/pci_handler.cpp
@@ -98,8 +98,10 @@
std::vector<std::uint8_t> PciDataHandler::copyFrom(std::uint32_t length)
{
- /* TODO: implement this. */
- return {};
+ std::vector<std::uint8_t> results(length);
+ std::memcpy(results.data(), mapped, length);
+
+ return results;
}
bool PciDataHandler::writeMeta(const std::vector<std::uint8_t>& configuration)
diff --git a/tools/io.cpp b/tools/io.cpp
index cc9e7d1..420dd94 100644
--- a/tools/io.cpp
+++ b/tools/io.cpp
@@ -16,15 +16,10 @@
bool DevMemDevice::read(const std::size_t offset, const std::size_t length,
void* const destination)
{
- if (!opened)
+ devMemFd = sys->open(devMemPath.c_str(), O_RDONLY);
+ if (devMemFd < 0)
{
- devMemFd = sys->open(devMemPath.c_str(), O_RDWR);
- if (devMemFd < 0)
- {
- return false;
- }
-
- opened = true;
+ return false;
}
/* Map based on aligned addresses - behind the scenes. */
@@ -37,7 +32,10 @@
alignedOffset);
if (devMemMapped == MAP_FAILED)
{
- return false; /* but leave the file open. */
+ std::fprintf(stderr, "Failed to mmap at offset: 0x%lx, length: %lu\n",
+ offset, length);
+ sys->close(devMemFd);
+ return false;
}
void* alignedSource =
@@ -48,6 +46,7 @@
/* Close the map between reads for now. */
sys->munmap(devMemMapped, length);
+ sys->close(devMemFd);
return true;
}
@@ -55,15 +54,11 @@
bool DevMemDevice::write(const std::size_t offset, const std::size_t length,
const void* const source)
{
- if (!opened)
+ devMemFd = sys->open(devMemPath.c_str(), O_RDWR);
+ if (devMemFd < 0)
{
- devMemFd = sys->open(devMemPath.c_str(), O_RDWR);
- if (devMemFd < 0)
- {
- return false;
- }
-
- opened = true;
+ std::fprintf(stderr, "Failed to open /dev/mem for writing\n");
+ return false;
}
/* Map based on aligned addresses - behind the scenes. */
@@ -77,7 +72,10 @@
if (devMemMapped == MAP_FAILED)
{
- return false; /* but leave the file open. */
+ std::fprintf(stderr, "Failed to mmap at offset: 0x%lx, length: %lu\n",
+ offset, length);
+ sys->close(devMemFd);
+ return false;
}
void* alignedDestination =
@@ -88,6 +86,7 @@
/* Close the map between writes for now. */
sys->munmap(devMemMapped, length);
+ sys->close(devMemFd);
return true;
}
diff --git a/tools/io.hpp b/tools/io.hpp
index 0712694..44cd2cb 100644
--- a/tools/io.hpp
+++ b/tools/io.hpp
@@ -47,14 +47,7 @@
{
}
- /* On destruction, close /dev/mem if it was open. */
- ~DevMemDevice()
- {
- if (opened)
- {
- sys->close(devMemFd);
- }
- }
+ ~DevMemDevice() = default;
/* Don't allow copying or assignment, only moving. */
DevMemDevice(const DevMemDevice&) = delete;
@@ -70,7 +63,6 @@
private:
static const std::string devMemPath;
- bool opened = false;
int devMemFd = -1;
void* devMemMapped = nullptr;
const internal::Sys* sys;
diff --git a/tools/p2a.cpp b/tools/p2a.cpp
index 5dcf6c9..dd05ccd 100644
--- a/tools/p2a.cpp
+++ b/tools/p2a.cpp
@@ -16,10 +16,12 @@
#include "p2a.hpp"
+#include "firmware_handler.hpp"
#include "pci.hpp"
#include "pci_handler.hpp"
#include <cstring>
+#include <ipmiblob/blob_errors.hpp>
namespace host_tool
{
@@ -31,6 +33,7 @@
PciUtilImpl pci;
PciFilter filter;
bool found = false;
+ pciaddr_t bar1;
filter.vid = aspeedVendorId;
filter.did = aspeedDeviceId;
@@ -42,13 +45,14 @@
std::fprintf(stderr, "[0x%x 0x%x] ", d.vid, d.did);
/* Verify it's a memory-based bar -- we want bar1. */
- pciaddr_t bar1 = d.bars[1];
+ bar1 = d.bars[1];
if ((bar1 & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
{
/* We want it to not be IO-based access. */
continue;
}
+ /* For now capture the entire device even if we're only using BAR1 */
result = d;
found = true;
break;
@@ -65,7 +69,7 @@
* the bridge enabled.
*/
std::uint32_t value;
- if (!io->read(result.bars[1] | aspeedP2aConfig, sizeof(value), &value))
+ if (!io->read(bar1 | aspeedP2aConfig, sizeof(value), &value))
{
if (0 == (value & p2ABridgeEnabled))
{
@@ -89,16 +93,73 @@
std::memcpy(&pciResp, stat.metadata.data(), sizeof(pciResp));
std::fprintf(stderr, "Received address: 0x%x\n", pciResp.address);
-#if 0
/* Configure the mmio to point there. */
- if (!io->IoWrite(bar | kAspeedP2aBridge, sizeof(phys), &phys)) {
+ if (!io->write(bar1 | aspeedP2aBridge, sizeof(pciResp.address),
+ &pciResp.address))
+ {
// Failed to set it up, so fall back.
std::fprintf(stderr, "Failed to update the bridge address\n");
return false;
}
-#endif
- return false;
+ /* For data blocks in 64kb, stage data, and send blob write command. */
+ int inputFd = sys->open(input.c_str(), 0);
+ if (inputFd < 0)
+ {
+ return false;
+ }
+
+ int bytesRead = 0;
+ std::uint32_t offset = 0;
+ const std::uint32_t p2aLength = aspeedP2aOffset;
+
+ auto readBuffer = std::make_unique<std::uint8_t[]>(p2aLength);
+ if (nullptr == readBuffer)
+ {
+ std::fprintf(stderr, "Unable to allocate memory for read buffer.\n");
+ return false;
+ }
+
+ try
+ {
+ do
+ {
+ bytesRead = sys->read(inputFd, readBuffer.get(), p2aLength);
+ if (bytesRead > 0)
+ {
+ /* TODO: Will likely need to store an rv somewhere to know when
+ * we're exiting from failure.
+ */
+ if (!io->write(bar1 | aspeedP2aOffset, bytesRead,
+ readBuffer.get()))
+ {
+ std::fprintf(stderr,
+ "Failed to write to region in memory!\n");
+ break;
+ }
+
+ /* Ok, so the data is staged, now send the blob write with the
+ * details.
+ */
+ struct blobs::ExtChunkHdr chunk;
+ chunk.length = bytesRead;
+ std::vector<std::uint8_t> chunkBytes(sizeof(chunk));
+ std::memcpy(chunkBytes.data(), &chunk, sizeof(chunk));
+
+ /* This doesn't return anything on success. */
+ blob->writeBytes(session, offset, chunkBytes);
+ offset += bytesRead;
+ }
+ } while (bytesRead > 0);
+ }
+ catch (const ipmiblob::BlobException& b)
+ {
+ sys->close(inputFd);
+ return false;
+ }
+
+ sys->close(inputFd);
+ return true;
}
} // namespace host_tool
diff --git a/tools/p2a.hpp b/tools/p2a.hpp
index f229449..eda8f61 100644
--- a/tools/p2a.hpp
+++ b/tools/p2a.hpp
@@ -1,6 +1,7 @@
#pragma once
#include "interface.hpp"
+#include "internal/sys.hpp"
#include "io.hpp"
#include "pci.hpp"
@@ -9,6 +10,7 @@
constexpr std::uint16_t aspeedVendorId = 0x1a03;
constexpr std::uint16_t aspeedDeviceId = 0x2000;
+constexpr std::size_t aspeedP2aOffset = 0x10000;
constexpr std::size_t aspeedP2aConfig = 0x0f000;
constexpr std::size_t aspeedP2aBridge = 0x0f004;
constexpr std::uint32_t p2ABridgeEnabled = 0x1;
@@ -20,9 +22,10 @@
{
public:
P2aDataHandler(ipmiblob::BlobInterface* blob, HostIoInterface* io,
- PciUtilInterface* pci) :
+ PciUtilInterface* pci,
+ const internal::Sys* sys = &internal::sys_impl) :
blob(blob),
- io(io), pci(pci)
+ io(io), pci(pci), sys(sys)
{
}
@@ -36,6 +39,7 @@
ipmiblob::BlobInterface* blob;
HostIoInterface* io;
PciUtilInterface* pci;
+ const internal::Sys* sys;
};
} // namespace host_tool