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