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