blob: 00b8e9927e98cb486d1ea36f8927d64c4908986d [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"
6#include "oem/ibm/libpldm/file_io.h"
7
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 {
118 std::cerr << "GetPEL D-Bus call failed, PEL id = " << fileHandle
119 << ", error = " << e.what() << "\n";
120 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 {
186 std::cerr << "GetPEL D-Bus call failed";
187 return PLDM_ERROR;
188 }
189 return PLDM_SUCCESS;
Deepak Kodihalli75e02f82019-11-20 02:51:05 -0600190}
191
Sampa Misra854e61f2019-08-22 04:36:47 -0500192int PelHandler::writeFromMemory(uint32_t offset, uint32_t length,
Sampa Misra69508502020-09-08 00:08:21 -0500193 uint64_t address,
194 oem_platform::Handler* /*oemPlatformHandler*/)
Sampa Misra854e61f2019-08-22 04:36:47 -0500195{
Sampa Misraf5087a42019-12-03 04:51:36 -0600196 char tmpFile[] = "/tmp/pel.XXXXXX";
197 int fd = mkstemp(tmpFile);
198 if (fd == -1)
199 {
Sampa Misraaa8ae722019-12-12 03:20:40 -0600200 std::cerr << "failed to create a temporary pel, ERROR=" << errno
201 << "\n";
Sampa Misraf5087a42019-12-03 04:51:36 -0600202 return PLDM_ERROR;
203 }
204 close(fd);
205 fs::path path(tmpFile);
Sampa Misra854e61f2019-08-22 04:36:47 -0500206
207 auto rc = transferFileData(path, false, offset, length, address);
208 if (rc == PLDM_SUCCESS)
209 {
210 rc = storePel(path.string());
211 }
Sampa Misra854e61f2019-08-22 04:36:47 -0500212 return rc;
213}
214
Deepak Kodihalli2da1bfe2019-12-14 08:28:09 -0600215int PelHandler::fileAck(uint8_t /*fileStatus*/)
216{
217 static constexpr auto logObjPath = "/xyz/openbmc_project/logging";
218 static constexpr auto logInterface = "org.open_power.Logging.PEL";
George Liu0e02c322020-01-01 09:41:51 +0800219 auto& bus = pldm::utils::DBusHandler::getBus();
Deepak Kodihalli2da1bfe2019-12-14 08:28:09 -0600220
221 try
222 {
George Liu0e02c322020-01-01 09:41:51 +0800223 auto service =
224 pldm::utils::DBusHandler().getService(logObjPath, logInterface);
Deepak Kodihalli2da1bfe2019-12-14 08:28:09 -0600225 auto method = bus.new_method_call(service.c_str(), logObjPath,
226 logInterface, "HostAck");
227 method.append(fileHandle);
228 bus.call_noreply(method);
229 }
230 catch (const std::exception& e)
231 {
232 std::cerr << "HostAck D-Bus call failed";
233 return PLDM_ERROR;
234 }
235
236 return PLDM_SUCCESS;
237}
238
Sampa Misra854e61f2019-08-22 04:36:47 -0500239int PelHandler::storePel(std::string&& pelFileName)
240{
241 static constexpr auto logObjPath = "/xyz/openbmc_project/logging";
242 static constexpr auto logInterface = "xyz.openbmc_project.Logging.Create";
243
George Liu0e02c322020-01-01 09:41:51 +0800244 auto& bus = pldm::utils::DBusHandler::getBus();
Sampa Misra854e61f2019-08-22 04:36:47 -0500245
246 try
247 {
George Liu0e02c322020-01-01 09:41:51 +0800248 auto service =
249 pldm::utils::DBusHandler().getService(logObjPath, logInterface);
Sampa Misra854e61f2019-08-22 04:36:47 -0500250 using namespace sdbusplus::xyz::openbmc_project::Logging::server;
251 std::map<std::string, std::string> addlData{};
Sampa Misra854e61f2019-08-22 04:36:47 -0500252 auto severity =
253 sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage(
Matt Spinler39d8c7a2020-03-05 11:28:59 -0600254 detail::getEntryLevelFromPEL(pelFileName));
255 addlData.emplace("RAWPEL", std::move(pelFileName));
Sampa Misra854e61f2019-08-22 04:36:47 -0500256
257 auto method = bus.new_method_call(service.c_str(), logObjPath,
258 logInterface, "Create");
259 method.append("xyz.openbmc_project.Host.Error.Event", severity,
260 addlData);
261 bus.call_noreply(method);
262 }
263 catch (const std::exception& e)
264 {
Sampa Misraaa8ae722019-12-12 03:20:40 -0600265 std::cerr << "failed to make a d-bus call to PEL daemon, ERROR="
266 << e.what() << "\n";
Sampa Misra854e61f2019-08-22 04:36:47 -0500267 return PLDM_ERROR;
268 }
269
270 return PLDM_SUCCESS;
271}
272
George Liud37b4952021-06-28 15:14:29 +0800273int PelHandler::write(const char* buffer, uint32_t offset, uint32_t& length,
274 oem_platform::Handler* /*oemPlatformHandler*/)
275{
276 int rc = PLDM_SUCCESS;
277
278 if (offset > 0)
279 {
280 std::cerr << "Offset is non zero \n";
281 return PLDM_ERROR;
282 }
283
284 char tmpFile[] = "/tmp/pel.XXXXXX";
285 auto fd = mkstemp(tmpFile);
286 if (fd == -1)
287 {
288 std::cerr << "failed to create a temporary pel, ERROR=" << errno
289 << "\n";
290 return PLDM_ERROR;
291 }
292
293 size_t written = 0;
294 do
295 {
296 if ((rc = ::write(fd, buffer, length - written)) == -1)
297 {
298 break;
299 }
300 written += rc;
301 buffer += rc;
302 } while (rc && written < length);
303 close(fd);
304
305 if (rc == -1)
306 {
307 std::cerr << "file write failed, ERROR=" << errno
308 << ", LENGTH=" << length << ", OFFSET=" << offset << "\n";
309 fs::remove(tmpFile);
310 return PLDM_ERROR;
311 }
312
313 if (written == length)
314 {
315 fs::path path(tmpFile);
316 rc = storePel(path.string());
317 if (rc != PLDM_SUCCESS)
318 {
319 std::cerr << "save PEL failed, ERROR = " << rc
320 << "tmpFile = " << tmpFile << "\n";
321 }
322 }
323
324 return rc;
325}
326
Sampa Misra854e61f2019-08-22 04:36:47 -0500327} // namespace responder
328} // namespace pldm