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