blob: 9de60f09fcc6074f7e642870ed7460e35a5c0847 [file] [log] [blame]
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -07001/*
2 * Copyright 2019 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "p2a.hpp"
18
Patrick Venture84778b82019-06-26 20:11:09 -070019#include "data.hpp"
20#include "flags.hpp"
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -070021#include "pci.hpp"
Patrick Venturec73dce92019-05-07 11:32:44 -070022
Patrick Venture9b37b092020-05-28 20:58:57 -070023#include <ipmiblob/blob_errors.hpp>
24
Patrick Venture84778b82019-06-26 20:11:09 -070025#include <cstdint>
Patrick Venturec73dce92019-05-07 11:32:44 -070026#include <cstring>
Patrick Venture84778b82019-06-26 20:11:09 -070027#include <memory>
28#include <string>
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -070029
30namespace host_tool
31{
32
Patrick Venturecf0e5de2019-07-26 08:25:33 -070033namespace
34{
35void disablePciBridge(HostIoInterface* io, std::size_t address)
36{
37 /* Read current value, and just blindly unset the bit. */
38 std::uint32_t value;
39 if (!io->read(address + aspeedP2aConfig, sizeof(value), &value))
40 {
41 return;
42 }
43
44 value &= ~p2ABridgeEnabled;
45 io->write(address + aspeedP2aConfig, sizeof(value), &value);
46}
47
48} // namespace
49
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -070050bool P2aDataHandler::sendContents(const std::string& input,
51 std::uint16_t session)
52{
Patrick Venture24141612019-05-03 17:59:18 -070053 PciDevice result;
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -070054 PciFilter filter;
Patrick Venture36bb4672019-05-07 09:42:56 -070055 bool found = false;
Medad CChienc8445aa2020-04-23 09:47:46 +080056 pciaddr_t bar;
Patrick Venturecf0e5de2019-07-26 08:25:33 -070057 bool returnValue = false;
58 int inputFd = -1;
59 ipmi_flash::PciConfigResponse pciResp;
60 std::int64_t fileSize;
Patrick Venturecf0e5de2019-07-26 08:25:33 -070061 std::unique_ptr<std::uint8_t[]> readBuffer;
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -070062
Medad CChienc8445aa2020-04-23 09:47:46 +080063 std::uint16_t pciDeviceVID;
64 std::uint16_t pciDeviceDID;
65 std::uint32_t p2aOffset;
66 std::uint32_t p2aLength;
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -070067
Medad CChienc8445aa2020-04-23 09:47:46 +080068 for (auto device : PCIDeviceList)
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -070069 {
Medad CChienc8445aa2020-04-23 09:47:46 +080070 filter.vid = device.VID;
71 filter.did = device.DID;
Patrick Venture24141612019-05-03 17:59:18 -070072
Medad CChienc8445aa2020-04-23 09:47:46 +080073 /* Find the PCI device entry we want. */
74 auto output = pci->getPciDevices(filter);
75 for (const auto& d : output)
Patrick Venture24141612019-05-03 17:59:18 -070076 {
Medad CChienc8445aa2020-04-23 09:47:46 +080077 std::fprintf(stderr, "[0x%x 0x%x] \n", d.vid, d.did);
78
79 /* Verify it's a memory-based bar. */
80 bar = d.bars[device.bar];
81
82 if ((bar & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
83 {
84 /* We want it to not be IO-based access. */
85 continue;
86 }
87
88 /* For now capture the entire device even if we're only using BAR0
89 */
90 result = d;
91 found = true;
92 break;
Patrick Venture24141612019-05-03 17:59:18 -070093 }
94
Medad CChienc8445aa2020-04-23 09:47:46 +080095 if (found)
96 {
97 std::fprintf(stderr, "Find [0x%x 0x%x] \n", device.VID, device.DID);
98 std::fprintf(stderr, "bar%u[0x%x] \n", device.bar,
99 (unsigned int)bar);
100 pciDeviceVID = device.VID;
101 pciDeviceDID = device.DID;
102 p2aOffset = device.Offset;
103 p2aLength = device.Length;
104 break;
105 }
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -0700106 }
Patrick Venture36bb4672019-05-07 09:42:56 -0700107
108 if (!found)
109 {
110 return false;
111 }
112
Patrick Venture24141612019-05-03 17:59:18 -0700113 std::fprintf(stderr, "\n");
114
115 /* We sent the open command before this, so the window should be open and
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700116 * the bridge enabled on the BMC.
Patrick Venture24141612019-05-03 17:59:18 -0700117 */
Medad CChienc8445aa2020-04-23 09:47:46 +0800118 if (pciDeviceVID == aspeedPciDeviceInfo.VID &&
119 pciDeviceDID == aspeedPciDeviceInfo.DID)
Patrick Venture24141612019-05-03 17:59:18 -0700120 {
Medad CChienc8445aa2020-04-23 09:47:46 +0800121 std::uint32_t value;
122 if (!io->read(bar + aspeedP2aConfig, sizeof(value), &value))
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700123 {
Medad CChienc8445aa2020-04-23 09:47:46 +0800124 std::fprintf(stderr, "PCI config read failed\n");
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700125 return false;
126 }
Patrick Venture24141612019-05-03 17:59:18 -0700127
Medad CChienc8445aa2020-04-23 09:47:46 +0800128 if (0 == (value & p2ABridgeEnabled))
129 {
130 std::fprintf(stderr, "Bridge not enabled - Enabling from host\n");
131
132 value |= p2ABridgeEnabled;
133 if (!io->write(bar + aspeedP2aConfig, sizeof(value), &value))
134 {
135 std::fprintf(stderr, "PCI config write failed\n");
136 return false;
137 }
138 }
139
140 /* From this point down we need to disable the bridge. */
141 std::fprintf(stderr, "The bridge is enabled!\n");
142 }
Patrick Venture24141612019-05-03 17:59:18 -0700143
144 /* Read the configuration via blobs metadata (stat). */
Patrick Venturec73dce92019-05-07 11:32:44 -0700145 ipmiblob::StatResponse stat = blob->getStat(session);
Patrick Venture1d5a31c2019-05-20 11:38:22 -0700146 if (stat.metadata.size() != sizeof(ipmi_flash::PciConfigResponse))
Patrick Venturec73dce92019-05-07 11:32:44 -0700147 {
148 std::fprintf(stderr, "Didn't receive expected size of metadata for "
149 "PCI Configuration response\n");
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700150 goto exit;
Patrick Venturec73dce92019-05-07 11:32:44 -0700151 }
152
Patrick Venturec73dce92019-05-07 11:32:44 -0700153 std::memcpy(&pciResp, stat.metadata.data(), sizeof(pciResp));
154 std::fprintf(stderr, "Received address: 0x%x\n", pciResp.address);
Patrick Venture24141612019-05-03 17:59:18 -0700155
Medad CChienc8445aa2020-04-23 09:47:46 +0800156 if (pciDeviceVID == aspeedPciDeviceInfo.VID &&
157 pciDeviceDID == aspeedPciDeviceInfo.DID)
Patrick Venture18bbe3c2019-05-14 11:40:57 -0700158 {
Medad CChienc8445aa2020-04-23 09:47:46 +0800159 /* Configure the mmio to point there. */
160 if (!io->write(bar + aspeedP2aBridge, sizeof(pciResp.address),
161 &pciResp.address))
162 {
163 // Failed to set it up, so fall back.
164 std::fprintf(stderr, "Failed to update the bridge address\n");
165 goto exit;
166 }
Patrick Venture24141612019-05-03 17:59:18 -0700167 }
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -0700168
Patrick Venture18bbe3c2019-05-14 11:40:57 -0700169 /* For data blocks in 64kb, stage data, and send blob write command. */
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700170 inputFd = sys->open(input.c_str(), 0);
Patrick Venture18bbe3c2019-05-14 11:40:57 -0700171 if (inputFd < 0)
172 {
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700173 std::fprintf(stderr, "Unable to open file: '%s'\n", input.c_str());
174 goto exit;
Patrick Venture18bbe3c2019-05-14 11:40:57 -0700175 }
176
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700177 fileSize = sys->getSize(input.c_str());
Patrick Venturecf9b2192019-06-27 12:09:52 -0700178 if (fileSize == 0)
179 {
180 std::fprintf(stderr, "Zero-length file, or other file access error\n");
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700181 goto exit;
Patrick Venturecf9b2192019-06-27 12:09:52 -0700182 }
183
184 progress->start(fileSize);
185
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700186 readBuffer = std::make_unique<std::uint8_t[]>(p2aLength);
Patrick Venture18bbe3c2019-05-14 11:40:57 -0700187 if (nullptr == readBuffer)
188 {
189 std::fprintf(stderr, "Unable to allocate memory for read buffer.\n");
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700190 goto exit;
Patrick Venture18bbe3c2019-05-14 11:40:57 -0700191 }
192
193 try
194 {
Patrick Venture63528042019-05-20 18:10:02 -0700195 int bytesRead = 0;
196 std::uint32_t offset = 0;
197
Patrick Venture18bbe3c2019-05-14 11:40:57 -0700198 do
199 {
200 bytesRead = sys->read(inputFd, readBuffer.get(), p2aLength);
201 if (bytesRead > 0)
202 {
Medad CChienc8445aa2020-04-23 09:47:46 +0800203 /* TODO: Will likely need to store an rv somewhere to know when
204 * we're exiting from failure.
Patrick Venture18bbe3c2019-05-14 11:40:57 -0700205 */
Medad CChienc8445aa2020-04-23 09:47:46 +0800206 if (!io->write(bar + p2aOffset, bytesRead, readBuffer.get()))
Patrick Venture18bbe3c2019-05-14 11:40:57 -0700207 {
208 std::fprintf(stderr,
209 "Failed to write to region in memory!\n");
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700210 goto exit;
Patrick Venture18bbe3c2019-05-14 11:40:57 -0700211 }
212
Medad CChienc8445aa2020-04-23 09:47:46 +0800213 /* Ok, so the data is staged, now send the blob write with the
214 * details.
Patrick Venture18bbe3c2019-05-14 11:40:57 -0700215 */
Patrick Venture1d5a31c2019-05-20 11:38:22 -0700216 struct ipmi_flash::ExtChunkHdr chunk;
Patrick Venture18bbe3c2019-05-14 11:40:57 -0700217 chunk.length = bytesRead;
218 std::vector<std::uint8_t> chunkBytes(sizeof(chunk));
219 std::memcpy(chunkBytes.data(), &chunk, sizeof(chunk));
220
221 /* This doesn't return anything on success. */
222 blob->writeBytes(session, offset, chunkBytes);
223 offset += bytesRead;
Patrick Venturecf9b2192019-06-27 12:09:52 -0700224 progress->updateProgress(bytesRead);
Patrick Venture18bbe3c2019-05-14 11:40:57 -0700225 }
226 } while (bytesRead > 0);
227 }
228 catch (const ipmiblob::BlobException& b)
229 {
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700230 goto exit;
Patrick Venture18bbe3c2019-05-14 11:40:57 -0700231 }
232
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700233 /* defaults to failure. */
234 returnValue = true;
235
236exit:
Medad CChienc8445aa2020-04-23 09:47:46 +0800237 /* disable ASPEED PCI bridge. */
238 if (pciDeviceVID == aspeedPciDeviceInfo.VID &&
239 pciDeviceDID == aspeedPciDeviceInfo.DID)
240 {
241 disablePciBridge(io, bar);
242 }
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700243
244 /* close input file. */
245 if (inputFd != -1)
246 {
247 sys->close(inputFd);
248 }
249 return returnValue;
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -0700250}
251
252} // namespace host_tool