blob: 9caa45aef602e1497208ba028a4e87eafbd7163b [file] [log] [blame]
Tom Josephf8329ac2019-04-11 22:13:22 +05301#include "file_io.hpp"
2
3#include <fcntl.h>
4#include <sys/mman.h>
5#include <sys/stat.h>
6#include <sys/types.h>
7#include <unistd.h>
8
9#include <cstring>
10#include <fstream>
11#include <phosphor-logging/log.hpp>
12
13#include "libpldm/base.h"
14
15namespace pldm
16{
17
18namespace responder
19{
20
21namespace fs = std::filesystem;
22using namespace phosphor::logging;
23
24int transferDatatoHost(const fs::path& file, uint32_t offset, uint32_t length,
25 uint64_t address)
26{
27 // Align the length of the memory mapping to the page size.
28 static const size_t pageSize = getpagesize();
29 uint32_t numPages = length / pageSize;
30 uint32_t pageLength = numPages * pageSize;
31 if (length > pageLength)
32 {
33 pageLength += pageSize;
34 }
35
36 auto mmapCleanup = [pageLength](void* vgaMem) {
37 munmap(vgaMem, pageLength);
38 };
39
40 int fd = -1;
41 int rc = 0;
42 fd = open(dma::xdmaDev, O_RDWR);
43 if (fd < 0)
44 {
45 log<level::ERR>("Opening the xdma device failed", entry("RC=%d", rc));
46 return rc;
47 }
48 auto xdmaFDPtr = std::make_unique<utils::CustomFD>(fd);
49 auto& xdmaFD = *(xdmaFDPtr.get());
50
51 void* vgaMem = nullptr;
52
53 vgaMem = mmap(nullptr, pageLength, PROT_WRITE, MAP_SHARED, xdmaFD(), 0);
54 if (MAP_FAILED == vgaMem)
55 {
56 rc = -errno;
57 log<level::ERR>("mmap operation failed", entry("RC=%d", rc));
58 return rc;
59 }
60 std::unique_ptr<void, decltype(mmapCleanup)> vgaMemPtr(vgaMem, mmapCleanup);
61
62 // Populate the VGA memory with the contents of the file
63 std::ifstream stream(file.string());
64 stream.seekg(offset);
65 stream.read(static_cast<char*>(vgaMemPtr.get()), length);
66 if (stream.gcount() != length)
67 {
68 log<level::ERR>(
69 "mismatch between number of characters to read and the length read",
70 entry("LENGTH=%d", length), entry("COUNT=%d", stream.gcount()));
71 return -1;
72 }
73
74 struct dma::AspeedXdmaOp xdmaOp
75 {
76 };
77 xdmaOp.upstream = true;
78 xdmaOp.hostAddr = address;
79 xdmaOp.len = length;
80
81 // Initiate the DMA operation
82 rc = write(xdmaFD(), &xdmaOp, sizeof(xdmaOp));
83 if (rc < 0)
84 {
85 rc = -errno;
86 log<level::ERR>("the dma operation failed", entry("RC=%d", rc),
87 entry("UPSTREAM=%d", xdmaOp.upstream),
88 entry("ADDRESS=%lld", address),
89 entry("LENGTH=%d", length));
90 return rc;
91 }
92
93 return rc;
94}
95
96void readFileIntoMemory(const uint8_t* request, size_t payloadLength,
97 pldm_msg* response)
98{
99 uint32_t fileHandle = 0;
100 uint32_t offset = 0;
101 uint32_t length = 0;
102 uint64_t address = 0;
103
104 if (payloadLength != PLDM_READ_FILE_MEM_REQ_BYTES)
105 {
106 encode_read_file_memory_resp(0, PLDM_ERROR_INVALID_LENGTH, 0, response);
107 return;
108 }
109
110 decode_read_file_memory_req(request, payloadLength, &fileHandle, &offset,
111 &length, &address);
112
113 constexpr auto readFilePath = "";
114
115 fs::path path{readFilePath};
116 if (!fs::exists(path))
117 {
118 log<level::ERR>("File does not exist", entry("HANDLE=%d", fileHandle));
119 encode_read_file_memory_resp(0, PLDM_INVALID_FILE_HANDLE, 0, response);
120 return;
121 }
122
123 auto fileSize = fs::file_size(path);
124
125 if (offset >= fileSize)
126 {
127 log<level::ERR>("Offset exceeds file size", entry("OFFSET=%d", offset),
128 entry("FILE_SIZE=%d", fileSize));
129 encode_read_file_memory_resp(0, PLDM_DATA_OUT_OF_RANGE, 0, response);
130 return;
131 }
132
133 if (offset + length > fileSize)
134 {
135 length = fileSize - offset;
136 }
137
138 if (length % dma::minSize)
139 {
140 log<level::ERR>("Readlength is not a multiple of DMA minSize",
141 entry("LENGTH=%d", length));
142 encode_read_file_memory_resp(0, PLDM_INVALID_READ_LENGTH, 0, response);
143 return;
144 }
145
146 uint32_t origLength = length;
147
148 while (length > 0)
149 {
150 if (length > dma::maxSize)
151 {
152 auto rc =
153 dma::transferDatatoHost(path, offset, dma::maxSize, address);
154 if (rc < 0)
155 {
156 encode_read_file_memory_resp(0, PLDM_ERROR, 0, response);
157 return;
158 }
159 offset += dma::maxSize;
160 length -= dma::maxSize;
161 address += dma::maxSize;
162 }
163 else
164 {
165 auto rc = dma::transferDatatoHost(path, offset, length, address);
166 if (rc < 0)
167 {
168 encode_read_file_memory_resp(0, PLDM_ERROR, 0, response);
169 return;
170 }
171 encode_read_file_memory_resp(0, PLDM_SUCCESS, origLength, response);
172 return;
173 }
174 }
175}
176
177} // namespace responder
178} // namespace pldm