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 120 try 121 { 122 auto service = 123 pldm::utils::DBusHandler().getService(notifyObjPath, dumpInterface); 124 using namespace sdbusplus::xyz::openbmc_project::Dump::server; 125 auto method = bus.new_method_call(service.c_str(), notifyObjPath, 126 dumpInterface, "Notify"); 127 method.append(fileHandle, length); 128 bus.call_noreply(method); 129 } 130 catch (const std::exception& e) 131 { 132 std::cerr << "failed to make a d-bus call to DUMP manager, ERROR=" 133 << e.what() << "\n"; 134 return PLDM_ERROR; 135 } 136 137 return PLDM_SUCCESS; 138 } 139 140 std::string DumpHandler::getOffloadUri(uint32_t fileHandle) 141 { 142 auto path = findDumpObjPath(fileHandle); 143 if (path.empty()) 144 { 145 return {}; 146 } 147 148 std::string socketInterface{}; 149 150 try 151 { 152 socketInterface = 153 pldm::utils::DBusHandler().getDbusProperty<std::string>( 154 path.c_str(), "OffloadUri", dumpEntry); 155 } 156 catch (const std::exception& e) 157 { 158 std::cerr << "failed to make a d-bus call to DUMP manager, ERROR=" 159 << e.what() << "\n"; 160 } 161 162 return socketInterface; 163 } 164 165 int DumpHandler::writeFromMemory(uint32_t, uint32_t length, uint64_t address, 166 oem_platform::Handler* /*oemPlatformHandler*/) 167 { 168 if (DumpHandler::fd == -1) 169 { 170 auto socketInterface = getOffloadUri(fileHandle); 171 int sock = setupUnixSocket(socketInterface); 172 if (sock < 0) 173 { 174 sock = -errno; 175 close(DumpHandler::fd); 176 std::cerr 177 << "DumpHandler::writeFromMemory: setupUnixSocket() failed" 178 << std::endl; 179 std::remove(socketInterface.c_str()); 180 return PLDM_ERROR; 181 } 182 183 DumpHandler::fd = sock; 184 } 185 return transferFileDataToSocket(DumpHandler::fd, length, address); 186 } 187 188 int DumpHandler::write(const char* buffer, uint32_t, uint32_t& length, 189 oem_platform::Handler* /*oemPlatformHandler*/) 190 { 191 int rc = writeToUnixSocket(DumpHandler::fd, buffer, length); 192 if (rc < 0) 193 { 194 rc = -errno; 195 close(DumpHandler::fd); 196 auto socketInterface = getOffloadUri(fileHandle); 197 std::remove(socketInterface.c_str()); 198 std::cerr << "DumpHandler::write: writeToUnixSocket() failed" 199 << std::endl; 200 return PLDM_ERROR; 201 } 202 203 return PLDM_SUCCESS; 204 } 205 206 int DumpHandler::fileAck(uint8_t fileStatus) 207 { 208 auto path = findDumpObjPath(fileHandle); 209 if (dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS) 210 { 211 if (fileStatus != PLDM_SUCCESS) 212 { 213 std::cerr << "Failue in resource dump file ack" << std::endl; 214 pldm::utils::reportError( 215 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 216 217 PropertyValue value{ 218 "xyz.openbmc_project.Common.Progress.OperationStatus.Failed"}; 219 DBusMapping dbusMapping{path, "xyz.openbmc_project.Common.Progress", 220 "Status", "string"}; 221 try 222 { 223 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value); 224 } 225 catch (const std::exception& e) 226 { 227 std::cerr << "failed to make a d-bus call to DUMP " 228 "manager, ERROR=" 229 << e.what() << "\n"; 230 } 231 } 232 233 if (fs::exists(resDumpDirPath)) 234 { 235 fs::remove_all(resDumpDirPath); 236 } 237 return PLDM_SUCCESS; 238 } 239 240 if (DumpHandler::fd >= 0 && !path.empty()) 241 { 242 if (dumpType == PLDM_FILE_TYPE_DUMP || 243 dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP) 244 { 245 PropertyValue value{true}; 246 DBusMapping dbusMapping{path, dumpEntry, "Offloaded", "bool"}; 247 try 248 { 249 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value); 250 } 251 catch (const std::exception& e) 252 { 253 std::cerr 254 << "failed to make a d-bus call to DUMP manager, ERROR=" 255 << e.what() << "\n"; 256 } 257 258 close(DumpHandler::fd); 259 auto socketInterface = getOffloadUri(fileHandle); 260 std::remove(socketInterface.c_str()); 261 DumpHandler::fd = -1; 262 } 263 return PLDM_SUCCESS; 264 } 265 266 return PLDM_ERROR; 267 } 268 269 int DumpHandler::readIntoMemory(uint32_t offset, uint32_t& length, 270 uint64_t address, 271 oem_platform::Handler* /*oemPlatformHandler*/) 272 { 273 if (dumpType != PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS) 274 { 275 return PLDM_ERROR_UNSUPPORTED_PLDM_CMD; 276 } 277 return transferFileData(resDumpDirPath, true, offset, length, address); 278 } 279 280 int DumpHandler::read(uint32_t offset, uint32_t& length, Response& response, 281 oem_platform::Handler* /*oemPlatformHandler*/) 282 { 283 if (dumpType != PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS) 284 { 285 return PLDM_ERROR_UNSUPPORTED_PLDM_CMD; 286 } 287 return readFile(resDumpDirPath, offset, length, response); 288 } 289 290 } // namespace responder 291 } // namespace pldm 292