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 <sdbusplus/server.hpp> 14 #include <xyz/openbmc_project/Dump/NewDump/server.hpp> 15 16 #include <exception> 17 #include <filesystem> 18 #include <iostream> 19 #include <type_traits> 20 21 using namespace pldm::responder::utils; 22 using namespace pldm::utils; 23 24 namespace pldm 25 { 26 namespace responder 27 { 28 static constexpr auto dumpEntry = "xyz.openbmc_project.Dump.Entry"; 29 static constexpr auto dumpObjPath = "/xyz/openbmc_project/dump/system"; 30 static constexpr auto systemDumpEntry = "xyz.openbmc_project.Dump.Entry.System"; 31 static constexpr auto resDumpObjPath = "/xyz/openbmc_project/dump/resource"; 32 static constexpr auto resDumpEntry = "com.ibm.Dump.Entry.Resource"; 33 34 // Resource dump file path to be deleted once hyperviosr validates the input 35 // parameters. Need to re-look in to this name when we support multiple 36 // resource dumps. 37 static constexpr auto resDumpDirPath = "/var/lib/pldm/resourcedump/1"; 38 39 int DumpHandler::fd = -1; 40 namespace fs = std::filesystem; 41 42 std::string DumpHandler::findDumpObjPath(uint32_t fileHandle) 43 { 44 static constexpr auto DUMP_MANAGER_BUSNAME = 45 "xyz.openbmc_project.Dump.Manager"; 46 static constexpr auto DUMP_MANAGER_PATH = "/xyz/openbmc_project/dump"; 47 static constexpr auto OBJECT_MANAGER_INTERFACE = 48 "org.freedesktop.DBus.ObjectManager"; 49 auto& bus = pldm::utils::DBusHandler::getBus(); 50 51 // Stores the current resource dump entry path 52 std::string curResDumpEntryPath{}; 53 54 dbus::ObjectValueTree objects; 55 auto method = 56 bus.new_method_call(DUMP_MANAGER_BUSNAME, DUMP_MANAGER_PATH, 57 OBJECT_MANAGER_INTERFACE, "GetManagedObjects"); 58 59 // Select the dump entry interface for system dump or resource dump 60 DumpEntryInterface dumpEntryIntf = systemDumpEntry; 61 if ((dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP) || 62 (dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS)) 63 { 64 dumpEntryIntf = resDumpEntry; 65 } 66 67 try 68 { 69 auto reply = bus.call(method); 70 reply.read(objects); 71 } 72 73 catch (const std::exception& e) 74 { 75 std::cerr << "findDumpObjPath: Error " << e.what() 76 << "found with GetManagedObjects call in findDumpObjPath " 77 << "with objPath=" << DUMP_MANAGER_PATH 78 << " and intf=" << dumpEntryIntf << "\n"; 79 return curResDumpEntryPath; 80 } 81 82 for (const auto& object : objects) 83 { 84 for (const auto& interface : object.second) 85 { 86 if (interface.first != dumpEntryIntf) 87 { 88 continue; 89 } 90 91 for (auto& propertyMap : interface.second) 92 { 93 if (propertyMap.first == "SourceDumpId") 94 { 95 auto dumpIdPtr = std::get_if<uint32_t>(&propertyMap.second); 96 if (dumpIdPtr != nullptr) 97 { 98 auto dumpId = *dumpIdPtr; 99 if (fileHandle == dumpId) 100 { 101 curResDumpEntryPath = object.first.str; 102 return curResDumpEntryPath; 103 } 104 } 105 else 106 { 107 std::cerr 108 << "Invalid SourceDumpId in curResDumpEntryPath " 109 << curResDumpEntryPath 110 << " but continuing with next entry for a match..." 111 << "\n"; 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 = 135 pldm::utils::DBusHandler().getService(notifyObjPath, 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); 141 } 142 catch (const std::exception& e) 143 { 144 std::cerr << "newFileAvailable: Error " << e.what() 145 << "found while notifying new dump to dump manager " 146 << "with objPath=" << notifyObjPath 147 << " and intf=" << dumpInterface << "\n"; 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 std::cerr << "getOffloadUri: Error " << e.what() 173 << "found while fetching the dump offload URI " 174 << "with objPath=" << path.c_str() 175 << " and intf=" << socketInterface << "\n"; 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 std::cerr 193 << "DumpHandler::writeFromMemory: setupUnixSocket() failed" 194 << std::endl; 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 std::cerr << "DumpHandler::write: writeToUnixSocket() failed" 215 << std::endl; 216 return PLDM_ERROR; 217 } 218 219 return PLDM_SUCCESS; 220 } 221 222 int DumpHandler::fileAck(uint8_t fileStatus) 223 { 224 auto path = findDumpObjPath(fileHandle); 225 if (dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS) 226 { 227 if (fileStatus != PLDM_SUCCESS) 228 { 229 std::cerr << "Failue in resource dump file ack" << std::endl; 230 pldm::utils::reportError( 231 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 232 233 PropertyValue value{ 234 "xyz.openbmc_project.Common.Progress.OperationStatus.Failed"}; 235 DBusMapping dbusMapping{path, "xyz.openbmc_project.Common.Progress", 236 "Status", "string"}; 237 try 238 { 239 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value); 240 } 241 catch (const std::exception& e) 242 { 243 std::cerr << "fileAck: Error " << e.what() 244 << "found while setting the dump progress status as " 245 << "Failed with objPath=" << path.c_str() 246 << " and intf=Common.Progress" 247 << "\n"; 248 } 249 } 250 251 if (fs::exists(resDumpDirPath)) 252 { 253 fs::remove_all(resDumpDirPath); 254 } 255 return PLDM_SUCCESS; 256 } 257 258 if (!path.empty()) 259 { 260 if (fileStatus == PLDM_ERROR_FILE_DISCARDED) 261 { 262 uint32_t val = 0xFFFFFFFF; 263 PropertyValue value = static_cast<uint32_t>(val); 264 auto dumpIntf = resDumpEntry; 265 266 if (dumpType == PLDM_FILE_TYPE_DUMP) 267 { 268 dumpIntf = systemDumpEntry; 269 } 270 271 DBusMapping dbusMapping{path.c_str(), dumpIntf, "SourceDumpId", 272 "uint32_t"}; 273 try 274 { 275 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value); 276 } 277 catch (const std::exception& e) 278 { 279 std::cerr << "fileAck: Failed to make a d-bus call to DUMP " 280 "manager to reset source dump id of " 281 << path.c_str() << ", with ERROR=" << e.what() 282 << "\n"; 283 pldm::utils::reportError( 284 "xyz.openbmc_project.bmc.PLDM.fileAck.SourceDumpIdResetFail"); 285 return PLDM_ERROR; 286 } 287 288 auto& bus = pldm::utils::DBusHandler::getBus(); 289 try 290 { 291 auto method = bus.new_method_call( 292 "xyz.openbmc_project.Dump.Manager", path.c_str(), 293 "xyz.openbmc_project.Object.Delete", "Delete"); 294 bus.call(method); 295 } 296 catch (const std::exception& e) 297 { 298 std::cerr 299 << "fileAck: Failed to make a d-bus method to delete the dump entry " 300 << path.c_str() << ", with ERROR=" << e.what() << "\n"; 301 pldm::utils::reportError( 302 "xyz.openbmc_project.bmc.PLDM.fileAck.DumpEntryDeleteFail"); 303 return PLDM_ERROR; 304 } 305 return PLDM_SUCCESS; 306 } 307 308 if (dumpType == PLDM_FILE_TYPE_DUMP || 309 dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP) 310 { 311 PropertyValue value{true}; 312 DBusMapping dbusMapping{path, dumpEntry, "Offloaded", "bool"}; 313 try 314 { 315 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value); 316 } 317 catch (const std::exception& e) 318 { 319 std::cerr 320 << "fileAck: Failed to make a d-bus method to set the dump " 321 << "offloaded property to true with path=" << path.c_str() 322 << "and with ERROR=" << e.what() << "\n"; 323 } 324 325 auto socketInterface = getOffloadUri(fileHandle); 326 std::remove(socketInterface.c_str()); 327 if (DumpHandler::fd >= 0) 328 { 329 close(DumpHandler::fd); 330 DumpHandler::fd = -1; 331 } 332 } 333 return PLDM_SUCCESS; 334 } 335 336 return PLDM_ERROR; 337 } 338 339 int DumpHandler::readIntoMemory(uint32_t offset, uint32_t& length, 340 uint64_t address, 341 oem_platform::Handler* /*oemPlatformHandler*/) 342 { 343 if (dumpType != PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS) 344 { 345 return PLDM_ERROR_UNSUPPORTED_PLDM_CMD; 346 } 347 return transferFileData(resDumpDirPath, true, offset, length, address); 348 } 349 350 int DumpHandler::read(uint32_t offset, uint32_t& length, Response& response, 351 oem_platform::Handler* /*oemPlatformHandler*/) 352 { 353 if (dumpType != PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS) 354 { 355 return PLDM_ERROR_UNSUPPORTED_PLDM_CMD; 356 } 357 return readFile(resDumpDirPath, offset, length, response); 358 } 359 360 } // namespace responder 361 } // namespace pldm 362