xref: /openbmc/phosphor-ipmi-flash/tools/p2a.cpp (revision 63528046)
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 
1918bbe3c6SPatrick Venture #include "firmware_handler.hpp"
20b5bf0fc2SPatrick Venture #include "pci.hpp"
21c73dce91SPatrick Venture #include "pci_handler.hpp"
22c73dce91SPatrick Venture 
23c73dce91SPatrick Venture #include <cstring>
2418bbe3c6SPatrick Venture #include <ipmiblob/blob_errors.hpp>
25b5bf0fc2SPatrick Venture 
26b5bf0fc2SPatrick Venture namespace host_tool
27b5bf0fc2SPatrick Venture {
28b5bf0fc2SPatrick Venture 
29b5bf0fc2SPatrick Venture bool P2aDataHandler::sendContents(const std::string& input,
30b5bf0fc2SPatrick Venture                                   std::uint16_t session)
31b5bf0fc2SPatrick Venture {
3224141611SPatrick Venture     PciDevice result;
33b5bf0fc2SPatrick Venture     PciFilter filter;
3436bb4670SPatrick Venture     bool found = false;
3518bbe3c6SPatrick Venture     pciaddr_t bar1;
36b5bf0fc2SPatrick Venture 
37b5bf0fc2SPatrick Venture     filter.vid = aspeedVendorId;
38b5bf0fc2SPatrick Venture     filter.did = aspeedDeviceId;
39b5bf0fc2SPatrick Venture 
4024141611SPatrick Venture     /* Find the ASPEED PCI device entry we want. */
4146e69491SPatrick Venture     auto output = pci->getPciDevices(filter);
42b5bf0fc2SPatrick Venture     for (const auto& d : output)
43b5bf0fc2SPatrick Venture     {
4424141611SPatrick Venture         std::fprintf(stderr, "[0x%x 0x%x] ", d.vid, d.did);
4524141611SPatrick Venture 
4624141611SPatrick Venture         /* Verify it's a memory-based bar -- we want bar1. */
4718bbe3c6SPatrick Venture         bar1 = d.bars[1];
4824141611SPatrick Venture         if ((bar1 & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
4924141611SPatrick Venture         {
5024141611SPatrick Venture             /* We want it to not be IO-based access. */
5124141611SPatrick Venture             continue;
52b5bf0fc2SPatrick Venture         }
53b5bf0fc2SPatrick Venture 
5418bbe3c6SPatrick Venture         /* For now capture the entire device even if we're only using BAR1 */
5524141611SPatrick Venture         result = d;
5636bb4670SPatrick Venture         found = true;
5736bb4670SPatrick Venture         break;
5824141611SPatrick Venture     }
5936bb4670SPatrick Venture 
6036bb4670SPatrick Venture     if (!found)
6136bb4670SPatrick Venture     {
6236bb4670SPatrick Venture         return false;
6336bb4670SPatrick Venture     }
6436bb4670SPatrick Venture 
6524141611SPatrick Venture     std::fprintf(stderr, "\n");
6624141611SPatrick Venture 
6724141611SPatrick Venture     /* We sent the open command before this, so the window should be open and
6824141611SPatrick Venture      * the bridge enabled.
6924141611SPatrick Venture      */
7024141611SPatrick Venture     std::uint32_t value;
7118bbe3c6SPatrick Venture     if (!io->read(bar1 | aspeedP2aConfig, sizeof(value), &value))
7224141611SPatrick Venture     {
7324141611SPatrick Venture         if (0 == (value & p2ABridgeEnabled))
7424141611SPatrick Venture         {
7524141611SPatrick Venture             std::fprintf(stderr, "Bridge not enabled.\n");
7624141611SPatrick Venture             return false;
7724141611SPatrick Venture         }
7824141611SPatrick Venture     }
7924141611SPatrick Venture 
8024141611SPatrick Venture     std::fprintf(stderr, "The bridge is enabled!\n");
8124141611SPatrick Venture 
8224141611SPatrick Venture     /* Read the configuration via blobs metadata (stat). */
83c73dce91SPatrick Venture     ipmiblob::StatResponse stat = blob->getStat(session);
841d5a31c9SPatrick Venture     if (stat.metadata.size() != sizeof(ipmi_flash::PciConfigResponse))
85c73dce91SPatrick Venture     {
86c73dce91SPatrick Venture         std::fprintf(stderr, "Didn't receive expected size of metadata for "
87c73dce91SPatrick Venture                              "PCI Configuration response\n");
88c73dce91SPatrick Venture         return false;
89c73dce91SPatrick Venture     }
90c73dce91SPatrick Venture 
911d5a31c9SPatrick Venture     ipmi_flash::PciConfigResponse pciResp;
92c73dce91SPatrick Venture     std::memcpy(&pciResp, stat.metadata.data(), sizeof(pciResp));
93c73dce91SPatrick Venture     std::fprintf(stderr, "Received address: 0x%x\n", pciResp.address);
9424141611SPatrick Venture 
9524141611SPatrick Venture     /* Configure the mmio to point there. */
9618bbe3c6SPatrick Venture     if (!io->write(bar1 | aspeedP2aBridge, sizeof(pciResp.address),
9718bbe3c6SPatrick Venture                    &pciResp.address))
9818bbe3c6SPatrick Venture     {
9924141611SPatrick Venture         // Failed to set it up, so fall back.
10024141611SPatrick Venture         std::fprintf(stderr, "Failed to update the bridge address\n");
10124141611SPatrick Venture         return false;
10224141611SPatrick Venture     }
10324141611SPatrick Venture 
10418bbe3c6SPatrick Venture     /* For data blocks in 64kb, stage data, and send blob write command. */
10518bbe3c6SPatrick Venture     int inputFd = sys->open(input.c_str(), 0);
10618bbe3c6SPatrick Venture     if (inputFd < 0)
10718bbe3c6SPatrick Venture     {
108b5bf0fc2SPatrick Venture         return false;
109b5bf0fc2SPatrick Venture     }
110b5bf0fc2SPatrick Venture 
11118bbe3c6SPatrick Venture     const std::uint32_t p2aLength = aspeedP2aOffset;
11218bbe3c6SPatrick Venture 
11318bbe3c6SPatrick Venture     auto readBuffer = std::make_unique<std::uint8_t[]>(p2aLength);
11418bbe3c6SPatrick Venture     if (nullptr == readBuffer)
11518bbe3c6SPatrick Venture     {
11618bbe3c6SPatrick Venture         std::fprintf(stderr, "Unable to allocate memory for read buffer.\n");
11718bbe3c6SPatrick Venture         return false;
11818bbe3c6SPatrick Venture     }
11918bbe3c6SPatrick Venture 
12018bbe3c6SPatrick Venture     try
12118bbe3c6SPatrick Venture     {
122*63528046SPatrick Venture         int bytesRead = 0;
123*63528046SPatrick Venture         std::uint32_t offset = 0;
124*63528046SPatrick Venture 
12518bbe3c6SPatrick Venture         do
12618bbe3c6SPatrick Venture         {
12718bbe3c6SPatrick Venture             bytesRead = sys->read(inputFd, readBuffer.get(), p2aLength);
12818bbe3c6SPatrick Venture             if (bytesRead > 0)
12918bbe3c6SPatrick Venture             {
13018bbe3c6SPatrick Venture                 /* TODO: Will likely need to store an rv somewhere to know when
13118bbe3c6SPatrick Venture                  * we're exiting from failure.
13218bbe3c6SPatrick Venture                  */
13318bbe3c6SPatrick Venture                 if (!io->write(bar1 | aspeedP2aOffset, bytesRead,
13418bbe3c6SPatrick Venture                                readBuffer.get()))
13518bbe3c6SPatrick Venture                 {
13618bbe3c6SPatrick Venture                     std::fprintf(stderr,
13718bbe3c6SPatrick Venture                                  "Failed to write to region in memory!\n");
13818bbe3c6SPatrick Venture                     break;
13918bbe3c6SPatrick Venture                 }
14018bbe3c6SPatrick Venture 
14118bbe3c6SPatrick Venture                 /* Ok, so the data is staged, now send the blob write with the
14218bbe3c6SPatrick Venture                  * details.
14318bbe3c6SPatrick Venture                  */
1441d5a31c9SPatrick Venture                 struct ipmi_flash::ExtChunkHdr chunk;
14518bbe3c6SPatrick Venture                 chunk.length = bytesRead;
14618bbe3c6SPatrick Venture                 std::vector<std::uint8_t> chunkBytes(sizeof(chunk));
14718bbe3c6SPatrick Venture                 std::memcpy(chunkBytes.data(), &chunk, sizeof(chunk));
14818bbe3c6SPatrick Venture 
14918bbe3c6SPatrick Venture                 /* This doesn't return anything on success. */
15018bbe3c6SPatrick Venture                 blob->writeBytes(session, offset, chunkBytes);
15118bbe3c6SPatrick Venture                 offset += bytesRead;
15218bbe3c6SPatrick Venture             }
15318bbe3c6SPatrick Venture         } while (bytesRead > 0);
15418bbe3c6SPatrick Venture     }
15518bbe3c6SPatrick Venture     catch (const ipmiblob::BlobException& b)
15618bbe3c6SPatrick Venture     {
15718bbe3c6SPatrick Venture         sys->close(inputFd);
15818bbe3c6SPatrick Venture         return false;
15918bbe3c6SPatrick Venture     }
16018bbe3c6SPatrick Venture 
16118bbe3c6SPatrick Venture     sys->close(inputFd);
16218bbe3c6SPatrick Venture     return true;
16318bbe3c6SPatrick Venture }
16418bbe3c6SPatrick Venture 
165b5bf0fc2SPatrick Venture } // namespace host_tool
166