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