diff options
| author | Patrick Venture <venture@google.com> | 2019-05-14 11:40:57 -0700 |
|---|---|---|
| committer | Patrick Venture <venture@google.com> | 2019-05-14 21:09:24 +0000 |
| commit | 18bbe3c686c2ff1dd202161aaeb4d9e0d971cafe (patch) | |
| tree | ca9d0c9c18646a1cb040012c558d2930d2cce5c0 /tools | |
| parent | e564d5bcb43d45a694a7b0a7c9fec3090dd8b107 (diff) | |
| download | phosphor-ipmi-flash-18bbe3c686c2ff1dd202161aaeb4d9e0d971cafe.tar.gz phosphor-ipmi-flash-18bbe3c686c2ff1dd202161aaeb4d9e0d971cafe.zip | |
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
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/io.cpp | 35 | ||||
| -rw-r--r-- | tools/io.hpp | 10 | ||||
| -rw-r--r-- | tools/p2a.cpp | 73 | ||||
| -rw-r--r-- | tools/p2a.hpp | 8 |
4 files changed, 91 insertions, 35 deletions
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 @@ const std::string DevMemDevice::devMemPath = "/dev/mem"; 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 @@ bool DevMemDevice::read(const std::size_t offset, const std::size_t length, 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 @@ bool DevMemDevice::read(const std::size_t offset, const std::size_t length, /* Close the map between reads for now. */ sys->munmap(devMemMapped, length); + sys->close(devMemFd); return true; } @@ -55,15 +54,11 @@ bool DevMemDevice::read(const std::size_t offset, const std::size_t length, 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 @@ bool DevMemDevice::write(const std::size_t offset, const std::size_t length, 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 @@ bool DevMemDevice::write(const std::size_t offset, const std::size_t length, /* 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 @@ class DevMemDevice : public HostIoInterface { } - /* 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 @@ class DevMemDevice : public HostIoInterface 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 @@ bool P2aDataHandler::sendContents(const std::string& input, PciUtilImpl pci; PciFilter filter; bool found = false; + pciaddr_t bar1; filter.vid = aspeedVendorId; filter.did = aspeedDeviceId; @@ -42,13 +45,14 @@ bool P2aDataHandler::sendContents(const std::string& input, 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 @@ bool P2aDataHandler::sendContents(const std::string& input, * 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 @@ bool P2aDataHandler::sendContents(const std::string& input, 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 @@ class P2aDataHandler : public DataInterface { 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 @@ class P2aDataHandler : public DataInterface ipmiblob::BlobInterface* blob; HostIoInterface* io; PciUtilInterface* pci; + const internal::Sys* sys; }; } // namespace host_tool |

