1 #include "file_io_type_dump.hpp"
2
3 #include "common/utils.hpp"
4 #include "utils.hpp"
5 #include "xyz/openbmc_project/Common/error.hpp"
6
7 #include <libpldm/base.h>
8 #include <libpldm/oem/ibm/file_io.h>
9 #include <systemd/sd-bus.h>
10 #include <unistd.h>
11
12 #include <phosphor-logging/lg2.hpp>
13 #include <sdbusplus/server.hpp>
14 #include <xyz/openbmc_project/Dump/NewDump/server.hpp>
15
16 #include <cstdint>
17 #include <exception>
18 #include <filesystem>
19 #include <type_traits>
20
21 PHOSPHOR_LOG2_USING;
22
23 using namespace pldm::responder::utils;
24 using namespace pldm::utils;
25
26 namespace pldm
27 {
28 namespace responder
29 {
30 static constexpr auto dumpEntry = "xyz.openbmc_project.Dump.Entry";
31 static constexpr auto dumpObjPath = "/xyz/openbmc_project/dump/system";
32 static constexpr auto systemDumpEntry = "xyz.openbmc_project.Dump.Entry.System";
33 static constexpr auto resDumpObjPath = "/xyz/openbmc_project/dump/resource";
34 static constexpr auto resDumpEntry = "com.ibm.Dump.Entry.Resource";
35
36 // Resource dump file path to be deleted once hyperviosr validates the input
37 // parameters. Need to re-look in to this name when we support multiple
38 // resource dumps.
39 static constexpr auto resDumpDirPath = "/var/lib/pldm/resourcedump/1";
40
41 int DumpHandler::fd = -1;
42 namespace fs = std::filesystem;
43
findDumpObjPath(uint32_t fileHandle)44 std::string DumpHandler::findDumpObjPath(uint32_t fileHandle)
45 {
46 static constexpr auto DUMP_MANAGER_BUSNAME =
47 "xyz.openbmc_project.Dump.Manager";
48 static constexpr auto DUMP_MANAGER_PATH = "/xyz/openbmc_project/dump";
49
50 // Stores the current resource dump entry path
51 std::string curResDumpEntryPath{};
52
53 ObjectValueTree objects;
54 // Select the dump entry interface for system dump or resource dump
55 DumpEntryInterface dumpEntryIntf = systemDumpEntry;
56 if ((dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP) ||
57 (dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS))
58 {
59 dumpEntryIntf = resDumpEntry;
60 }
61
62 try
63 {
64 objects = pldm::utils::DBusHandler::getManagedObj(DUMP_MANAGER_BUSNAME,
65 DUMP_MANAGER_PATH);
66 }
67 catch (const sdbusplus::exception_t& e)
68 {
69 error(
70 "Failed to retrieve dump object using GetManagedObjects call for path '{PATH}' and interface '{INTERFACE}', error - {ERROR}",
71 "PATH", DUMP_MANAGER_PATH, "INTERFACE", dumpEntryIntf, "ERROR", e);
72 return curResDumpEntryPath;
73 }
74
75 for (const auto& object : objects)
76 {
77 for (const auto& interface : object.second)
78 {
79 if (interface.first != dumpEntryIntf)
80 {
81 continue;
82 }
83
84 for (auto& propertyMap : interface.second)
85 {
86 if (propertyMap.first == "SourceDumpId")
87 {
88 auto dumpIdPtr = std::get_if<uint32_t>(&propertyMap.second);
89 if (dumpIdPtr != nullptr)
90 {
91 auto dumpId = *dumpIdPtr;
92 if (fileHandle == dumpId)
93 {
94 curResDumpEntryPath = object.first.str;
95 return curResDumpEntryPath;
96 }
97 }
98 else
99 {
100 error(
101 "Invalid SourceDumpId in curResDumpEntryPath '{PATH}' but continuing with next entry for a match...",
102 "PATH", object.first.str);
103 }
104 }
105 }
106 }
107 }
108 return curResDumpEntryPath;
109 }
110
newFileAvailable(uint64_t length)111 int DumpHandler::newFileAvailable(uint64_t length)
112 {
113 static constexpr auto dumpInterface = "xyz.openbmc_project.Dump.NewDump";
114 auto& bus = pldm::utils::DBusHandler::getBus();
115
116 auto notifyObjPath = dumpObjPath;
117 if (dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP)
118 {
119 // Setting the Notify path for resource dump
120 notifyObjPath = resDumpObjPath;
121 }
122
123 try
124 {
125 auto service =
126 pldm::utils::DBusHandler().getService(notifyObjPath, dumpInterface);
127 using namespace sdbusplus::xyz::openbmc_project::Dump::server;
128 auto method = bus.new_method_call(service.c_str(), notifyObjPath,
129 dumpInterface, "Notify");
130 method.append(fileHandle, length);
131 bus.call_noreply(method, dbusTimeout);
132 }
133 catch (const std::exception& e)
134 {
135 error(
136 "Error '{ERROR}' found for new file available while notifying new dump to dump manager with object path {PATH} and interface {INTERFACE}",
137 "ERROR", e, "PATH", notifyObjPath, "INTERFACE", dumpInterface);
138 return PLDM_ERROR;
139 }
140
141 return PLDM_SUCCESS;
142 }
143
getOffloadUri(uint32_t fileHandle)144 std::string DumpHandler::getOffloadUri(uint32_t fileHandle)
145 {
146 auto path = findDumpObjPath(fileHandle);
147 if (path.empty())
148 {
149 return {};
150 }
151
152 std::string socketInterface{};
153
154 try
155 {
156 socketInterface =
157 pldm::utils::DBusHandler().getDbusProperty<std::string>(
158 path.c_str(), "OffloadUri", dumpEntry);
159 }
160 catch (const std::exception& e)
161 {
162 error(
163 "Error '{ERROR}' found while fetching the dump offload URI with object path '{PATH}' and interface '{INTERFACE}'",
164 "ERROR", e, "PATH", path, "INTERFACE", socketInterface);
165 }
166
167 return socketInterface;
168 }
169
writeFromMemory(uint32_t,uint32_t length,uint64_t address,oem_platform::Handler *)170 int DumpHandler::writeFromMemory(uint32_t, uint32_t length, uint64_t address,
171 oem_platform::Handler* /*oemPlatformHandler*/)
172 {
173 if (DumpHandler::fd == -1)
174 {
175 auto socketInterface = getOffloadUri(fileHandle);
176 int sock = setupUnixSocket(socketInterface);
177 if (sock < 0)
178 {
179 sock = -errno;
180 close(DumpHandler::fd);
181 error(
182 "Failed to setup Unix socket while write from memory for interface '{INTERFACE}', response code '{SOCKET_RC}'",
183 "INTERFACE", socketInterface, "SOCKET_RC", sock);
184 std::remove(socketInterface.c_str());
185 return PLDM_ERROR;
186 }
187
188 DumpHandler::fd = sock;
189 }
190 return transferFileDataToSocket(DumpHandler::fd, length, address);
191 }
192
write(const char * buffer,uint32_t,uint32_t & length,oem_platform::Handler *)193 int DumpHandler::write(const char* buffer, uint32_t, uint32_t& length,
194 oem_platform::Handler* /*oemPlatformHandler*/)
195 {
196 int rc = writeToUnixSocket(DumpHandler::fd, buffer, length);
197 if (rc < 0)
198 {
199 rc = -errno;
200 close(DumpHandler::fd);
201 auto socketInterface = getOffloadUri(fileHandle);
202 std::remove(socketInterface.c_str());
203 error(
204 "Failed to do dump write to Unix socket for interface '{INTERFACE}', response code '{RC}'",
205 "INTERFACE", socketInterface, "RC", rc);
206 return PLDM_ERROR;
207 }
208
209 return PLDM_SUCCESS;
210 }
211
fileAck(uint8_t fileStatus)212 int DumpHandler::fileAck(uint8_t fileStatus)
213 {
214 auto path = findDumpObjPath(fileHandle);
215 if (dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS)
216 {
217 if (fileStatus != PLDM_SUCCESS)
218 {
219 error("Failure in resource dump file ack");
220 pldm::utils::reportError(
221 "xyz.openbmc_project.PLDM.Error.fileAck.ResourceDumpFileAckFail");
222
223 PropertyValue value{
224 "xyz.openbmc_project.Common.Progress.OperationStatus.Failed"};
225 DBusMapping dbusMapping{path, "xyz.openbmc_project.Common.Progress",
226 "Status", "string"};
227 try
228 {
229 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
230 }
231 catch (const std::exception& e)
232 {
233 error(
234 "Error '{ERROR}' found for file ack while setting the dump progress status as 'Failed' with object path '{PATH}' and interface 'xyz.openbmc_project.Common.Progress'",
235 "ERROR", e, "PATH", path);
236 }
237 }
238
239 if (fs::exists(resDumpDirPath))
240 {
241 fs::remove_all(resDumpDirPath);
242 }
243 return PLDM_SUCCESS;
244 }
245
246 if (!path.empty())
247 {
248 if (fileStatus == PLDM_ERROR_FILE_DISCARDED)
249 {
250 uint32_t val = 0xFFFFFFFF;
251 PropertyValue value = static_cast<uint32_t>(val);
252 auto dumpIntf = resDumpEntry;
253
254 if (dumpType == PLDM_FILE_TYPE_DUMP)
255 {
256 dumpIntf = systemDumpEntry;
257 }
258
259 DBusMapping dbusMapping{path.c_str(), dumpIntf, "SourceDumpId",
260 "uint32_t"};
261 try
262 {
263 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
264 }
265 catch (const std::exception& e)
266 {
267 error(
268 "Failed to make a D-bus call to DUMP manager for resetting source dump file '{PATH}' on interface '{INTERFACE}', error - {ERROR}",
269 "PATH", path, "INTERFACE", dumpIntf, "ERROR", e);
270 pldm::utils::reportError(
271 "xyz.openbmc_project.bmc.PLDM.fileAck.SourceDumpIdResetFail");
272 return PLDM_ERROR;
273 }
274
275 auto& bus = pldm::utils::DBusHandler::getBus();
276 try
277 {
278 auto method = bus.new_method_call(
279 "xyz.openbmc_project.Dump.Manager", path.c_str(),
280 "xyz.openbmc_project.Object.Delete", "Delete");
281 bus.call(method, dbusTimeout);
282 }
283 catch (const std::exception& e)
284 {
285 error(
286 "Failed to make a D-bus call to DUMP manager for delete dump file '{PATH}', error - {ERROR}",
287 "PATH", path, "ERROR", e);
288 pldm::utils::reportError(
289 "xyz.openbmc_project.bmc.PLDM.fileAck.DumpEntryDeleteFail");
290 return PLDM_ERROR;
291 }
292 return PLDM_SUCCESS;
293 }
294
295 if (dumpType == PLDM_FILE_TYPE_DUMP ||
296 dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP)
297 {
298 PropertyValue value{true};
299 DBusMapping dbusMapping{path, dumpEntry, "Offloaded", "bool"};
300 try
301 {
302 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
303 }
304 catch (const std::exception& e)
305 {
306 error(
307 "Failed to make a D-bus call to DUMP manager to set the dump offloaded property 'true' for dump file '{PATH}', error - {ERROR}",
308 "PATH", path, "ERROR", e);
309 }
310
311 auto socketInterface = getOffloadUri(fileHandle);
312 std::remove(socketInterface.c_str());
313 if (DumpHandler::fd >= 0)
314 {
315 close(DumpHandler::fd);
316 DumpHandler::fd = -1;
317 }
318 }
319 return PLDM_SUCCESS;
320 }
321
322 return PLDM_ERROR;
323 }
324
readIntoMemory(uint32_t offset,uint32_t length,uint64_t address,oem_platform::Handler *)325 int DumpHandler::readIntoMemory(uint32_t offset, uint32_t length,
326 uint64_t address,
327 oem_platform::Handler* /*oemPlatformHandler*/)
328 {
329 if (dumpType != PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS)
330 {
331 return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
332 }
333 return transferFileData(resDumpDirPath, true, offset, length, address);
334 }
335
read(uint32_t offset,uint32_t & length,Response & response,oem_platform::Handler *)336 int DumpHandler::read(uint32_t offset, uint32_t& length, Response& response,
337 oem_platform::Handler* /*oemPlatformHandler*/)
338 {
339 if (dumpType != PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS)
340 {
341 return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
342 }
343 return readFile(resDumpDirPath, offset, length, response);
344 }
345
346 } // namespace responder
347 } // namespace pldm
348