xref: /openbmc/pldm/libpldmresponder/bios_table.cpp (revision d15ecf92d789a4673a249b590e6855d17af70c04)
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& e)
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     auto sizeWithoutPad = table.size();
85     auto padAndChecksumSize = pldm_bios_table_pad_checksum_size(sizeWithoutPad);
86     table.resize(table.size() + padAndChecksumSize);
87 
88     pldm_bios_table_append_pad_checksum(table.data(), table.size(),
89                                         sizeWithoutPad);
90 }
91 
92 namespace string
93 {
94 uint16_t decodeHandle(const pldm_bios_string_table_entry* entry)
95 {
96     return pldm_bios_table_string_entry_decode_handle(entry);
97 }
98 
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_check(entry, buffer.data(),
105                                                      buffer.size());
106     return std::string(buffer.data(), buffer.data() + strLength);
107 }
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_check(
116         table.data() + tableSize, entryLength, str.c_str(), str.length());
117     return reinterpret_cast<pldm_bios_string_table_entry*>(table.data() +
118                                                            tableSize);
119 }
120 
121 } // namespace string
122 
123 namespace attribute
124 {
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 
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 
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 
147 const pldm_bios_attr_table_entry*
148     constructStringEntry(Table& table,
149                          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_check(
157         table.data() + tableSize, entryLength, info);
158     if (rc != PLDM_SUCCESS)
159     {
160         lg2::error("Failed to encode BIOS table string entry: {LIBPLDM_ERROR}",
161                    "LIBPLDM_ERROR", rc);
162         throw std::runtime_error("Failed to encode BIOS table string entry");
163     }
164     return reinterpret_cast<pldm_bios_attr_table_entry*>(table.data() +
165                                                          tableSize);
166 }
167 
168 const pldm_bios_attr_table_entry*
169     constructIntegerEntry(Table& table,
170                           pldm_bios_table_attr_entry_integer_info* info)
171 {
172     auto entryLength = pldm_bios_table_attr_entry_integer_encode_length();
173     auto tableSize = table.size();
174     table.resize(tableSize + entryLength, 0);
175     int rc = pldm_bios_table_attr_entry_integer_encode_check(
176         table.data() + tableSize, entryLength, info);
177     if (rc != PLDM_SUCCESS)
178     {
179         lg2::error(
180             "Failed to encode BIOS attribute table integer entry: {LIBPLDM_ERROR}",
181             "LIBPLDM_ERROR", rc);
182         throw std::runtime_error(
183             "Failed to encode BIOS attribute table integer entry");
184     }
185     return reinterpret_cast<pldm_bios_attr_table_entry*>(table.data() +
186                                                          tableSize);
187 }
188 
189 StringField decodeStringEntry(const pldm_bios_attr_table_entry* entry)
190 {
191     auto strType = pldm_bios_table_attr_entry_string_decode_string_type(entry);
192     auto minLength = pldm_bios_table_attr_entry_string_decode_min_length(entry);
193     auto maxLength = pldm_bios_table_attr_entry_string_decode_max_length(entry);
194     uint16_t defLength;
195     int rc = pldm_bios_table_attr_entry_string_decode_def_string_length_check(
196         entry, &defLength);
197     if (rc != PLDM_SUCCESS)
198     {
199         lg2::error(
200             "Failed to decode BIOS table string definition length: {LIBPLDM_ERROR}",
201             "LIBPLDM_ERROR", rc);
202         throw std::runtime_error(
203             "Failed to decode BIOS table string definitionlength");
204     }
205 
206     std::vector<char> buffer(defLength + 1);
207     pldm_bios_table_attr_entry_string_decode_def_string(entry, buffer.data(),
208                                                         buffer.size());
209     return {strType, minLength, maxLength, defLength,
210             std::string(buffer.data(), buffer.data() + defLength)};
211 }
212 
213 IntegerField decodeIntegerEntry(const pldm_bios_attr_table_entry* entry)
214 {
215     uint64_t lower, upper, def;
216     uint32_t scalar;
217 
218     pldm_bios_table_attr_entry_integer_decode(entry, &lower, &upper, &scalar,
219                                               &def);
220     return {lower, upper, scalar, def};
221 }
222 
223 const pldm_bios_attr_table_entry*
224     constructEnumEntry(Table& table, pldm_bios_table_attr_entry_enum_info* info)
225 {
226     auto entryLength = pldm_bios_table_attr_entry_enum_encode_length(
227         info->pv_num, info->def_num);
228 
229     auto tableSize = table.size();
230     table.resize(tableSize + entryLength, 0);
231     // Preconditions are upheld therefore no error check necessary
232     pldm_bios_table_attr_entry_enum_encode_check(table.data() + tableSize,
233                                                  entryLength, info);
234 
235     return reinterpret_cast<pldm_bios_attr_table_entry*>(table.data() +
236                                                          tableSize);
237 }
238 
239 EnumField decodeEnumEntry(const pldm_bios_attr_table_entry* entry)
240 {
241     uint8_t pvNum;
242     int rc = pldm_bios_table_attr_entry_enum_decode_pv_num_check(entry, &pvNum);
243     if (rc != PLDM_SUCCESS)
244     {
245         lg2::error(
246             "Failed to decode the number of possible values for BIOS table enum entry: {LIBPLDM_ERROR}",
247             "LIBPLDM_ERROR", rc);
248         throw std::runtime_error(
249             "Failed to decode the number of possible values for BIOS table enum entry");
250     }
251     std::vector<uint16_t> pvHdls(pvNum, 0);
252     // Preconditions are upheld therefore no error check necessary
253     pldm_bios_table_attr_entry_enum_decode_pv_hdls_check(entry, pvHdls.data(),
254                                                          pvNum);
255     // Preconditions are upheld therefore no error check necessary
256     uint8_t defNum;
257     pldm_bios_table_attr_entry_enum_decode_def_num_check(entry, &defNum);
258     std::vector<uint8_t> defIndices(defNum, 0);
259     pldm_bios_table_attr_entry_enum_decode_def_indices(entry, defIndices.data(),
260                                                        defIndices.size());
261     return {pvHdls, defIndices};
262 }
263 
264 } // namespace attribute
265 
266 namespace attribute_value
267 {
268 TableHeader decodeHeader(const pldm_bios_attr_val_table_entry* entry)
269 {
270     auto handle =
271         pldm_bios_table_attr_value_entry_decode_attribute_handle(entry);
272     auto type = pldm_bios_table_attr_value_entry_decode_attribute_type(entry);
273     return {handle, type};
274 }
275 
276 std::string decodeStringEntry(const pldm_bios_attr_val_table_entry* entry)
277 {
278     variable_field currentString{};
279     pldm_bios_table_attr_value_entry_string_decode_string(entry,
280                                                           &currentString);
281     return std::string(currentString.ptr,
282                        currentString.ptr + currentString.length);
283 }
284 
285 uint64_t decodeIntegerEntry(const pldm_bios_attr_val_table_entry* entry)
286 {
287     return pldm_bios_table_attr_value_entry_integer_decode_cv(entry);
288 }
289 
290 std::vector<uint8_t>
291     decodeEnumEntry(const pldm_bios_attr_val_table_entry* entry)
292 {
293     auto number = pldm_bios_table_attr_value_entry_enum_decode_number(entry);
294     std::vector<uint8_t> currHdls(number, 0);
295     pldm_bios_table_attr_value_entry_enum_decode_handles(entry, currHdls.data(),
296                                                          currHdls.size());
297     return currHdls;
298 }
299 
300 const pldm_bios_attr_val_table_entry*
301     constructStringEntry(Table& table, uint16_t attrHandle, uint8_t attrType,
302                          const std::string& str)
303 {
304     auto strLen = str.size();
305     auto entryLength =
306         pldm_bios_table_attr_value_entry_encode_string_length(strLen);
307     auto tableSize = table.size();
308     table.resize(tableSize + entryLength);
309     int rc = pldm_bios_table_attr_value_entry_encode_string_check(
310         table.data() + tableSize, entryLength, attrHandle, attrType, strLen,
311         str.c_str());
312     if (rc != PLDM_SUCCESS)
313     {
314         lg2::error(
315             "Failed to encode BIOS attribute table string entry: {LIBPLDM_ERROR}",
316             "LIBPLDM_ERROR", rc);
317         throw std::runtime_error(
318             "Failed to encode BIOS attribute table string entry");
319     }
320     return reinterpret_cast<pldm_bios_attr_val_table_entry*>(table.data() +
321                                                              tableSize);
322 }
323 
324 const pldm_bios_attr_val_table_entry* constructIntegerEntry(Table& table,
325                                                             uint16_t attrHandle,
326                                                             uint8_t attrType,
327                                                             uint64_t value)
328 {
329     auto entryLength = pldm_bios_table_attr_value_entry_encode_integer_length();
330 
331     auto tableSize = table.size();
332     table.resize(tableSize + entryLength);
333     pldm_bios_table_attr_value_entry_encode_integer(
334         table.data() + tableSize, entryLength, attrHandle, attrType, value);
335     return reinterpret_cast<pldm_bios_attr_val_table_entry*>(table.data() +
336                                                              tableSize);
337 }
338 
339 const pldm_bios_attr_val_table_entry*
340     constructEnumEntry(Table& table, uint16_t attrHandle, uint8_t attrType,
341                        const std::vector<uint8_t>& handleIndices)
342 {
343     auto entryLength = pldm_bios_table_attr_value_entry_encode_enum_length(
344         handleIndices.size());
345     auto tableSize = table.size();
346     table.resize(tableSize + entryLength);
347     int rc = pldm_bios_table_attr_value_entry_encode_enum_check(
348         table.data() + tableSize, entryLength, attrHandle, attrType,
349         handleIndices.size(), handleIndices.data());
350     if (rc != PLDM_SUCCESS)
351     {
352         lg2::error(
353             "Failed to encode BIOS attribute table enum entry: {LIBPLDM_ERROR}",
354             "LIBPLDM_ERROR", rc);
355         throw std::runtime_error(
356             "Failed to encode BIOS attribute table enum entry");
357     }
358     return reinterpret_cast<pldm_bios_attr_val_table_entry*>(table.data() +
359                                                              tableSize);
360 }
361 
362 std::optional<Table> updateTable(const Table& table, const void* entry,
363                                  size_t size)
364 {
365     // Replace the old attribute with the new attribute, the size of table will
366     // change:
367     //   sizeof(newTableBuffer) = srcTableSize + sizeof(newAttribute) -
368     //                      sizeof(oldAttribute) + pad(4-byte alignment, max =
369     //                      3)
370     // For simplicity, we use
371     //   sizeof(newTableBuffer) = srcTableSize + sizeof(newAttribute) + 3
372     size_t destBufferLength = table.size() + size + 3;
373     Table destTable(destBufferLength);
374 
375     auto rc = pldm_bios_table_attr_value_copy_and_update(
376         table.data(), table.size(), destTable.data(), &destBufferLength, entry,
377         size);
378     if (rc != PLDM_SUCCESS)
379     {
380         return std::nullopt;
381     }
382     destTable.resize(destBufferLength);
383 
384     return destTable;
385 }
386 
387 } // namespace attribute_value
388 
389 } // namespace table
390 
391 } // namespace bios
392 } // namespace responder
393 } // namespace pldm
394