1b5bf0fc2SPatrick Venture /* 2b5bf0fc2SPatrick Venture * Copyright 2019 Google Inc. 3b5bf0fc2SPatrick Venture * 4b5bf0fc2SPatrick Venture * Licensed under the Apache License, Version 2.0 (the "License"); 5b5bf0fc2SPatrick Venture * you may not use this file except in compliance with the License. 6b5bf0fc2SPatrick Venture * You may obtain a copy of the License at 7b5bf0fc2SPatrick Venture * 8b5bf0fc2SPatrick Venture * http://www.apache.org/licenses/LICENSE-2.0 9b5bf0fc2SPatrick Venture * 10b5bf0fc2SPatrick Venture * Unless required by applicable law or agreed to in writing, software 11b5bf0fc2SPatrick Venture * distributed under the License is distributed on an "AS IS" BASIS, 12b5bf0fc2SPatrick Venture * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b5bf0fc2SPatrick Venture * See the License for the specific language governing permissions and 14b5bf0fc2SPatrick Venture * limitations under the License. 15b5bf0fc2SPatrick Venture */ 16b5bf0fc2SPatrick Venture 17b5bf0fc2SPatrick Venture #include "p2a.hpp" 18b5bf0fc2SPatrick Venture 1984778b8dSPatrick Venture #include "data.hpp" 2084778b8dSPatrick Venture #include "flags.hpp" 21b5bf0fc2SPatrick Venture #include "pci.hpp" 22c73dce91SPatrick Venture 23*9b37b095SPatrick Venture #include <ipmiblob/blob_errors.hpp> 24*9b37b095SPatrick Venture 2584778b8dSPatrick Venture #include <cstdint> 26c73dce91SPatrick Venture #include <cstring> 2784778b8dSPatrick Venture #include <memory> 2884778b8dSPatrick Venture #include <string> 29b5bf0fc2SPatrick Venture 30b5bf0fc2SPatrick Venture namespace host_tool 31b5bf0fc2SPatrick Venture { 32b5bf0fc2SPatrick Venture 33cf0e5de3SPatrick Venture namespace 34cf0e5de3SPatrick Venture { 35cf0e5de3SPatrick Venture void disablePciBridge(HostIoInterface* io, std::size_t address) 36cf0e5de3SPatrick Venture { 37cf0e5de3SPatrick Venture /* Read current value, and just blindly unset the bit. */ 38cf0e5de3SPatrick Venture std::uint32_t value; 39cf0e5de3SPatrick Venture if (!io->read(address + aspeedP2aConfig, sizeof(value), &value)) 40cf0e5de3SPatrick Venture { 41cf0e5de3SPatrick Venture return; 42cf0e5de3SPatrick Venture } 43cf0e5de3SPatrick Venture 44cf0e5de3SPatrick Venture value &= ~p2ABridgeEnabled; 45cf0e5de3SPatrick Venture io->write(address + aspeedP2aConfig, sizeof(value), &value); 46cf0e5de3SPatrick Venture } 47cf0e5de3SPatrick Venture 48cf0e5de3SPatrick Venture } // namespace 49cf0e5de3SPatrick Venture 50b5bf0fc2SPatrick Venture bool P2aDataHandler::sendContents(const std::string& input, 51b5bf0fc2SPatrick Venture std::uint16_t session) 52b5bf0fc2SPatrick Venture { 5324141611SPatrick Venture PciDevice result; 54b5bf0fc2SPatrick Venture PciFilter filter; 5536bb4670SPatrick Venture bool found = false; 56c8445aaaSMedad CChien pciaddr_t bar; 57cf0e5de3SPatrick Venture bool returnValue = false; 58cf0e5de3SPatrick Venture int inputFd = -1; 59cf0e5de3SPatrick Venture ipmi_flash::PciConfigResponse pciResp; 60cf0e5de3SPatrick Venture std::int64_t fileSize; 61cf0e5de3SPatrick Venture std::unique_ptr<std::uint8_t[]> readBuffer; 62b5bf0fc2SPatrick Venture 63c8445aaaSMedad CChien std::uint16_t pciDeviceVID; 64c8445aaaSMedad CChien std::uint16_t pciDeviceDID; 65c8445aaaSMedad CChien std::uint32_t p2aOffset; 66c8445aaaSMedad CChien std::uint32_t p2aLength; 67b5bf0fc2SPatrick Venture 68c8445aaaSMedad CChien for (auto device : PCIDeviceList) 69c8445aaaSMedad CChien { 70c8445aaaSMedad CChien filter.vid = device.VID; 71c8445aaaSMedad CChien filter.did = device.DID; 72c8445aaaSMedad CChien 73c8445aaaSMedad CChien /* Find the PCI device entry we want. */ 7446e69491SPatrick Venture auto output = pci->getPciDevices(filter); 75b5bf0fc2SPatrick Venture for (const auto& d : output) 76b5bf0fc2SPatrick Venture { 77c8445aaaSMedad CChien std::fprintf(stderr, "[0x%x 0x%x] \n", d.vid, d.did); 7824141611SPatrick Venture 79c8445aaaSMedad CChien /* Verify it's a memory-based bar. */ 80c8445aaaSMedad CChien bar = d.bars[device.bar]; 81c8445aaaSMedad CChien 82c8445aaaSMedad CChien if ((bar & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) 8324141611SPatrick Venture { 8424141611SPatrick Venture /* We want it to not be IO-based access. */ 8524141611SPatrick Venture continue; 86b5bf0fc2SPatrick Venture } 87b5bf0fc2SPatrick Venture 88c8445aaaSMedad CChien /* For now capture the entire device even if we're only using BAR0 89c8445aaaSMedad CChien */ 9024141611SPatrick Venture result = d; 9136bb4670SPatrick Venture found = true; 9236bb4670SPatrick Venture break; 9324141611SPatrick Venture } 9436bb4670SPatrick Venture 95c8445aaaSMedad CChien if (found) 96c8445aaaSMedad CChien { 97c8445aaaSMedad CChien std::fprintf(stderr, "Find [0x%x 0x%x] \n", device.VID, device.DID); 98c8445aaaSMedad CChien std::fprintf(stderr, "bar%u[0x%x] \n", device.bar, 99c8445aaaSMedad CChien (unsigned int)bar); 100c8445aaaSMedad CChien pciDeviceVID = device.VID; 101c8445aaaSMedad CChien pciDeviceDID = device.DID; 102c8445aaaSMedad CChien p2aOffset = device.Offset; 103c8445aaaSMedad CChien p2aLength = device.Length; 104c8445aaaSMedad CChien break; 105c8445aaaSMedad CChien } 106c8445aaaSMedad CChien } 107c8445aaaSMedad CChien 10836bb4670SPatrick Venture if (!found) 10936bb4670SPatrick Venture { 11036bb4670SPatrick Venture return false; 11136bb4670SPatrick Venture } 11236bb4670SPatrick Venture 11324141611SPatrick Venture std::fprintf(stderr, "\n"); 11424141611SPatrick Venture 11524141611SPatrick Venture /* We sent the open command before this, so the window should be open and 116cf0e5de3SPatrick Venture * the bridge enabled on the BMC. 11724141611SPatrick Venture */ 118c8445aaaSMedad CChien if (pciDeviceVID == aspeedPciDeviceInfo.VID && 119c8445aaaSMedad CChien pciDeviceDID == aspeedPciDeviceInfo.DID) 120c8445aaaSMedad CChien { 12124141611SPatrick Venture std::uint32_t value; 122c8445aaaSMedad CChien if (!io->read(bar + aspeedP2aConfig, sizeof(value), &value)) 12324141611SPatrick Venture { 124e3feacfaSPatrick Venture std::fprintf(stderr, "PCI config read failed\n"); 125e3feacfaSPatrick Venture return false; 126e3feacfaSPatrick Venture } 127e3feacfaSPatrick Venture 12824141611SPatrick Venture if (0 == (value & p2ABridgeEnabled)) 12924141611SPatrick Venture { 130cf0e5de3SPatrick Venture std::fprintf(stderr, "Bridge not enabled - Enabling from host\n"); 131cf0e5de3SPatrick Venture 132cf0e5de3SPatrick Venture value |= p2ABridgeEnabled; 133c8445aaaSMedad CChien if (!io->write(bar + aspeedP2aConfig, sizeof(value), &value)) 134cf0e5de3SPatrick Venture { 135cf0e5de3SPatrick Venture std::fprintf(stderr, "PCI config write failed\n"); 13624141611SPatrick Venture return false; 13724141611SPatrick Venture } 138cf0e5de3SPatrick Venture } 13924141611SPatrick Venture 140cf0e5de3SPatrick Venture /* From this point down we need to disable the bridge. */ 14124141611SPatrick Venture std::fprintf(stderr, "The bridge is enabled!\n"); 142c8445aaaSMedad CChien } 14324141611SPatrick Venture 14424141611SPatrick Venture /* Read the configuration via blobs metadata (stat). */ 145c73dce91SPatrick Venture ipmiblob::StatResponse stat = blob->getStat(session); 1461d5a31c9SPatrick Venture if (stat.metadata.size() != sizeof(ipmi_flash::PciConfigResponse)) 147c73dce91SPatrick Venture { 148c73dce91SPatrick Venture std::fprintf(stderr, "Didn't receive expected size of metadata for " 149c73dce91SPatrick Venture "PCI Configuration response\n"); 150cf0e5de3SPatrick Venture goto exit; 151c73dce91SPatrick Venture } 152c73dce91SPatrick Venture 153c73dce91SPatrick Venture std::memcpy(&pciResp, stat.metadata.data(), sizeof(pciResp)); 154c73dce91SPatrick Venture std::fprintf(stderr, "Received address: 0x%x\n", pciResp.address); 15524141611SPatrick Venture 156c8445aaaSMedad CChien if (pciDeviceVID == aspeedPciDeviceInfo.VID && 157c8445aaaSMedad CChien pciDeviceDID == aspeedPciDeviceInfo.DID) 158c8445aaaSMedad CChien { 15924141611SPatrick Venture /* Configure the mmio to point there. */ 160c8445aaaSMedad CChien if (!io->write(bar + aspeedP2aBridge, sizeof(pciResp.address), 16118bbe3c6SPatrick Venture &pciResp.address)) 16218bbe3c6SPatrick Venture { 16324141611SPatrick Venture // Failed to set it up, so fall back. 16424141611SPatrick Venture std::fprintf(stderr, "Failed to update the bridge address\n"); 165cf0e5de3SPatrick Venture goto exit; 16624141611SPatrick Venture } 167c8445aaaSMedad CChien } 16824141611SPatrick Venture 16918bbe3c6SPatrick Venture /* For data blocks in 64kb, stage data, and send blob write command. */ 170cf0e5de3SPatrick Venture inputFd = sys->open(input.c_str(), 0); 17118bbe3c6SPatrick Venture if (inputFd < 0) 17218bbe3c6SPatrick Venture { 173cf0e5de3SPatrick Venture std::fprintf(stderr, "Unable to open file: '%s'\n", input.c_str()); 174cf0e5de3SPatrick Venture goto exit; 175b5bf0fc2SPatrick Venture } 176b5bf0fc2SPatrick Venture 177cf0e5de3SPatrick Venture fileSize = sys->getSize(input.c_str()); 178cf9b2195SPatrick Venture if (fileSize == 0) 179cf9b2195SPatrick Venture { 180cf9b2195SPatrick Venture std::fprintf(stderr, "Zero-length file, or other file access error\n"); 181cf0e5de3SPatrick Venture goto exit; 182cf9b2195SPatrick Venture } 183cf9b2195SPatrick Venture 184cf9b2195SPatrick Venture progress->start(fileSize); 185cf9b2195SPatrick Venture 186cf0e5de3SPatrick Venture readBuffer = std::make_unique<std::uint8_t[]>(p2aLength); 18718bbe3c6SPatrick Venture if (nullptr == readBuffer) 18818bbe3c6SPatrick Venture { 18918bbe3c6SPatrick Venture std::fprintf(stderr, "Unable to allocate memory for read buffer.\n"); 190cf0e5de3SPatrick Venture goto exit; 19118bbe3c6SPatrick Venture } 19218bbe3c6SPatrick Venture 19318bbe3c6SPatrick Venture try 19418bbe3c6SPatrick Venture { 19563528046SPatrick Venture int bytesRead = 0; 19663528046SPatrick Venture std::uint32_t offset = 0; 19763528046SPatrick Venture 19818bbe3c6SPatrick Venture do 19918bbe3c6SPatrick Venture { 20018bbe3c6SPatrick Venture bytesRead = sys->read(inputFd, readBuffer.get(), p2aLength); 20118bbe3c6SPatrick Venture if (bytesRead > 0) 20218bbe3c6SPatrick Venture { 203c8445aaaSMedad CChien /* TODO: Will likely need to store an rv somewhere to know when 204c8445aaaSMedad CChien * we're exiting from failure. 20518bbe3c6SPatrick Venture */ 206c8445aaaSMedad CChien if (!io->write(bar + p2aOffset, bytesRead, readBuffer.get())) 20718bbe3c6SPatrick Venture { 20818bbe3c6SPatrick Venture std::fprintf(stderr, 20918bbe3c6SPatrick Venture "Failed to write to region in memory!\n"); 210cf0e5de3SPatrick Venture goto exit; 21118bbe3c6SPatrick Venture } 21218bbe3c6SPatrick Venture 213c8445aaaSMedad CChien /* Ok, so the data is staged, now send the blob write with the 214c8445aaaSMedad CChien * details. 21518bbe3c6SPatrick Venture */ 2161d5a31c9SPatrick Venture struct ipmi_flash::ExtChunkHdr chunk; 21718bbe3c6SPatrick Venture chunk.length = bytesRead; 21818bbe3c6SPatrick Venture std::vector<std::uint8_t> chunkBytes(sizeof(chunk)); 21918bbe3c6SPatrick Venture std::memcpy(chunkBytes.data(), &chunk, sizeof(chunk)); 22018bbe3c6SPatrick Venture 22118bbe3c6SPatrick Venture /* This doesn't return anything on success. */ 22218bbe3c6SPatrick Venture blob->writeBytes(session, offset, chunkBytes); 22318bbe3c6SPatrick Venture offset += bytesRead; 224cf9b2195SPatrick Venture progress->updateProgress(bytesRead); 22518bbe3c6SPatrick Venture } 22618bbe3c6SPatrick Venture } while (bytesRead > 0); 22718bbe3c6SPatrick Venture } 22818bbe3c6SPatrick Venture catch (const ipmiblob::BlobException& b) 22918bbe3c6SPatrick Venture { 230cf0e5de3SPatrick Venture goto exit; 23118bbe3c6SPatrick Venture } 23218bbe3c6SPatrick Venture 233cf0e5de3SPatrick Venture /* defaults to failure. */ 234cf0e5de3SPatrick Venture returnValue = true; 235cf0e5de3SPatrick Venture 236cf0e5de3SPatrick Venture exit: 237c8445aaaSMedad CChien /* disable ASPEED PCI bridge. */ 238c8445aaaSMedad CChien if (pciDeviceVID == aspeedPciDeviceInfo.VID && 239c8445aaaSMedad CChien pciDeviceDID == aspeedPciDeviceInfo.DID) 240c8445aaaSMedad CChien { 241c8445aaaSMedad CChien disablePciBridge(io, bar); 242c8445aaaSMedad CChien } 243cf0e5de3SPatrick Venture 244cf0e5de3SPatrick Venture /* close input file. */ 245cf0e5de3SPatrick Venture if (inputFd != -1) 246cf0e5de3SPatrick Venture { 24718bbe3c6SPatrick Venture sys->close(inputFd); 248cf0e5de3SPatrick Venture } 249cf0e5de3SPatrick Venture return returnValue; 25018bbe3c6SPatrick Venture } 25118bbe3c6SPatrick Venture 252b5bf0fc2SPatrick Venture } // namespace host_tool 253