blob: 022b75e704dc098da9a7bd7850213365626b14c6 [file] [log] [blame]
Sampa Misra854e61f2019-08-22 04:36:47 -05001#include "config.h"
2
3#include "file_io_type_pel.hpp"
4
George Liu6492f522020-06-16 10:34:05 +08005#include "libpldm/base.h"
Andrew Jeffery27a022c2022-08-10 23:12:49 +09306#include "libpldm/file_io.h"
George Liu6492f522020-06-16 10:34:05 +08007
Deepak Kodihallid130e1a2020-06-17 05:55:32 -05008#include "common/utils.hpp"
Sampa Misra854e61f2019-08-22 04:36:47 -05009#include "xyz/openbmc_project/Common/error.hpp"
10
11#include <stdint.h>
12#include <systemd/sd-bus.h>
13#include <unistd.h>
14
George Liu6492f522020-06-16 10:34:05 +080015#include <sdbusplus/server.hpp>
16#include <xyz/openbmc_project/Logging/Entry/server.hpp>
17
Sampa Misra854e61f2019-08-22 04:36:47 -050018#include <exception>
19#include <filesystem>
Matt Spinler39d8c7a2020-03-05 11:28:59 -060020#include <fstream>
Sampa Misraaa8ae722019-12-12 03:20:40 -060021#include <iostream>
Sampa Misra854e61f2019-08-22 04:36:47 -050022#include <vector>
Sampa Misra854e61f2019-08-22 04:36:47 -050023
24namespace pldm
25{
26namespace responder
27{
28
Matt Spinler39d8c7a2020-03-05 11:28:59 -060029using namespace sdbusplus::xyz::openbmc_project::Logging::server;
30
31namespace detail
32{
33
34/**
35 * @brief Finds the Entry::Level value for the severity of the PEL
36 * passed in.
37 *
38 * The severity byte is at offset 10 in the User Header section,
39 * which is always after the 48 byte Private Header section.
40 *
41 * @param[in] pelFileName - The file containing the PEL
42 *
43 * @return Entry::Level - The severity value for the Entry
44 */
45Entry::Level getEntryLevelFromPEL(const std::string& pelFileName)
46{
47 const std::map<uint8_t, Entry::Level> severityMap{
48 {0x00, Entry::Level::Informational}, // Informational event
49 {0x10, Entry::Level::Warning}, // Recoverable error
50 {0x20, Entry::Level::Warning}, // Predictive error
51 {0x40, Entry::Level::Error}, // Unrecoverable error
52 {0x50, Entry::Level::Error}, // Critical error
53 {0x60, Entry::Level::Error}, // Error from a diagnostic test
54 {0x70, Entry::Level::Warning} // Recoverable symptom
55 };
56
57 const size_t severityOffset = 0x3A;
58
59 size_t size = 0;
60 if (fs::exists(pelFileName))
61 {
62 size = fs::file_size(pelFileName);
63 }
64
65 if (size > severityOffset)
66 {
67 std::ifstream pel{pelFileName};
68 if (pel.good())
69 {
70 pel.seekg(severityOffset);
71
72 uint8_t sev;
73 pel.read(reinterpret_cast<char*>(&sev), 1);
74
75 // Get the type
76 sev = sev & 0xF0;
77
78 auto entry = severityMap.find(sev);
79 if (entry != severityMap.end())
80 {
81 return entry->second;
82 }
83 }
84 else
85 {
86 std::cerr << "Unable to open PEL file " << pelFileName << "\n";
87 }
88 }
89
90 return Entry::Level::Error;
91}
92} // namespace detail
93
Deepak Kodihalli15211b42019-12-14 02:24:49 -060094int PelHandler::readIntoMemory(uint32_t offset, uint32_t& length,
Sampa Misra69508502020-09-08 00:08:21 -050095 uint64_t address,
96 oem_platform::Handler* /*oemPlatformHandler*/)
Deepak Kodihallif6d3a832019-11-19 07:00:29 -060097{
Deepak Kodihalli15211b42019-12-14 02:24:49 -060098 static constexpr auto logObjPath = "/xyz/openbmc_project/logging";
99 static constexpr auto logInterface = "org.open_power.Logging.PEL";
100
George Liu0e02c322020-01-01 09:41:51 +0800101 auto& bus = pldm::utils::DBusHandler::getBus();
Deepak Kodihalli15211b42019-12-14 02:24:49 -0600102
103 try
104 {
George Liu0e02c322020-01-01 09:41:51 +0800105 auto service =
106 pldm::utils::DBusHandler().getService(logObjPath, logInterface);
Deepak Kodihalli15211b42019-12-14 02:24:49 -0600107 auto method = bus.new_method_call(service.c_str(), logObjPath,
108 logInterface, "GetPEL");
109 method.append(fileHandle);
110 auto reply = bus.call(method);
111 sdbusplus::message::unix_fd fd{};
112 reply.read(fd);
113 auto rc = transferFileData(fd, true, offset, length, address);
114 return rc;
115 }
116 catch (const std::exception& e)
117 {
Matt Spinler72bf78e2021-09-24 13:46:13 -0500118 std::cerr << "GetPEL D-Bus call failed, PEL id = 0x" << std::hex
119 << fileHandle << ", error = " << e.what() << "\n";
Deepak Kodihalli15211b42019-12-14 02:24:49 -0600120 return PLDM_ERROR;
121 }
122
123 return PLDM_SUCCESS;
Deepak Kodihallif6d3a832019-11-19 07:00:29 -0600124}
125
Sampa Misra69508502020-09-08 00:08:21 -0500126int PelHandler::read(uint32_t offset, uint32_t& length, Response& response,
127 oem_platform::Handler* /*oemPlatformHandler*/)
Deepak Kodihalli75e02f82019-11-20 02:51:05 -0600128{
Deepak Kodihalli15211b42019-12-14 02:24:49 -0600129 static constexpr auto logObjPath = "/xyz/openbmc_project/logging";
130 static constexpr auto logInterface = "org.open_power.Logging.PEL";
George Liu0e02c322020-01-01 09:41:51 +0800131 auto& bus = pldm::utils::DBusHandler::getBus();
Deepak Kodihalli15211b42019-12-14 02:24:49 -0600132
133 try
134 {
George Liu0e02c322020-01-01 09:41:51 +0800135 auto service =
136 pldm::utils::DBusHandler().getService(logObjPath, logInterface);
Deepak Kodihalli15211b42019-12-14 02:24:49 -0600137 auto method = bus.new_method_call(service.c_str(), logObjPath,
138 logInterface, "GetPEL");
139 method.append(fileHandle);
140 auto reply = bus.call(method);
141 sdbusplus::message::unix_fd fd{};
142 reply.read(fd);
Pavithraba0738b2020-01-29 08:47:51 -0600143
Deepak Kodihalli15211b42019-12-14 02:24:49 -0600144 off_t fileSize = lseek(fd, 0, SEEK_END);
145 if (fileSize == -1)
146 {
147 std::cerr << "file seek failed";
148 return PLDM_ERROR;
149 }
150 if (offset >= fileSize)
151 {
152 std::cerr << "Offset exceeds file size, OFFSET=" << offset
153 << " FILE_SIZE=" << fileSize << std::endl;
154 return PLDM_DATA_OUT_OF_RANGE;
155 }
156 if (offset + length > fileSize)
157 {
158 length = fileSize - offset;
159 }
160 auto rc = lseek(fd, offset, SEEK_SET);
161 if (rc == -1)
162 {
163 std::cerr << "file seek failed";
164 return PLDM_ERROR;
165 }
166 size_t currSize = response.size();
167 response.resize(currSize + length);
168 auto filePos = reinterpret_cast<char*>(response.data());
169 filePos += currSize;
170 rc = ::read(fd, filePos, length);
171 if (rc == -1)
172 {
173 std::cerr << "file read failed";
174 return PLDM_ERROR;
175 }
176 if (rc != length)
177 {
178 std::cerr << "mismatch between number of characters to read and "
179 << "the length read, LENGTH=" << length << " COUNT=" << rc
180 << std::endl;
181 return PLDM_ERROR;
182 }
183 }
184 catch (const std::exception& e)
185 {
Matt Spinler72bf78e2021-09-24 13:46:13 -0500186 std::cerr << "GetPEL D-Bus call failed on PEL ID 0x" << std::hex
187 << fileHandle << ", error = " << e.what() << "\n";
Deepak Kodihalli15211b42019-12-14 02:24:49 -0600188 return PLDM_ERROR;
189 }
190 return PLDM_SUCCESS;
Deepak Kodihalli75e02f82019-11-20 02:51:05 -0600191}
192
Sampa Misra854e61f2019-08-22 04:36:47 -0500193int PelHandler::writeFromMemory(uint32_t offset, uint32_t length,
Sampa Misra69508502020-09-08 00:08:21 -0500194 uint64_t address,
195 oem_platform::Handler* /*oemPlatformHandler*/)
Sampa Misra854e61f2019-08-22 04:36:47 -0500196{
Sampa Misraf5087a42019-12-03 04:51:36 -0600197 char tmpFile[] = "/tmp/pel.XXXXXX";
198 int fd = mkstemp(tmpFile);
199 if (fd == -1)
200 {
Sampa Misraaa8ae722019-12-12 03:20:40 -0600201 std::cerr << "failed to create a temporary pel, ERROR=" << errno
202 << "\n";
Sampa Misraf5087a42019-12-03 04:51:36 -0600203 return PLDM_ERROR;
204 }
205 close(fd);
206 fs::path path(tmpFile);
Sampa Misra854e61f2019-08-22 04:36:47 -0500207
208 auto rc = transferFileData(path, false, offset, length, address);
209 if (rc == PLDM_SUCCESS)
210 {
211 rc = storePel(path.string());
212 }
Sampa Misra854e61f2019-08-22 04:36:47 -0500213 return rc;
214}
215
Deepak Kodihalli2da1bfe2019-12-14 08:28:09 -0600216int PelHandler::fileAck(uint8_t /*fileStatus*/)
217{
218 static constexpr auto logObjPath = "/xyz/openbmc_project/logging";
219 static constexpr auto logInterface = "org.open_power.Logging.PEL";
George Liu0e02c322020-01-01 09:41:51 +0800220 auto& bus = pldm::utils::DBusHandler::getBus();
Deepak Kodihalli2da1bfe2019-12-14 08:28:09 -0600221
222 try
223 {
George Liu0e02c322020-01-01 09:41:51 +0800224 auto service =
225 pldm::utils::DBusHandler().getService(logObjPath, logInterface);
Deepak Kodihalli2da1bfe2019-12-14 08:28:09 -0600226 auto method = bus.new_method_call(service.c_str(), logObjPath,
227 logInterface, "HostAck");
228 method.append(fileHandle);
229 bus.call_noreply(method);
230 }
231 catch (const std::exception& e)
232 {
Matt Spinler72bf78e2021-09-24 13:46:13 -0500233 std::cerr << "HostAck D-Bus call failed on PEL ID 0x" << std::hex
234 << fileHandle << ", error = " << e.what() << "\n";
Deepak Kodihalli2da1bfe2019-12-14 08:28:09 -0600235 return PLDM_ERROR;
236 }
237
238 return PLDM_SUCCESS;
239}
240
Sampa Misra854e61f2019-08-22 04:36:47 -0500241int PelHandler::storePel(std::string&& pelFileName)
242{
243 static constexpr auto logObjPath = "/xyz/openbmc_project/logging";
244 static constexpr auto logInterface = "xyz.openbmc_project.Logging.Create";
245
George Liu0e02c322020-01-01 09:41:51 +0800246 auto& bus = pldm::utils::DBusHandler::getBus();
Sampa Misra854e61f2019-08-22 04:36:47 -0500247
248 try
249 {
George Liu0e02c322020-01-01 09:41:51 +0800250 auto service =
251 pldm::utils::DBusHandler().getService(logObjPath, logInterface);
Sampa Misra854e61f2019-08-22 04:36:47 -0500252 using namespace sdbusplus::xyz::openbmc_project::Logging::server;
253 std::map<std::string, std::string> addlData{};
Sampa Misra854e61f2019-08-22 04:36:47 -0500254 auto severity =
255 sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage(
Matt Spinler39d8c7a2020-03-05 11:28:59 -0600256 detail::getEntryLevelFromPEL(pelFileName));
257 addlData.emplace("RAWPEL", std::move(pelFileName));
Sampa Misra854e61f2019-08-22 04:36:47 -0500258
259 auto method = bus.new_method_call(service.c_str(), logObjPath,
260 logInterface, "Create");
261 method.append("xyz.openbmc_project.Host.Error.Event", severity,
262 addlData);
263 bus.call_noreply(method);
264 }
265 catch (const std::exception& e)
266 {
Sampa Misraaa8ae722019-12-12 03:20:40 -0600267 std::cerr << "failed to make a d-bus call to PEL daemon, ERROR="
268 << e.what() << "\n";
Sampa Misra854e61f2019-08-22 04:36:47 -0500269 return PLDM_ERROR;
270 }
271
272 return PLDM_SUCCESS;
273}
274
George Liud37b4952021-06-28 15:14:29 +0800275int PelHandler::write(const char* buffer, uint32_t offset, uint32_t& length,
276 oem_platform::Handler* /*oemPlatformHandler*/)
277{
278 int rc = PLDM_SUCCESS;
279
280 if (offset > 0)
281 {
282 std::cerr << "Offset is non zero \n";
283 return PLDM_ERROR;
284 }
285
286 char tmpFile[] = "/tmp/pel.XXXXXX";
287 auto fd = mkstemp(tmpFile);
288 if (fd == -1)
289 {
290 std::cerr << "failed to create a temporary pel, ERROR=" << errno
291 << "\n";
292 return PLDM_ERROR;
293 }
294
295 size_t written = 0;
296 do
297 {
298 if ((rc = ::write(fd, buffer, length - written)) == -1)
299 {
300 break;
301 }
302 written += rc;
303 buffer += rc;
304 } while (rc && written < length);
305 close(fd);
306
307 if (rc == -1)
308 {
309 std::cerr << "file write failed, ERROR=" << errno
310 << ", LENGTH=" << length << ", OFFSET=" << offset << "\n";
311 fs::remove(tmpFile);
312 return PLDM_ERROR;
313 }
314
315 if (written == length)
316 {
317 fs::path path(tmpFile);
318 rc = storePel(path.string());
319 if (rc != PLDM_SUCCESS)
320 {
321 std::cerr << "save PEL failed, ERROR = " << rc
322 << "tmpFile = " << tmpFile << "\n";
323 }
324 }
325
326 return rc;
327}
328
Sampa Misra854e61f2019-08-22 04:36:47 -0500329} // namespace responder
330} // namespace pldm