xref: /openbmc/pldm/libpldmresponder/bios_table.cpp (revision 9c1455c067c2f11b85d52ce217a795db6857507e)
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, &currentString);
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