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