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.PLDM.Error.fileAck.ResourceDumpFileAckFail", 224 pldm::PelSeverity::Informational); 225 226 PropertyValue value{ 227 "xyz.openbmc_project.Common.Progress.OperationStatus.Failed"}; 228 DBusMapping dbusMapping{path, "xyz.openbmc_project.Common.Progress", 229 "Status", "string"}; 230 try 231 { 232 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value); 233 } 234 catch (const std::exception& e) 235 { 236 error( 237 "fileAck: Error {ERR_EXCEP} found while setting the dump progress status as Failed with objPath={OBJ_PATH} and intf=Common.Progress", 238 "ERR_EXCEP", e.what(), "OBJ_PATH", path.c_str()); 239 } 240 } 241 242 if (fs::exists(resDumpDirPath)) 243 { 244 fs::remove_all(resDumpDirPath); 245 } 246 return PLDM_SUCCESS; 247 } 248 249 if (!path.empty()) 250 { 251 if (fileStatus == PLDM_ERROR_FILE_DISCARDED) 252 { 253 uint32_t val = 0xFFFFFFFF; 254 PropertyValue value = static_cast<uint32_t>(val); 255 auto dumpIntf = resDumpEntry; 256 257 if (dumpType == PLDM_FILE_TYPE_DUMP) 258 { 259 dumpIntf = systemDumpEntry; 260 } 261 262 DBusMapping dbusMapping{path.c_str(), dumpIntf, "SourceDumpId", 263 "uint32_t"}; 264 try 265 { 266 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value); 267 } 268 catch (const std::exception& e) 269 { 270 error( 271 "fileAck: Failed to make a d-bus call to DUMP manager to reset source dump id of {FILE_PATH}, with ERROR={ERR_EXCEP}", 272 "FILE_PATH", path.c_str(), "ERR_EXCEP", e.what()); 273 pldm::utils::reportError( 274 "xyz.openbmc_project.PLDM.Error.fileAck.SourceDumpIdResetFail"); 275 return PLDM_ERROR; 276 } 277 278 auto& bus = pldm::utils::DBusHandler::getBus(); 279 try 280 { 281 auto method = bus.new_method_call( 282 "xyz.openbmc_project.Dump.Manager", path.c_str(), 283 "xyz.openbmc_project.Object.Delete", "Delete"); 284 bus.call(method, dbusTimeout); 285 } 286 catch (const std::exception& e) 287 { 288 error( 289 "fileAck: Failed to make a d-bus method to delete the dump entry {FILE_PATH}, with ERROR={ERR_EXCEP}", 290 "FILE_PATH", path.c_str(), "ERR_EXCEP", e.what()); 291 pldm::utils::reportError( 292 "xyz.openbmc_project.PLDM.Error.fileAck.DumpEntryDeleteFail"); 293 return PLDM_ERROR; 294 } 295 return PLDM_SUCCESS; 296 } 297 298 if (dumpType == PLDM_FILE_TYPE_DUMP || 299 dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP) 300 { 301 PropertyValue value{true}; 302 DBusMapping dbusMapping{path, dumpEntry, "Offloaded", "bool"}; 303 try 304 { 305 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value); 306 } 307 catch (const std::exception& e) 308 { 309 error( 310 "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}", 311 "FILE_PATH", path.c_str(), "ERR_EXCEP", e.what()); 312 } 313 314 auto socketInterface = getOffloadUri(fileHandle); 315 std::remove(socketInterface.c_str()); 316 if (DumpHandler::fd >= 0) 317 { 318 close(DumpHandler::fd); 319 DumpHandler::fd = -1; 320 } 321 } 322 return PLDM_SUCCESS; 323 } 324 325 return PLDM_ERROR; 326 } 327 328 int DumpHandler::readIntoMemory(uint32_t offset, uint32_t& length, 329 uint64_t address, 330 oem_platform::Handler* /*oemPlatformHandler*/) 331 { 332 if (dumpType != PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS) 333 { 334 return PLDM_ERROR_UNSUPPORTED_PLDM_CMD; 335 } 336 return transferFileData(resDumpDirPath, true, offset, length, address); 337 } 338 339 int DumpHandler::read(uint32_t offset, uint32_t& length, Response& response, 340 oem_platform::Handler* /*oemPlatformHandler*/) 341 { 342 if (dumpType != PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS) 343 { 344 return PLDM_ERROR_UNSUPPORTED_PLDM_CMD; 345 } 346 return readFile(resDumpDirPath, offset, length, response); 347 } 348 349 } // namespace responder 350 } // namespace pldm 351