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