xref: /openbmc/phosphor-ipmi-flash/tools/p2a.cpp (revision cf9b2195)
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 
2384778b8dSPatrick Venture #include <cstdint>
24c73dce91SPatrick Venture #include <cstring>
2518bbe3c6SPatrick Venture #include <ipmiblob/blob_errors.hpp>
2684778b8dSPatrick Venture #include <memory>
2784778b8dSPatrick Venture #include <string>
28b5bf0fc2SPatrick Venture 
29b5bf0fc2SPatrick Venture namespace host_tool
30b5bf0fc2SPatrick Venture {
31b5bf0fc2SPatrick Venture 
32b5bf0fc2SPatrick Venture bool P2aDataHandler::sendContents(const std::string& input,
33b5bf0fc2SPatrick Venture                                   std::uint16_t session)
34b5bf0fc2SPatrick Venture {
3524141611SPatrick Venture     PciDevice result;
36b5bf0fc2SPatrick Venture     PciFilter filter;
3736bb4670SPatrick Venture     bool found = false;
3818bbe3c6SPatrick Venture     pciaddr_t bar1;
39b5bf0fc2SPatrick Venture 
40b5bf0fc2SPatrick Venture     filter.vid = aspeedVendorId;
41b5bf0fc2SPatrick Venture     filter.did = aspeedDeviceId;
42b5bf0fc2SPatrick Venture 
4324141611SPatrick Venture     /* Find the ASPEED PCI device entry we want. */
4446e69491SPatrick Venture     auto output = pci->getPciDevices(filter);
45b5bf0fc2SPatrick Venture     for (const auto& d : output)
46b5bf0fc2SPatrick Venture     {
4724141611SPatrick Venture         std::fprintf(stderr, "[0x%x 0x%x] ", d.vid, d.did);
4824141611SPatrick Venture 
4924141611SPatrick Venture         /* Verify it's a memory-based bar -- we want bar1. */
5018bbe3c6SPatrick Venture         bar1 = d.bars[1];
5124141611SPatrick Venture         if ((bar1 & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
5224141611SPatrick Venture         {
5324141611SPatrick Venture             /* We want it to not be IO-based access. */
5424141611SPatrick Venture             continue;
55b5bf0fc2SPatrick Venture         }
56b5bf0fc2SPatrick Venture 
5718bbe3c6SPatrick Venture         /* For now capture the entire device even if we're only using BAR1 */
5824141611SPatrick Venture         result = d;
5936bb4670SPatrick Venture         found = true;
6036bb4670SPatrick Venture         break;
6124141611SPatrick Venture     }
6236bb4670SPatrick Venture 
6336bb4670SPatrick Venture     if (!found)
6436bb4670SPatrick Venture     {
6536bb4670SPatrick Venture         return false;
6636bb4670SPatrick Venture     }
6736bb4670SPatrick Venture 
6824141611SPatrick Venture     std::fprintf(stderr, "\n");
6924141611SPatrick Venture 
7024141611SPatrick Venture     /* We sent the open command before this, so the window should be open and
7124141611SPatrick Venture      * the bridge enabled.
7224141611SPatrick Venture      */
7324141611SPatrick Venture     std::uint32_t value;
7418bbe3c6SPatrick Venture     if (!io->read(bar1 | aspeedP2aConfig, sizeof(value), &value))
7524141611SPatrick Venture     {
7624141611SPatrick Venture         if (0 == (value & p2ABridgeEnabled))
7724141611SPatrick Venture         {
7824141611SPatrick Venture             std::fprintf(stderr, "Bridge not enabled.\n");
7924141611SPatrick Venture             return false;
8024141611SPatrick Venture         }
8124141611SPatrick Venture     }
8224141611SPatrick Venture 
8324141611SPatrick Venture     std::fprintf(stderr, "The bridge is enabled!\n");
8424141611SPatrick Venture 
8524141611SPatrick Venture     /* Read the configuration via blobs metadata (stat). */
86c73dce91SPatrick Venture     ipmiblob::StatResponse stat = blob->getStat(session);
871d5a31c9SPatrick Venture     if (stat.metadata.size() != sizeof(ipmi_flash::PciConfigResponse))
88c73dce91SPatrick Venture     {
89c73dce91SPatrick Venture         std::fprintf(stderr, "Didn't receive expected size of metadata for "
90c73dce91SPatrick Venture                              "PCI Configuration response\n");
91c73dce91SPatrick Venture         return false;
92c73dce91SPatrick Venture     }
93c73dce91SPatrick Venture 
941d5a31c9SPatrick Venture     ipmi_flash::PciConfigResponse pciResp;
95c73dce91SPatrick Venture     std::memcpy(&pciResp, stat.metadata.data(), sizeof(pciResp));
96c73dce91SPatrick Venture     std::fprintf(stderr, "Received address: 0x%x\n", pciResp.address);
9724141611SPatrick Venture 
9824141611SPatrick Venture     /* Configure the mmio to point there. */
9918bbe3c6SPatrick Venture     if (!io->write(bar1 | aspeedP2aBridge, sizeof(pciResp.address),
10018bbe3c6SPatrick Venture                    &pciResp.address))
10118bbe3c6SPatrick Venture     {
10224141611SPatrick Venture         // Failed to set it up, so fall back.
10324141611SPatrick Venture         std::fprintf(stderr, "Failed to update the bridge address\n");
10424141611SPatrick Venture         return false;
10524141611SPatrick Venture     }
10624141611SPatrick Venture 
10718bbe3c6SPatrick Venture     /* For data blocks in 64kb, stage data, and send blob write command. */
10818bbe3c6SPatrick Venture     int inputFd = sys->open(input.c_str(), 0);
10918bbe3c6SPatrick Venture     if (inputFd < 0)
11018bbe3c6SPatrick Venture     {
111b5bf0fc2SPatrick Venture         return false;
112b5bf0fc2SPatrick Venture     }
113b5bf0fc2SPatrick Venture 
114*cf9b2195SPatrick Venture     std::int64_t fileSize = sys->getSize(input.c_str());
115*cf9b2195SPatrick Venture     if (fileSize == 0)
116*cf9b2195SPatrick Venture     {
117*cf9b2195SPatrick Venture         std::fprintf(stderr, "Zero-length file, or other file access error\n");
118*cf9b2195SPatrick Venture         return false;
119*cf9b2195SPatrick Venture     }
120*cf9b2195SPatrick Venture 
121*cf9b2195SPatrick Venture     progress->start(fileSize);
122*cf9b2195SPatrick Venture 
12318bbe3c6SPatrick Venture     const std::uint32_t p2aLength = aspeedP2aOffset;
12418bbe3c6SPatrick Venture 
12518bbe3c6SPatrick Venture     auto readBuffer = std::make_unique<std::uint8_t[]>(p2aLength);
12618bbe3c6SPatrick Venture     if (nullptr == readBuffer)
12718bbe3c6SPatrick Venture     {
12818bbe3c6SPatrick Venture         std::fprintf(stderr, "Unable to allocate memory for read buffer.\n");
12918bbe3c6SPatrick Venture         return false;
13018bbe3c6SPatrick Venture     }
13118bbe3c6SPatrick Venture 
13218bbe3c6SPatrick Venture     try
13318bbe3c6SPatrick Venture     {
13463528046SPatrick Venture         int bytesRead = 0;
13563528046SPatrick Venture         std::uint32_t offset = 0;
13663528046SPatrick Venture 
13718bbe3c6SPatrick Venture         do
13818bbe3c6SPatrick Venture         {
13918bbe3c6SPatrick Venture             bytesRead = sys->read(inputFd, readBuffer.get(), p2aLength);
14018bbe3c6SPatrick Venture             if (bytesRead > 0)
14118bbe3c6SPatrick Venture             {
14218bbe3c6SPatrick Venture                 /* TODO: Will likely need to store an rv somewhere to know when
14318bbe3c6SPatrick Venture                  * we're exiting from failure.
14418bbe3c6SPatrick Venture                  */
14518bbe3c6SPatrick Venture                 if (!io->write(bar1 | aspeedP2aOffset, bytesRead,
14618bbe3c6SPatrick Venture                                readBuffer.get()))
14718bbe3c6SPatrick Venture                 {
14818bbe3c6SPatrick Venture                     std::fprintf(stderr,
14918bbe3c6SPatrick Venture                                  "Failed to write to region in memory!\n");
15018bbe3c6SPatrick Venture                     break;
15118bbe3c6SPatrick Venture                 }
15218bbe3c6SPatrick Venture 
15318bbe3c6SPatrick Venture                 /* Ok, so the data is staged, now send the blob write with the
15418bbe3c6SPatrick Venture                  * details.
15518bbe3c6SPatrick Venture                  */
1561d5a31c9SPatrick Venture                 struct ipmi_flash::ExtChunkHdr chunk;
15718bbe3c6SPatrick Venture                 chunk.length = bytesRead;
15818bbe3c6SPatrick Venture                 std::vector<std::uint8_t> chunkBytes(sizeof(chunk));
15918bbe3c6SPatrick Venture                 std::memcpy(chunkBytes.data(), &chunk, sizeof(chunk));
16018bbe3c6SPatrick Venture 
16118bbe3c6SPatrick Venture                 /* This doesn't return anything on success. */
16218bbe3c6SPatrick Venture                 blob->writeBytes(session, offset, chunkBytes);
16318bbe3c6SPatrick Venture                 offset += bytesRead;
164*cf9b2195SPatrick Venture                 progress->updateProgress(bytesRead);
16518bbe3c6SPatrick Venture             }
16618bbe3c6SPatrick Venture         } while (bytesRead > 0);
16718bbe3c6SPatrick Venture     }
16818bbe3c6SPatrick Venture     catch (const ipmiblob::BlobException& b)
16918bbe3c6SPatrick Venture     {
17018bbe3c6SPatrick Venture         sys->close(inputFd);
17118bbe3c6SPatrick Venture         return false;
17218bbe3c6SPatrick Venture     }
17318bbe3c6SPatrick Venture 
17418bbe3c6SPatrick Venture     sys->close(inputFd);
17518bbe3c6SPatrick Venture     return true;
17618bbe3c6SPatrick Venture }
17718bbe3c6SPatrick Venture 
178b5bf0fc2SPatrick Venture } // namespace host_tool
179