xref: /openbmc/phosphor-ipmi-flash/tools/p2a.cpp (revision 18bbe3c6)
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 
19*18bbe3c6SPatrick Venture #include "firmware_handler.hpp"
20b5bf0fc2SPatrick Venture #include "pci.hpp"
21c73dce91SPatrick Venture #include "pci_handler.hpp"
22c73dce91SPatrick Venture 
23c73dce91SPatrick Venture #include <cstring>
24*18bbe3c6SPatrick 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     PciUtilImpl pci;
34b5bf0fc2SPatrick Venture     PciFilter filter;
3536bb4670SPatrick Venture     bool found = false;
36*18bbe3c6SPatrick Venture     pciaddr_t bar1;
37b5bf0fc2SPatrick Venture 
38b5bf0fc2SPatrick Venture     filter.vid = aspeedVendorId;
39b5bf0fc2SPatrick Venture     filter.did = aspeedDeviceId;
40b5bf0fc2SPatrick Venture 
4124141611SPatrick Venture     /* Find the ASPEED PCI device entry we want. */
42b5bf0fc2SPatrick Venture     auto output = pci.getPciDevices(filter);
43b5bf0fc2SPatrick Venture     for (const auto& d : output)
44b5bf0fc2SPatrick Venture     {
4524141611SPatrick Venture         std::fprintf(stderr, "[0x%x 0x%x] ", d.vid, d.did);
4624141611SPatrick Venture 
4724141611SPatrick Venture         /* Verify it's a memory-based bar -- we want bar1. */
48*18bbe3c6SPatrick Venture         bar1 = d.bars[1];
4924141611SPatrick Venture         if ((bar1 & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
5024141611SPatrick Venture         {
5124141611SPatrick Venture             /* We want it to not be IO-based access. */
5224141611SPatrick Venture             continue;
53b5bf0fc2SPatrick Venture         }
54b5bf0fc2SPatrick Venture 
55*18bbe3c6SPatrick Venture         /* For now capture the entire device even if we're only using BAR1 */
5624141611SPatrick Venture         result = d;
5736bb4670SPatrick Venture         found = true;
5836bb4670SPatrick Venture         break;
5924141611SPatrick Venture     }
6036bb4670SPatrick Venture 
6136bb4670SPatrick Venture     if (!found)
6236bb4670SPatrick Venture     {
6336bb4670SPatrick Venture         return false;
6436bb4670SPatrick Venture     }
6536bb4670SPatrick Venture 
6624141611SPatrick Venture     std::fprintf(stderr, "\n");
6724141611SPatrick Venture 
6824141611SPatrick Venture     /* We sent the open command before this, so the window should be open and
6924141611SPatrick Venture      * the bridge enabled.
7024141611SPatrick Venture      */
7124141611SPatrick Venture     std::uint32_t value;
72*18bbe3c6SPatrick Venture     if (!io->read(bar1 | aspeedP2aConfig, sizeof(value), &value))
7324141611SPatrick Venture     {
7424141611SPatrick Venture         if (0 == (value & p2ABridgeEnabled))
7524141611SPatrick Venture         {
7624141611SPatrick Venture             std::fprintf(stderr, "Bridge not enabled.\n");
7724141611SPatrick Venture             return false;
7824141611SPatrick Venture         }
7924141611SPatrick Venture     }
8024141611SPatrick Venture 
8124141611SPatrick Venture     std::fprintf(stderr, "The bridge is enabled!\n");
8224141611SPatrick Venture 
8324141611SPatrick Venture     /* Read the configuration via blobs metadata (stat). */
84c73dce91SPatrick Venture     ipmiblob::StatResponse stat = blob->getStat(session);
85c73dce91SPatrick Venture     if (stat.metadata.size() != sizeof(blobs::PciConfigResponse))
86c73dce91SPatrick Venture     {
87c73dce91SPatrick Venture         std::fprintf(stderr, "Didn't receive expected size of metadata for "
88c73dce91SPatrick Venture                              "PCI Configuration response\n");
89c73dce91SPatrick Venture         return false;
90c73dce91SPatrick Venture     }
91c73dce91SPatrick Venture 
92c73dce91SPatrick Venture     blobs::PciConfigResponse pciResp;
93c73dce91SPatrick Venture     std::memcpy(&pciResp, stat.metadata.data(), sizeof(pciResp));
94c73dce91SPatrick Venture     std::fprintf(stderr, "Received address: 0x%x\n", pciResp.address);
9524141611SPatrick Venture 
9624141611SPatrick Venture     /* Configure the mmio to point there. */
97*18bbe3c6SPatrick Venture     if (!io->write(bar1 | aspeedP2aBridge, sizeof(pciResp.address),
98*18bbe3c6SPatrick Venture                    &pciResp.address))
99*18bbe3c6SPatrick Venture     {
10024141611SPatrick Venture         // Failed to set it up, so fall back.
10124141611SPatrick Venture         std::fprintf(stderr, "Failed to update the bridge address\n");
10224141611SPatrick Venture         return false;
10324141611SPatrick Venture     }
10424141611SPatrick Venture 
105*18bbe3c6SPatrick Venture     /* For data blocks in 64kb, stage data, and send blob write command. */
106*18bbe3c6SPatrick Venture     int inputFd = sys->open(input.c_str(), 0);
107*18bbe3c6SPatrick Venture     if (inputFd < 0)
108*18bbe3c6SPatrick Venture     {
109b5bf0fc2SPatrick Venture         return false;
110b5bf0fc2SPatrick Venture     }
111b5bf0fc2SPatrick Venture 
112*18bbe3c6SPatrick Venture     int bytesRead = 0;
113*18bbe3c6SPatrick Venture     std::uint32_t offset = 0;
114*18bbe3c6SPatrick Venture     const std::uint32_t p2aLength = aspeedP2aOffset;
115*18bbe3c6SPatrick Venture 
116*18bbe3c6SPatrick Venture     auto readBuffer = std::make_unique<std::uint8_t[]>(p2aLength);
117*18bbe3c6SPatrick Venture     if (nullptr == readBuffer)
118*18bbe3c6SPatrick Venture     {
119*18bbe3c6SPatrick Venture         std::fprintf(stderr, "Unable to allocate memory for read buffer.\n");
120*18bbe3c6SPatrick Venture         return false;
121*18bbe3c6SPatrick Venture     }
122*18bbe3c6SPatrick Venture 
123*18bbe3c6SPatrick Venture     try
124*18bbe3c6SPatrick Venture     {
125*18bbe3c6SPatrick Venture         do
126*18bbe3c6SPatrick Venture         {
127*18bbe3c6SPatrick Venture             bytesRead = sys->read(inputFd, readBuffer.get(), p2aLength);
128*18bbe3c6SPatrick Venture             if (bytesRead > 0)
129*18bbe3c6SPatrick Venture             {
130*18bbe3c6SPatrick Venture                 /* TODO: Will likely need to store an rv somewhere to know when
131*18bbe3c6SPatrick Venture                  * we're exiting from failure.
132*18bbe3c6SPatrick Venture                  */
133*18bbe3c6SPatrick Venture                 if (!io->write(bar1 | aspeedP2aOffset, bytesRead,
134*18bbe3c6SPatrick Venture                                readBuffer.get()))
135*18bbe3c6SPatrick Venture                 {
136*18bbe3c6SPatrick Venture                     std::fprintf(stderr,
137*18bbe3c6SPatrick Venture                                  "Failed to write to region in memory!\n");
138*18bbe3c6SPatrick Venture                     break;
139*18bbe3c6SPatrick Venture                 }
140*18bbe3c6SPatrick Venture 
141*18bbe3c6SPatrick Venture                 /* Ok, so the data is staged, now send the blob write with the
142*18bbe3c6SPatrick Venture                  * details.
143*18bbe3c6SPatrick Venture                  */
144*18bbe3c6SPatrick Venture                 struct blobs::ExtChunkHdr chunk;
145*18bbe3c6SPatrick Venture                 chunk.length = bytesRead;
146*18bbe3c6SPatrick Venture                 std::vector<std::uint8_t> chunkBytes(sizeof(chunk));
147*18bbe3c6SPatrick Venture                 std::memcpy(chunkBytes.data(), &chunk, sizeof(chunk));
148*18bbe3c6SPatrick Venture 
149*18bbe3c6SPatrick Venture                 /* This doesn't return anything on success. */
150*18bbe3c6SPatrick Venture                 blob->writeBytes(session, offset, chunkBytes);
151*18bbe3c6SPatrick Venture                 offset += bytesRead;
152*18bbe3c6SPatrick Venture             }
153*18bbe3c6SPatrick Venture         } while (bytesRead > 0);
154*18bbe3c6SPatrick Venture     }
155*18bbe3c6SPatrick Venture     catch (const ipmiblob::BlobException& b)
156*18bbe3c6SPatrick Venture     {
157*18bbe3c6SPatrick Venture         sys->close(inputFd);
158*18bbe3c6SPatrick Venture         return false;
159*18bbe3c6SPatrick Venture     }
160*18bbe3c6SPatrick Venture 
161*18bbe3c6SPatrick Venture     sys->close(inputFd);
162*18bbe3c6SPatrick Venture     return true;
163*18bbe3c6SPatrick Venture }
164*18bbe3c6SPatrick Venture 
165b5bf0fc2SPatrick Venture } // namespace host_tool
166