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 <fstream>
8 
9 namespace pldm
10 {
11 namespace responder
12 {
13 namespace bios
14 {
15 BIOSTable::BIOSTable(const char* filePath) : filePath(filePath)
16 {}
17 
18 bool BIOSTable::isEmpty() const noexcept
19 {
20     bool empty = false;
21     try
22     {
23         empty = fs::is_empty(filePath);
24     }
25     catch (const fs::filesystem_error& e)
26     {
27         return true;
28     }
29     return empty;
30 }
31 
32 void BIOSTable::store(const Table& table)
33 {
34     std::ofstream stream(filePath.string(), std::ios::out | std::ios::binary);
35     stream.write(reinterpret_cast<const char*>(table.data()), table.size());
36 }
37 
38 void BIOSTable::load(Response& response) const
39 {
40     auto currSize = response.size();
41     auto fileSize = fs::file_size(filePath);
42     response.resize(currSize + fileSize);
43     std::ifstream stream(filePath.string(), std::ios::in | std::ios::binary);
44     stream.read(reinterpret_cast<char*>(response.data() + currSize), fileSize);
45 }
46 
47 BIOSStringTable::BIOSStringTable(const Table& stringTable) :
48     stringTable(stringTable)
49 {}
50 
51 BIOSStringTable::BIOSStringTable(const BIOSTable& biosTable)
52 {
53     biosTable.load(stringTable);
54 }
55 
56 std::string BIOSStringTable::findString(uint16_t handle) const
57 {
58     auto stringEntry = pldm_bios_table_string_find_by_handle(
59         stringTable.data(), stringTable.size(), handle);
60     if (stringEntry == nullptr)
61     {
62         throw std::invalid_argument("Invalid String Handle");
63     }
64     return table::string::decodeString(stringEntry);
65 }
66 
67 uint16_t BIOSStringTable::findHandle(const std::string& name) const
68 {
69     auto stringEntry = pldm_bios_table_string_find_by_string(
70         stringTable.data(), stringTable.size(), name.c_str());
71     if (stringEntry == nullptr)
72     {
73         throw std::invalid_argument("Invalid String Name");
74     }
75 
76     return table::string::decodeHandle(stringEntry);
77 }
78 
79 namespace table
80 {
81 void appendPadAndChecksum(Table& table)
82 {
83     auto sizeWithoutPad = table.size();
84     auto padAndChecksumSize = pldm_bios_table_pad_checksum_size(sizeWithoutPad);
85     table.resize(table.size() + padAndChecksumSize);
86 
87     pldm_bios_table_append_pad_checksum(table.data(), table.size(),
88                                         sizeWithoutPad);
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     pldm_bios_table_string_entry_decode_string(entry, buffer.data(),
103                                                buffer.size());
104     return std::string(buffer.data(), buffer.data() + strLength);
105 }
106 const pldm_bios_string_table_entry* constructEntry(Table& table,
107                                                    const std::string& str)
108 {
109     auto tableSize = table.size();
110     auto entryLength = pldm_bios_table_string_entry_encode_length(str.length());
111     table.resize(tableSize + entryLength);
112     pldm_bios_table_string_entry_encode(table.data() + tableSize, entryLength,
113                                         str.c_str(), str.length());
114     return reinterpret_cast<pldm_bios_string_table_entry*>(table.data() +
115                                                            tableSize);
116 }
117 
118 } // namespace string
119 
120 namespace attribute
121 {
122 TableHeader decodeHeader(const pldm_bios_attr_table_entry* entry)
123 {
124     auto attrHandle = pldm_bios_table_attr_entry_decode_attribute_handle(entry);
125     auto attrType = pldm_bios_table_attr_entry_decode_attribute_type(entry);
126     auto stringHandle = pldm_bios_table_attr_entry_decode_string_handle(entry);
127     return {attrHandle, attrType, stringHandle};
128 }
129 
130 const pldm_bios_attr_table_entry* findByHandle(const Table& table,
131                                                uint16_t handle)
132 {
133     return pldm_bios_table_attr_find_by_handle(table.data(), table.size(),
134                                                handle);
135 }
136 
137 const pldm_bios_attr_table_entry* findByStringHandle(const Table& table,
138                                                      uint16_t handle)
139 {
140     return pldm_bios_table_attr_find_by_string_handle(table.data(),
141                                                       table.size(), handle);
142 }
143 
144 const pldm_bios_attr_table_entry*
145     constructStringEntry(Table& table,
146                          pldm_bios_table_attr_entry_string_info* info)
147 {
148     auto entryLength =
149         pldm_bios_table_attr_entry_string_encode_length(info->def_length);
150 
151     auto tableSize = table.size();
152     table.resize(tableSize + entryLength, 0);
153     pldm_bios_table_attr_entry_string_encode(table.data() + tableSize,
154                                              entryLength, info);
155     return reinterpret_cast<pldm_bios_attr_table_entry*>(table.data() +
156                                                          tableSize);
157 }
158 
159 const pldm_bios_attr_table_entry*
160     constructIntegerEntry(Table& table,
161                           pldm_bios_table_attr_entry_integer_info* info)
162 {
163     auto entryLength = pldm_bios_table_attr_entry_integer_encode_length();
164     auto tableSize = table.size();
165     table.resize(tableSize + entryLength, 0);
166     pldm_bios_table_attr_entry_integer_encode(table.data() + tableSize,
167                                               entryLength, info);
168     return reinterpret_cast<pldm_bios_attr_table_entry*>(table.data() +
169                                                          tableSize);
170 }
171 
172 StringField decodeStringEntry(const pldm_bios_attr_table_entry* entry)
173 {
174     auto strType = pldm_bios_table_attr_entry_string_decode_string_type(entry);
175     auto minLength = pldm_bios_table_attr_entry_string_decode_min_length(entry);
176     auto maxLength = pldm_bios_table_attr_entry_string_decode_max_length(entry);
177     auto defLength =
178         pldm_bios_table_attr_entry_string_decode_def_string_length(entry);
179 
180     std::vector<char> buffer(defLength + 1);
181     pldm_bios_table_attr_entry_string_decode_def_string(entry, buffer.data(),
182                                                         buffer.size());
183     return {strType, minLength, maxLength, defLength,
184             std::string(buffer.data(), buffer.data() + defLength)};
185 }
186 
187 IntegerField decodeIntegerEntry(const pldm_bios_attr_table_entry* entry)
188 {
189     uint64_t lower, upper, def;
190     uint32_t scalar;
191 
192     pldm_bios_table_attr_entry_integer_decode(entry, &lower, &upper, &scalar,
193                                               &def);
194     return {lower, upper, scalar, def};
195 }
196 
197 const pldm_bios_attr_table_entry*
198     constructEnumEntry(Table& table, pldm_bios_table_attr_entry_enum_info* info)
199 {
200     auto entryLength = pldm_bios_table_attr_entry_enum_encode_length(
201         info->pv_num, info->def_num);
202 
203     auto tableSize = table.size();
204     table.resize(tableSize + entryLength, 0);
205     pldm_bios_table_attr_entry_enum_encode(table.data() + tableSize,
206                                            entryLength, info);
207 
208     return reinterpret_cast<pldm_bios_attr_table_entry*>(table.data() +
209                                                          tableSize);
210 }
211 
212 EnumField decodeEnumEntry(const pldm_bios_attr_table_entry* entry)
213 {
214     uint8_t pvNum = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
215     std::vector<uint16_t> pvHdls(pvNum, 0);
216     pldm_bios_table_attr_entry_enum_decode_pv_hdls(entry, pvHdls.data(), pvNum);
217     auto defNum = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
218     std::vector<uint8_t> defIndices(defNum, 0);
219     pldm_bios_table_attr_entry_enum_decode_def_indices(entry, defIndices.data(),
220                                                        defIndices.size());
221     return {pvHdls, defIndices};
222 }
223 
224 } // namespace attribute
225 
226 namespace attribute_value
227 {
228 TableHeader decodeHeader(const pldm_bios_attr_val_table_entry* entry)
229 {
230     auto handle =
231         pldm_bios_table_attr_value_entry_decode_attribute_handle(entry);
232     auto type = pldm_bios_table_attr_value_entry_decode_attribute_type(entry);
233     return {handle, type};
234 }
235 
236 std::string decodeStringEntry(const pldm_bios_attr_val_table_entry* entry)
237 {
238     variable_field currentString{};
239     pldm_bios_table_attr_value_entry_string_decode_string(entry,
240                                                           &currentString);
241     return std::string(currentString.ptr,
242                        currentString.ptr + currentString.length);
243 }
244 
245 uint64_t decodeIntegerEntry(const pldm_bios_attr_val_table_entry* entry)
246 {
247     return pldm_bios_table_attr_value_entry_integer_decode_cv(entry);
248 }
249 
250 std::vector<uint8_t>
251     decodeEnumEntry(const pldm_bios_attr_val_table_entry* entry)
252 {
253     auto number = pldm_bios_table_attr_value_entry_enum_decode_number(entry);
254     std::vector<uint8_t> currHdls(number, 0);
255     pldm_bios_table_attr_value_entry_enum_decode_handles(entry, currHdls.data(),
256                                                          currHdls.size());
257     return currHdls;
258 }
259 
260 const pldm_bios_attr_val_table_entry*
261     constructStringEntry(Table& table, uint16_t attrHandle, uint8_t attrType,
262                          const std::string& str)
263 {
264     auto strLen = str.size();
265     auto entryLength =
266         pldm_bios_table_attr_value_entry_encode_string_length(strLen);
267     auto tableSize = table.size();
268     table.resize(tableSize + entryLength);
269     pldm_bios_table_attr_value_entry_encode_string(
270         table.data() + tableSize, entryLength, attrHandle, attrType, strLen,
271         str.c_str());
272     return reinterpret_cast<pldm_bios_attr_val_table_entry*>(table.data() +
273                                                              tableSize);
274 }
275 
276 const pldm_bios_attr_val_table_entry* constructIntegerEntry(Table& table,
277                                                             uint16_t attrHandle,
278                                                             uint8_t attrType,
279                                                             uint64_t value)
280 {
281     auto entryLength = pldm_bios_table_attr_value_entry_encode_integer_length();
282 
283     auto tableSize = table.size();
284     table.resize(tableSize + entryLength);
285     pldm_bios_table_attr_value_entry_encode_integer(
286         table.data() + tableSize, entryLength, attrHandle, attrType, value);
287     return reinterpret_cast<pldm_bios_attr_val_table_entry*>(table.data() +
288                                                              tableSize);
289 }
290 
291 const pldm_bios_attr_val_table_entry*
292     constructEnumEntry(Table& table, uint16_t attrHandle, uint8_t attrType,
293                        const std::vector<uint8_t>& handleIndices)
294 {
295     auto entryLength = pldm_bios_table_attr_value_entry_encode_enum_length(
296         handleIndices.size());
297     auto tableSize = table.size();
298     table.resize(tableSize + entryLength);
299     pldm_bios_table_attr_value_entry_encode_enum(
300         table.data() + tableSize, entryLength, attrHandle, attrType,
301         handleIndices.size(), handleIndices.data());
302     return reinterpret_cast<pldm_bios_attr_val_table_entry*>(table.data() +
303                                                              tableSize);
304 }
305 
306 std::optional<Table> updateTable(const Table& table, const void* entry,
307                                  size_t size)
308 {
309     // Replace the old attribute with the new attribute, the size of table will
310     // change:
311     //   sizeof(newTableBuffer) = srcTableSize + sizeof(newAttribute) -
312     //                      sizeof(oldAttribute) + pad(4-byte alignment, max =
313     //                      3)
314     // For simplicity, we use
315     //   sizeof(newTableBuffer) = srcTableSize + sizeof(newAttribute) + 3
316     size_t destBufferLength = table.size() + size + 3;
317     Table destTable(destBufferLength);
318 
319     auto rc = pldm_bios_table_attr_value_copy_and_update(
320         table.data(), table.size(), destTable.data(), &destBufferLength, entry,
321         size);
322     if (rc != PLDM_SUCCESS)
323     {
324         return std::nullopt;
325     }
326     destTable.resize(destBufferLength);
327 
328     return destTable;
329 }
330 
331 } // namespace attribute_value
332 
333 } // namespace table
334 
335 } // namespace bios
336 } // namespace responder
337 } // namespace pldm
338