blob: a3a81b4b550438a60fa64590bbe4e75eaaeeaabc [file] [log] [blame]
Tom Joseph0c6d22c2019-06-26 09:58:41 +05301#include "config.h"
2
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +05303#include "file_io.hpp"
4
Tom Joseph0c6d22c2019-06-26 09:58:41 +05305#include "file_table.hpp"
Jinu Joy Thomasf666db12019-05-29 05:22:31 -05006#include "libpldmresponder/utils.hpp"
7#include "registration.hpp"
8
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +05309#include <fcntl.h>
10#include <sys/mman.h>
11#include <sys/stat.h>
12#include <sys/types.h>
13#include <unistd.h>
14
15#include <cstring>
16#include <fstream>
17#include <phosphor-logging/log.hpp>
18
19#include "libpldm/base.h"
20
21namespace pldm
22{
23
24namespace responder
25{
26
Jinu Joy Thomasf666db12019-05-29 05:22:31 -050027namespace oem_ibm
28{
29
30void registerHandlers()
31{
Tom Joseph0c6d22c2019-06-26 09:58:41 +053032 registerHandler(PLDM_OEM, PLDM_GET_FILE_TABLE, std::move(getFileTable));
Jinu Joy Thomasf666db12019-05-29 05:22:31 -050033 registerHandler(PLDM_OEM, PLDM_READ_FILE_INTO_MEMORY,
34 std::move(readFileIntoMemory));
35 registerHandler(PLDM_OEM, PLDM_WRITE_FILE_FROM_MEMORY,
36 std::move(writeFileFromMemory));
37}
38
39} // namespace oem_ibm
40
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +053041namespace fs = std::filesystem;
42using namespace phosphor::logging;
43
44namespace dma
45{
46
47/** @struct AspeedXdmaOp
48 *
49 * Structure representing XDMA operation
50 */
51struct AspeedXdmaOp
52{
53 uint64_t hostAddr; //!< the DMA address on the host side, configured by
54 //!< PCI subsystem.
55 uint32_t len; //!< the size of the transfer in bytes, it should be a
56 //!< multiple of 16 bytes
57 uint32_t upstream; //!< boolean indicating the direction of the DMA
58 //!< operation, true means a transfer from BMC to host.
59};
60
61constexpr auto xdmaDev = "/dev/xdma";
62
63int DMA::transferDataHost(const fs::path& path, uint32_t offset,
64 uint32_t length, uint64_t address, bool upstream)
65{
66 static const size_t pageSize = getpagesize();
67 uint32_t numPages = length / pageSize;
68 uint32_t pageAlignedLength = numPages * pageSize;
69
70 if (length > pageAlignedLength)
71 {
72 pageAlignedLength += pageSize;
73 }
74
75 auto mmapCleanup = [pageAlignedLength](void* vgaMem) {
76 munmap(vgaMem, pageAlignedLength);
77 };
78
79 int fd = -1;
80 int rc = 0;
81 fd = open(xdmaDev, O_RDWR);
82 if (fd < 0)
83 {
84 rc = -errno;
85 log<level::ERR>("Failed to open the XDMA device", entry("RC=%d", rc));
86 return rc;
87 }
88
89 utils::CustomFD xdmaFd(fd);
90
91 void* vgaMem;
92 vgaMem = mmap(nullptr, pageAlignedLength, upstream ? PROT_WRITE : PROT_READ,
93 MAP_SHARED, xdmaFd(), 0);
94 if (MAP_FAILED == vgaMem)
95 {
96 rc = -errno;
97 log<level::ERR>("Failed to mmap the XDMA device", entry("RC=%d", rc));
98 return rc;
99 }
100
101 std::unique_ptr<void, decltype(mmapCleanup)> vgaMemPtr(vgaMem, mmapCleanup);
102
103 if (upstream)
104 {
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530105 std::ifstream stream(path.string(), std::ios::in | std::ios::binary);
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530106 stream.seekg(offset);
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530107
108 // Writing to the VGA memory should be aligned at page boundary,
109 // otherwise write data into a buffer aligned at page boundary and
110 // then write to the VGA memory.
111 std::vector<char> buffer{};
112 buffer.resize(pageAlignedLength);
113 stream.read(buffer.data(), length);
114 memcpy(static_cast<char*>(vgaMemPtr.get()), buffer.data(),
115 pageAlignedLength);
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530116
117 if (static_cast<uint32_t>(stream.gcount()) != length)
118 {
119 log<level::ERR>("mismatch between number of characters to read and "
120 "the length read",
121 entry("LENGTH=%d", length),
122 entry("COUNT=%d", stream.gcount()));
123 return -1;
124 }
125 }
126
127 AspeedXdmaOp xdmaOp;
128 xdmaOp.upstream = upstream ? 1 : 0;
129 xdmaOp.hostAddr = address;
130 xdmaOp.len = length;
131
132 rc = write(xdmaFd(), &xdmaOp, sizeof(xdmaOp));
133 if (rc < 0)
134 {
135 rc = -errno;
136 log<level::ERR>("Failed to execute the DMA operation",
137 entry("RC=%d", rc), entry("UPSTREAM=%d", upstream),
138 entry("ADDRESS=%lld", address),
139 entry("LENGTH=%d", length));
140 return rc;
141 }
142
143 if (!upstream)
144 {
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530145 std::ofstream stream(path.string(),
146 std::ios::in | std::ios::out | std::ios::binary);
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530147
148 stream.seekp(offset);
149 stream.write(static_cast<const char*>(vgaMemPtr.get()), length);
150 }
151
152 return 0;
153}
154
155} // namespace dma
156
Jinu Joy Thomasf666db12019-05-29 05:22:31 -0500157Response readFileIntoMemory(const pldm_msg* request, size_t payloadLength)
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530158{
159 uint32_t fileHandle = 0;
160 uint32_t offset = 0;
161 uint32_t length = 0;
162 uint64_t address = 0;
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530163
164 Response response((sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES), 0);
165 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
166
167 if (payloadLength != PLDM_RW_FILE_MEM_REQ_BYTES)
168 {
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530169 encode_rw_file_memory_resp(request->hdr.instance_id,
170 PLDM_READ_FILE_INTO_MEMORY,
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530171 PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
172 return response;
173 }
174
Zahed Hossain223a73d2019-07-04 12:46:18 -0500175 decode_rw_file_memory_req(request, payloadLength, &fileHandle, &offset,
176 &length, &address);
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530177
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530178 using namespace pldm::filetable;
179 auto& table = buildFileTable(FILE_TABLE_JSON);
180 FileEntry value{};
181
182 try
183 {
184 value = table.at(fileHandle);
185 }
186 catch (std::exception& e)
187 {
188 log<level::ERR>("File handle does not exist in the file table",
189 entry("HANDLE=%d", fileHandle));
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530190 encode_rw_file_memory_resp(request->hdr.instance_id,
191 PLDM_READ_FILE_INTO_MEMORY,
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530192 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
193 return response;
194 }
195
196 if (!fs::exists(value.fsPath))
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530197 {
198 log<level::ERR>("File does not exist", entry("HANDLE=%d", fileHandle));
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530199 encode_rw_file_memory_resp(request->hdr.instance_id,
200 PLDM_READ_FILE_INTO_MEMORY,
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530201 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
202 return response;
203 }
204
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530205 auto fileSize = fs::file_size(value.fsPath);
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530206 if (offset >= fileSize)
207 {
208 log<level::ERR>("Offset exceeds file size", entry("OFFSET=%d", offset),
209 entry("FILE_SIZE=%d", fileSize));
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530210 encode_rw_file_memory_resp(request->hdr.instance_id,
211 PLDM_READ_FILE_INTO_MEMORY,
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530212 PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
213 return response;
214 }
215
216 if (offset + length > fileSize)
217 {
218 length = fileSize - offset;
219 }
220
221 if (length % dma::minSize)
222 {
223 log<level::ERR>("Read length is not a multiple of DMA minSize",
224 entry("LENGTH=%d", length));
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530225 encode_rw_file_memory_resp(request->hdr.instance_id,
226 PLDM_READ_FILE_INTO_MEMORY,
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530227 PLDM_INVALID_READ_LENGTH, 0, responsePtr);
228 return response;
229 }
230
231 using namespace dma;
232 DMA intf;
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530233 return transferAll<DMA>(&intf, PLDM_READ_FILE_INTO_MEMORY, value.fsPath,
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530234 offset, length, address, true,
235 request->hdr.instance_id);
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530236}
237
Jinu Joy Thomasf666db12019-05-29 05:22:31 -0500238Response writeFileFromMemory(const pldm_msg* request, size_t payloadLength)
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530239{
240 uint32_t fileHandle = 0;
241 uint32_t offset = 0;
242 uint32_t length = 0;
243 uint64_t address = 0;
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530244
245 Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES, 0);
246 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
247
248 if (payloadLength != PLDM_RW_FILE_MEM_REQ_BYTES)
249 {
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530250 encode_rw_file_memory_resp(request->hdr.instance_id,
251 PLDM_WRITE_FILE_FROM_MEMORY,
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530252 PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
253 return response;
254 }
255
Zahed Hossain223a73d2019-07-04 12:46:18 -0500256 decode_rw_file_memory_req(request, payloadLength, &fileHandle, &offset,
257 &length, &address);
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530258
259 if (length % dma::minSize)
260 {
261 log<level::ERR>("Write length is not a multiple of DMA minSize",
262 entry("LENGTH=%d", length));
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530263 encode_rw_file_memory_resp(request->hdr.instance_id,
264 PLDM_WRITE_FILE_FROM_MEMORY,
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530265 PLDM_INVALID_WRITE_LENGTH, 0, responsePtr);
266 return response;
267 }
268
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530269 using namespace pldm::filetable;
270 auto& table = buildFileTable(FILE_TABLE_JSON);
271 FileEntry value{};
272
273 try
274 {
275 value = table.at(fileHandle);
276 }
277 catch (std::exception& e)
278 {
279 log<level::ERR>("File handle does not exist in the file table",
280 entry("HANDLE=%d", fileHandle));
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530281 encode_rw_file_memory_resp(request->hdr.instance_id,
282 PLDM_WRITE_FILE_FROM_MEMORY,
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530283 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
284 return response;
285 }
286
287 if (!fs::exists(value.fsPath))
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530288 {
289 log<level::ERR>("File does not exist", entry("HANDLE=%d", fileHandle));
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530290 encode_rw_file_memory_resp(request->hdr.instance_id,
291 PLDM_WRITE_FILE_FROM_MEMORY,
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530292 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
293 return response;
294 }
295
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530296 auto fileSize = fs::file_size(value.fsPath);
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530297 if (offset >= fileSize)
298 {
299 log<level::ERR>("Offset exceeds file size", entry("OFFSET=%d", offset),
300 entry("FILE_SIZE=%d", fileSize));
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530301 encode_rw_file_memory_resp(request->hdr.instance_id,
302 PLDM_WRITE_FILE_FROM_MEMORY,
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530303 PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
304 return response;
305 }
306
307 using namespace dma;
308 DMA intf;
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530309 return transferAll<DMA>(&intf, PLDM_WRITE_FILE_FROM_MEMORY, value.fsPath,
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530310 offset, length, address, false,
311 request->hdr.instance_id);
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530312}
313
314Response getFileTable(const pldm_msg* request, size_t payloadLength)
315{
316 uint32_t transferHandle = 0;
317 uint8_t transferFlag = 0;
318 uint8_t tableType = 0;
319
320 Response response(sizeof(pldm_msg_hdr) +
321 PLDM_GET_FILE_TABLE_MIN_RESP_BYTES);
322 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
323
324 if (payloadLength != PLDM_GET_FILE_TABLE_REQ_BYTES)
325 {
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530326 encode_get_file_table_resp(request->hdr.instance_id,
327 PLDM_ERROR_INVALID_LENGTH, 0, 0, nullptr, 0,
328 responsePtr);
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530329 return response;
330 }
331
Zahed Hossain223a73d2019-07-04 12:46:18 -0500332 auto rc = decode_get_file_table_req(request, payloadLength, &transferHandle,
333 &transferFlag, &tableType);
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530334 if (rc)
335 {
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530336 encode_get_file_table_resp(request->hdr.instance_id, rc, 0, 0, nullptr,
337 0, responsePtr);
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530338 return response;
339 }
340
341 if (tableType != PLDM_FILE_ATTRIBUTE_TABLE)
342 {
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530343 encode_get_file_table_resp(request->hdr.instance_id,
344 PLDM_INVALID_FILE_TABLE_TYPE, 0, 0, nullptr,
345 0, responsePtr);
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530346 return response;
347 }
348
349 using namespace pldm::filetable;
350 auto table = buildFileTable(FILE_TABLE_JSON);
351 auto attrTable = table();
352 response.resize(response.size() + attrTable.size());
353 responsePtr = reinterpret_cast<pldm_msg*>(response.data());
354
355 if (attrTable.empty())
356 {
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530357 encode_get_file_table_resp(request->hdr.instance_id,
358 PLDM_FILE_TABLE_UNAVAILABLE, 0, 0, nullptr,
359 0, responsePtr);
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530360 return response;
361 }
362
Jinu Joy Thomas33705fd2019-07-02 16:03:05 +0530363 encode_get_file_table_resp(request->hdr.instance_id, PLDM_SUCCESS, 0,
364 PLDM_START_AND_END, attrTable.data(),
365 attrTable.size(), responsePtr);
Tom Joseph0c6d22c2019-06-26 09:58:41 +0530366 return response;
Jinu Joy Thomas7f57f442019-06-13 20:38:49 +0530367}
368
369} // namespace responder
370} // namespace pldm