blob: b9eeb79949e7d6cad046ca5ef499357a0a5e0bc5 [file] [log] [blame]
John Wangd9659342020-02-27 16:46:05 +08001#include "bios_config.hpp"
2
John Wang3be70852020-02-13 15:59:04 +08003#include "bios_enum_attribute.hpp"
John Wang95e6b3c2020-02-13 09:43:24 +08004#include "bios_integer_attribute.hpp"
John Wangd9659342020-02-27 16:46:05 +08005#include "bios_string_attribute.hpp"
Sampa Misra46ece062020-03-18 07:17:44 -05006#include "bios_table.hpp"
George Liu1b180d82020-07-23 14:01:58 +08007#include "common/bios_utils.hpp"
John Wangd9659342020-02-27 16:46:05 +08008
George Liu1244acf2020-08-14 09:11:11 +08009#include <xyz/openbmc_project/BIOSConfig/Manager/server.hpp>
10
John Wangd9659342020-02-27 16:46:05 +080011#include <fstream>
12#include <iostream>
13
Tom Joseph7f839f92020-09-21 10:20:44 +053014#ifdef OEM_IBM
15#include "oem/ibm/libpldmresponder/platform_oem_ibm.hpp"
16#endif
17
Brad Bishop5079ac42021-08-19 18:35:06 -040018using namespace pldm::dbus_api;
19using namespace pldm::utils;
20
John Wangd9659342020-02-27 16:46:05 +080021namespace pldm
22{
23namespace responder
24{
25namespace bios
26{
27namespace
28{
George Liu1244acf2020-08-14 09:11:11 +080029using BIOSConfigManager =
30 sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager;
31
John Wangd9659342020-02-27 16:46:05 +080032constexpr auto enumJsonFile = "enum_attrs.json";
33constexpr auto stringJsonFile = "string_attrs.json";
34constexpr auto integerJsonFile = "integer_attrs.json";
35
36constexpr auto stringTableFile = "stringTable";
37constexpr auto attrTableFile = "attributeTable";
38constexpr auto attrValueTableFile = "attributeValueTable";
39
40} // namespace
41
Sampa Misrac0c79482021-06-02 08:01:54 -050042BIOSConfig::BIOSConfig(
43 const char* jsonDir, const char* tableDir, DBusHandler* const dbusHandler,
44 int fd, uint8_t eid, dbus_api::Requester* requester,
45 pldm::requester::Handler<pldm::requester::Request>* handler) :
John Wangd9659342020-02-27 16:46:05 +080046 jsonDir(jsonDir),
Tom Joseph7f839f92020-09-21 10:20:44 +053047 tableDir(tableDir), dbusHandler(dbusHandler), fd(fd), eid(eid),
Sampa Misrac0c79482021-06-02 08:01:54 -050048 requester(requester), handler(handler)
Tom Joseph7f839f92020-09-21 10:20:44 +053049
John Wangd9659342020-02-27 16:46:05 +080050{
George Liu9d8921e2020-05-14 15:41:50 +080051 fs::create_directories(tableDir);
John Wangd9659342020-02-27 16:46:05 +080052 constructAttributes();
George Liu1244acf2020-08-14 09:11:11 +080053 listenPendingAttributes();
John Wangd9659342020-02-27 16:46:05 +080054}
55
56void BIOSConfig::buildTables()
57{
John Wangd9659342020-02-27 16:46:05 +080058 auto stringTable = buildAndStoreStringTable();
59 if (stringTable)
60 {
61 buildAndStoreAttrTables(*stringTable);
62 }
63}
64
65std::optional<Table> BIOSConfig::getBIOSTable(pldm_bios_table_types tableType)
66{
67 fs::path tablePath;
68 switch (tableType)
69 {
70 case PLDM_BIOS_STRING_TABLE:
71 tablePath = tableDir / stringTableFile;
72 break;
73 case PLDM_BIOS_ATTR_TABLE:
74 tablePath = tableDir / attrTableFile;
75 break;
76 case PLDM_BIOS_ATTR_VAL_TABLE:
77 tablePath = tableDir / attrValueTableFile;
78 break;
79 }
80 return loadTable(tablePath);
81}
82
Tom Joseph7f839f92020-09-21 10:20:44 +053083int BIOSConfig::setBIOSTable(uint8_t tableType, const Table& table,
84 bool updateBaseBIOSTable)
George Liu1b180d82020-07-23 14:01:58 +080085{
86 fs::path stringTablePath(tableDir / stringTableFile);
87 fs::path attrTablePath(tableDir / attrTableFile);
88 fs::path attrValueTablePath(tableDir / attrValueTableFile);
89
90 if (!pldm_bios_table_checksum(table.data(), table.size()))
91 {
92 return PLDM_INVALID_BIOS_TABLE_DATA_INTEGRITY_CHECK;
93 }
94
95 if (tableType == PLDM_BIOS_STRING_TABLE)
96 {
97 storeTable(stringTablePath, table);
98 }
99 else if (tableType == PLDM_BIOS_ATTR_TABLE)
100 {
101 BIOSTable biosStringTable(stringTablePath.c_str());
102 if (biosStringTable.isEmpty())
103 {
104 return PLDM_INVALID_BIOS_TABLE_TYPE;
105 }
106
107 auto rc = checkAttributeTable(table);
108 if (rc != PLDM_SUCCESS)
109 {
110 return rc;
111 }
112
113 storeTable(attrTablePath, table);
114 }
115 else if (tableType == PLDM_BIOS_ATTR_VAL_TABLE)
116 {
117 BIOSTable biosStringTable(stringTablePath.c_str());
118 BIOSTable biosStringValueTable(attrTablePath.c_str());
119 if (biosStringTable.isEmpty() || biosStringValueTable.isEmpty())
120 {
121 return PLDM_INVALID_BIOS_TABLE_TYPE;
122 }
123
124 auto rc = checkAttributeValueTable(table);
125 if (rc != PLDM_SUCCESS)
126 {
127 return rc;
128 }
129
130 storeTable(attrValueTablePath, table);
George Liu1b180d82020-07-23 14:01:58 +0800131 }
132 else
133 {
134 return PLDM_INVALID_BIOS_TABLE_TYPE;
135 }
136
Tom Joseph7f839f92020-09-21 10:20:44 +0530137 if ((tableType == PLDM_BIOS_ATTR_VAL_TABLE) && updateBaseBIOSTable)
George Liu1b180d82020-07-23 14:01:58 +0800138 {
George Liu1b180d82020-07-23 14:01:58 +0800139 updateBaseBIOSTableProperty();
140 }
141
142 return PLDM_SUCCESS;
143}
144
145int BIOSConfig::checkAttributeTable(const Table& table)
146{
147 using namespace pldm::bios::utils;
148 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
149 for (auto entry :
150 BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(table.data(), table.size()))
151 {
152 auto attrNameHandle =
153 pldm_bios_table_attr_entry_decode_string_handle(entry);
154
155 auto stringEnty = pldm_bios_table_string_find_by_handle(
156 stringTable->data(), stringTable->size(), attrNameHandle);
157 if (stringEnty == nullptr)
158 {
159 return PLDM_INVALID_BIOS_ATTR_HANDLE;
160 }
161
162 auto attrType = static_cast<pldm_bios_attribute_type>(
163 pldm_bios_table_attr_entry_decode_attribute_type(entry));
164
165 switch (attrType)
166 {
167 case PLDM_BIOS_ENUMERATION:
168 case PLDM_BIOS_ENUMERATION_READ_ONLY:
169 {
170 auto pvNum =
171 pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
172 std::vector<uint16_t> pvHandls(pvNum);
173 pldm_bios_table_attr_entry_enum_decode_pv_hdls(
174 entry, pvHandls.data(), pvHandls.size());
175 auto defNum =
176 pldm_bios_table_attr_entry_enum_decode_def_num(entry);
177 std::vector<uint8_t> defIndices(defNum);
178 pldm_bios_table_attr_entry_enum_decode_def_indices(
179 entry, defIndices.data(), defIndices.size());
180
181 for (size_t i = 0; i < pvHandls.size(); i++)
182 {
183 auto stringEntry = pldm_bios_table_string_find_by_handle(
184 stringTable->data(), stringTable->size(), pvHandls[i]);
185 if (stringEntry == nullptr)
186 {
187 return PLDM_INVALID_BIOS_ATTR_HANDLE;
188 }
189 }
190
191 for (size_t i = 0; i < defIndices.size(); i++)
192 {
193 auto stringEntry = pldm_bios_table_string_find_by_handle(
194 stringTable->data(), stringTable->size(),
195 pvHandls[defIndices[i]]);
196 if (stringEntry == nullptr)
197 {
198 return PLDM_INVALID_BIOS_ATTR_HANDLE;
199 }
200 }
201 break;
202 }
203 case PLDM_BIOS_INTEGER:
204 case PLDM_BIOS_INTEGER_READ_ONLY:
205 case PLDM_BIOS_STRING:
206 case PLDM_BIOS_STRING_READ_ONLY:
207 case PLDM_BIOS_PASSWORD:
208 case PLDM_BIOS_PASSWORD_READ_ONLY:
209 break;
210 default:
211 return PLDM_INVALID_BIOS_ATTR_HANDLE;
212 }
213 }
214
215 return PLDM_SUCCESS;
216}
217
218int BIOSConfig::checkAttributeValueTable(const Table& table)
219{
220 using namespace pldm::bios::utils;
221 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
222 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
223
224 baseBIOSTableMaps.clear();
225
226 for (auto tableEntry :
227 BIOSTableIter<PLDM_BIOS_ATTR_VAL_TABLE>(table.data(), table.size()))
228 {
229 AttributeName attributeName{};
230 AttributeType attributeType{};
231 ReadonlyStatus readonlyStatus{};
232 DisplayName displayName{};
233 Description description{};
234 MenuPath menuPath{};
235 CurrentValue currentValue{};
236 DefaultValue defaultValue{};
237 Option options{};
238
239 auto attrValueHandle =
240 pldm_bios_table_attr_value_entry_decode_attribute_handle(
241 tableEntry);
242 auto attrType = static_cast<pldm_bios_attribute_type>(
243 pldm_bios_table_attr_value_entry_decode_attribute_type(tableEntry));
244
245 auto attrEntry = pldm_bios_table_attr_find_by_handle(
246 attrTable->data(), attrTable->size(), attrValueHandle);
247 if (attrEntry == nullptr)
248 {
249 return PLDM_INVALID_BIOS_ATTR_HANDLE;
250 }
251 auto attrHandle =
252 pldm_bios_table_attr_entry_decode_attribute_handle(attrEntry);
253 auto attrNameHandle =
254 pldm_bios_table_attr_entry_decode_string_handle(attrEntry);
255
256 auto stringEntry = pldm_bios_table_string_find_by_handle(
257 stringTable->data(), stringTable->size(), attrNameHandle);
258 if (stringEntry == nullptr)
259 {
260 return PLDM_INVALID_BIOS_ATTR_HANDLE;
261 }
262 auto strLength =
263 pldm_bios_table_string_entry_decode_string_length(stringEntry);
264 std::vector<char> buffer(strLength + 1 /* sizeof '\0' */);
265 pldm_bios_table_string_entry_decode_string(stringEntry, buffer.data(),
266 buffer.size());
267 attributeName = std::string(buffer.data(), buffer.data() + strLength);
268
269 if (!biosAttributes.empty())
270 {
271 readonlyStatus =
George Liub1fbeec2020-09-04 09:59:46 +0800272 biosAttributes[attrHandle % biosAttributes.size()]->readOnly;
George Liu92bb4022020-09-03 14:58:24 +0800273 description =
274 biosAttributes[attrHandle % biosAttributes.size()]->helpText;
275 displayName =
276 biosAttributes[attrHandle % biosAttributes.size()]->displayName;
George Liu1b180d82020-07-23 14:01:58 +0800277 }
278
279 switch (attrType)
280 {
281 case PLDM_BIOS_ENUMERATION:
282 case PLDM_BIOS_ENUMERATION_READ_ONLY:
283 {
284 auto getValue = [](uint16_t handle,
285 const Table& table) -> std::string {
286 auto stringEntry = pldm_bios_table_string_find_by_handle(
287 table.data(), table.size(), handle);
288
289 auto strLength =
290 pldm_bios_table_string_entry_decode_string_length(
291 stringEntry);
292 std::vector<char> buffer(strLength + 1 /* sizeof '\0' */);
293 pldm_bios_table_string_entry_decode_string(
294 stringEntry, buffer.data(), buffer.size());
295
296 return std::string(buffer.data(),
297 buffer.data() + strLength);
298 };
299
300 attributeType = "xyz.openbmc_project.BIOSConfig.Manager."
301 "AttributeType.Enumeration";
302
303 auto pvNum =
304 pldm_bios_table_attr_entry_enum_decode_pv_num(attrEntry);
305 std::vector<uint16_t> pvHandls(pvNum);
306 pldm_bios_table_attr_entry_enum_decode_pv_hdls(
307 attrEntry, pvHandls.data(), pvHandls.size());
308
309 // get possible_value
310 for (size_t i = 0; i < pvHandls.size(); i++)
311 {
312 options.push_back(
313 std::make_tuple("xyz.openbmc_project.BIOSConfig."
314 "Manager.BoundType.OneOf",
315 getValue(pvHandls[i], *stringTable)));
316 }
317
318 auto count =
319 pldm_bios_table_attr_value_entry_enum_decode_number(
320 tableEntry);
321 std::vector<uint8_t> handles(count);
322 pldm_bios_table_attr_value_entry_enum_decode_handles(
323 tableEntry, handles.data(), handles.size());
324
325 // get current_value
326 for (size_t i = 0; i < handles.size(); i++)
327 {
328 currentValue = getValue(pvHandls[handles[i]], *stringTable);
329 }
330
331 auto defNum =
332 pldm_bios_table_attr_entry_enum_decode_def_num(attrEntry);
333 std::vector<uint8_t> defIndices(defNum);
334 pldm_bios_table_attr_entry_enum_decode_def_indices(
335 attrEntry, defIndices.data(), defIndices.size());
336
337 // get default_value
338 for (size_t i = 0; i < defIndices.size(); i++)
339 {
340 defaultValue =
341 getValue(pvHandls[defIndices[i]], *stringTable);
342 }
343
344 break;
345 }
346 case PLDM_BIOS_INTEGER:
347 case PLDM_BIOS_INTEGER_READ_ONLY:
348 {
349 attributeType = "xyz.openbmc_project.BIOSConfig.Manager."
350 "AttributeType.Integer";
351 currentValue = static_cast<int64_t>(
352 pldm_bios_table_attr_value_entry_integer_decode_cv(
353 tableEntry));
354
355 uint64_t lower, upper, def;
356 uint32_t scalar;
357 pldm_bios_table_attr_entry_integer_decode(
358 attrEntry, &lower, &upper, &scalar, &def);
359 options.push_back(
360 std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
361 "BoundType.LowerBound",
362 static_cast<int64_t>(lower)));
363 options.push_back(
364 std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
365 "BoundType.UpperBound",
366 static_cast<int64_t>(upper)));
367 options.push_back(
368 std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
369 "BoundType.ScalarIncrement",
370 static_cast<int64_t>(scalar)));
371 defaultValue = static_cast<int64_t>(def);
372 break;
373 }
374 case PLDM_BIOS_STRING:
375 case PLDM_BIOS_STRING_READ_ONLY:
376 {
377 attributeType = "xyz.openbmc_project.BIOSConfig.Manager."
378 "AttributeType.String";
379 variable_field currentString;
380 pldm_bios_table_attr_value_entry_string_decode_string(
381 tableEntry, &currentString);
382 currentValue = std::string(
383 reinterpret_cast<const char*>(currentString.ptr),
384 currentString.length);
385 auto min = pldm_bios_table_attr_entry_string_decode_min_length(
386 attrEntry);
387 auto max = pldm_bios_table_attr_entry_string_decode_max_length(
388 attrEntry);
389 auto def =
390 pldm_bios_table_attr_entry_string_decode_def_string_length(
391 attrEntry);
392 std::vector<char> defString(def + 1);
393 pldm_bios_table_attr_entry_string_decode_def_string(
394 attrEntry, defString.data(), defString.size());
395 options.push_back(
396 std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
397 "BoundType.MinStringLength",
398 static_cast<int64_t>(min)));
399 options.push_back(
400 std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
401 "BoundType.MaxStringLength",
402 static_cast<int64_t>(max)));
403 defaultValue = defString.data();
404 break;
405 }
406 case PLDM_BIOS_PASSWORD:
407 case PLDM_BIOS_PASSWORD_READ_ONLY:
408 {
409 attributeType = "xyz.openbmc_project.BIOSConfig.Manager."
410 "AttributeType.Password";
411 break;
412 }
413 default:
414 return PLDM_INVALID_BIOS_ATTR_HANDLE;
415 }
416 baseBIOSTableMaps.emplace(
417 std::move(attributeName),
418 std::make_tuple(attributeType, readonlyStatus, displayName,
419 description, menuPath, currentValue, defaultValue,
420 std::move(options)));
421 }
422
423 return PLDM_SUCCESS;
424}
425
426void BIOSConfig::updateBaseBIOSTableProperty()
427{
428 constexpr static auto biosConfigPath =
429 "/xyz/openbmc_project/bios_config/manager";
430 constexpr static auto biosConfigInterface =
431 "xyz.openbmc_project.BIOSConfig.Manager";
432 constexpr static auto biosConfigPropertyName = "BaseBIOSTable";
433 constexpr static auto dbusProperties = "org.freedesktop.DBus.Properties";
434
435 if (baseBIOSTableMaps.empty())
436 {
437 return;
438 }
439
440 try
441 {
442 auto& bus = dbusHandler->getBus();
443 auto service =
444 dbusHandler->getService(biosConfigPath, biosConfigInterface);
445 auto method = bus.new_method_call(service.c_str(), biosConfigPath,
446 dbusProperties, "Set");
447 std::variant<BaseBIOSTable> value = baseBIOSTableMaps;
448 method.append(biosConfigInterface, biosConfigPropertyName, value);
449 bus.call_noreply(method);
450 }
451 catch (const std::exception& e)
452 {
453 std::cerr << "failed to update BaseBIOSTable property, ERROR="
454 << e.what() << "\n";
455 }
456}
457
John Wangd9659342020-02-27 16:46:05 +0800458void BIOSConfig::constructAttributes()
459{
460 load(jsonDir / stringJsonFile, [this](const Json& entry) {
461 constructAttribute<BIOSStringAttribute>(entry);
462 });
John Wang3be70852020-02-13 15:59:04 +0800463 load(jsonDir / integerJsonFile, [this](const Json& entry) {
John Wang95e6b3c2020-02-13 09:43:24 +0800464 constructAttribute<BIOSIntegerAttribute>(entry);
465 });
John Wang3be70852020-02-13 15:59:04 +0800466 load(jsonDir / enumJsonFile, [this](const Json& entry) {
467 constructAttribute<BIOSEnumAttribute>(entry);
468 });
John Wangd9659342020-02-27 16:46:05 +0800469}
470
471void BIOSConfig::buildAndStoreAttrTables(const Table& stringTable)
472{
473 BIOSStringTable biosStringTable(stringTable);
474
475 if (biosAttributes.empty())
476 {
477 return;
478 }
479
Tom Josephca7b2522020-11-18 12:27:11 +0530480 BaseBIOSTable biosTable{};
481 constexpr auto biosObjPath = "/xyz/openbmc_project/bios_config/manager";
482 constexpr auto biosInterface = "xyz.openbmc_project.BIOSConfig.Manager";
483
484 try
485 {
486 auto& bus = dbusHandler->getBus();
487 auto service = dbusHandler->getService(biosObjPath, biosInterface);
488 auto method =
489 bus.new_method_call(service.c_str(), biosObjPath,
490 "org.freedesktop.DBus.Properties", "Get");
491 method.append(biosInterface, "BaseBIOSTable");
492 auto reply = bus.call(method);
493 std::variant<BaseBIOSTable> varBiosTable{};
494 reply.read(varBiosTable);
495 biosTable = std::get<BaseBIOSTable>(varBiosTable);
496 }
497 // Failed to read the BaseBIOSTable, so update the BaseBIOSTable with the
498 // default values populated from the BIOS JSONs to keep PLDM and
499 // bios-settings-manager in sync
500 catch (const std::exception& e)
501 {
502 std::cerr << "Failed to read BaseBIOSTable property, ERROR=" << e.what()
503 << "\n";
504 }
505
John Wangd9659342020-02-27 16:46:05 +0800506 Table attrTable, attrValueTable;
507
508 for (auto& attr : biosAttributes)
509 {
510 try
511 {
Tom Josephca7b2522020-11-18 12:27:11 +0530512 auto iter = biosTable.find(attr->name);
513 if (iter == biosTable.end())
514 {
515 attr->constructEntry(biosStringTable, attrTable, attrValueTable,
516 std::nullopt);
517 }
518 else
519 {
520 attr->constructEntry(
521 biosStringTable, attrTable, attrValueTable,
522 std::get<static_cast<uint8_t>(Index::currentValue)>(
523 iter->second));
524 }
John Wangd9659342020-02-27 16:46:05 +0800525 }
526 catch (const std::exception& e)
527 {
528 std::cerr << "Construct Table Entry Error, AttributeName = "
529 << attr->name << std::endl;
530 }
531 }
532
533 table::appendPadAndChecksum(attrTable);
534 table::appendPadAndChecksum(attrValueTable);
George Liu1b180d82020-07-23 14:01:58 +0800535 setBIOSTable(PLDM_BIOS_ATTR_TABLE, attrTable);
536 setBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE, attrValueTable);
John Wangd9659342020-02-27 16:46:05 +0800537}
538
539std::optional<Table> BIOSConfig::buildAndStoreStringTable()
540{
541 std::set<std::string> strings;
542 auto handler = [&strings](const Json& entry) {
543 strings.emplace(entry.at("attribute_name"));
544 };
545
546 load(jsonDir / stringJsonFile, handler);
547 load(jsonDir / integerJsonFile, handler);
548 load(jsonDir / enumJsonFile, [&strings](const Json& entry) {
549 strings.emplace(entry.at("attribute_name"));
550 auto possibleValues = entry.at("possible_values");
551 for (auto& pv : possibleValues)
552 {
553 strings.emplace(pv);
554 }
555 });
556
557 if (strings.empty())
558 {
559 return std::nullopt;
560 }
561
562 Table table;
563 for (const auto& elem : strings)
564 {
565 table::string::constructEntry(table, elem);
566 }
567
568 table::appendPadAndChecksum(table);
George Liu1b180d82020-07-23 14:01:58 +0800569 setBIOSTable(PLDM_BIOS_STRING_TABLE, table);
John Wangd9659342020-02-27 16:46:05 +0800570 return table;
571}
572
573void BIOSConfig::storeTable(const fs::path& path, const Table& table)
574{
575 BIOSTable biosTable(path.c_str());
576 biosTable.store(table);
577}
578
579std::optional<Table> BIOSConfig::loadTable(const fs::path& path)
580{
581 BIOSTable biosTable(path.c_str());
582 if (biosTable.isEmpty())
583 {
584 return std::nullopt;
585 }
586
587 Table table;
588 biosTable.load(table);
589 return table;
590}
591
592void BIOSConfig::load(const fs::path& filePath, ParseHandler handler)
593{
594 std::ifstream file;
595 Json jsonConf;
596 if (fs::exists(filePath))
597 {
598 try
599 {
600 file.open(filePath);
601 jsonConf = Json::parse(file);
602 auto entries = jsonConf.at("entries");
603 for (auto& entry : entries)
604 {
605 try
606 {
607 handler(entry);
608 }
609 catch (const std::exception& e)
610 {
611 std::cerr
612 << "Failed to parse JSON config file(entry handler) : "
613 << filePath.c_str() << ", " << e.what() << std::endl;
614 }
615 }
616 }
617 catch (const std::exception& e)
618 {
619 std::cerr << "Failed to parse JSON config file : "
620 << filePath.c_str() << std::endl;
621 }
622 }
623}
624
Sagar Srinivascac0ebb2021-11-23 07:50:28 -0600625std::string BIOSConfig::decodeStringFromStringEntry(
626 const pldm_bios_string_table_entry* stringEntry)
627{
628 auto strLength =
629 pldm_bios_table_string_entry_decode_string_length(stringEntry);
630 std::vector<char> buffer(strLength + 1 /* sizeof '\0' */);
631 pldm_bios_table_string_entry_decode_string(stringEntry, buffer.data(),
632 buffer.size());
633 return std::string(buffer.data(), buffer.data() + strLength);
634}
635
636std::string
637 BIOSConfig::displayStringHandle(uint16_t handle, uint8_t index,
638 const std::optional<Table>& attrTable,
639 const std::optional<Table>& stringTable)
640{
641 auto attrEntry = pldm_bios_table_attr_find_by_handle(
642 attrTable->data(), attrTable->size(), handle);
643 auto pvNum = pldm_bios_table_attr_entry_enum_decode_pv_num(attrEntry);
644 std::vector<uint16_t> pvHandls(pvNum);
645 pldm_bios_table_attr_entry_enum_decode_pv_hdls(attrEntry, pvHandls.data(),
646 pvHandls.size());
647
648 std::string displayString = std::to_string(pvHandls[index]);
649
650 auto stringEntry = pldm_bios_table_string_find_by_handle(
651 stringTable->data(), stringTable->size(), pvHandls[index]);
652
653 auto decodedStr = decodeStringFromStringEntry(stringEntry);
654
655 return decodedStr + "(" + displayString + ")";
656}
657
658void BIOSConfig::traceBIOSUpdate(
659 const pldm_bios_attr_val_table_entry* attrValueEntry,
660 const pldm_bios_attr_table_entry* attrEntry, bool isBMC)
661{
662 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
663 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
664
665 auto [attrHandle, attrType] =
666 table::attribute_value::decodeHeader(attrValueEntry);
667
668 auto attrHeader = table::attribute::decodeHeader(attrEntry);
669 BIOSStringTable biosStringTable(*stringTable);
670 auto attrName = biosStringTable.findString(attrHeader.stringHandle);
671
672 switch (attrType)
673 {
674 case PLDM_BIOS_ENUMERATION:
675 case PLDM_BIOS_ENUMERATION_READ_ONLY:
676 {
677 auto count = pldm_bios_table_attr_value_entry_enum_decode_number(
678 attrValueEntry);
679 std::vector<uint8_t> handles(count);
680 pldm_bios_table_attr_value_entry_enum_decode_handles(
681 attrValueEntry, handles.data(), handles.size());
682
683 for (uint8_t handle : handles)
684 {
685 std::cout << "BIOS:" << attrName << ", updated to value: "
686 << displayStringHandle(attrHandle, handle, attrTable,
687 stringTable)
688 << ", by BMC: " << std::boolalpha << isBMC << "\n";
689 }
690 break;
691 }
692 case PLDM_BIOS_INTEGER:
693 case PLDM_BIOS_INTEGER_READ_ONLY:
694 {
695 auto value =
696 table::attribute_value::decodeIntegerEntry(attrValueEntry);
697 std::cout << "BIOS:" << attrName << ", updated to value: " << value
698 << ", by BMC:" << std::boolalpha << isBMC << std::endl;
699 break;
700 }
701 case PLDM_BIOS_STRING:
702 case PLDM_BIOS_STRING_READ_ONLY:
703 {
704 auto value =
705 table::attribute_value::decodeStringEntry(attrValueEntry);
706 std::cout << "BIOS:" << attrName << " updated to value: " << value
707 << ", by BMC:" << std::boolalpha << isBMC << std::endl;
708 break;
709 }
710 default:
711 break;
712 };
713}
714
John Wang8241b342020-06-05 10:49:17 +0800715int BIOSConfig::checkAttrValueToUpdate(
716 const pldm_bios_attr_val_table_entry* attrValueEntry,
717 const pldm_bios_attr_table_entry* attrEntry, Table&)
718
719{
720 auto [attrHandle, attrType] =
721 table::attribute_value::decodeHeader(attrValueEntry);
722
723 switch (attrType)
724 {
725 case PLDM_BIOS_ENUMERATION:
George Liu5bb9edb2021-08-05 20:10:32 +0800726 case PLDM_BIOS_ENUMERATION_READ_ONLY:
John Wang8241b342020-06-05 10:49:17 +0800727 {
728 auto value =
729 table::attribute_value::decodeEnumEntry(attrValueEntry);
730 auto [pvHdls, defIndex] =
731 table::attribute::decodeEnumEntry(attrEntry);
Varsha Kaverappa6a4d1cf2021-11-24 21:15:42 -0600732 if (!(value.size() == 1))
733 {
734 return PLDM_ERROR_INVALID_LENGTH;
735 }
John Wang8241b342020-06-05 10:49:17 +0800736 if (value[0] >= pvHdls.size())
737 {
738 std::cerr << "Enum: Illgeal index, Index = " << (int)value[0]
739 << std::endl;
740 return PLDM_ERROR_INVALID_DATA;
741 }
John Wang8241b342020-06-05 10:49:17 +0800742 return PLDM_SUCCESS;
743 }
744 case PLDM_BIOS_INTEGER:
George Liu5bb9edb2021-08-05 20:10:32 +0800745 case PLDM_BIOS_INTEGER_READ_ONLY:
John Wang8241b342020-06-05 10:49:17 +0800746 {
747 auto value =
748 table::attribute_value::decodeIntegerEntry(attrValueEntry);
749 auto [lower, upper, scalar, def] =
750 table::attribute::decodeIntegerEntry(attrEntry);
751
752 if (value < lower || value > upper)
753 {
754 std::cerr << "Integer: out of bound, value = " << value
755 << std::endl;
756 return PLDM_ERROR_INVALID_DATA;
757 }
758 return PLDM_SUCCESS;
759 }
760 case PLDM_BIOS_STRING:
George Liu5bb9edb2021-08-05 20:10:32 +0800761 case PLDM_BIOS_STRING_READ_ONLY:
John Wang8241b342020-06-05 10:49:17 +0800762 {
763 auto stringConf = table::attribute::decodeStringEntry(attrEntry);
764 auto value =
765 table::attribute_value::decodeStringEntry(attrValueEntry);
766 if (value.size() < stringConf.minLength ||
767 value.size() > stringConf.maxLength)
768 {
769 std::cerr << "String: Length error, string = " << value
770 << " length = " << value.size() << std::endl;
771 return PLDM_ERROR_INVALID_LENGTH;
772 }
773 return PLDM_SUCCESS;
774 }
775 default:
776 std::cerr << "ReadOnly or Unspported type, type = " << attrType
777 << std::endl;
778 return PLDM_ERROR;
779 };
780}
781
Sagar Srinivascac0ebb2021-11-23 07:50:28 -0600782int BIOSConfig::setAttrValue(const void* entry, size_t size, bool isBMC,
783 bool updateDBus, bool updateBaseBIOSTable)
John Wangd9659342020-02-27 16:46:05 +0800784{
785 auto attrValueTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
786 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
787 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
788 if (!attrValueTable || !attrTable || !stringTable)
789 {
790 return PLDM_BIOS_TABLE_UNAVAILABLE;
791 }
792
John Wangd9659342020-02-27 16:46:05 +0800793 auto attrValueEntry =
794 reinterpret_cast<const pldm_bios_attr_val_table_entry*>(entry);
795
796 auto attrValHeader = table::attribute_value::decodeHeader(attrValueEntry);
797
798 auto attrEntry =
799 table::attribute::findByHandle(*attrTable, attrValHeader.attrHandle);
800 if (!attrEntry)
801 {
802 return PLDM_ERROR;
803 }
804
John Wang8241b342020-06-05 10:49:17 +0800805 auto rc = checkAttrValueToUpdate(attrValueEntry, attrEntry, *stringTable);
806 if (rc != PLDM_SUCCESS)
807 {
808 return rc;
809 }
810
811 auto destTable =
812 table::attribute_value::updateTable(*attrValueTable, entry, size);
813
814 if (!destTable)
815 {
816 return PLDM_ERROR;
817 }
818
John Wangd9659342020-02-27 16:46:05 +0800819 try
820 {
821 auto attrHeader = table::attribute::decodeHeader(attrEntry);
822
823 BIOSStringTable biosStringTable(*stringTable);
824 auto attrName = biosStringTable.findString(attrHeader.stringHandle);
John Wangd9659342020-02-27 16:46:05 +0800825 auto iter = std::find_if(
826 biosAttributes.begin(), biosAttributes.end(),
827 [&attrName](const auto& attr) { return attr->name == attrName; });
828
829 if (iter == biosAttributes.end())
830 {
831 return PLDM_ERROR;
832 }
George Liu6d6d1e82021-02-16 11:08:55 +0800833 if (updateDBus)
834 {
835 (*iter)->setAttrValueOnDbus(attrValueEntry, attrEntry,
836 biosStringTable);
837 }
John Wangd9659342020-02-27 16:46:05 +0800838 }
839 catch (const std::exception& e)
840 {
841 std::cerr << "Set attribute value error: " << e.what() << std::endl;
842 return PLDM_ERROR;
843 }
844
Tom Joseph7f839f92020-09-21 10:20:44 +0530845 setBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE, *destTable, updateBaseBIOSTable);
George Liu5c3192b2020-08-13 17:35:43 +0800846
Sagar Srinivascac0ebb2021-11-23 07:50:28 -0600847 traceBIOSUpdate(attrValueEntry, attrEntry, isBMC);
848
John Wangd9659342020-02-27 16:46:05 +0800849 return PLDM_SUCCESS;
850}
851
852void BIOSConfig::removeTables()
853{
854 try
855 {
856 fs::remove(tableDir / stringTableFile);
857 fs::remove(tableDir / attrTableFile);
858 fs::remove(tableDir / attrValueTableFile);
859 }
860 catch (const std::exception& e)
861 {
862 std::cerr << "Remove the tables error: " << e.what() << std::endl;
863 }
864}
865
Sampa Misra46ece062020-03-18 07:17:44 -0500866void BIOSConfig::processBiosAttrChangeNotification(
867 const DbusChObjProperties& chProperties, uint32_t biosAttrIndex)
868{
869 const auto& dBusMap = biosAttributes[biosAttrIndex]->getDBusMap();
870 const auto& propertyName = dBusMap->propertyName;
871 const auto& attrName = biosAttributes[biosAttrIndex]->name;
872
873 const auto it = chProperties.find(propertyName);
874 if (it == chProperties.end())
875 {
876 return;
877 }
878
879 PropertyValue newPropVal = it->second;
880 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
881 if (!stringTable.has_value())
882 {
883 std::cerr << "BIOS string table unavailable\n";
884 return;
885 }
886 BIOSStringTable biosStringTable(*stringTable);
887 uint16_t attrNameHdl{};
888 try
889 {
890 attrNameHdl = biosStringTable.findHandle(attrName);
891 }
Patrick Williams51330582021-10-06 12:48:56 -0500892 catch (const std::invalid_argument& e)
Sampa Misra46ece062020-03-18 07:17:44 -0500893 {
894 std::cerr << "Could not find handle for BIOS string, ATTRIBUTE="
895 << attrName.c_str() << "\n";
896 return;
897 }
898
899 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
900 if (!attrTable.has_value())
901 {
902 std::cerr << "Attribute table not present\n";
903 return;
904 }
905 const struct pldm_bios_attr_table_entry* tableEntry =
906 table::attribute::findByStringHandle(*attrTable, attrNameHdl);
907 if (tableEntry == nullptr)
908 {
909 std::cerr << "Attribute not found in attribute table, name= "
910 << attrName.c_str() << "name handle=" << attrNameHdl << "\n";
911 return;
912 }
913
914 auto [attrHdl, attrType, stringHdl] =
915 table::attribute::decodeHeader(tableEntry);
916
917 auto attrValueSrcTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
918
919 if (!attrValueSrcTable.has_value())
920 {
921 std::cerr << "Attribute value table not present\n";
922 return;
923 }
924
925 Table newValue;
926 auto rc = biosAttributes[biosAttrIndex]->updateAttrVal(
927 newValue, attrHdl, attrType, newPropVal);
928 if (rc != PLDM_SUCCESS)
929 {
930 std::cerr << "Could not update the attribute value table for attribute "
931 "handle="
932 << attrHdl << " and type=" << (uint32_t)attrType << "\n";
933 return;
934 }
935 auto destTable = table::attribute_value::updateTable(
936 *attrValueSrcTable, newValue.data(), newValue.size());
937 if (destTable.has_value())
938 {
939 storeTable(tableDir / attrValueTableFile, *destTable);
940 }
Sampa Misra0f262332021-02-15 00:13:51 -0600941
Sagar Srinivascac0ebb2021-11-23 07:50:28 -0600942 rc = setAttrValue(newValue.data(), newValue.size(), true, false);
Sampa Misra0f262332021-02-15 00:13:51 -0600943 if (rc != PLDM_SUCCESS)
944 {
George Liu6d6d1e82021-02-16 11:08:55 +0800945 std::cerr << "could not setAttrValue on base bios table and dbus, rc = "
946 << rc << "\n";
Sampa Misra0f262332021-02-15 00:13:51 -0600947 }
Sampa Misra46ece062020-03-18 07:17:44 -0500948}
949
George Liu1244acf2020-08-14 09:11:11 +0800950uint16_t BIOSConfig::findAttrHandle(const std::string& attrName)
951{
952 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
953 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
954
955 BIOSStringTable biosStringTable(*stringTable);
956 pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE> attrTableIter(
957 attrTable->data(), attrTable->size());
958 auto stringHandle = biosStringTable.findHandle(attrName);
959
960 for (auto entry : pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(
961 attrTable->data(), attrTable->size()))
962 {
963 auto header = table::attribute::decodeHeader(entry);
964 if (header.stringHandle == stringHandle)
965 {
966 return header.attrHandle;
967 }
968 }
969
970 throw std::invalid_argument("Unknow attribute Name");
971}
972
973void BIOSConfig::constructPendingAttribute(
974 const PendingAttributes& pendingAttributes)
975{
Tom Joseph7f839f92020-09-21 10:20:44 +0530976 std::vector<uint16_t> listOfHandles{};
977
George Liu1244acf2020-08-14 09:11:11 +0800978 for (auto& attribute : pendingAttributes)
979 {
980 std::string attributeName = attribute.first;
981 auto& [attributeType, attributevalue] = attribute.second;
982
983 auto iter = std::find_if(biosAttributes.begin(), biosAttributes.end(),
984 [&attributeName](const auto& attr) {
985 return attr->name == attributeName;
986 });
987
988 if (iter == biosAttributes.end())
989 {
990 std::cerr << "Wrong attribute name, attributeName = "
991 << attributeName << std::endl;
992 continue;
993 }
994
995 Table attrValueEntry(sizeof(pldm_bios_attr_val_table_entry), 0);
996 auto entry = reinterpret_cast<pldm_bios_attr_val_table_entry*>(
997 attrValueEntry.data());
998
999 auto handler = findAttrHandle(attributeName);
1000 auto type =
1001 BIOSConfigManager::convertAttributeTypeFromString(attributeType);
1002
1003 if (type != BIOSConfigManager::AttributeType::Enumeration &&
1004 type != BIOSConfigManager::AttributeType::String &&
1005 type != BIOSConfigManager::AttributeType::Integer)
1006 {
1007 std::cerr << "Attribute type not supported, attributeType = "
1008 << attributeType << std::endl;
1009 continue;
1010 }
1011
George Liu4876c542022-06-08 15:59:54 +08001012 const auto [attrType, readonlyStatus, displayName, description,
1013 menuPath, currentValue, defaultValue, option] =
1014 baseBIOSTableMaps.at(attributeName);
1015
George Liu1244acf2020-08-14 09:11:11 +08001016 entry->attr_handle = htole16(handler);
George Liu4876c542022-06-08 15:59:54 +08001017
1018 // Need to verify that the current value has really changed
1019 if (attributeType == attrType && attributevalue != currentValue)
1020 {
1021 listOfHandles.emplace_back(htole16(handler));
1022 }
Tom Joseph7f839f92020-09-21 10:20:44 +05301023
George Liu1244acf2020-08-14 09:11:11 +08001024 (*iter)->generateAttributeEntry(attributevalue, attrValueEntry);
1025
Sagar Srinivascac0ebb2021-11-23 07:50:28 -06001026 setAttrValue(attrValueEntry.data(), attrValueEntry.size(), true);
Tom Joseph7f839f92020-09-21 10:20:44 +05301027 }
1028
1029 if (listOfHandles.size())
1030 {
1031#ifdef OEM_IBM
1032 auto rc = pldm::responder::platform::sendBiosAttributeUpdateEvent(
Sampa Misrac0c79482021-06-02 08:01:54 -05001033 eid, requester, listOfHandles, handler);
Tom Joseph7f839f92020-09-21 10:20:44 +05301034 if (rc != PLDM_SUCCESS)
1035 {
1036 return;
1037 }
1038#endif
George Liu1244acf2020-08-14 09:11:11 +08001039 }
1040}
1041
1042void BIOSConfig::listenPendingAttributes()
1043{
1044 constexpr auto objPath = "/xyz/openbmc_project/bios_config/manager";
1045 constexpr auto objInterface = "xyz.openbmc_project.BIOSConfig.Manager";
1046
1047 using namespace sdbusplus::bus::match::rules;
Patrick Williams84b790c2022-07-22 19:26:56 -05001048 auto updateBIOSMatch = std::make_unique<sdbusplus::bus::match_t>(
George Liu1244acf2020-08-14 09:11:11 +08001049 pldm::utils::DBusHandler::getBus(),
1050 propertiesChanged(objPath, objInterface),
Patrick Williams84b790c2022-07-22 19:26:56 -05001051 [this](sdbusplus::message_t& msg) {
George Liu1244acf2020-08-14 09:11:11 +08001052 constexpr auto propertyName = "PendingAttributes";
1053
1054 using Value =
1055 std::variant<std::string, PendingAttributes, BaseBIOSTable>;
1056 using Properties = std::map<DbusProp, Value>;
1057
1058 Properties props{};
1059 std::string intf;
1060 msg.read(intf, props);
1061
1062 auto valPropMap = props.find(propertyName);
1063 if (valPropMap == props.end())
1064 {
1065 return;
1066 }
1067
1068 PendingAttributes pendingAttributes =
1069 std::get<PendingAttributes>(valPropMap->second);
1070 this->constructPendingAttribute(pendingAttributes);
1071 });
1072
1073 biosAttrMatch.emplace_back(std::move(updateBIOSMatch));
1074}
1075
John Wangd9659342020-02-27 16:46:05 +08001076} // namespace bios
1077} // namespace responder
1078} // namespace pldm