blob: 10ec89c8efe53f29fa53897520f556837dd3119c [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:
639 {
640 auto value =
641 table::attribute_value::decodeEnumEntry(attrValueEntry);
642 auto [pvHdls, defIndex] =
643 table::attribute::decodeEnumEntry(attrEntry);
644 assert(value.size() == 1);
645 if (value[0] >= pvHdls.size())
646 {
647 std::cerr << "Enum: Illgeal index, Index = " << (int)value[0]
648 << std::endl;
649 return PLDM_ERROR_INVALID_DATA;
650 }
651
652 return PLDM_SUCCESS;
653 }
654 case PLDM_BIOS_INTEGER:
655 {
656 auto value =
657 table::attribute_value::decodeIntegerEntry(attrValueEntry);
658 auto [lower, upper, scalar, def] =
659 table::attribute::decodeIntegerEntry(attrEntry);
660
661 if (value < lower || value > upper)
662 {
663 std::cerr << "Integer: out of bound, value = " << value
664 << std::endl;
665 return PLDM_ERROR_INVALID_DATA;
666 }
667 return PLDM_SUCCESS;
668 }
669 case PLDM_BIOS_STRING:
670 {
671 auto stringConf = table::attribute::decodeStringEntry(attrEntry);
672 auto value =
673 table::attribute_value::decodeStringEntry(attrValueEntry);
674 if (value.size() < stringConf.minLength ||
675 value.size() > stringConf.maxLength)
676 {
677 std::cerr << "String: Length error, string = " << value
678 << " length = " << value.size() << std::endl;
679 return PLDM_ERROR_INVALID_LENGTH;
680 }
681 return PLDM_SUCCESS;
682 }
683 default:
684 std::cerr << "ReadOnly or Unspported type, type = " << attrType
685 << std::endl;
686 return PLDM_ERROR;
687 };
688}
689
George Liu6d6d1e82021-02-16 11:08:55 +0800690int BIOSConfig::setAttrValue(const void* entry, size_t size, bool updateDBus,
Tom Joseph7f839f92020-09-21 10:20:44 +0530691 bool updateBaseBIOSTable)
John Wangd9659342020-02-27 16:46:05 +0800692{
693 auto attrValueTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
694 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
695 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
696 if (!attrValueTable || !attrTable || !stringTable)
697 {
698 return PLDM_BIOS_TABLE_UNAVAILABLE;
699 }
700
John Wangd9659342020-02-27 16:46:05 +0800701 auto attrValueEntry =
702 reinterpret_cast<const pldm_bios_attr_val_table_entry*>(entry);
703
704 auto attrValHeader = table::attribute_value::decodeHeader(attrValueEntry);
705
706 auto attrEntry =
707 table::attribute::findByHandle(*attrTable, attrValHeader.attrHandle);
708 if (!attrEntry)
709 {
710 return PLDM_ERROR;
711 }
712
John Wang8241b342020-06-05 10:49:17 +0800713 auto rc = checkAttrValueToUpdate(attrValueEntry, attrEntry, *stringTable);
714 if (rc != PLDM_SUCCESS)
715 {
716 return rc;
717 }
718
719 auto destTable =
720 table::attribute_value::updateTable(*attrValueTable, entry, size);
721
722 if (!destTable)
723 {
724 return PLDM_ERROR;
725 }
726
John Wangd9659342020-02-27 16:46:05 +0800727 try
728 {
729 auto attrHeader = table::attribute::decodeHeader(attrEntry);
730
731 BIOSStringTable biosStringTable(*stringTable);
732 auto attrName = biosStringTable.findString(attrHeader.stringHandle);
733
734 auto iter = std::find_if(
735 biosAttributes.begin(), biosAttributes.end(),
736 [&attrName](const auto& attr) { return attr->name == attrName; });
737
738 if (iter == biosAttributes.end())
739 {
740 return PLDM_ERROR;
741 }
George Liu6d6d1e82021-02-16 11:08:55 +0800742 if (updateDBus)
743 {
744 (*iter)->setAttrValueOnDbus(attrValueEntry, attrEntry,
745 biosStringTable);
746 }
John Wangd9659342020-02-27 16:46:05 +0800747 }
748 catch (const std::exception& e)
749 {
750 std::cerr << "Set attribute value error: " << e.what() << std::endl;
751 return PLDM_ERROR;
752 }
753
Tom Joseph7f839f92020-09-21 10:20:44 +0530754 setBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE, *destTable, updateBaseBIOSTable);
George Liu5c3192b2020-08-13 17:35:43 +0800755
John Wangd9659342020-02-27 16:46:05 +0800756 return PLDM_SUCCESS;
757}
758
759void BIOSConfig::removeTables()
760{
761 try
762 {
763 fs::remove(tableDir / stringTableFile);
764 fs::remove(tableDir / attrTableFile);
765 fs::remove(tableDir / attrValueTableFile);
766 }
767 catch (const std::exception& e)
768 {
769 std::cerr << "Remove the tables error: " << e.what() << std::endl;
770 }
771}
772
Sampa Misra46ece062020-03-18 07:17:44 -0500773void BIOSConfig::processBiosAttrChangeNotification(
774 const DbusChObjProperties& chProperties, uint32_t biosAttrIndex)
775{
776 const auto& dBusMap = biosAttributes[biosAttrIndex]->getDBusMap();
777 const auto& propertyName = dBusMap->propertyName;
778 const auto& attrName = biosAttributes[biosAttrIndex]->name;
779
780 const auto it = chProperties.find(propertyName);
781 if (it == chProperties.end())
782 {
783 return;
784 }
785
786 PropertyValue newPropVal = it->second;
787 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
788 if (!stringTable.has_value())
789 {
790 std::cerr << "BIOS string table unavailable\n";
791 return;
792 }
793 BIOSStringTable biosStringTable(*stringTable);
794 uint16_t attrNameHdl{};
795 try
796 {
797 attrNameHdl = biosStringTable.findHandle(attrName);
798 }
799 catch (std::invalid_argument& e)
800 {
801 std::cerr << "Could not find handle for BIOS string, ATTRIBUTE="
802 << attrName.c_str() << "\n";
803 return;
804 }
805
806 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
807 if (!attrTable.has_value())
808 {
809 std::cerr << "Attribute table not present\n";
810 return;
811 }
812 const struct pldm_bios_attr_table_entry* tableEntry =
813 table::attribute::findByStringHandle(*attrTable, attrNameHdl);
814 if (tableEntry == nullptr)
815 {
816 std::cerr << "Attribute not found in attribute table, name= "
817 << attrName.c_str() << "name handle=" << attrNameHdl << "\n";
818 return;
819 }
820
821 auto [attrHdl, attrType, stringHdl] =
822 table::attribute::decodeHeader(tableEntry);
823
824 auto attrValueSrcTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
825
826 if (!attrValueSrcTable.has_value())
827 {
828 std::cerr << "Attribute value table not present\n";
829 return;
830 }
831
832 Table newValue;
833 auto rc = biosAttributes[biosAttrIndex]->updateAttrVal(
834 newValue, attrHdl, attrType, newPropVal);
835 if (rc != PLDM_SUCCESS)
836 {
837 std::cerr << "Could not update the attribute value table for attribute "
838 "handle="
839 << attrHdl << " and type=" << (uint32_t)attrType << "\n";
840 return;
841 }
842 auto destTable = table::attribute_value::updateTable(
843 *attrValueSrcTable, newValue.data(), newValue.size());
844 if (destTable.has_value())
845 {
846 storeTable(tableDir / attrValueTableFile, *destTable);
847 }
Sampa Misra0f262332021-02-15 00:13:51 -0600848
George Liu6d6d1e82021-02-16 11:08:55 +0800849 rc = setAttrValue(newValue.data(), newValue.size(), false);
Sampa Misra0f262332021-02-15 00:13:51 -0600850 if (rc != PLDM_SUCCESS)
851 {
George Liu6d6d1e82021-02-16 11:08:55 +0800852 std::cerr << "could not setAttrValue on base bios table and dbus, rc = "
853 << rc << "\n";
Sampa Misra0f262332021-02-15 00:13:51 -0600854 }
Sampa Misra46ece062020-03-18 07:17:44 -0500855}
856
George Liu1244acf2020-08-14 09:11:11 +0800857uint16_t BIOSConfig::findAttrHandle(const std::string& attrName)
858{
859 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
860 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
861
862 BIOSStringTable biosStringTable(*stringTable);
863 pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE> attrTableIter(
864 attrTable->data(), attrTable->size());
865 auto stringHandle = biosStringTable.findHandle(attrName);
866
867 for (auto entry : pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(
868 attrTable->data(), attrTable->size()))
869 {
870 auto header = table::attribute::decodeHeader(entry);
871 if (header.stringHandle == stringHandle)
872 {
873 return header.attrHandle;
874 }
875 }
876
877 throw std::invalid_argument("Unknow attribute Name");
878}
879
880void BIOSConfig::constructPendingAttribute(
881 const PendingAttributes& pendingAttributes)
882{
Tom Joseph7f839f92020-09-21 10:20:44 +0530883 std::vector<uint16_t> listOfHandles{};
884
George Liu1244acf2020-08-14 09:11:11 +0800885 for (auto& attribute : pendingAttributes)
886 {
887 std::string attributeName = attribute.first;
888 auto& [attributeType, attributevalue] = attribute.second;
889
890 auto iter = std::find_if(biosAttributes.begin(), biosAttributes.end(),
891 [&attributeName](const auto& attr) {
892 return attr->name == attributeName;
893 });
894
895 if (iter == biosAttributes.end())
896 {
897 std::cerr << "Wrong attribute name, attributeName = "
898 << attributeName << std::endl;
899 continue;
900 }
901
902 Table attrValueEntry(sizeof(pldm_bios_attr_val_table_entry), 0);
903 auto entry = reinterpret_cast<pldm_bios_attr_val_table_entry*>(
904 attrValueEntry.data());
905
906 auto handler = findAttrHandle(attributeName);
907 auto type =
908 BIOSConfigManager::convertAttributeTypeFromString(attributeType);
909
910 if (type != BIOSConfigManager::AttributeType::Enumeration &&
911 type != BIOSConfigManager::AttributeType::String &&
912 type != BIOSConfigManager::AttributeType::Integer)
913 {
914 std::cerr << "Attribute type not supported, attributeType = "
915 << attributeType << std::endl;
916 continue;
917 }
918
919 entry->attr_handle = htole16(handler);
Tom Joseph7f839f92020-09-21 10:20:44 +0530920 listOfHandles.emplace_back(htole16(handler));
921
George Liu1244acf2020-08-14 09:11:11 +0800922 (*iter)->generateAttributeEntry(attributevalue, attrValueEntry);
923
George Liu6d6d1e82021-02-16 11:08:55 +0800924 setAttrValue(attrValueEntry.data(), attrValueEntry.size());
Tom Joseph7f839f92020-09-21 10:20:44 +0530925 }
926
927 if (listOfHandles.size())
928 {
929#ifdef OEM_IBM
930 auto rc = pldm::responder::platform::sendBiosAttributeUpdateEvent(
Sampa Misrac0c79482021-06-02 08:01:54 -0500931 eid, requester, listOfHandles, handler);
Tom Joseph7f839f92020-09-21 10:20:44 +0530932 if (rc != PLDM_SUCCESS)
933 {
934 return;
935 }
936#endif
George Liu1244acf2020-08-14 09:11:11 +0800937 }
938}
939
940void BIOSConfig::listenPendingAttributes()
941{
942 constexpr auto objPath = "/xyz/openbmc_project/bios_config/manager";
943 constexpr auto objInterface = "xyz.openbmc_project.BIOSConfig.Manager";
944
945 using namespace sdbusplus::bus::match::rules;
946 auto updateBIOSMatch = std::make_unique<sdbusplus::bus::match::match>(
947 pldm::utils::DBusHandler::getBus(),
948 propertiesChanged(objPath, objInterface),
949 [this](sdbusplus::message::message& msg) {
950 constexpr auto propertyName = "PendingAttributes";
951
952 using Value =
953 std::variant<std::string, PendingAttributes, BaseBIOSTable>;
954 using Properties = std::map<DbusProp, Value>;
955
956 Properties props{};
957 std::string intf;
958 msg.read(intf, props);
959
960 auto valPropMap = props.find(propertyName);
961 if (valPropMap == props.end())
962 {
963 return;
964 }
965
966 PendingAttributes pendingAttributes =
967 std::get<PendingAttributes>(valPropMap->second);
968 this->constructPendingAttribute(pendingAttributes);
969 });
970
971 biosAttrMatch.emplace_back(std::move(updateBIOSMatch));
972}
973
John Wangd9659342020-02-27 16:46:05 +0800974} // namespace bios
975} // namespace responder
976} // namespace pldm