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