blob: ff68353595ea8d07aac011e6f9fe0370c63ed907 [file] [log] [blame]
Jie Yangfbe1b682021-02-19 04:54:55 -08001#include "handler.hpp"
2
3#include "mdrv2.hpp"
4#include "smbios_mdrv2.hpp"
5
6#include <sys/stat.h>
7#include <unistd.h>
8
9#include <ipmid/api.hpp>
Prithvi Pai6981b7f2025-04-02 10:33:29 +053010#include <phosphor-logging/lg2.hpp>
Jie Yangfbe1b682021-02-19 04:54:55 -080011#include <sdbusplus/bus.hpp>
12#include <sdbusplus/exception.hpp>
13#include <sdbusplus/message.hpp>
14
15#include <algorithm>
16#include <cstdint>
17#include <ctime>
Josh Lehan027277a2023-09-11 05:28:19 -070018#include <filesystem>
Jie Yangfbe1b682021-02-19 04:54:55 -080019#include <fstream>
20#include <memory>
21#include <string>
22#include <vector>
23
24namespace blobs
25{
26
27namespace internal
28{
29
30constexpr const char* mdrV2Service = "xyz.openbmc_project.Smbios.MDR_V2";
31constexpr const char* mdrV2Interface = "xyz.openbmc_project.Smbios.MDR_V2";
32
33bool syncSmbiosData()
34{
35 bool status = false;
Patrick Williams77b9c472022-07-22 19:26:57 -050036 sdbusplus::bus_t bus = sdbusplus::bus_t(ipmid_get_sd_bus_connection());
37 sdbusplus::message_t method =
Josh Lehan027277a2023-09-11 05:28:19 -070038 bus.new_method_call(mdrV2Service, phosphor::smbios::defaultObjectPath,
Jie Yangfbe1b682021-02-19 04:54:55 -080039 mdrV2Interface, "AgentSynchronizeData");
40
41 try
42 {
Patrick Williams77b9c472022-07-22 19:26:57 -050043 sdbusplus::message_t reply = bus.call(method);
Jie Yangfbe1b682021-02-19 04:54:55 -080044 reply.read(status);
45 }
Patrick Williams9ab8c8d2021-10-06 14:39:31 -050046 catch (const sdbusplus::exception_t& e)
Jie Yangfbe1b682021-02-19 04:54:55 -080047 {
Prithvi Pai6981b7f2025-04-02 10:33:29 +053048 lg2::error("Error Sync data with service: {E} SERVICE={S} PATH={P}",
49 "E", e.what(), "S", mdrV2Service, "P",
50 phosphor::smbios::defaultObjectPath);
Jie Yangfbe1b682021-02-19 04:54:55 -080051 return false;
52 }
53
54 if (!status)
55 {
Prithvi Pai6981b7f2025-04-02 10:33:29 +053056 lg2::error("Sync data with service failure");
Jie Yangfbe1b682021-02-19 04:54:55 -080057 return false;
58 }
59
60 return true;
61}
62
63} // namespace internal
64
65bool SmbiosBlobHandler::canHandleBlob(const std::string& path)
66{
67 return path == blobId;
68}
69
70std::vector<std::string> SmbiosBlobHandler::getBlobIds()
71{
72 return std::vector<std::string>(1, blobId);
73}
74
Jonathan Domanf2d8bb42023-07-26 10:13:34 -070075bool SmbiosBlobHandler::deleteBlob(const std::string& /* path */)
Jie Yangfbe1b682021-02-19 04:54:55 -080076{
77 return false;
78}
79
80bool SmbiosBlobHandler::stat(const std::string& path, struct BlobMeta* meta)
81{
82 if (!blobPtr || blobPtr->blobId != path)
83 {
84 return false;
85 }
86
87 meta->size = blobPtr->buffer.size();
88 meta->blobState = blobPtr->state;
89 return true;
90}
91
92bool SmbiosBlobHandler::open(uint16_t session, uint16_t flags,
93 const std::string& path)
94{
95 if (flags & blobs::OpenFlags::read)
96 {
97 /* Disable the read operation. */
98 return false;
99 }
100
101 /* The handler only allows one session. If an open blob exists, return
102 * false directly.
103 */
104 if (blobPtr)
105 {
106 return false;
107 }
108 blobPtr = std::make_unique<SmbiosBlob>(session, path, flags);
109 return true;
110}
111
Patrick Williams1d73dcc2024-08-16 15:21:42 -0400112std::vector<uint8_t> SmbiosBlobHandler::read(
113 uint16_t /* session */, uint32_t /* offset */, uint32_t /* requestedSize */)
Jie Yangfbe1b682021-02-19 04:54:55 -0800114{
115 /* SMBIOS blob handler does not support read. */
116 return std::vector<uint8_t>();
117}
118
119bool SmbiosBlobHandler::write(uint16_t session, uint32_t offset,
120 const std::vector<uint8_t>& data)
121{
122 if (!blobPtr || blobPtr->sessionId != session)
123 {
124 return false;
125 }
126
127 if (!(blobPtr->state & blobs::StateFlags::open_write))
128 {
Prithvi Pai6981b7f2025-04-02 10:33:29 +0530129 lg2::error("No open blob to write");
Jie Yangfbe1b682021-02-19 04:54:55 -0800130 return false;
131 }
132
133 /* Is the offset beyond the array? */
134 if (offset >= maxBufferSize)
135 {
136 return false;
137 }
138
139 /* Determine whether all their bytes will fit. */
140 uint32_t remain = maxBufferSize - offset;
141 if (data.size() > remain)
142 {
143 return false;
144 }
145
146 /* Resize the buffer if what we're writing will go over the size */
147 uint32_t newBufferSize = data.size() + offset;
148 if (newBufferSize > blobPtr->buffer.size())
149 {
150 blobPtr->buffer.resize(newBufferSize);
151 }
152
153 std::memcpy(blobPtr->buffer.data() + offset, data.data(), data.size());
154 return true;
155}
156
Jonathan Domanf2d8bb42023-07-26 10:13:34 -0700157bool SmbiosBlobHandler::writeMeta(uint16_t /* session */, uint32_t /* offset */,
158 const std::vector<uint8_t>& /* data */)
Jie Yangfbe1b682021-02-19 04:54:55 -0800159{
160 return false;
161}
162
163bool SmbiosBlobHandler::commit(uint16_t session,
164 const std::vector<uint8_t>& data)
165{
166 if (!data.empty())
167 {
Prithvi Pai6981b7f2025-04-02 10:33:29 +0530168 lg2::error("Unexpected data provided to commit call");
Jie Yangfbe1b682021-02-19 04:54:55 -0800169 return false;
170 }
171
172 if (!blobPtr || blobPtr->sessionId != session)
173 {
174 return false;
175 }
176
Manojkiran Eda0fe13ab2024-06-17 14:55:10 +0530177 /* If a blob is committing or committed, return true directly. But if last
Jie Yangfbe1b682021-02-19 04:54:55 -0800178 * commit fails, may try to commit again.
179 */
180 if (blobPtr->state &
181 (blobs::StateFlags::committing | blobs::StateFlags::committed))
182 {
183 return true;
184 }
185
186 /* Clear the commit_error bit. */
187 blobPtr->state &= ~blobs::StateFlags::commit_error;
188
Josh Lehan027277a2023-09-11 05:28:19 -0700189 std::string defaultDir =
190 std::filesystem::path(mdrDefaultFile).parent_path();
191
Jie Yangfbe1b682021-02-19 04:54:55 -0800192 MDRSMBIOSHeader mdrHdr;
Josh Lehanf079e832023-09-19 15:52:52 -0700193 mdrHdr.dirVer = mdrDirVersion;
Jie Yangfbe1b682021-02-19 04:54:55 -0800194 mdrHdr.mdrType = mdrTypeII;
195 mdrHdr.timestamp = std::time(nullptr);
196 mdrHdr.dataSize = blobPtr->buffer.size();
Josh Lehan027277a2023-09-11 05:28:19 -0700197 if (access(defaultDir.c_str(), F_OK) == -1)
Jie Yangfbe1b682021-02-19 04:54:55 -0800198 {
Josh Lehan027277a2023-09-11 05:28:19 -0700199 int flag = mkdir(defaultDir.c_str(), S_IRWXU);
Jie Yangfbe1b682021-02-19 04:54:55 -0800200 if (flag != 0)
201 {
Prithvi Pai6981b7f2025-04-02 10:33:29 +0530202 lg2::error("create folder failed for writing smbios file");
Jie Yangfbe1b682021-02-19 04:54:55 -0800203 blobPtr->state |= blobs::StateFlags::commit_error;
204 return false;
205 }
206 }
207
Josh Lehan027277a2023-09-11 05:28:19 -0700208 std::ofstream smbiosFile(mdrDefaultFile,
Jie Yangfbe1b682021-02-19 04:54:55 -0800209 std::ios_base::binary | std::ios_base::trunc);
210 if (!smbiosFile.good())
211 {
Prithvi Pai6981b7f2025-04-02 10:33:29 +0530212 lg2::error(
Jie Yangfbe1b682021-02-19 04:54:55 -0800213 "Write data from flash error - Open SMBIOS table file failure");
214 blobPtr->state |= blobs::StateFlags::commit_error;
215 return false;
216 }
217
218 smbiosFile.exceptions(std::ofstream::badbit | std::ofstream::failbit);
219 try
220 {
221 smbiosFile.write(reinterpret_cast<char*>(&mdrHdr),
222 sizeof(MDRSMBIOSHeader));
223 smbiosFile.write(reinterpret_cast<char*>(blobPtr->buffer.data()),
224 mdrHdr.dataSize);
Konstantin Aladyshev6106d542023-06-29 15:36:02 +0300225 smbiosFile.close();
Jie Yangfbe1b682021-02-19 04:54:55 -0800226 blobPtr->state |= blobs::StateFlags::committing;
227 }
Patrick Williams9ab8c8d2021-10-06 14:39:31 -0500228 catch (const std::ofstream::failure& e)
Jie Yangfbe1b682021-02-19 04:54:55 -0800229 {
Prithvi Pai6981b7f2025-04-02 10:33:29 +0530230 lg2::error("Write data from flash error - write data error: {E}", "E",
231 e.what());
Jie Yangfbe1b682021-02-19 04:54:55 -0800232 blobPtr->state |= blobs::StateFlags::commit_error;
233 return false;
234 }
235
236 if (!internal::syncSmbiosData())
237 {
238 blobPtr->state &= ~blobs::StateFlags::committing;
239 blobPtr->state |= blobs::StateFlags::commit_error;
240 return false;
241 }
242
243 // Unset committing state and set committed state
244 blobPtr->state &= ~blobs::StateFlags::committing;
245 blobPtr->state |= blobs::StateFlags::committed;
246
247 return true;
248}
249
250bool SmbiosBlobHandler::close(uint16_t session)
251{
252 if (!blobPtr || blobPtr->sessionId != session)
253 {
254 return false;
255 }
256
257 blobPtr = nullptr;
258 return true;
259}
260
261bool SmbiosBlobHandler::stat(uint16_t session, struct BlobMeta* meta)
262{
263 if (!blobPtr || blobPtr->sessionId != session)
264 {
265 return false;
266 }
267
268 meta->size = blobPtr->buffer.size();
269 meta->blobState = blobPtr->state;
270 return true;
271}
272
273bool SmbiosBlobHandler::expire(uint16_t session)
274{
275 return close(session);
276}
277
278} // namespace blobs