blob: 704fa339f9c9f0426fc8234956be43915ac0f891 [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{
29
George Liu1244acf2020-08-14 09:11:11 +080030using BIOSConfigManager =
31 sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager;
32
John Wangd9659342020-02-27 16:46:05 +080033constexpr auto enumJsonFile = "enum_attrs.json";
34constexpr auto stringJsonFile = "string_attrs.json";
35constexpr auto integerJsonFile = "integer_attrs.json";
36
37constexpr auto stringTableFile = "stringTable";
38constexpr auto attrTableFile = "attributeTable";
39constexpr auto attrValueTableFile = "attributeValueTable";
40
41} // namespace
42
Sampa Misrac0c79482021-06-02 08:01:54 -050043BIOSConfig::BIOSConfig(
44 const char* jsonDir, const char* tableDir, DBusHandler* const dbusHandler,
45 int fd, uint8_t eid, dbus_api::Requester* requester,
46 pldm::requester::Handler<pldm::requester::Request>* handler) :
John Wangd9659342020-02-27 16:46:05 +080047 jsonDir(jsonDir),
Tom Joseph7f839f92020-09-21 10:20:44 +053048 tableDir(tableDir), dbusHandler(dbusHandler), fd(fd), eid(eid),
Sampa Misrac0c79482021-06-02 08:01:54 -050049 requester(requester), handler(handler)
Tom Joseph7f839f92020-09-21 10:20:44 +053050
John Wangd9659342020-02-27 16:46:05 +080051{
George Liu9d8921e2020-05-14 15:41:50 +080052 fs::create_directories(tableDir);
John Wangd9659342020-02-27 16:46:05 +080053 constructAttributes();
George Liu1244acf2020-08-14 09:11:11 +080054 listenPendingAttributes();
John Wangd9659342020-02-27 16:46:05 +080055}
56
57void BIOSConfig::buildTables()
58{
John Wangd9659342020-02-27 16:46:05 +080059 auto stringTable = buildAndStoreStringTable();
60 if (stringTable)
61 {
62 buildAndStoreAttrTables(*stringTable);
63 }
64}
65
66std::optional<Table> BIOSConfig::getBIOSTable(pldm_bios_table_types tableType)
67{
68 fs::path tablePath;
69 switch (tableType)
70 {
71 case PLDM_BIOS_STRING_TABLE:
72 tablePath = tableDir / stringTableFile;
73 break;
74 case PLDM_BIOS_ATTR_TABLE:
75 tablePath = tableDir / attrTableFile;
76 break;
77 case PLDM_BIOS_ATTR_VAL_TABLE:
78 tablePath = tableDir / attrValueTableFile;
79 break;
80 }
81 return loadTable(tablePath);
82}
83
Tom Joseph7f839f92020-09-21 10:20:44 +053084int BIOSConfig::setBIOSTable(uint8_t tableType, const Table& table,
85 bool updateBaseBIOSTable)
George Liu1b180d82020-07-23 14:01:58 +080086{
87 fs::path stringTablePath(tableDir / stringTableFile);
88 fs::path attrTablePath(tableDir / attrTableFile);
89 fs::path attrValueTablePath(tableDir / attrValueTableFile);
90
91 if (!pldm_bios_table_checksum(table.data(), table.size()))
92 {
93 return PLDM_INVALID_BIOS_TABLE_DATA_INTEGRITY_CHECK;
94 }
95
96 if (tableType == PLDM_BIOS_STRING_TABLE)
97 {
98 storeTable(stringTablePath, table);
99 }
100 else if (tableType == PLDM_BIOS_ATTR_TABLE)
101 {
102 BIOSTable biosStringTable(stringTablePath.c_str());
103 if (biosStringTable.isEmpty())
104 {
105 return PLDM_INVALID_BIOS_TABLE_TYPE;
106 }
107
108 auto rc = checkAttributeTable(table);
109 if (rc != PLDM_SUCCESS)
110 {
111 return rc;
112 }
113
114 storeTable(attrTablePath, table);
115 }
116 else if (tableType == PLDM_BIOS_ATTR_VAL_TABLE)
117 {
118 BIOSTable biosStringTable(stringTablePath.c_str());
119 BIOSTable biosStringValueTable(attrTablePath.c_str());
120 if (biosStringTable.isEmpty() || biosStringValueTable.isEmpty())
121 {
122 return PLDM_INVALID_BIOS_TABLE_TYPE;
123 }
124
125 auto rc = checkAttributeValueTable(table);
126 if (rc != PLDM_SUCCESS)
127 {
128 return rc;
129 }
130
131 storeTable(attrValueTablePath, table);
George Liu1b180d82020-07-23 14:01:58 +0800132 }
133 else
134 {
135 return PLDM_INVALID_BIOS_TABLE_TYPE;
136 }
137
Tom Joseph7f839f92020-09-21 10:20:44 +0530138 if ((tableType == PLDM_BIOS_ATTR_VAL_TABLE) && updateBaseBIOSTable)
George Liu1b180d82020-07-23 14:01:58 +0800139 {
Tom Joseph7f839f92020-09-21 10:20:44 +0530140 std::cout << "setBIOSTable:: updateBaseBIOSTableProperty() "
141 << "\n";
George Liu1b180d82020-07-23 14:01:58 +0800142 updateBaseBIOSTableProperty();
143 }
144
145 return PLDM_SUCCESS;
146}
147
148int BIOSConfig::checkAttributeTable(const Table& table)
149{
150 using namespace pldm::bios::utils;
151 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
152 for (auto entry :
153 BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(table.data(), table.size()))
154 {
155 auto attrNameHandle =
156 pldm_bios_table_attr_entry_decode_string_handle(entry);
157
158 auto stringEnty = pldm_bios_table_string_find_by_handle(
159 stringTable->data(), stringTable->size(), attrNameHandle);
160 if (stringEnty == nullptr)
161 {
162 return PLDM_INVALID_BIOS_ATTR_HANDLE;
163 }
164
165 auto attrType = static_cast<pldm_bios_attribute_type>(
166 pldm_bios_table_attr_entry_decode_attribute_type(entry));
167
168 switch (attrType)
169 {
170 case PLDM_BIOS_ENUMERATION:
171 case PLDM_BIOS_ENUMERATION_READ_ONLY:
172 {
173 auto pvNum =
174 pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
175 std::vector<uint16_t> pvHandls(pvNum);
176 pldm_bios_table_attr_entry_enum_decode_pv_hdls(
177 entry, pvHandls.data(), pvHandls.size());
178 auto defNum =
179 pldm_bios_table_attr_entry_enum_decode_def_num(entry);
180 std::vector<uint8_t> defIndices(defNum);
181 pldm_bios_table_attr_entry_enum_decode_def_indices(
182 entry, defIndices.data(), defIndices.size());
183
184 for (size_t i = 0; i < pvHandls.size(); i++)
185 {
186 auto stringEntry = pldm_bios_table_string_find_by_handle(
187 stringTable->data(), stringTable->size(), pvHandls[i]);
188 if (stringEntry == nullptr)
189 {
190 return PLDM_INVALID_BIOS_ATTR_HANDLE;
191 }
192 }
193
194 for (size_t i = 0; i < defIndices.size(); i++)
195 {
196 auto stringEntry = pldm_bios_table_string_find_by_handle(
197 stringTable->data(), stringTable->size(),
198 pvHandls[defIndices[i]]);
199 if (stringEntry == nullptr)
200 {
201 return PLDM_INVALID_BIOS_ATTR_HANDLE;
202 }
203 }
204 break;
205 }
206 case PLDM_BIOS_INTEGER:
207 case PLDM_BIOS_INTEGER_READ_ONLY:
208 case PLDM_BIOS_STRING:
209 case PLDM_BIOS_STRING_READ_ONLY:
210 case PLDM_BIOS_PASSWORD:
211 case PLDM_BIOS_PASSWORD_READ_ONLY:
212 break;
213 default:
214 return PLDM_INVALID_BIOS_ATTR_HANDLE;
215 }
216 }
217
218 return PLDM_SUCCESS;
219}
220
221int BIOSConfig::checkAttributeValueTable(const Table& table)
222{
223 using namespace pldm::bios::utils;
224 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
225 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
226
227 baseBIOSTableMaps.clear();
228
229 for (auto tableEntry :
230 BIOSTableIter<PLDM_BIOS_ATTR_VAL_TABLE>(table.data(), table.size()))
231 {
232 AttributeName attributeName{};
233 AttributeType attributeType{};
234 ReadonlyStatus readonlyStatus{};
235 DisplayName displayName{};
236 Description description{};
237 MenuPath menuPath{};
238 CurrentValue currentValue{};
239 DefaultValue defaultValue{};
240 Option options{};
241
242 auto attrValueHandle =
243 pldm_bios_table_attr_value_entry_decode_attribute_handle(
244 tableEntry);
245 auto attrType = static_cast<pldm_bios_attribute_type>(
246 pldm_bios_table_attr_value_entry_decode_attribute_type(tableEntry));
247
248 auto attrEntry = pldm_bios_table_attr_find_by_handle(
249 attrTable->data(), attrTable->size(), attrValueHandle);
250 if (attrEntry == nullptr)
251 {
252 return PLDM_INVALID_BIOS_ATTR_HANDLE;
253 }
254 auto attrHandle =
255 pldm_bios_table_attr_entry_decode_attribute_handle(attrEntry);
256 auto attrNameHandle =
257 pldm_bios_table_attr_entry_decode_string_handle(attrEntry);
258
259 auto stringEntry = pldm_bios_table_string_find_by_handle(
260 stringTable->data(), stringTable->size(), attrNameHandle);
261 if (stringEntry == nullptr)
262 {
263 return PLDM_INVALID_BIOS_ATTR_HANDLE;
264 }
265 auto strLength =
266 pldm_bios_table_string_entry_decode_string_length(stringEntry);
267 std::vector<char> buffer(strLength + 1 /* sizeof '\0' */);
268 pldm_bios_table_string_entry_decode_string(stringEntry, buffer.data(),
269 buffer.size());
270 attributeName = std::string(buffer.data(), buffer.data() + strLength);
271
272 if (!biosAttributes.empty())
273 {
274 readonlyStatus =
George Liub1fbeec2020-09-04 09:59:46 +0800275 biosAttributes[attrHandle % biosAttributes.size()]->readOnly;
George Liu92bb4022020-09-03 14:58:24 +0800276 description =
277 biosAttributes[attrHandle % biosAttributes.size()]->helpText;
278 displayName =
279 biosAttributes[attrHandle % biosAttributes.size()]->displayName;
George Liu1b180d82020-07-23 14:01:58 +0800280 }
281
282 switch (attrType)
283 {
284 case PLDM_BIOS_ENUMERATION:
285 case PLDM_BIOS_ENUMERATION_READ_ONLY:
286 {
287 auto getValue = [](uint16_t handle,
288 const Table& table) -> std::string {
289 auto stringEntry = pldm_bios_table_string_find_by_handle(
290 table.data(), table.size(), handle);
291
292 auto strLength =
293 pldm_bios_table_string_entry_decode_string_length(
294 stringEntry);
295 std::vector<char> buffer(strLength + 1 /* sizeof '\0' */);
296 pldm_bios_table_string_entry_decode_string(
297 stringEntry, buffer.data(), buffer.size());
298
299 return std::string(buffer.data(),
300 buffer.data() + strLength);
301 };
302
303 attributeType = "xyz.openbmc_project.BIOSConfig.Manager."
304 "AttributeType.Enumeration";
305
306 auto pvNum =
307 pldm_bios_table_attr_entry_enum_decode_pv_num(attrEntry);
308 std::vector<uint16_t> pvHandls(pvNum);
309 pldm_bios_table_attr_entry_enum_decode_pv_hdls(
310 attrEntry, pvHandls.data(), pvHandls.size());
311
312 // get possible_value
313 for (size_t i = 0; i < pvHandls.size(); i++)
314 {
315 options.push_back(
316 std::make_tuple("xyz.openbmc_project.BIOSConfig."
317 "Manager.BoundType.OneOf",
318 getValue(pvHandls[i], *stringTable)));
319 }
320
321 auto count =
322 pldm_bios_table_attr_value_entry_enum_decode_number(
323 tableEntry);
324 std::vector<uint8_t> handles(count);
325 pldm_bios_table_attr_value_entry_enum_decode_handles(
326 tableEntry, handles.data(), handles.size());
327
328 // get current_value
329 for (size_t i = 0; i < handles.size(); i++)
330 {
331 currentValue = getValue(pvHandls[handles[i]], *stringTable);
332 }
333
334 auto defNum =
335 pldm_bios_table_attr_entry_enum_decode_def_num(attrEntry);
336 std::vector<uint8_t> defIndices(defNum);
337 pldm_bios_table_attr_entry_enum_decode_def_indices(
338 attrEntry, defIndices.data(), defIndices.size());
339
340 // get default_value
341 for (size_t i = 0; i < defIndices.size(); i++)
342 {
343 defaultValue =
344 getValue(pvHandls[defIndices[i]], *stringTable);
345 }
346
347 break;
348 }
349 case PLDM_BIOS_INTEGER:
350 case PLDM_BIOS_INTEGER_READ_ONLY:
351 {
352 attributeType = "xyz.openbmc_project.BIOSConfig.Manager."
353 "AttributeType.Integer";
354 currentValue = static_cast<int64_t>(
355 pldm_bios_table_attr_value_entry_integer_decode_cv(
356 tableEntry));
357
358 uint64_t lower, upper, def;
359 uint32_t scalar;
360 pldm_bios_table_attr_entry_integer_decode(
361 attrEntry, &lower, &upper, &scalar, &def);
362 options.push_back(
363 std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
364 "BoundType.LowerBound",
365 static_cast<int64_t>(lower)));
366 options.push_back(
367 std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
368 "BoundType.UpperBound",
369 static_cast<int64_t>(upper)));
370 options.push_back(
371 std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
372 "BoundType.ScalarIncrement",
373 static_cast<int64_t>(scalar)));
374 defaultValue = static_cast<int64_t>(def);
375 break;
376 }
377 case PLDM_BIOS_STRING:
378 case PLDM_BIOS_STRING_READ_ONLY:
379 {
380 attributeType = "xyz.openbmc_project.BIOSConfig.Manager."
381 "AttributeType.String";
382 variable_field currentString;
383 pldm_bios_table_attr_value_entry_string_decode_string(
384 tableEntry, &currentString);
385 currentValue = std::string(
386 reinterpret_cast<const char*>(currentString.ptr),
387 currentString.length);
388 auto min = pldm_bios_table_attr_entry_string_decode_min_length(
389 attrEntry);
390 auto max = pldm_bios_table_attr_entry_string_decode_max_length(
391 attrEntry);
392 auto def =
393 pldm_bios_table_attr_entry_string_decode_def_string_length(
394 attrEntry);
395 std::vector<char> defString(def + 1);
396 pldm_bios_table_attr_entry_string_decode_def_string(
397 attrEntry, defString.data(), defString.size());
398 options.push_back(
399 std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
400 "BoundType.MinStringLength",
401 static_cast<int64_t>(min)));
402 options.push_back(
403 std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
404 "BoundType.MaxStringLength",
405 static_cast<int64_t>(max)));
406 defaultValue = defString.data();
407 break;
408 }
409 case PLDM_BIOS_PASSWORD:
410 case PLDM_BIOS_PASSWORD_READ_ONLY:
411 {
412 attributeType = "xyz.openbmc_project.BIOSConfig.Manager."
413 "AttributeType.Password";
414 break;
415 }
416 default:
417 return PLDM_INVALID_BIOS_ATTR_HANDLE;
418 }
419 baseBIOSTableMaps.emplace(
420 std::move(attributeName),
421 std::make_tuple(attributeType, readonlyStatus, displayName,
422 description, menuPath, currentValue, defaultValue,
423 std::move(options)));
424 }
425
426 return PLDM_SUCCESS;
427}
428
429void BIOSConfig::updateBaseBIOSTableProperty()
430{
431 constexpr static auto biosConfigPath =
432 "/xyz/openbmc_project/bios_config/manager";
433 constexpr static auto biosConfigInterface =
434 "xyz.openbmc_project.BIOSConfig.Manager";
435 constexpr static auto biosConfigPropertyName = "BaseBIOSTable";
436 constexpr static auto dbusProperties = "org.freedesktop.DBus.Properties";
437
438 if (baseBIOSTableMaps.empty())
439 {
440 return;
441 }
442
443 try
444 {
445 auto& bus = dbusHandler->getBus();
446 auto service =
447 dbusHandler->getService(biosConfigPath, biosConfigInterface);
448 auto method = bus.new_method_call(service.c_str(), biosConfigPath,
449 dbusProperties, "Set");
450 std::variant<BaseBIOSTable> value = baseBIOSTableMaps;
451 method.append(biosConfigInterface, biosConfigPropertyName, value);
452 bus.call_noreply(method);
453 }
454 catch (const std::exception& e)
455 {
456 std::cerr << "failed to update BaseBIOSTable property, ERROR="
457 << e.what() << "\n";
458 }
459}
460
John Wangd9659342020-02-27 16:46:05 +0800461void BIOSConfig::constructAttributes()
462{
463 load(jsonDir / stringJsonFile, [this](const Json& entry) {
464 constructAttribute<BIOSStringAttribute>(entry);
465 });
John Wang3be70852020-02-13 15:59:04 +0800466 load(jsonDir / integerJsonFile, [this](const Json& entry) {
John Wang95e6b3c2020-02-13 09:43:24 +0800467 constructAttribute<BIOSIntegerAttribute>(entry);
468 });
John Wang3be70852020-02-13 15:59:04 +0800469 load(jsonDir / enumJsonFile, [this](const Json& entry) {
470 constructAttribute<BIOSEnumAttribute>(entry);
471 });
John Wangd9659342020-02-27 16:46:05 +0800472}
473
474void BIOSConfig::buildAndStoreAttrTables(const Table& stringTable)
475{
476 BIOSStringTable biosStringTable(stringTable);
477
478 if (biosAttributes.empty())
479 {
480 return;
481 }
482
Tom Josephca7b2522020-11-18 12:27:11 +0530483 BaseBIOSTable biosTable{};
484 constexpr auto biosObjPath = "/xyz/openbmc_project/bios_config/manager";
485 constexpr auto biosInterface = "xyz.openbmc_project.BIOSConfig.Manager";
486
487 try
488 {
489 auto& bus = dbusHandler->getBus();
490 auto service = dbusHandler->getService(biosObjPath, biosInterface);
491 auto method =
492 bus.new_method_call(service.c_str(), biosObjPath,
493 "org.freedesktop.DBus.Properties", "Get");
494 method.append(biosInterface, "BaseBIOSTable");
495 auto reply = bus.call(method);
496 std::variant<BaseBIOSTable> varBiosTable{};
497 reply.read(varBiosTable);
498 biosTable = std::get<BaseBIOSTable>(varBiosTable);
499 }
500 // Failed to read the BaseBIOSTable, so update the BaseBIOSTable with the
501 // default values populated from the BIOS JSONs to keep PLDM and
502 // bios-settings-manager in sync
503 catch (const std::exception& e)
504 {
505 std::cerr << "Failed to read BaseBIOSTable property, ERROR=" << e.what()
506 << "\n";
507 }
508
John Wangd9659342020-02-27 16:46:05 +0800509 Table attrTable, attrValueTable;
510
511 for (auto& attr : biosAttributes)
512 {
513 try
514 {
Tom Josephca7b2522020-11-18 12:27:11 +0530515 auto iter = biosTable.find(attr->name);
516 if (iter == biosTable.end())
517 {
518 attr->constructEntry(biosStringTable, attrTable, attrValueTable,
519 std::nullopt);
520 }
521 else
522 {
523 attr->constructEntry(
524 biosStringTable, attrTable, attrValueTable,
525 std::get<static_cast<uint8_t>(Index::currentValue)>(
526 iter->second));
527 }
John Wangd9659342020-02-27 16:46:05 +0800528 }
529 catch (const std::exception& e)
530 {
531 std::cerr << "Construct Table Entry Error, AttributeName = "
532 << attr->name << std::endl;
533 }
534 }
535
536 table::appendPadAndChecksum(attrTable);
537 table::appendPadAndChecksum(attrValueTable);
George Liu1b180d82020-07-23 14:01:58 +0800538 setBIOSTable(PLDM_BIOS_ATTR_TABLE, attrTable);
539 setBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE, attrValueTable);
John Wangd9659342020-02-27 16:46:05 +0800540}
541
542std::optional<Table> BIOSConfig::buildAndStoreStringTable()
543{
544 std::set<std::string> strings;
545 auto handler = [&strings](const Json& entry) {
546 strings.emplace(entry.at("attribute_name"));
547 };
548
549 load(jsonDir / stringJsonFile, handler);
550 load(jsonDir / integerJsonFile, handler);
551 load(jsonDir / enumJsonFile, [&strings](const Json& entry) {
552 strings.emplace(entry.at("attribute_name"));
553 auto possibleValues = entry.at("possible_values");
554 for (auto& pv : possibleValues)
555 {
556 strings.emplace(pv);
557 }
558 });
559
560 if (strings.empty())
561 {
562 return std::nullopt;
563 }
564
565 Table table;
566 for (const auto& elem : strings)
567 {
568 table::string::constructEntry(table, elem);
569 }
570
571 table::appendPadAndChecksum(table);
George Liu1b180d82020-07-23 14:01:58 +0800572 setBIOSTable(PLDM_BIOS_STRING_TABLE, table);
John Wangd9659342020-02-27 16:46:05 +0800573 return table;
574}
575
576void BIOSConfig::storeTable(const fs::path& path, const Table& table)
577{
578 BIOSTable biosTable(path.c_str());
579 biosTable.store(table);
580}
581
582std::optional<Table> BIOSConfig::loadTable(const fs::path& path)
583{
584 BIOSTable biosTable(path.c_str());
585 if (biosTable.isEmpty())
586 {
587 return std::nullopt;
588 }
589
590 Table table;
591 biosTable.load(table);
592 return table;
593}
594
595void BIOSConfig::load(const fs::path& filePath, ParseHandler handler)
596{
597 std::ifstream file;
598 Json jsonConf;
599 if (fs::exists(filePath))
600 {
601 try
602 {
603 file.open(filePath);
604 jsonConf = Json::parse(file);
605 auto entries = jsonConf.at("entries");
606 for (auto& entry : entries)
607 {
608 try
609 {
610 handler(entry);
611 }
612 catch (const std::exception& e)
613 {
614 std::cerr
615 << "Failed to parse JSON config file(entry handler) : "
616 << filePath.c_str() << ", " << e.what() << std::endl;
617 }
618 }
619 }
620 catch (const std::exception& e)
621 {
622 std::cerr << "Failed to parse JSON config file : "
623 << filePath.c_str() << std::endl;
624 }
625 }
626}
627
John Wang8241b342020-06-05 10:49:17 +0800628int BIOSConfig::checkAttrValueToUpdate(
629 const pldm_bios_attr_val_table_entry* attrValueEntry,
630 const pldm_bios_attr_table_entry* attrEntry, Table&)
631
632{
633 auto [attrHandle, attrType] =
634 table::attribute_value::decodeHeader(attrValueEntry);
635
636 switch (attrType)
637 {
638 case PLDM_BIOS_ENUMERATION:
George Liu5bb9edb2021-08-05 20:10:32 +0800639 case PLDM_BIOS_ENUMERATION_READ_ONLY:
John Wang8241b342020-06-05 10:49:17 +0800640 {
641 auto value =
642 table::attribute_value::decodeEnumEntry(attrValueEntry);
643 auto [pvHdls, defIndex] =
644 table::attribute::decodeEnumEntry(attrEntry);
Varsha Kaverappa6a4d1cf2021-11-24 21:15:42 -0600645 if (!(value.size() == 1))
646 {
647 return PLDM_ERROR_INVALID_LENGTH;
648 }
John Wang8241b342020-06-05 10:49:17 +0800649 if (value[0] >= pvHdls.size())
650 {
651 std::cerr << "Enum: Illgeal index, Index = " << (int)value[0]
652 << std::endl;
653 return PLDM_ERROR_INVALID_DATA;
654 }
655
656 return PLDM_SUCCESS;
657 }
658 case PLDM_BIOS_INTEGER:
George Liu5bb9edb2021-08-05 20:10:32 +0800659 case PLDM_BIOS_INTEGER_READ_ONLY:
John Wang8241b342020-06-05 10:49:17 +0800660 {
661 auto value =
662 table::attribute_value::decodeIntegerEntry(attrValueEntry);
663 auto [lower, upper, scalar, def] =
664 table::attribute::decodeIntegerEntry(attrEntry);
665
666 if (value < lower || value > upper)
667 {
668 std::cerr << "Integer: out of bound, value = " << value
669 << std::endl;
670 return PLDM_ERROR_INVALID_DATA;
671 }
672 return PLDM_SUCCESS;
673 }
674 case PLDM_BIOS_STRING:
George Liu5bb9edb2021-08-05 20:10:32 +0800675 case PLDM_BIOS_STRING_READ_ONLY:
John Wang8241b342020-06-05 10:49:17 +0800676 {
677 auto stringConf = table::attribute::decodeStringEntry(attrEntry);
678 auto value =
679 table::attribute_value::decodeStringEntry(attrValueEntry);
680 if (value.size() < stringConf.minLength ||
681 value.size() > stringConf.maxLength)
682 {
683 std::cerr << "String: Length error, string = " << value
684 << " length = " << value.size() << std::endl;
685 return PLDM_ERROR_INVALID_LENGTH;
686 }
687 return PLDM_SUCCESS;
688 }
689 default:
690 std::cerr << "ReadOnly or Unspported type, type = " << attrType
691 << std::endl;
692 return PLDM_ERROR;
693 };
694}
695
George Liu6d6d1e82021-02-16 11:08:55 +0800696int BIOSConfig::setAttrValue(const void* entry, size_t size, bool updateDBus,
Tom Joseph7f839f92020-09-21 10:20:44 +0530697 bool updateBaseBIOSTable)
John Wangd9659342020-02-27 16:46:05 +0800698{
699 auto attrValueTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
700 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
701 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
702 if (!attrValueTable || !attrTable || !stringTable)
703 {
704 return PLDM_BIOS_TABLE_UNAVAILABLE;
705 }
706
John Wangd9659342020-02-27 16:46:05 +0800707 auto attrValueEntry =
708 reinterpret_cast<const pldm_bios_attr_val_table_entry*>(entry);
709
710 auto attrValHeader = table::attribute_value::decodeHeader(attrValueEntry);
711
712 auto attrEntry =
713 table::attribute::findByHandle(*attrTable, attrValHeader.attrHandle);
714 if (!attrEntry)
715 {
716 return PLDM_ERROR;
717 }
718
John Wang8241b342020-06-05 10:49:17 +0800719 auto rc = checkAttrValueToUpdate(attrValueEntry, attrEntry, *stringTable);
720 if (rc != PLDM_SUCCESS)
721 {
722 return rc;
723 }
724
725 auto destTable =
726 table::attribute_value::updateTable(*attrValueTable, entry, size);
727
728 if (!destTable)
729 {
730 return PLDM_ERROR;
731 }
732
John Wangd9659342020-02-27 16:46:05 +0800733 try
734 {
735 auto attrHeader = table::attribute::decodeHeader(attrEntry);
736
737 BIOSStringTable biosStringTable(*stringTable);
738 auto attrName = biosStringTable.findString(attrHeader.stringHandle);
739
740 auto iter = std::find_if(
741 biosAttributes.begin(), biosAttributes.end(),
742 [&attrName](const auto& attr) { return attr->name == attrName; });
743
744 if (iter == biosAttributes.end())
745 {
746 return PLDM_ERROR;
747 }
George Liu6d6d1e82021-02-16 11:08:55 +0800748 if (updateDBus)
749 {
750 (*iter)->setAttrValueOnDbus(attrValueEntry, attrEntry,
751 biosStringTable);
752 }
John Wangd9659342020-02-27 16:46:05 +0800753 }
754 catch (const std::exception& e)
755 {
756 std::cerr << "Set attribute value error: " << e.what() << std::endl;
757 return PLDM_ERROR;
758 }
759
Tom Joseph7f839f92020-09-21 10:20:44 +0530760 setBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE, *destTable, updateBaseBIOSTable);
George Liu5c3192b2020-08-13 17:35:43 +0800761
John Wangd9659342020-02-27 16:46:05 +0800762 return PLDM_SUCCESS;
763}
764
765void BIOSConfig::removeTables()
766{
767 try
768 {
769 fs::remove(tableDir / stringTableFile);
770 fs::remove(tableDir / attrTableFile);
771 fs::remove(tableDir / attrValueTableFile);
772 }
773 catch (const std::exception& e)
774 {
775 std::cerr << "Remove the tables error: " << e.what() << std::endl;
776 }
777}
778
Sampa Misra46ece062020-03-18 07:17:44 -0500779void BIOSConfig::processBiosAttrChangeNotification(
780 const DbusChObjProperties& chProperties, uint32_t biosAttrIndex)
781{
782 const auto& dBusMap = biosAttributes[biosAttrIndex]->getDBusMap();
783 const auto& propertyName = dBusMap->propertyName;
784 const auto& attrName = biosAttributes[biosAttrIndex]->name;
785
786 const auto it = chProperties.find(propertyName);
787 if (it == chProperties.end())
788 {
789 return;
790 }
791
792 PropertyValue newPropVal = it->second;
793 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
794 if (!stringTable.has_value())
795 {
796 std::cerr << "BIOS string table unavailable\n";
797 return;
798 }
799 BIOSStringTable biosStringTable(*stringTable);
800 uint16_t attrNameHdl{};
801 try
802 {
803 attrNameHdl = biosStringTable.findHandle(attrName);
804 }
Patrick Williams51330582021-10-06 12:48:56 -0500805 catch (const std::invalid_argument& e)
Sampa Misra46ece062020-03-18 07:17:44 -0500806 {
807 std::cerr << "Could not find handle for BIOS string, ATTRIBUTE="
808 << attrName.c_str() << "\n";
809 return;
810 }
811
812 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
813 if (!attrTable.has_value())
814 {
815 std::cerr << "Attribute table not present\n";
816 return;
817 }
818 const struct pldm_bios_attr_table_entry* tableEntry =
819 table::attribute::findByStringHandle(*attrTable, attrNameHdl);
820 if (tableEntry == nullptr)
821 {
822 std::cerr << "Attribute not found in attribute table, name= "
823 << attrName.c_str() << "name handle=" << attrNameHdl << "\n";
824 return;
825 }
826
827 auto [attrHdl, attrType, stringHdl] =
828 table::attribute::decodeHeader(tableEntry);
829
830 auto attrValueSrcTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
831
832 if (!attrValueSrcTable.has_value())
833 {
834 std::cerr << "Attribute value table not present\n";
835 return;
836 }
837
838 Table newValue;
839 auto rc = biosAttributes[biosAttrIndex]->updateAttrVal(
840 newValue, attrHdl, attrType, newPropVal);
841 if (rc != PLDM_SUCCESS)
842 {
843 std::cerr << "Could not update the attribute value table for attribute "
844 "handle="
845 << attrHdl << " and type=" << (uint32_t)attrType << "\n";
846 return;
847 }
848 auto destTable = table::attribute_value::updateTable(
849 *attrValueSrcTable, newValue.data(), newValue.size());
850 if (destTable.has_value())
851 {
852 storeTable(tableDir / attrValueTableFile, *destTable);
853 }
Sampa Misra0f262332021-02-15 00:13:51 -0600854
George Liu6d6d1e82021-02-16 11:08:55 +0800855 rc = setAttrValue(newValue.data(), newValue.size(), false);
Sampa Misra0f262332021-02-15 00:13:51 -0600856 if (rc != PLDM_SUCCESS)
857 {
George Liu6d6d1e82021-02-16 11:08:55 +0800858 std::cerr << "could not setAttrValue on base bios table and dbus, rc = "
859 << rc << "\n";
Sampa Misra0f262332021-02-15 00:13:51 -0600860 }
Sampa Misra46ece062020-03-18 07:17:44 -0500861}
862
George Liu1244acf2020-08-14 09:11:11 +0800863uint16_t BIOSConfig::findAttrHandle(const std::string& attrName)
864{
865 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
866 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
867
868 BIOSStringTable biosStringTable(*stringTable);
869 pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE> attrTableIter(
870 attrTable->data(), attrTable->size());
871 auto stringHandle = biosStringTable.findHandle(attrName);
872
873 for (auto entry : pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(
874 attrTable->data(), attrTable->size()))
875 {
876 auto header = table::attribute::decodeHeader(entry);
877 if (header.stringHandle == stringHandle)
878 {
879 return header.attrHandle;
880 }
881 }
882
883 throw std::invalid_argument("Unknow attribute Name");
884}
885
886void BIOSConfig::constructPendingAttribute(
887 const PendingAttributes& pendingAttributes)
888{
Tom Joseph7f839f92020-09-21 10:20:44 +0530889 std::vector<uint16_t> listOfHandles{};
890
George Liu1244acf2020-08-14 09:11:11 +0800891 for (auto& attribute : pendingAttributes)
892 {
893 std::string attributeName = attribute.first;
894 auto& [attributeType, attributevalue] = attribute.second;
895
896 auto iter = std::find_if(biosAttributes.begin(), biosAttributes.end(),
897 [&attributeName](const auto& attr) {
898 return attr->name == attributeName;
899 });
900
901 if (iter == biosAttributes.end())
902 {
903 std::cerr << "Wrong attribute name, attributeName = "
904 << attributeName << std::endl;
905 continue;
906 }
907
908 Table attrValueEntry(sizeof(pldm_bios_attr_val_table_entry), 0);
909 auto entry = reinterpret_cast<pldm_bios_attr_val_table_entry*>(
910 attrValueEntry.data());
911
912 auto handler = findAttrHandle(attributeName);
913 auto type =
914 BIOSConfigManager::convertAttributeTypeFromString(attributeType);
915
916 if (type != BIOSConfigManager::AttributeType::Enumeration &&
917 type != BIOSConfigManager::AttributeType::String &&
918 type != BIOSConfigManager::AttributeType::Integer)
919 {
920 std::cerr << "Attribute type not supported, attributeType = "
921 << attributeType << std::endl;
922 continue;
923 }
924
George Liu4876c542022-06-08 15:59:54 +0800925 const auto [attrType, readonlyStatus, displayName, description,
926 menuPath, currentValue, defaultValue, option] =
927 baseBIOSTableMaps.at(attributeName);
928
George Liu1244acf2020-08-14 09:11:11 +0800929 entry->attr_handle = htole16(handler);
George Liu4876c542022-06-08 15:59:54 +0800930
931 // Need to verify that the current value has really changed
932 if (attributeType == attrType && attributevalue != currentValue)
933 {
934 listOfHandles.emplace_back(htole16(handler));
935 }
Tom Joseph7f839f92020-09-21 10:20:44 +0530936
George Liu1244acf2020-08-14 09:11:11 +0800937 (*iter)->generateAttributeEntry(attributevalue, attrValueEntry);
938
George Liu6d6d1e82021-02-16 11:08:55 +0800939 setAttrValue(attrValueEntry.data(), attrValueEntry.size());
Tom Joseph7f839f92020-09-21 10:20:44 +0530940 }
941
942 if (listOfHandles.size())
943 {
944#ifdef OEM_IBM
945 auto rc = pldm::responder::platform::sendBiosAttributeUpdateEvent(
Sampa Misrac0c79482021-06-02 08:01:54 -0500946 eid, requester, listOfHandles, handler);
Tom Joseph7f839f92020-09-21 10:20:44 +0530947 if (rc != PLDM_SUCCESS)
948 {
949 return;
950 }
951#endif
George Liu1244acf2020-08-14 09:11:11 +0800952 }
953}
954
955void BIOSConfig::listenPendingAttributes()
956{
957 constexpr auto objPath = "/xyz/openbmc_project/bios_config/manager";
958 constexpr auto objInterface = "xyz.openbmc_project.BIOSConfig.Manager";
959
960 using namespace sdbusplus::bus::match::rules;
Patrick Williams84b790c2022-07-22 19:26:56 -0500961 auto updateBIOSMatch = std::make_unique<sdbusplus::bus::match_t>(
George Liu1244acf2020-08-14 09:11:11 +0800962 pldm::utils::DBusHandler::getBus(),
963 propertiesChanged(objPath, objInterface),
Patrick Williams84b790c2022-07-22 19:26:56 -0500964 [this](sdbusplus::message_t& msg) {
George Liu1244acf2020-08-14 09:11:11 +0800965 constexpr auto propertyName = "PendingAttributes";
966
967 using Value =
968 std::variant<std::string, PendingAttributes, BaseBIOSTable>;
969 using Properties = std::map<DbusProp, Value>;
970
971 Properties props{};
972 std::string intf;
973 msg.read(intf, props);
974
975 auto valPropMap = props.find(propertyName);
976 if (valPropMap == props.end())
977 {
978 return;
979 }
980
981 PendingAttributes pendingAttributes =
982 std::get<PendingAttributes>(valPropMap->second);
983 this->constructPendingAttribute(pendingAttributes);
984 });
985
986 biosAttrMatch.emplace_back(std::move(updateBIOSMatch));
987}
988
John Wangd9659342020-02-27 16:46:05 +0800989} // namespace bios
990} // namespace responder
991} // namespace pldm