blob: 69d3f2e4eab04b68b6c701cd1497587f129d50fd [file] [log] [blame]
Sampa Misra854e61f2019-08-22 04:36:47 -05001#include "config.h"
2
3#include "file_io_type_pel.hpp"
4
George Liu83409572019-12-24 18:42:54 +08005#include "utils.hpp"
Sampa Misra854e61f2019-08-22 04:36:47 -05006#include "xyz/openbmc_project/Common/error.hpp"
7
8#include <stdint.h>
9#include <systemd/sd-bus.h>
10#include <unistd.h>
11
12#include <exception>
13#include <filesystem>
Matt Spinler39d8c7a2020-03-05 11:28:59 -060014#include <fstream>
Sampa Misraaa8ae722019-12-12 03:20:40 -060015#include <iostream>
Sampa Misra854e61f2019-08-22 04:36:47 -050016#include <sdbusplus/server.hpp>
17#include <vector>
18#include <xyz/openbmc_project/Logging/Entry/server.hpp>
19
20#include "libpldm/base.h"
21#include "oem/ibm/libpldm/file_io.h"
22
23namespace pldm
24{
25namespace responder
26{
27
Matt Spinler39d8c7a2020-03-05 11:28:59 -060028using namespace sdbusplus::xyz::openbmc_project::Logging::server;
29
30namespace detail
31{
32
33/**
34 * @brief Finds the Entry::Level value for the severity of the PEL
35 * passed in.
36 *
37 * The severity byte is at offset 10 in the User Header section,
38 * which is always after the 48 byte Private Header section.
39 *
40 * @param[in] pelFileName - The file containing the PEL
41 *
42 * @return Entry::Level - The severity value for the Entry
43 */
44Entry::Level getEntryLevelFromPEL(const std::string& pelFileName)
45{
46 const std::map<uint8_t, Entry::Level> severityMap{
47 {0x00, Entry::Level::Informational}, // Informational event
48 {0x10, Entry::Level::Warning}, // Recoverable error
49 {0x20, Entry::Level::Warning}, // Predictive error
50 {0x40, Entry::Level::Error}, // Unrecoverable error
51 {0x50, Entry::Level::Error}, // Critical error
52 {0x60, Entry::Level::Error}, // Error from a diagnostic test
53 {0x70, Entry::Level::Warning} // Recoverable symptom
54 };
55
56 const size_t severityOffset = 0x3A;
57
58 size_t size = 0;
59 if (fs::exists(pelFileName))
60 {
61 size = fs::file_size(pelFileName);
62 }
63
64 if (size > severityOffset)
65 {
66 std::ifstream pel{pelFileName};
67 if (pel.good())
68 {
69 pel.seekg(severityOffset);
70
71 uint8_t sev;
72 pel.read(reinterpret_cast<char*>(&sev), 1);
73
74 // Get the type
75 sev = sev & 0xF0;
76
77 auto entry = severityMap.find(sev);
78 if (entry != severityMap.end())
79 {
80 return entry->second;
81 }
82 }
83 else
84 {
85 std::cerr << "Unable to open PEL file " << pelFileName << "\n";
86 }
87 }
88
89 return Entry::Level::Error;
90}
91} // namespace detail
92
Deepak Kodihalli15211b42019-12-14 02:24:49 -060093int PelHandler::readIntoMemory(uint32_t offset, uint32_t& length,
94 uint64_t address)
Deepak Kodihallif6d3a832019-11-19 07:00:29 -060095{
Deepak Kodihalli15211b42019-12-14 02:24:49 -060096 static constexpr auto logObjPath = "/xyz/openbmc_project/logging";
97 static constexpr auto logInterface = "org.open_power.Logging.PEL";
98
George Liu0e02c322020-01-01 09:41:51 +080099 auto& bus = pldm::utils::DBusHandler::getBus();
Deepak Kodihalli15211b42019-12-14 02:24:49 -0600100
101 try
102 {
George Liu0e02c322020-01-01 09:41:51 +0800103 auto service =
104 pldm::utils::DBusHandler().getService(logObjPath, logInterface);
Deepak Kodihalli15211b42019-12-14 02:24:49 -0600105 auto method = bus.new_method_call(service.c_str(), logObjPath,
106 logInterface, "GetPEL");
107 method.append(fileHandle);
108 auto reply = bus.call(method);
109 sdbusplus::message::unix_fd fd{};
110 reply.read(fd);
111 auto rc = transferFileData(fd, true, offset, length, address);
112 return rc;
113 }
114 catch (const std::exception& e)
115 {
116 std::cerr << "GetPEL D-Bus call failed, PEL id = " << fileHandle
117 << ", error = " << e.what() << "\n";
118 return PLDM_ERROR;
119 }
120
121 return PLDM_SUCCESS;
Deepak Kodihallif6d3a832019-11-19 07:00:29 -0600122}
123
Deepak Kodihalli15211b42019-12-14 02:24:49 -0600124int PelHandler::read(uint32_t offset, uint32_t& length, Response& response)
Deepak Kodihalli75e02f82019-11-20 02:51:05 -0600125{
Deepak Kodihalli15211b42019-12-14 02:24:49 -0600126 static constexpr auto logObjPath = "/xyz/openbmc_project/logging";
127 static constexpr auto logInterface = "org.open_power.Logging.PEL";
George Liu0e02c322020-01-01 09:41:51 +0800128 auto& bus = pldm::utils::DBusHandler::getBus();
Deepak Kodihalli15211b42019-12-14 02:24:49 -0600129
130 try
131 {
George Liu0e02c322020-01-01 09:41:51 +0800132 auto service =
133 pldm::utils::DBusHandler().getService(logObjPath, logInterface);
Deepak Kodihalli15211b42019-12-14 02:24:49 -0600134 auto method = bus.new_method_call(service.c_str(), logObjPath,
135 logInterface, "GetPEL");
136 method.append(fileHandle);
137 auto reply = bus.call(method);
138 sdbusplus::message::unix_fd fd{};
139 reply.read(fd);
Pavithraba0738b2020-01-29 08:47:51 -0600140
Deepak Kodihalli15211b42019-12-14 02:24:49 -0600141 off_t fileSize = lseek(fd, 0, SEEK_END);
142 if (fileSize == -1)
143 {
144 std::cerr << "file seek failed";
145 return PLDM_ERROR;
146 }
147 if (offset >= fileSize)
148 {
149 std::cerr << "Offset exceeds file size, OFFSET=" << offset
150 << " FILE_SIZE=" << fileSize << std::endl;
151 return PLDM_DATA_OUT_OF_RANGE;
152 }
153 if (offset + length > fileSize)
154 {
155 length = fileSize - offset;
156 }
157 auto rc = lseek(fd, offset, SEEK_SET);
158 if (rc == -1)
159 {
160 std::cerr << "file seek failed";
161 return PLDM_ERROR;
162 }
163 size_t currSize = response.size();
164 response.resize(currSize + length);
165 auto filePos = reinterpret_cast<char*>(response.data());
166 filePos += currSize;
167 rc = ::read(fd, filePos, length);
168 if (rc == -1)
169 {
170 std::cerr << "file read failed";
171 return PLDM_ERROR;
172 }
173 if (rc != length)
174 {
175 std::cerr << "mismatch between number of characters to read and "
176 << "the length read, LENGTH=" << length << " COUNT=" << rc
177 << std::endl;
178 return PLDM_ERROR;
179 }
180 }
181 catch (const std::exception& e)
182 {
183 std::cerr << "GetPEL D-Bus call failed";
184 return PLDM_ERROR;
185 }
186 return PLDM_SUCCESS;
Deepak Kodihalli75e02f82019-11-20 02:51:05 -0600187}
188
Sampa Misra854e61f2019-08-22 04:36:47 -0500189int PelHandler::writeFromMemory(uint32_t offset, uint32_t length,
190 uint64_t address)
191{
Sampa Misraf5087a42019-12-03 04:51:36 -0600192 char tmpFile[] = "/tmp/pel.XXXXXX";
193 int fd = mkstemp(tmpFile);
194 if (fd == -1)
195 {
Sampa Misraaa8ae722019-12-12 03:20:40 -0600196 std::cerr << "failed to create a temporary pel, ERROR=" << errno
197 << "\n";
Sampa Misraf5087a42019-12-03 04:51:36 -0600198 return PLDM_ERROR;
199 }
200 close(fd);
201 fs::path path(tmpFile);
Sampa Misra854e61f2019-08-22 04:36:47 -0500202
203 auto rc = transferFileData(path, false, offset, length, address);
204 if (rc == PLDM_SUCCESS)
205 {
206 rc = storePel(path.string());
207 }
208 fs::remove(path);
209 return rc;
210}
211
Deepak Kodihalli2da1bfe2019-12-14 08:28:09 -0600212int PelHandler::fileAck(uint8_t /*fileStatus*/)
213{
214 static constexpr auto logObjPath = "/xyz/openbmc_project/logging";
215 static constexpr auto logInterface = "org.open_power.Logging.PEL";
George Liu0e02c322020-01-01 09:41:51 +0800216 auto& bus = pldm::utils::DBusHandler::getBus();
Deepak Kodihalli2da1bfe2019-12-14 08:28:09 -0600217
218 try
219 {
George Liu0e02c322020-01-01 09:41:51 +0800220 auto service =
221 pldm::utils::DBusHandler().getService(logObjPath, logInterface);
Deepak Kodihalli2da1bfe2019-12-14 08:28:09 -0600222 auto method = bus.new_method_call(service.c_str(), logObjPath,
223 logInterface, "HostAck");
224 method.append(fileHandle);
225 bus.call_noreply(method);
226 }
227 catch (const std::exception& e)
228 {
229 std::cerr << "HostAck D-Bus call failed";
230 return PLDM_ERROR;
231 }
232
233 return PLDM_SUCCESS;
234}
235
Sampa Misra854e61f2019-08-22 04:36:47 -0500236int PelHandler::storePel(std::string&& pelFileName)
237{
238 static constexpr auto logObjPath = "/xyz/openbmc_project/logging";
239 static constexpr auto logInterface = "xyz.openbmc_project.Logging.Create";
240
George Liu0e02c322020-01-01 09:41:51 +0800241 auto& bus = pldm::utils::DBusHandler::getBus();
Sampa Misra854e61f2019-08-22 04:36:47 -0500242
243 try
244 {
George Liu0e02c322020-01-01 09:41:51 +0800245 auto service =
246 pldm::utils::DBusHandler().getService(logObjPath, logInterface);
Sampa Misra854e61f2019-08-22 04:36:47 -0500247 using namespace sdbusplus::xyz::openbmc_project::Logging::server;
248 std::map<std::string, std::string> addlData{};
Sampa Misra854e61f2019-08-22 04:36:47 -0500249 auto severity =
250 sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage(
Matt Spinler39d8c7a2020-03-05 11:28:59 -0600251 detail::getEntryLevelFromPEL(pelFileName));
252 addlData.emplace("RAWPEL", std::move(pelFileName));
Sampa Misra854e61f2019-08-22 04:36:47 -0500253
254 auto method = bus.new_method_call(service.c_str(), logObjPath,
255 logInterface, "Create");
256 method.append("xyz.openbmc_project.Host.Error.Event", severity,
257 addlData);
258 bus.call_noreply(method);
259 }
260 catch (const std::exception& e)
261 {
Sampa Misraaa8ae722019-12-12 03:20:40 -0600262 std::cerr << "failed to make a d-bus call to PEL daemon, ERROR="
263 << e.what() << "\n";
Sampa Misra854e61f2019-08-22 04:36:47 -0500264 return PLDM_ERROR;
265 }
266
267 return PLDM_SUCCESS;
268}
269
270} // namespace responder
271} // namespace pldm