1 #include "bios_table.hpp"
2
3 #include <libpldm/base.h>
4 #include <libpldm/bios_table.h>
5
6 #include <phosphor-logging/lg2.hpp>
7
8 #include <fstream>
9
10 PHOSPHOR_LOG2_USING;
11
12 namespace pldm
13 {
14 namespace responder
15 {
16 namespace bios
17 {
BIOSTable(const char * filePath)18 BIOSTable::BIOSTable(const char* filePath) : filePath(filePath) {}
19
isEmpty() const20 bool BIOSTable::isEmpty() const noexcept
21 {
22 bool empty = false;
23 try
24 {
25 empty = fs::is_empty(filePath);
26 }
27 catch (const fs::filesystem_error&)
28 {
29 return true;
30 }
31 return empty;
32 }
33
store(const Table & table)34 void BIOSTable::store(const Table& table)
35 {
36 std::ofstream stream(filePath.string(), std::ios::out | std::ios::binary);
37 stream.write(reinterpret_cast<const char*>(table.data()), table.size());
38 }
39
load(Response & response) const40 void BIOSTable::load(Response& response) const
41 {
42 auto currSize = response.size();
43 auto fileSize = fs::file_size(filePath);
44 response.resize(currSize + fileSize);
45 std::ifstream stream(filePath.string(), std::ios::in | std::ios::binary);
46 stream.read(reinterpret_cast<char*>(response.data() + currSize), fileSize);
47 }
48
BIOSStringTable(const Table & stringTable)49 BIOSStringTable::BIOSStringTable(const Table& stringTable) :
50 stringTable(stringTable)
51 {}
52
BIOSStringTable(const BIOSTable & biosTable)53 BIOSStringTable::BIOSStringTable(const BIOSTable& biosTable)
54 {
55 biosTable.load(stringTable);
56 }
57
findString(uint16_t handle) const58 std::string BIOSStringTable::findString(uint16_t handle) const
59 {
60 auto stringEntry = pldm_bios_table_string_find_by_handle(
61 stringTable.data(), stringTable.size(), handle);
62 if (stringEntry == nullptr)
63 {
64 throw std::invalid_argument("Invalid String Handle");
65 }
66 return table::string::decodeString(stringEntry);
67 }
68
findHandle(const std::string & name) const69 uint16_t BIOSStringTable::findHandle(const std::string& name) const
70 {
71 auto stringEntry = pldm_bios_table_string_find_by_string(
72 stringTable.data(), stringTable.size(), name.c_str());
73 if (stringEntry == nullptr)
74 {
75 throw std::invalid_argument("Invalid String Name");
76 }
77
78 return table::string::decodeHandle(stringEntry);
79 }
80
81 namespace table
82 {
appendPadAndChecksum(Table & table)83 void appendPadAndChecksum(Table& table)
84 {
85 size_t payloadSize = table.size();
86 table.resize(payloadSize + pldm_bios_table_pad_checksum_size(payloadSize));
87 // No validation of return value as preconditions are satisfied
88 pldm_bios_table_append_pad_checksum(table.data(), table.size(),
89 &payloadSize);
90 }
91
92 namespace string
93 {
decodeHandle(const pldm_bios_string_table_entry * entry)94 uint16_t decodeHandle(const pldm_bios_string_table_entry* entry)
95 {
96 return pldm_bios_table_string_entry_decode_handle(entry);
97 }
98
decodeString(const pldm_bios_string_table_entry * entry)99 std::string decodeString(const pldm_bios_string_table_entry* entry)
100 {
101 auto strLength = pldm_bios_table_string_entry_decode_string_length(entry);
102 std::vector<char> buffer(strLength + 1 /* sizeof '\0' */);
103 // Preconditions are upheld therefore no error check necessary
104 pldm_bios_table_string_entry_decode_string(entry, buffer.data(),
105 buffer.size());
106 return std::string(buffer.data(), buffer.data() + strLength);
107 }
constructEntry(Table & table,const std::string & str)108 const pldm_bios_string_table_entry* constructEntry(Table& table,
109 const std::string& str)
110 {
111 auto tableSize = table.size();
112 auto entryLength = pldm_bios_table_string_entry_encode_length(str.length());
113 table.resize(tableSize + entryLength);
114 // Preconditions are upheld therefore no error check necessary
115 pldm_bios_table_string_entry_encode(table.data() + tableSize, entryLength,
116 str.c_str(), str.length());
117 return reinterpret_cast<pldm_bios_string_table_entry*>(
118 table.data() + tableSize);
119 }
120
121 } // namespace string
122
123 namespace attribute
124 {
decodeHeader(const pldm_bios_attr_table_entry * entry)125 TableHeader decodeHeader(const pldm_bios_attr_table_entry* entry)
126 {
127 auto attrHandle = pldm_bios_table_attr_entry_decode_attribute_handle(entry);
128 auto attrType = pldm_bios_table_attr_entry_decode_attribute_type(entry);
129 auto stringHandle = pldm_bios_table_attr_entry_decode_string_handle(entry);
130 return {attrHandle, attrType, stringHandle};
131 }
132
findByHandle(const Table & table,uint16_t handle)133 const pldm_bios_attr_table_entry* findByHandle(const Table& table,
134 uint16_t handle)
135 {
136 return pldm_bios_table_attr_find_by_handle(table.data(), table.size(),
137 handle);
138 }
139
findByStringHandle(const Table & table,uint16_t handle)140 const pldm_bios_attr_table_entry* findByStringHandle(const Table& table,
141 uint16_t handle)
142 {
143 return pldm_bios_table_attr_find_by_string_handle(table.data(),
144 table.size(), handle);
145 }
146
constructStringEntry(Table & table,pldm_bios_table_attr_entry_string_info * info)147 const pldm_bios_attr_table_entry* constructStringEntry(
148 Table& table, pldm_bios_table_attr_entry_string_info* info)
149 {
150 auto entryLength =
151 pldm_bios_table_attr_entry_string_encode_length(info->def_length);
152
153 auto tableSize = table.size();
154 table.resize(tableSize + entryLength, 0);
155 int rc = pldm_bios_table_attr_entry_string_encode(table.data() + tableSize,
156 entryLength, info);
157 if (rc != PLDM_SUCCESS)
158 {
159 error("Failed to encode BIOS table string entry, response code '{RC}'",
160 "RC", rc);
161 throw std::runtime_error("Failed to encode BIOS table string entry");
162 }
163 return reinterpret_cast<pldm_bios_attr_table_entry*>(
164 table.data() + tableSize);
165 }
166
constructIntegerEntry(Table & table,pldm_bios_table_attr_entry_integer_info * info)167 const pldm_bios_attr_table_entry* constructIntegerEntry(
168 Table& table, pldm_bios_table_attr_entry_integer_info* info)
169 {
170 auto entryLength = pldm_bios_table_attr_entry_integer_encode_length();
171 auto tableSize = table.size();
172 table.resize(tableSize + entryLength, 0);
173 int rc = pldm_bios_table_attr_entry_integer_encode(table.data() + tableSize,
174 entryLength, info);
175 if (rc != PLDM_SUCCESS)
176 {
177 error(
178 "Failed to encode BIOS attribute table integer entry, response code '{RC}'",
179 "RC", rc);
180 throw std::runtime_error(
181 "Failed to encode BIOS attribute table integer entry");
182 }
183 return reinterpret_cast<pldm_bios_attr_table_entry*>(
184 table.data() + tableSize);
185 }
186
decodeStringEntry(const pldm_bios_attr_table_entry * entry)187 StringField decodeStringEntry(const pldm_bios_attr_table_entry* entry)
188 {
189 auto strType = pldm_bios_table_attr_entry_string_decode_string_type(entry);
190 auto minLength = pldm_bios_table_attr_entry_string_decode_min_length(entry);
191 auto maxLength = pldm_bios_table_attr_entry_string_decode_max_length(entry);
192 uint16_t defLength;
193 int rc = pldm_bios_table_attr_entry_string_decode_def_string_length(
194 entry, &defLength);
195 if (rc != PLDM_SUCCESS)
196 {
197 error(
198 "Failed to decode BIOS table string definition length, response code '{RC}'",
199 "RC", rc);
200 throw std::runtime_error(
201 "Failed to decode BIOS table string definitionlength");
202 }
203
204 std::vector<char> buffer(defLength + 1);
205 pldm_bios_table_attr_entry_string_decode_def_string(entry, buffer.data(),
206 buffer.size());
207 return {strType, minLength, maxLength, defLength,
208 std::string(buffer.data(), buffer.data() + defLength)};
209 }
210
decodeIntegerEntry(const pldm_bios_attr_table_entry * entry)211 IntegerField decodeIntegerEntry(const pldm_bios_attr_table_entry* entry)
212 {
213 uint64_t lower, upper, def;
214 uint32_t scalar;
215
216 pldm_bios_table_attr_entry_integer_decode(entry, &lower, &upper, &scalar,
217 &def);
218 return {lower, upper, scalar, def};
219 }
220
constructEnumEntry(Table & table,pldm_bios_table_attr_entry_enum_info * info)221 const pldm_bios_attr_table_entry* constructEnumEntry(
222 Table& table, pldm_bios_table_attr_entry_enum_info* info)
223 {
224 auto entryLength = pldm_bios_table_attr_entry_enum_encode_length(
225 info->pv_num, info->def_num);
226
227 auto tableSize = table.size();
228 table.resize(tableSize + entryLength, 0);
229 // Preconditions are upheld therefore no error check necessary
230 pldm_bios_table_attr_entry_enum_encode(table.data() + tableSize,
231 entryLength, info);
232
233 return reinterpret_cast<pldm_bios_attr_table_entry*>(
234 table.data() + tableSize);
235 }
236
decodeEnumEntry(const pldm_bios_attr_table_entry * entry)237 EnumField decodeEnumEntry(const pldm_bios_attr_table_entry* entry)
238 {
239 uint8_t pvNum;
240 int rc = pldm_bios_table_attr_entry_enum_decode_pv_num(entry, &pvNum);
241 if (rc != PLDM_SUCCESS)
242 {
243 error(
244 "Failed to decode the number of possible values for BIOS table enum entry, response code '{RC}'",
245 "RC", rc);
246 throw std::runtime_error(
247 "Failed to decode the number of possible values for BIOS table enum entry");
248 }
249 std::vector<uint16_t> pvHdls(pvNum, 0);
250 // Preconditions are upheld therefore no error check necessary
251 pldm_bios_table_attr_entry_enum_decode_pv_hdls(entry, pvHdls.data(), pvNum);
252 // Preconditions are upheld therefore no error check necessary
253 uint8_t defNum;
254 pldm_bios_table_attr_entry_enum_decode_def_num(entry, &defNum);
255 std::vector<uint8_t> defIndices(defNum, 0);
256 pldm_bios_table_attr_entry_enum_decode_def_indices(entry, defIndices.data(),
257 defIndices.size());
258 return {pvHdls, defIndices};
259 }
260
261 } // namespace attribute
262
263 namespace attribute_value
264 {
decodeHeader(const pldm_bios_attr_val_table_entry * entry)265 TableHeader decodeHeader(const pldm_bios_attr_val_table_entry* entry)
266 {
267 auto handle =
268 pldm_bios_table_attr_value_entry_decode_attribute_handle(entry);
269 auto type = pldm_bios_table_attr_value_entry_decode_attribute_type(entry);
270 return {handle, type};
271 }
272
decodeStringEntry(const pldm_bios_attr_val_table_entry * entry)273 std::string decodeStringEntry(const pldm_bios_attr_val_table_entry* entry)
274 {
275 variable_field currentString{};
276 pldm_bios_table_attr_value_entry_string_decode_string(
277 entry, ¤tString);
278 return std::string(currentString.ptr,
279 currentString.ptr + currentString.length);
280 }
281
decodeIntegerEntry(const pldm_bios_attr_val_table_entry * entry)282 uint64_t decodeIntegerEntry(const pldm_bios_attr_val_table_entry* entry)
283 {
284 return pldm_bios_table_attr_value_entry_integer_decode_cv(entry);
285 }
286
decodeEnumEntry(const pldm_bios_attr_val_table_entry * entry)287 std::vector<uint8_t> decodeEnumEntry(
288 const pldm_bios_attr_val_table_entry* entry)
289 {
290 auto number = pldm_bios_table_attr_value_entry_enum_decode_number(entry);
291 std::vector<uint8_t> currHdls(number, 0);
292 pldm_bios_table_attr_value_entry_enum_decode_handles(entry, currHdls.data(),
293 currHdls.size());
294 return currHdls;
295 }
296
constructStringEntry(Table & table,uint16_t attrHandle,uint8_t attrType,const std::string & str)297 const pldm_bios_attr_val_table_entry* constructStringEntry(
298 Table& table, uint16_t attrHandle, uint8_t attrType, const std::string& str)
299 {
300 auto strLen = str.size();
301 auto entryLength =
302 pldm_bios_table_attr_value_entry_encode_string_length(strLen);
303 auto tableSize = table.size();
304 table.resize(tableSize + entryLength);
305 int rc = pldm_bios_table_attr_value_entry_encode_string(
306 table.data() + tableSize, entryLength, attrHandle, attrType, strLen,
307 str.c_str());
308 if (rc != PLDM_SUCCESS)
309 {
310 error(
311 "Failed to encode BIOS attribute table string entry, response code '{RC}'",
312 "RC", rc);
313 throw std::runtime_error(
314 "Failed to encode BIOS attribute table string entry");
315 }
316 return reinterpret_cast<pldm_bios_attr_val_table_entry*>(
317 table.data() + tableSize);
318 }
319
constructIntegerEntry(Table & table,uint16_t attrHandle,uint8_t attrType,uint64_t value)320 const pldm_bios_attr_val_table_entry* constructIntegerEntry(
321 Table& table, uint16_t attrHandle, uint8_t attrType, uint64_t value)
322 {
323 auto entryLength = pldm_bios_table_attr_value_entry_encode_integer_length();
324
325 auto tableSize = table.size();
326 table.resize(tableSize + entryLength);
327 int rc = pldm_bios_table_attr_value_entry_encode_integer(
328 table.data() + tableSize, entryLength, attrHandle, attrType, value);
329 if (rc != PLDM_SUCCESS)
330 {
331 error(
332 "Failed to encode BIOS attribute table integer entry, response code '{RC}'",
333 "RC", rc);
334 throw std::runtime_error(
335 "Failed to encode BIOS attribute table integery entry");
336 }
337 return reinterpret_cast<pldm_bios_attr_val_table_entry*>(
338 table.data() + tableSize);
339 }
340
constructEnumEntry(Table & table,uint16_t attrHandle,uint8_t attrType,const std::vector<uint8_t> & handleIndices)341 const pldm_bios_attr_val_table_entry* constructEnumEntry(
342 Table& table, uint16_t attrHandle, uint8_t attrType,
343 const std::vector<uint8_t>& handleIndices)
344 {
345 auto entryLength = pldm_bios_table_attr_value_entry_encode_enum_length(
346 handleIndices.size());
347 auto tableSize = table.size();
348 table.resize(tableSize + entryLength);
349 int rc = pldm_bios_table_attr_value_entry_encode_enum(
350 table.data() + tableSize, entryLength, attrHandle, attrType,
351 handleIndices.size(), handleIndices.data());
352 if (rc != PLDM_SUCCESS)
353 {
354 error(
355 "Failed to encode BIOS attribute table enum entry, response code '{RC}'",
356 "RC", rc);
357 throw std::runtime_error(
358 "Failed to encode BIOS attribute table enum entry");
359 }
360 return reinterpret_cast<pldm_bios_attr_val_table_entry*>(
361 table.data() + tableSize);
362 }
363
updateTable(const Table & table,const void * entry,size_t size)364 std::optional<Table> updateTable(const Table& table, const void* entry,
365 size_t size)
366 {
367 // Replace the old attribute with the new attribute, the size of table will
368 // change:
369 // sizeof(newTableBuffer) = srcTableSize + sizeof(newAttribute) -
370 // sizeof(oldAttribute) + pad(4-byte alignment, max =
371 // 3)
372 // For simplicity, we use
373 // sizeof(newTableBuffer) = srcTableSize + sizeof(newAttribute) + 3
374 size_t destBufferLength = table.size() + size + 3;
375 Table destTable(destBufferLength);
376
377 auto rc = pldm_bios_table_attr_value_copy_and_update(
378 table.data(), table.size(), destTable.data(), &destBufferLength, entry,
379 size);
380 if (rc != PLDM_SUCCESS)
381 {
382 return std::nullopt;
383 }
384 destTable.resize(destBufferLength);
385
386 return destTable;
387 }
388
389 } // namespace attribute_value
390
391 } // namespace table
392
393 } // namespace bios
394 } // namespace responder
395 } // namespace pldm
396