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 {
BIOSTable(const char * filePath)19 BIOSTable::BIOSTable(const char* filePath) : filePath(filePath) {}
20 
isEmpty() const21 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 
store(const Table & table)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 
load(Response & response) const41 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 
BIOSStringTable(const Table & stringTable)50 BIOSStringTable::BIOSStringTable(const Table& stringTable) :
51     stringTable(stringTable)
52 {}
53 
BIOSStringTable(const BIOSTable & biosTable)54 BIOSStringTable::BIOSStringTable(const BIOSTable& biosTable)
55 {
56     biosTable.load(stringTable);
57 }
58 
findString(uint16_t handle) const59 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 
findHandle(const std::string & name) const70 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 {
appendPadAndChecksum(Table & table)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(table.data(), table.size(),
90                                         &payloadSize);
91 }
92 
93 namespace string
94 {
decodeHandle(const pldm_bios_string_table_entry * entry)95 uint16_t decodeHandle(const pldm_bios_string_table_entry* entry)
96 {
97     return pldm_bios_table_string_entry_decode_handle(entry);
98 }
99 
decodeString(const pldm_bios_string_table_entry * entry)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(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,const std::string & str)110     constructEntry(Table& table, 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*>(
119         table.data() + tableSize);
120 }
121 
122 } // namespace string
123 
124 namespace attribute
125 {
decodeHeader(const pldm_bios_attr_table_entry * entry)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,uint16_t handle)135     findByHandle(const Table& table, 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,uint16_t handle)142     findByStringHandle(const Table& table, uint16_t handle)
143 {
144     return pldm_bios_table_attr_find_by_string_handle(table.data(),
145                                                       table.size(), handle);
146 }
147 
constructStringEntry(Table & table,pldm_bios_table_attr_entry_string_info * info)148 const pldm_bios_attr_table_entry* constructStringEntry(
149     Table& table, pldm_bios_table_attr_entry_string_info* info)
150 {
151     auto entryLength =
152         pldm_bios_table_attr_entry_string_encode_length(info->def_length);
153 
154     auto tableSize = table.size();
155     table.resize(tableSize + entryLength, 0);
156     int rc = pldm_bios_table_attr_entry_string_encode(table.data() + tableSize,
157                                                       entryLength, info);
158     if (rc != PLDM_SUCCESS)
159     {
160         error("Failed to encode BIOS table string entry, response code '{RC}'",
161               "RC", rc);
162         throw std::runtime_error("Failed to encode BIOS table string entry");
163     }
164     return reinterpret_cast<pldm_bios_attr_table_entry*>(
165         table.data() + tableSize);
166 }
167 
constructIntegerEntry(Table & table,pldm_bios_table_attr_entry_integer_info * info)168 const pldm_bios_attr_table_entry* constructIntegerEntry(
169     Table& table, 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(table.data() + tableSize,
175                                                        entryLength, info);
176     if (rc != PLDM_SUCCESS)
177     {
178         error(
179             "Failed to encode BIOS attribute table integer entry, response code '{RC}'",
180             "RC", 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*>(
185         table.data() + tableSize);
186 }
187 
decodeStringEntry(const pldm_bios_attr_table_entry * entry)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(
195         entry, &defLength);
196     if (rc != PLDM_SUCCESS)
197     {
198         error(
199             "Failed to decode BIOS table string definition length, response code '{RC}'",
200             "RC", 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 
decodeIntegerEntry(const pldm_bios_attr_table_entry * entry)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*
constructEnumEntry(Table & table,pldm_bios_table_attr_entry_enum_info * info)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(table.data() + tableSize,
232                                            entryLength, info);
233 
234     return reinterpret_cast<pldm_bios_attr_table_entry*>(
235         table.data() + tableSize);
236 }
237 
decodeEnumEntry(const pldm_bios_attr_table_entry * entry)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(entry, &pvNum);
242     if (rc != PLDM_SUCCESS)
243     {
244         error(
245             "Failed to decode the number of possible values for BIOS table enum entry, response code '{RC}'",
246             "RC", 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(entry, pvHdls.data(), pvNum);
253     // Preconditions are upheld therefore no error check necessary
254     uint8_t defNum;
255     pldm_bios_table_attr_entry_enum_decode_def_num(entry, &defNum);
256     std::vector<uint8_t> defIndices(defNum, 0);
257     pldm_bios_table_attr_entry_enum_decode_def_indices(entry, defIndices.data(),
258                                                        defIndices.size());
259     return {pvHdls, defIndices};
260 }
261 
262 } // namespace attribute
263 
264 namespace attribute_value
265 {
decodeHeader(const pldm_bios_attr_val_table_entry * entry)266 TableHeader decodeHeader(const pldm_bios_attr_val_table_entry* entry)
267 {
268     auto handle =
269         pldm_bios_table_attr_value_entry_decode_attribute_handle(entry);
270     auto type = pldm_bios_table_attr_value_entry_decode_attribute_type(entry);
271     return {handle, type};
272 }
273 
decodeStringEntry(const pldm_bios_attr_val_table_entry * entry)274 std::string decodeStringEntry(const pldm_bios_attr_val_table_entry* entry)
275 {
276     variable_field currentString{};
277     pldm_bios_table_attr_value_entry_string_decode_string(
278         entry, &currentString);
279     return std::string(currentString.ptr,
280                        currentString.ptr + currentString.length);
281 }
282 
decodeIntegerEntry(const pldm_bios_attr_val_table_entry * entry)283 uint64_t decodeIntegerEntry(const pldm_bios_attr_val_table_entry* entry)
284 {
285     return pldm_bios_table_attr_value_entry_integer_decode_cv(entry);
286 }
287 
288 std::vector<uint8_t>
decodeEnumEntry(const pldm_bios_attr_val_table_entry * entry)289     decodeEnumEntry(const pldm_bios_attr_val_table_entry* entry)
290 {
291     auto number = pldm_bios_table_attr_value_entry_enum_decode_number(entry);
292     std::vector<uint8_t> currHdls(number, 0);
293     pldm_bios_table_attr_value_entry_enum_decode_handles(entry, currHdls.data(),
294                                                          currHdls.size());
295     return currHdls;
296 }
297 
constructStringEntry(Table & table,uint16_t attrHandle,uint8_t attrType,const std::string & str)298 const pldm_bios_attr_val_table_entry* constructStringEntry(
299     Table& table, uint16_t attrHandle, uint8_t attrType, const std::string& str)
300 {
301     auto strLen = str.size();
302     auto entryLength =
303         pldm_bios_table_attr_value_entry_encode_string_length(strLen);
304     auto tableSize = table.size();
305     table.resize(tableSize + entryLength);
306     int rc = pldm_bios_table_attr_value_entry_encode_string(
307         table.data() + tableSize, entryLength, attrHandle, attrType, strLen,
308         str.c_str());
309     if (rc != PLDM_SUCCESS)
310     {
311         error(
312             "Failed to encode BIOS attribute table string entry, response code '{RC}'",
313             "RC", rc);
314         throw std::runtime_error(
315             "Failed to encode BIOS attribute table string entry");
316     }
317     return reinterpret_cast<pldm_bios_attr_val_table_entry*>(
318         table.data() + tableSize);
319 }
320 
constructIntegerEntry(Table & table,uint16_t attrHandle,uint8_t attrType,uint64_t value)321 const pldm_bios_attr_val_table_entry* constructIntegerEntry(
322     Table& table, uint16_t attrHandle, uint8_t attrType, uint64_t value)
323 {
324     auto entryLength = pldm_bios_table_attr_value_entry_encode_integer_length();
325 
326     auto tableSize = table.size();
327     table.resize(tableSize + entryLength);
328     int rc = pldm_bios_table_attr_value_entry_encode_integer(
329         table.data() + tableSize, entryLength, attrHandle, attrType, value);
330     if (rc != PLDM_SUCCESS)
331     {
332         error(
333             "Failed to encode BIOS attribute table integer entry, response code '{RC}'",
334             "RC", rc);
335         throw std::runtime_error(
336             "Failed to encode BIOS attribute table integery entry");
337     }
338     return reinterpret_cast<pldm_bios_attr_val_table_entry*>(
339         table.data() + tableSize);
340 }
341 
342 const pldm_bios_attr_val_table_entry*
constructEnumEntry(Table & table,uint16_t attrHandle,uint8_t attrType,const std::vector<uint8_t> & handleIndices)343     constructEnumEntry(Table& table, uint16_t attrHandle, uint8_t attrType,
344                        const std::vector<uint8_t>& handleIndices)
345 {
346     auto entryLength = pldm_bios_table_attr_value_entry_encode_enum_length(
347         handleIndices.size());
348     auto tableSize = table.size();
349     table.resize(tableSize + entryLength);
350     int rc = pldm_bios_table_attr_value_entry_encode_enum(
351         table.data() + tableSize, entryLength, attrHandle, attrType,
352         handleIndices.size(), handleIndices.data());
353     if (rc != PLDM_SUCCESS)
354     {
355         error(
356             "Failed to encode BIOS attribute table enum entry, response code '{RC}'",
357             "RC", rc);
358         throw std::runtime_error(
359             "Failed to encode BIOS attribute table enum entry");
360     }
361     return reinterpret_cast<pldm_bios_attr_val_table_entry*>(
362         table.data() + tableSize);
363 }
364 
updateTable(const Table & table,const void * entry,size_t size)365 std::optional<Table> updateTable(const Table& table, const void* entry,
366                                  size_t size)
367 {
368     // Replace the old attribute with the new attribute, the size of table will
369     // change:
370     //   sizeof(newTableBuffer) = srcTableSize + sizeof(newAttribute) -
371     //                      sizeof(oldAttribute) + pad(4-byte alignment, max =
372     //                      3)
373     // For simplicity, we use
374     //   sizeof(newTableBuffer) = srcTableSize + sizeof(newAttribute) + 3
375     size_t destBufferLength = table.size() + size + 3;
376     Table destTable(destBufferLength);
377 
378     auto rc = pldm_bios_table_attr_value_copy_and_update(
379         table.data(), table.size(), destTable.data(), &destBufferLength, entry,
380         size);
381     if (rc != PLDM_SUCCESS)
382     {
383         return std::nullopt;
384     }
385     destTable.resize(destBufferLength);
386 
387     return destTable;
388 }
389 
390 } // namespace attribute_value
391 
392 } // namespace table
393 
394 } // namespace bios
395 } // namespace responder
396 } // namespace pldm
397