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