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_check(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_check(entry, buffer.data(),
106 buffer.size());
107 return std::string(buffer.data(), buffer.data() + strLength);
108 }
constructEntry(Table & table,const std::string & str)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_check(
117 table.data() + tableSize, entryLength, 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 {
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
findByHandle(const Table & table,uint16_t handle)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
findByStringHandle(const Table & table,uint16_t handle)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*
constructStringEntry(Table & table,pldm_bios_table_attr_entry_string_info * info)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*
constructIntegerEntry(Table & table,pldm_bios_table_attr_entry_integer_info * info)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
decodeStringEntry(const pldm_bios_attr_table_entry * entry)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
decodeIntegerEntry(const pldm_bios_attr_table_entry * entry)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*
constructEnumEntry(Table & table,pldm_bios_table_attr_entry_enum_info * info)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
decodeEnumEntry(const pldm_bios_attr_table_entry * entry)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 {
decodeHeader(const pldm_bios_attr_val_table_entry * entry)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
decodeStringEntry(const pldm_bios_attr_val_table_entry * entry)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 ¤tString);
282 return std::string(currentString.ptr,
283 currentString.ptr + currentString.length);
284 }
285
decodeIntegerEntry(const pldm_bios_attr_val_table_entry * entry)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>
decodeEnumEntry(const pldm_bios_attr_val_table_entry * entry)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*
constructStringEntry(Table & table,uint16_t attrHandle,uint8_t attrType,const std::string & str)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
constructIntegerEntry(Table & table,uint16_t attrHandle,uint8_t attrType,uint64_t value)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*
constructEnumEntry(Table & table,uint16_t attrHandle,uint8_t attrType,const std::vector<uint8_t> & handleIndices)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
updateTable(const Table & table,const void * entry,size_t size)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