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 // Select the dump entry interface for system dump or resource dump 56 DumpEntryInterface dumpEntryIntf = systemDumpEntry; 57 if ((dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP) || 58 (dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS)) 59 { 60 dumpEntryIntf = resDumpEntry; 61 } 62 63 try 64 { 65 auto method = 66 bus.new_method_call(DUMP_MANAGER_BUSNAME, DUMP_MANAGER_PATH, 67 OBJECT_MANAGER_INTERFACE, "GetManagedObjects"); 68 69 auto reply = bus.call(method); 70 reply.read(objects); 71 } 72 catch (const sdbusplus::exception_t& e) 73 { 74 std::cerr << "findDumpObjPath: Error " << e.what() 75 << "found with GetManagedObjects call in findDumpObjPath " 76 << "with objPath=" << DUMP_MANAGER_PATH 77 << " and intf=" << dumpEntryIntf << "\n"; 78 return curResDumpEntryPath; 79 } 80 81 for (const auto& object : objects) 82 { 83 for (const auto& interface : object.second) 84 { 85 if (interface.first != dumpEntryIntf) 86 { 87 continue; 88 } 89 90 for (auto& propertyMap : interface.second) 91 { 92 if (propertyMap.first == "SourceDumpId") 93 { 94 auto dumpIdPtr = std::get_if<uint32_t>(&propertyMap.second); 95 if (dumpIdPtr != nullptr) 96 { 97 auto dumpId = *dumpIdPtr; 98 if (fileHandle == dumpId) 99 { 100 curResDumpEntryPath = object.first.str; 101 return curResDumpEntryPath; 102 } 103 } 104 else 105 { 106 std::cerr 107 << "Invalid SourceDumpId in curResDumpEntryPath " 108 << curResDumpEntryPath 109 << " but continuing with next entry for a match..." 110 << "\n"; 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 = 134 pldm::utils::DBusHandler().getService(notifyObjPath, 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); 140 } 141 catch (const std::exception& e) 142 { 143 std::cerr << "newFileAvailable: Error " << e.what() 144 << "found while notifying new dump to dump manager " 145 << "with objPath=" << notifyObjPath 146 << " and intf=" << dumpInterface << "\n"; 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 std::cerr << "getOffloadUri: Error " << e.what() 172 << "found while fetching the dump offload URI " 173 << "with objPath=" << path.c_str() 174 << " and intf=" << socketInterface << "\n"; 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 std::cerr 192 << "DumpHandler::writeFromMemory: setupUnixSocket() failed" 193 << std::endl; 194 std::remove(socketInterface.c_str()); 195 return PLDM_ERROR; 196 } 197 198 DumpHandler::fd = sock; 199 } 200 return transferFileDataToSocket(DumpHandler::fd, length, address); 201 } 202 203 int DumpHandler::write(const char* buffer, uint32_t, uint32_t& length, 204 oem_platform::Handler* /*oemPlatformHandler*/) 205 { 206 int rc = writeToUnixSocket(DumpHandler::fd, buffer, length); 207 if (rc < 0) 208 { 209 rc = -errno; 210 close(DumpHandler::fd); 211 auto socketInterface = getOffloadUri(fileHandle); 212 std::remove(socketInterface.c_str()); 213 std::cerr << "DumpHandler::write: writeToUnixSocket() failed" 214 << std::endl; 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 std::cerr << "Failue in resource dump file ack" << std::endl; 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 std::cerr << "fileAck: Error " << e.what() 243 << "found while setting the dump progress status as " 244 << "Failed with objPath=" << path.c_str() 245 << " and intf=Common.Progress" 246 << "\n"; 247 } 248 } 249 250 if (fs::exists(resDumpDirPath)) 251 { 252 fs::remove_all(resDumpDirPath); 253 } 254 return PLDM_SUCCESS; 255 } 256 257 if (!path.empty()) 258 { 259 if (fileStatus == PLDM_ERROR_FILE_DISCARDED) 260 { 261 uint32_t val = 0xFFFFFFFF; 262 PropertyValue value = static_cast<uint32_t>(val); 263 auto dumpIntf = resDumpEntry; 264 265 if (dumpType == PLDM_FILE_TYPE_DUMP) 266 { 267 dumpIntf = systemDumpEntry; 268 } 269 270 DBusMapping dbusMapping{path.c_str(), dumpIntf, "SourceDumpId", 271 "uint32_t"}; 272 try 273 { 274 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value); 275 } 276 catch (const std::exception& e) 277 { 278 std::cerr << "fileAck: Failed to make a d-bus call to DUMP " 279 "manager to reset source dump id of " 280 << path.c_str() << ", with ERROR=" << e.what() 281 << "\n"; 282 pldm::utils::reportError( 283 "xyz.openbmc_project.bmc.PLDM.fileAck.SourceDumpIdResetFail"); 284 return PLDM_ERROR; 285 } 286 287 auto& bus = pldm::utils::DBusHandler::getBus(); 288 try 289 { 290 auto method = bus.new_method_call( 291 "xyz.openbmc_project.Dump.Manager", path.c_str(), 292 "xyz.openbmc_project.Object.Delete", "Delete"); 293 bus.call(method); 294 } 295 catch (const std::exception& e) 296 { 297 std::cerr 298 << "fileAck: Failed to make a d-bus method to delete the dump entry " 299 << path.c_str() << ", with ERROR=" << e.what() << "\n"; 300 pldm::utils::reportError( 301 "xyz.openbmc_project.bmc.PLDM.fileAck.DumpEntryDeleteFail"); 302 return PLDM_ERROR; 303 } 304 return PLDM_SUCCESS; 305 } 306 307 if (dumpType == PLDM_FILE_TYPE_DUMP || 308 dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP) 309 { 310 PropertyValue value{true}; 311 DBusMapping dbusMapping{path, dumpEntry, "Offloaded", "bool"}; 312 try 313 { 314 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value); 315 } 316 catch (const std::exception& e) 317 { 318 std::cerr 319 << "fileAck: Failed to make a d-bus method to set the dump " 320 << "offloaded property to true with path=" << path.c_str() 321 << "and with ERROR=" << e.what() << "\n"; 322 } 323 324 auto socketInterface = getOffloadUri(fileHandle); 325 std::remove(socketInterface.c_str()); 326 if (DumpHandler::fd >= 0) 327 { 328 close(DumpHandler::fd); 329 DumpHandler::fd = -1; 330 } 331 } 332 return PLDM_SUCCESS; 333 } 334 335 return PLDM_ERROR; 336 } 337 338 int DumpHandler::readIntoMemory(uint32_t offset, uint32_t& length, 339 uint64_t address, 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 transferFileData(resDumpDirPath, true, offset, length, address); 347 } 348 349 int DumpHandler::read(uint32_t offset, uint32_t& length, Response& response, 350 oem_platform::Handler* /*oemPlatformHandler*/) 351 { 352 if (dumpType != PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS) 353 { 354 return PLDM_ERROR_UNSUPPORTED_PLDM_CMD; 355 } 356 return readFile(resDumpDirPath, offset, length, response); 357 } 358 359 } // namespace responder 360 } // namespace pldm 361