blob: b1f8672b08cbabc295406adeaa78bbf09c8e66d1 [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 Venture84778b82019-06-26 20:11:09 -070023#include <cstdint>
Patrick Venturec73dce92019-05-07 11:32:44 -070024#include <cstring>
Patrick Venture18bbe3c2019-05-14 11:40:57 -070025#include <ipmiblob/blob_errors.hpp>
Patrick Venture84778b82019-06-26 20:11:09 -070026#include <memory>
27#include <string>
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -070028
29namespace host_tool
30{
31
Patrick Venturecf0e5de2019-07-26 08:25:33 -070032namespace
33{
34void disablePciBridge(HostIoInterface* io, std::size_t address)
35{
36 /* Read current value, and just blindly unset the bit. */
37 std::uint32_t value;
38 if (!io->read(address + aspeedP2aConfig, sizeof(value), &value))
39 {
40 return;
41 }
42
43 value &= ~p2ABridgeEnabled;
44 io->write(address + aspeedP2aConfig, sizeof(value), &value);
45}
46
47} // namespace
48
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -070049bool P2aDataHandler::sendContents(const std::string& input,
50 std::uint16_t session)
51{
Patrick Venture24141612019-05-03 17:59:18 -070052 PciDevice result;
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -070053 PciFilter filter;
Patrick Venture36bb4672019-05-07 09:42:56 -070054 bool found = false;
Patrick Venture18bbe3c2019-05-14 11:40:57 -070055 pciaddr_t bar1;
Patrick Venturecf0e5de2019-07-26 08:25:33 -070056 bool returnValue = false;
57 int inputFd = -1;
58 ipmi_flash::PciConfigResponse pciResp;
59 std::int64_t fileSize;
60 const std::uint32_t p2aLength = aspeedP2aOffset;
61 std::unique_ptr<std::uint8_t[]> readBuffer;
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -070062
63 filter.vid = aspeedVendorId;
64 filter.did = aspeedDeviceId;
65
Patrick Venture24141612019-05-03 17:59:18 -070066 /* Find the ASPEED PCI device entry we want. */
Patrick Venture46e69492019-05-15 07:54:44 -070067 auto output = pci->getPciDevices(filter);
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -070068 for (const auto& d : output)
69 {
Patrick Venture24141612019-05-03 17:59:18 -070070 std::fprintf(stderr, "[0x%x 0x%x] ", d.vid, d.did);
71
72 /* Verify it's a memory-based bar -- we want bar1. */
Patrick Venture18bbe3c2019-05-14 11:40:57 -070073 bar1 = d.bars[1];
Patrick Venture24141612019-05-03 17:59:18 -070074 if ((bar1 & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
75 {
76 /* We want it to not be IO-based access. */
77 continue;
78 }
79
Patrick Venture18bbe3c2019-05-14 11:40:57 -070080 /* For now capture the entire device even if we're only using BAR1 */
Patrick Venture24141612019-05-03 17:59:18 -070081 result = d;
Patrick Venture36bb4672019-05-07 09:42:56 -070082 found = true;
83 break;
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -070084 }
Patrick Venture36bb4672019-05-07 09:42:56 -070085
86 if (!found)
87 {
88 return false;
89 }
90
Patrick Venture24141612019-05-03 17:59:18 -070091 std::fprintf(stderr, "\n");
92
93 /* We sent the open command before this, so the window should be open and
Patrick Venturecf0e5de2019-07-26 08:25:33 -070094 * the bridge enabled on the BMC.
Patrick Venture24141612019-05-03 17:59:18 -070095 */
96 std::uint32_t value;
Patrick Venturecf0e5de2019-07-26 08:25:33 -070097 if (!io->read(bar1 + aspeedP2aConfig, sizeof(value), &value))
Patrick Venture24141612019-05-03 17:59:18 -070098 {
Patrick Venturee3feacf2019-07-26 08:28:36 -070099 std::fprintf(stderr, "PCI config read failed\n");
100 return false;
101 }
102
103 if (0 == (value & p2ABridgeEnabled))
104 {
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700105 std::fprintf(stderr, "Bridge not enabled - Enabling from host\n");
106
107 value |= p2ABridgeEnabled;
108 if (!io->write(bar1 + aspeedP2aConfig, sizeof(value), &value))
109 {
110 std::fprintf(stderr, "PCI config write failed\n");
111 return false;
112 }
Patrick Venture24141612019-05-03 17:59:18 -0700113 }
114
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700115 /* From this point down we need to disable the bridge. */
Patrick Venture24141612019-05-03 17:59:18 -0700116 std::fprintf(stderr, "The bridge is enabled!\n");
117
118 /* Read the configuration via blobs metadata (stat). */
Patrick Venturec73dce92019-05-07 11:32:44 -0700119 ipmiblob::StatResponse stat = blob->getStat(session);
Patrick Venture1d5a31c2019-05-20 11:38:22 -0700120 if (stat.metadata.size() != sizeof(ipmi_flash::PciConfigResponse))
Patrick Venturec73dce92019-05-07 11:32:44 -0700121 {
122 std::fprintf(stderr, "Didn't receive expected size of metadata for "
123 "PCI Configuration response\n");
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700124 goto exit;
Patrick Venturec73dce92019-05-07 11:32:44 -0700125 }
126
Patrick Venturec73dce92019-05-07 11:32:44 -0700127 std::memcpy(&pciResp, stat.metadata.data(), sizeof(pciResp));
128 std::fprintf(stderr, "Received address: 0x%x\n", pciResp.address);
Patrick Venture24141612019-05-03 17:59:18 -0700129
Patrick Venture24141612019-05-03 17:59:18 -0700130 /* Configure the mmio to point there. */
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700131 if (!io->write(bar1 + aspeedP2aBridge, sizeof(pciResp.address),
Patrick Venture18bbe3c2019-05-14 11:40:57 -0700132 &pciResp.address))
133 {
Patrick Venture24141612019-05-03 17:59:18 -0700134 // Failed to set it up, so fall back.
135 std::fprintf(stderr, "Failed to update the bridge address\n");
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700136 goto exit;
Patrick Venture24141612019-05-03 17:59:18 -0700137 }
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -0700138
Patrick Venture18bbe3c2019-05-14 11:40:57 -0700139 /* For data blocks in 64kb, stage data, and send blob write command. */
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700140 inputFd = sys->open(input.c_str(), 0);
Patrick Venture18bbe3c2019-05-14 11:40:57 -0700141 if (inputFd < 0)
142 {
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700143 std::fprintf(stderr, "Unable to open file: '%s'\n", input.c_str());
144 goto exit;
Patrick Venture18bbe3c2019-05-14 11:40:57 -0700145 }
146
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700147 fileSize = sys->getSize(input.c_str());
Patrick Venturecf9b2192019-06-27 12:09:52 -0700148 if (fileSize == 0)
149 {
150 std::fprintf(stderr, "Zero-length file, or other file access error\n");
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700151 goto exit;
Patrick Venturecf9b2192019-06-27 12:09:52 -0700152 }
153
154 progress->start(fileSize);
155
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700156 readBuffer = std::make_unique<std::uint8_t[]>(p2aLength);
Patrick Venture18bbe3c2019-05-14 11:40:57 -0700157 if (nullptr == readBuffer)
158 {
159 std::fprintf(stderr, "Unable to allocate memory for read buffer.\n");
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700160 goto exit;
Patrick Venture18bbe3c2019-05-14 11:40:57 -0700161 }
162
163 try
164 {
Patrick Venture63528042019-05-20 18:10:02 -0700165 int bytesRead = 0;
166 std::uint32_t offset = 0;
167
Patrick Venture18bbe3c2019-05-14 11:40:57 -0700168 do
169 {
170 bytesRead = sys->read(inputFd, readBuffer.get(), p2aLength);
171 if (bytesRead > 0)
172 {
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700173 /* TODO: Will likely need to store an rv somewhere to know
174 * when we're exiting from failure.
Patrick Venture18bbe3c2019-05-14 11:40:57 -0700175 */
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700176 if (!io->write(bar1 + aspeedP2aOffset, bytesRead,
Patrick Venture18bbe3c2019-05-14 11:40:57 -0700177 readBuffer.get()))
178 {
179 std::fprintf(stderr,
180 "Failed to write to region in memory!\n");
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700181 goto exit;
Patrick Venture18bbe3c2019-05-14 11:40:57 -0700182 }
183
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700184 /* Ok, so the data is staged, now send the blob write with
185 * the details.
Patrick Venture18bbe3c2019-05-14 11:40:57 -0700186 */
Patrick Venture1d5a31c2019-05-20 11:38:22 -0700187 struct ipmi_flash::ExtChunkHdr chunk;
Patrick Venture18bbe3c2019-05-14 11:40:57 -0700188 chunk.length = bytesRead;
189 std::vector<std::uint8_t> chunkBytes(sizeof(chunk));
190 std::memcpy(chunkBytes.data(), &chunk, sizeof(chunk));
191
192 /* This doesn't return anything on success. */
193 blob->writeBytes(session, offset, chunkBytes);
194 offset += bytesRead;
Patrick Venturecf9b2192019-06-27 12:09:52 -0700195 progress->updateProgress(bytesRead);
Patrick Venture18bbe3c2019-05-14 11:40:57 -0700196 }
197 } while (bytesRead > 0);
198 }
199 catch (const ipmiblob::BlobException& b)
200 {
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700201 goto exit;
Patrick Venture18bbe3c2019-05-14 11:40:57 -0700202 }
203
Patrick Venturecf0e5de2019-07-26 08:25:33 -0700204 /* defaults to failure. */
205 returnValue = true;
206
207exit:
208 /* disable PCI bridge. */
209 disablePciBridge(io, bar1);
210
211 /* close input file. */
212 if (inputFd != -1)
213 {
214 sys->close(inputFd);
215 }
216 return returnValue;
Patrick Ventureb5bf0fc2019-05-03 14:33:49 -0700217}
218
219} // namespace host_tool