1 #include "file_io_type_dump.hpp" 2 3 #include "libpldm/base.h" 4 #include "oem/ibm/libpldm/file_io.h" 5 6 #include "common/utils.hpp" 7 #include "utils.hpp" 8 #include "xyz/openbmc_project/Common/error.hpp" 9 10 #include <stdint.h> 11 #include <systemd/sd-bus.h> 12 #include <unistd.h> 13 14 #include <sdbusplus/server.hpp> 15 #include <xyz/openbmc_project/Dump/NewDump/server.hpp> 16 17 #include <exception> 18 #include <filesystem> 19 #include <iostream> 20 #include <type_traits> 21 22 using namespace pldm::responder::utils; 23 using namespace pldm::utils; 24 25 namespace pldm 26 { 27 namespace responder 28 { 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 MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper"; 47 static constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper"; 48 static constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper"; 49 auto& bus = pldm::utils::DBusHandler::getBus(); 50 51 // Stores the current resource dump entry path 52 std::string curResDumpEntryPath{}; 53 54 try 55 { 56 std::vector<std::string> paths; 57 auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH, 58 MAPPER_INTERFACE, "GetSubTreePaths"); 59 if (dumpType == PLDM_FILE_TYPE_DUMP) 60 { 61 method.append(dumpObjPath); 62 method.append(0); 63 method.append(std::vector<std::string>({systemDumpEntry})); 64 } 65 else if ((dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP) || 66 (dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS)) 67 { 68 method.append(resDumpObjPath); 69 method.append(0); 70 method.append(std::vector<std::string>({resDumpEntry})); 71 } 72 73 auto reply = bus.call(method); 74 reply.read(paths); 75 76 for (const auto& path : paths) 77 { 78 uint32_t dumpId = 0; 79 curResDumpEntryPath = path; 80 if (dumpType == PLDM_FILE_TYPE_DUMP) 81 { 82 dumpId = pldm::utils::DBusHandler().getDbusProperty<uint32_t>( 83 path.c_str(), "SourceDumpId", systemDumpEntry); 84 } 85 else if (dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP || 86 dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS) 87 { 88 dumpId = pldm::utils::DBusHandler().getDbusProperty<uint32_t>( 89 path.c_str(), "SourceDumpId", resDumpEntry); 90 } 91 92 if (dumpId == fileHandle) 93 { 94 curResDumpEntryPath = path; 95 break; 96 } 97 } 98 } 99 catch (const std::exception& e) 100 { 101 std::cerr << "failed to make a d-bus call to DUMP manager, ERROR=" 102 << e.what() << "\n"; 103 } 104 105 return curResDumpEntryPath; 106 } 107 108 int DumpHandler::newFileAvailable(uint64_t length) 109 { 110 static constexpr auto dumpInterface = "xyz.openbmc_project.Dump.NewDump"; 111 auto& bus = pldm::utils::DBusHandler::getBus(); 112 113 auto notifyObjPath = dumpObjPath; 114 if (dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP) 115 { 116 // Setting the Notify path for resource dump 117 notifyObjPath = resDumpObjPath; 118 119 uint32_t sourceDumpId = fileHandle; 120 auto path = findDumpObjPath(fileHandle); 121 122 pldm::utils::PropertyValue propValue{sourceDumpId}; 123 124 DBusMapping dbusMapping{path, resDumpEntry, "SourceDumpId", "uint32_t"}; 125 try 126 { 127 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, propValue); 128 } 129 catch (const std::exception& e) 130 { 131 std::cerr << "failed to make a d-bus call to DUMP manager to set " 132 "resource dump SourceDumpId, ERROR=" 133 << e.what() << "\n"; 134 } 135 } 136 137 try 138 { 139 auto service = 140 pldm::utils::DBusHandler().getService(notifyObjPath, dumpInterface); 141 using namespace sdbusplus::xyz::openbmc_project::Dump::server; 142 auto method = bus.new_method_call(service.c_str(), notifyObjPath, 143 dumpInterface, "Notify"); 144 method.append(fileHandle, length); 145 bus.call_noreply(method); 146 } 147 catch (const std::exception& e) 148 { 149 std::cerr << "failed to make a d-bus call to DUMP manager, ERROR=" 150 << e.what() << "\n"; 151 return PLDM_ERROR; 152 } 153 154 return PLDM_SUCCESS; 155 } 156 157 std::string DumpHandler::getOffloadUri(uint32_t fileHandle) 158 { 159 auto path = findDumpObjPath(fileHandle); 160 if (path.empty()) 161 { 162 return {}; 163 } 164 165 std::string socketInterface{}; 166 167 try 168 { 169 socketInterface = 170 pldm::utils::DBusHandler().getDbusProperty<std::string>( 171 path.c_str(), "OffloadUri", dumpEntry); 172 } 173 catch (const std::exception& e) 174 { 175 std::cerr << "failed to make a d-bus call to DUMP manager, ERROR=" 176 << e.what() << "\n"; 177 } 178 179 return socketInterface; 180 } 181 182 int DumpHandler::writeFromMemory(uint32_t, uint32_t length, uint64_t address, 183 oem_platform::Handler* /*oemPlatformHandler*/) 184 { 185 if (DumpHandler::fd == -1) 186 { 187 auto socketInterface = getOffloadUri(fileHandle); 188 int sock = setupUnixSocket(socketInterface); 189 if (sock < 0) 190 { 191 sock = -errno; 192 close(DumpHandler::fd); 193 std::cerr 194 << "DumpHandler::writeFromMemory: setupUnixSocket() failed" 195 << std::endl; 196 std::remove(socketInterface.c_str()); 197 return PLDM_ERROR; 198 } 199 200 DumpHandler::fd = sock; 201 } 202 return transferFileDataToSocket(DumpHandler::fd, length, address); 203 } 204 205 int DumpHandler::write(const char* buffer, uint32_t, uint32_t& length, 206 oem_platform::Handler* /*oemPlatformHandler*/) 207 { 208 int rc = writeToUnixSocket(DumpHandler::fd, buffer, length); 209 if (rc < 0) 210 { 211 rc = -errno; 212 close(DumpHandler::fd); 213 auto socketInterface = getOffloadUri(fileHandle); 214 std::remove(socketInterface.c_str()); 215 std::cerr << "DumpHandler::write: writeToUnixSocket() failed" 216 << std::endl; 217 return PLDM_ERROR; 218 } 219 220 return PLDM_SUCCESS; 221 } 222 223 int DumpHandler::fileAck(uint8_t fileStatus) 224 { 225 auto path = findDumpObjPath(fileHandle); 226 if (dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS) 227 { 228 if (fileStatus != PLDM_SUCCESS) 229 { 230 std::cerr << "Failue in resource dump file ack" << std::endl; 231 pldm::utils::reportError( 232 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 233 234 PropertyValue value{ 235 "xyz.openbmc_project.Common.Progress.OperationStatus.Failed"}; 236 DBusMapping dbusMapping{path, "xyz.openbmc_project.Common.Progress", 237 "Status", "string"}; 238 try 239 { 240 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value); 241 } 242 catch (const std::exception& e) 243 { 244 std::cerr << "failed to make a d-bus call to DUMP " 245 "manager, ERROR=" 246 << e.what() << "\n"; 247 } 248 } 249 250 if (fs::exists(resDumpDirPath)) 251 { 252 fs::remove_all(resDumpDirPath); 253 } 254 return PLDM_SUCCESS; 255 } 256 257 if (DumpHandler::fd >= 0 && !path.empty()) 258 { 259 if (dumpType == PLDM_FILE_TYPE_DUMP || 260 dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP) 261 { 262 PropertyValue value{true}; 263 DBusMapping dbusMapping{path, dumpEntry, "Offloaded", "bool"}; 264 try 265 { 266 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value); 267 } 268 catch (const std::exception& e) 269 { 270 std::cerr 271 << "failed to make a d-bus call to DUMP manager, ERROR=" 272 << e.what() << "\n"; 273 } 274 275 close(DumpHandler::fd); 276 auto socketInterface = getOffloadUri(fileHandle); 277 std::remove(socketInterface.c_str()); 278 DumpHandler::fd = -1; 279 } 280 return PLDM_SUCCESS; 281 } 282 283 return PLDM_ERROR; 284 } 285 286 int DumpHandler::readIntoMemory(uint32_t offset, uint32_t& length, 287 uint64_t address, 288 oem_platform::Handler* /*oemPlatformHandler*/) 289 { 290 if (dumpType != PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS) 291 { 292 return PLDM_ERROR_UNSUPPORTED_PLDM_CMD; 293 } 294 return transferFileData(resDumpDirPath, true, offset, length, address); 295 } 296 297 int DumpHandler::read(uint32_t offset, uint32_t& length, Response& response, 298 oem_platform::Handler* /*oemPlatformHandler*/) 299 { 300 if (dumpType != PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS) 301 { 302 return PLDM_ERROR_UNSUPPORTED_PLDM_CMD; 303 } 304 return readFile(resDumpDirPath, offset, length, response); 305 } 306 307 } // namespace responder 308 } // namespace pldm 309