xref: /openbmc/phosphor-ipmi-flash/tools/p2a.cpp (revision 9b37b095)
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