blob: 92a0d040cc55697ab8a7fba67af7dca23225a18e [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
Riya Dixit49cfb132023-03-02 04:26:53 -06009#include <phosphor-logging/lg2.hpp>
George Liu1244acf2020-08-14 09:11:11 +080010#include <xyz/openbmc_project/BIOSConfig/Manager/server.hpp>
11
John Wangd9659342020-02-27 16:46:05 +080012#include <fstream>
13#include <iostream>
14
Tom Joseph7f839f92020-09-21 10:20:44 +053015#ifdef OEM_IBM
16#include "oem/ibm/libpldmresponder/platform_oem_ibm.hpp"
17#endif
18
Riya Dixit49cfb132023-03-02 04:26:53 -060019PHOSPHOR_LOG2_USING;
20
Brad Bishop5079ac42021-08-19 18:35:06 -040021using namespace pldm::dbus_api;
22using namespace pldm::utils;
23
John Wangd9659342020-02-27 16:46:05 +080024namespace pldm
25{
26namespace responder
27{
28namespace bios
29{
30namespace
31{
George Liu1244acf2020-08-14 09:11:11 +080032using BIOSConfigManager =
33 sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager;
34
John Wangd9659342020-02-27 16:46:05 +080035constexpr auto enumJsonFile = "enum_attrs.json";
36constexpr auto stringJsonFile = "string_attrs.json";
37constexpr auto integerJsonFile = "integer_attrs.json";
38
39constexpr auto stringTableFile = "stringTable";
40constexpr auto attrTableFile = "attributeTable";
41constexpr auto attrValueTableFile = "attributeValueTable";
42
43} // namespace
44
Sampa Misrac0c79482021-06-02 08:01:54 -050045BIOSConfig::BIOSConfig(
46 const char* jsonDir, const char* tableDir, DBusHandler* const dbusHandler,
47 int fd, uint8_t eid, dbus_api::Requester* requester,
48 pldm::requester::Handler<pldm::requester::Request>* handler) :
John Wangd9659342020-02-27 16:46:05 +080049 jsonDir(jsonDir),
Tom Joseph7f839f92020-09-21 10:20:44 +053050 tableDir(tableDir), dbusHandler(dbusHandler), fd(fd), eid(eid),
Sampa Misrac0c79482021-06-02 08:01:54 -050051 requester(requester), handler(handler)
Tom Joseph7f839f92020-09-21 10:20:44 +053052
John Wangd9659342020-02-27 16:46:05 +080053{
George Liu9d8921e2020-05-14 15:41:50 +080054 fs::create_directories(tableDir);
John Wangd9659342020-02-27 16:46:05 +080055 constructAttributes();
George Liu1244acf2020-08-14 09:11:11 +080056 listenPendingAttributes();
John Wangd9659342020-02-27 16:46:05 +080057}
58
59void BIOSConfig::buildTables()
60{
John Wangd9659342020-02-27 16:46:05 +080061 auto stringTable = buildAndStoreStringTable();
62 if (stringTable)
63 {
64 buildAndStoreAttrTables(*stringTable);
65 }
66}
67
68std::optional<Table> BIOSConfig::getBIOSTable(pldm_bios_table_types tableType)
69{
70 fs::path tablePath;
71 switch (tableType)
72 {
73 case PLDM_BIOS_STRING_TABLE:
74 tablePath = tableDir / stringTableFile;
75 break;
76 case PLDM_BIOS_ATTR_TABLE:
77 tablePath = tableDir / attrTableFile;
78 break;
79 case PLDM_BIOS_ATTR_VAL_TABLE:
80 tablePath = tableDir / attrValueTableFile;
81 break;
82 }
83 return loadTable(tablePath);
84}
85
Tom Joseph7f839f92020-09-21 10:20:44 +053086int BIOSConfig::setBIOSTable(uint8_t tableType, const Table& table,
87 bool updateBaseBIOSTable)
George Liu1b180d82020-07-23 14:01:58 +080088{
89 fs::path stringTablePath(tableDir / stringTableFile);
90 fs::path attrTablePath(tableDir / attrTableFile);
91 fs::path attrValueTablePath(tableDir / attrValueTableFile);
92
93 if (!pldm_bios_table_checksum(table.data(), table.size()))
94 {
95 return PLDM_INVALID_BIOS_TABLE_DATA_INTEGRITY_CHECK;
96 }
97
98 if (tableType == PLDM_BIOS_STRING_TABLE)
99 {
100 storeTable(stringTablePath, table);
101 }
102 else if (tableType == PLDM_BIOS_ATTR_TABLE)
103 {
104 BIOSTable biosStringTable(stringTablePath.c_str());
105 if (biosStringTable.isEmpty())
106 {
107 return PLDM_INVALID_BIOS_TABLE_TYPE;
108 }
109
110 auto rc = checkAttributeTable(table);
111 if (rc != PLDM_SUCCESS)
112 {
113 return rc;
114 }
115
116 storeTable(attrTablePath, table);
117 }
118 else if (tableType == PLDM_BIOS_ATTR_VAL_TABLE)
119 {
120 BIOSTable biosStringTable(stringTablePath.c_str());
121 BIOSTable biosStringValueTable(attrTablePath.c_str());
122 if (biosStringTable.isEmpty() || biosStringValueTable.isEmpty())
123 {
124 return PLDM_INVALID_BIOS_TABLE_TYPE;
125 }
126
127 auto rc = checkAttributeValueTable(table);
128 if (rc != PLDM_SUCCESS)
129 {
130 return rc;
131 }
132
133 storeTable(attrValueTablePath, table);
George Liu1b180d82020-07-23 14:01:58 +0800134 }
135 else
136 {
137 return PLDM_INVALID_BIOS_TABLE_TYPE;
138 }
139
Tom Joseph7f839f92020-09-21 10:20:44 +0530140 if ((tableType == PLDM_BIOS_ATTR_VAL_TABLE) && updateBaseBIOSTable)
George Liu1b180d82020-07-23 14:01:58 +0800141 {
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 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600456 error("failed to update BaseBIOSTable property, ERROR={ERR_EXCEP}",
457 "ERR_EXCEP", e.what());
George Liu1b180d82020-07-23 14:01:58 +0800458 }
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 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600505 error("Failed to read BaseBIOSTable property, ERROR={ERR_EXCEP}",
506 "ERR_EXCEP", e.what());
Tom Josephca7b2522020-11-18 12:27:11 +0530507 }
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 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600531 error("Construct Table Entry Error, AttributeName = {ATTR_NAME}",
532 "ATTR_NAME", attr->name);
John Wangd9659342020-02-27 16:46:05 +0800533 }
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 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600614 error(
615 "Failed to parse JSON config file(entry handler) : {JSON_PATH}, {ERR_EXCEP}",
616 "JSON_PATH", filePath.c_str(), "ERR_EXCEP", e.what());
John Wangd9659342020-02-27 16:46:05 +0800617 }
618 }
619 }
620 catch (const std::exception& e)
621 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600622 error("Failed to parse JSON config file : {JSON_PATH}", "JSON_PATH",
623 filePath.c_str());
John Wangd9659342020-02-27 16:46:05 +0800624 }
625 }
626}
627
Sagar Srinivascac0ebb2021-11-23 07:50:28 -0600628std::string BIOSConfig::decodeStringFromStringEntry(
629 const pldm_bios_string_table_entry* stringEntry)
630{
631 auto strLength =
632 pldm_bios_table_string_entry_decode_string_length(stringEntry);
633 std::vector<char> buffer(strLength + 1 /* sizeof '\0' */);
634 pldm_bios_table_string_entry_decode_string(stringEntry, buffer.data(),
635 buffer.size());
636 return std::string(buffer.data(), buffer.data() + strLength);
637}
638
639std::string
640 BIOSConfig::displayStringHandle(uint16_t handle, uint8_t index,
641 const std::optional<Table>& attrTable,
642 const std::optional<Table>& stringTable)
643{
644 auto attrEntry = pldm_bios_table_attr_find_by_handle(
645 attrTable->data(), attrTable->size(), handle);
646 auto pvNum = pldm_bios_table_attr_entry_enum_decode_pv_num(attrEntry);
647 std::vector<uint16_t> pvHandls(pvNum);
648 pldm_bios_table_attr_entry_enum_decode_pv_hdls(attrEntry, pvHandls.data(),
649 pvHandls.size());
650
651 std::string displayString = std::to_string(pvHandls[index]);
652
653 auto stringEntry = pldm_bios_table_string_find_by_handle(
654 stringTable->data(), stringTable->size(), pvHandls[index]);
655
656 auto decodedStr = decodeStringFromStringEntry(stringEntry);
657
658 return decodedStr + "(" + displayString + ")";
659}
660
661void BIOSConfig::traceBIOSUpdate(
662 const pldm_bios_attr_val_table_entry* attrValueEntry,
663 const pldm_bios_attr_table_entry* attrEntry, bool isBMC)
664{
665 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
666 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
667
668 auto [attrHandle, attrType] =
669 table::attribute_value::decodeHeader(attrValueEntry);
670
671 auto attrHeader = table::attribute::decodeHeader(attrEntry);
672 BIOSStringTable biosStringTable(*stringTable);
673 auto attrName = biosStringTable.findString(attrHeader.stringHandle);
674
675 switch (attrType)
676 {
677 case PLDM_BIOS_ENUMERATION:
678 case PLDM_BIOS_ENUMERATION_READ_ONLY:
679 {
680 auto count = pldm_bios_table_attr_value_entry_enum_decode_number(
681 attrValueEntry);
682 std::vector<uint8_t> handles(count);
683 pldm_bios_table_attr_value_entry_enum_decode_handles(
684 attrValueEntry, handles.data(), handles.size());
685
686 for (uint8_t handle : handles)
687 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600688 auto nwVal = displayStringHandle(attrHandle, handle, attrTable,
689 stringTable);
690 auto chkBMC = isBMC ? "true" : "false";
691 info(
692 "BIOS:{ATTR_NAME}, updated to value: {NEW_VAL}, by BMC: {CHK_BMC} ",
693 "ATTR_NAME", attrName, "NEW_VAL", nwVal, "CHK_BMC", chkBMC);
Sagar Srinivascac0ebb2021-11-23 07:50:28 -0600694 }
695 break;
696 }
697 case PLDM_BIOS_INTEGER:
698 case PLDM_BIOS_INTEGER_READ_ONLY:
699 {
700 auto value =
701 table::attribute_value::decodeIntegerEntry(attrValueEntry);
Riya Dixit49cfb132023-03-02 04:26:53 -0600702 auto chkBMC = isBMC ? "true" : "false";
703 info(
704 "BIOS: {ATTR_NAME}, updated to value: {UPDATED_VAL}, by BMC: {CHK_BMC}",
705 "ATTR_NAME", attrName, "UPDATED_VAL", value, "CHK_BMC", chkBMC);
Sagar Srinivascac0ebb2021-11-23 07:50:28 -0600706 break;
707 }
708 case PLDM_BIOS_STRING:
709 case PLDM_BIOS_STRING_READ_ONLY:
710 {
711 auto value =
712 table::attribute_value::decodeStringEntry(attrValueEntry);
Riya Dixit49cfb132023-03-02 04:26:53 -0600713 auto chkBMC = isBMC ? "true" : "false";
714 info(
715 "BIOS: {ATTR_NAME}, updated to value: {UPDATED_VAL}, by BMC: {CHK_BMC}",
716 "ATTR_NAME", attrName, "UPDATED_VAL", value, "CHK_BMC", chkBMC);
Sagar Srinivascac0ebb2021-11-23 07:50:28 -0600717 break;
718 }
719 default:
720 break;
721 };
722}
723
John Wang8241b342020-06-05 10:49:17 +0800724int BIOSConfig::checkAttrValueToUpdate(
725 const pldm_bios_attr_val_table_entry* attrValueEntry,
726 const pldm_bios_attr_table_entry* attrEntry, Table&)
727
728{
729 auto [attrHandle, attrType] =
730 table::attribute_value::decodeHeader(attrValueEntry);
731
732 switch (attrType)
733 {
734 case PLDM_BIOS_ENUMERATION:
George Liu5bb9edb2021-08-05 20:10:32 +0800735 case PLDM_BIOS_ENUMERATION_READ_ONLY:
John Wang8241b342020-06-05 10:49:17 +0800736 {
737 auto value =
738 table::attribute_value::decodeEnumEntry(attrValueEntry);
739 auto [pvHdls, defIndex] =
740 table::attribute::decodeEnumEntry(attrEntry);
Varsha Kaverappa6a4d1cf2021-11-24 21:15:42 -0600741 if (!(value.size() == 1))
742 {
743 return PLDM_ERROR_INVALID_LENGTH;
744 }
John Wang8241b342020-06-05 10:49:17 +0800745 if (value[0] >= pvHdls.size())
746 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600747 error("Enum: Illgeal index, Index = {ATTR_INDEX}", "ATTR_INDEX",
748 (int)value[0]);
John Wang8241b342020-06-05 10:49:17 +0800749 return PLDM_ERROR_INVALID_DATA;
750 }
John Wang8241b342020-06-05 10:49:17 +0800751 return PLDM_SUCCESS;
752 }
753 case PLDM_BIOS_INTEGER:
George Liu5bb9edb2021-08-05 20:10:32 +0800754 case PLDM_BIOS_INTEGER_READ_ONLY:
John Wang8241b342020-06-05 10:49:17 +0800755 {
756 auto value =
757 table::attribute_value::decodeIntegerEntry(attrValueEntry);
758 auto [lower, upper, scalar, def] =
759 table::attribute::decodeIntegerEntry(attrEntry);
760
761 if (value < lower || value > upper)
762 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600763 error("Integer: out of bound, value = {ATTR_VALUE}",
764 "ATTR_VALUE", value);
John Wang8241b342020-06-05 10:49:17 +0800765 return PLDM_ERROR_INVALID_DATA;
766 }
767 return PLDM_SUCCESS;
768 }
769 case PLDM_BIOS_STRING:
George Liu5bb9edb2021-08-05 20:10:32 +0800770 case PLDM_BIOS_STRING_READ_ONLY:
John Wang8241b342020-06-05 10:49:17 +0800771 {
772 auto stringConf = table::attribute::decodeStringEntry(attrEntry);
773 auto value =
774 table::attribute_value::decodeStringEntry(attrValueEntry);
775 if (value.size() < stringConf.minLength ||
776 value.size() > stringConf.maxLength)
777 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600778 error(
779 "String: Length error, string = {ATTR_VALUE} length {LEN}",
780 "ATTR_VALUE", value, "LEN", value.size());
John Wang8241b342020-06-05 10:49:17 +0800781 return PLDM_ERROR_INVALID_LENGTH;
782 }
783 return PLDM_SUCCESS;
784 }
785 default:
Riya Dixit49cfb132023-03-02 04:26:53 -0600786 error("ReadOnly or Unspported type, type = {ATTR_TYPE}",
787 "ATTR_TYPE", attrType);
John Wang8241b342020-06-05 10:49:17 +0800788 return PLDM_ERROR;
789 };
790}
791
Sagar Srinivascac0ebb2021-11-23 07:50:28 -0600792int BIOSConfig::setAttrValue(const void* entry, size_t size, bool isBMC,
793 bool updateDBus, bool updateBaseBIOSTable)
John Wangd9659342020-02-27 16:46:05 +0800794{
795 auto attrValueTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
796 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
797 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
798 if (!attrValueTable || !attrTable || !stringTable)
799 {
800 return PLDM_BIOS_TABLE_UNAVAILABLE;
801 }
802
John Wangd9659342020-02-27 16:46:05 +0800803 auto attrValueEntry =
804 reinterpret_cast<const pldm_bios_attr_val_table_entry*>(entry);
805
806 auto attrValHeader = table::attribute_value::decodeHeader(attrValueEntry);
807
808 auto attrEntry =
809 table::attribute::findByHandle(*attrTable, attrValHeader.attrHandle);
810 if (!attrEntry)
811 {
812 return PLDM_ERROR;
813 }
814
John Wang8241b342020-06-05 10:49:17 +0800815 auto rc = checkAttrValueToUpdate(attrValueEntry, attrEntry, *stringTable);
816 if (rc != PLDM_SUCCESS)
817 {
818 return rc;
819 }
820
821 auto destTable =
822 table::attribute_value::updateTable(*attrValueTable, entry, size);
823
824 if (!destTable)
825 {
826 return PLDM_ERROR;
827 }
828
John Wangd9659342020-02-27 16:46:05 +0800829 try
830 {
831 auto attrHeader = table::attribute::decodeHeader(attrEntry);
832
833 BIOSStringTable biosStringTable(*stringTable);
834 auto attrName = biosStringTable.findString(attrHeader.stringHandle);
John Wangd9659342020-02-27 16:46:05 +0800835 auto iter = std::find_if(
836 biosAttributes.begin(), biosAttributes.end(),
837 [&attrName](const auto& attr) { return attr->name == attrName; });
838
839 if (iter == biosAttributes.end())
840 {
841 return PLDM_ERROR;
842 }
George Liu6d6d1e82021-02-16 11:08:55 +0800843 if (updateDBus)
844 {
845 (*iter)->setAttrValueOnDbus(attrValueEntry, attrEntry,
846 biosStringTable);
847 }
John Wangd9659342020-02-27 16:46:05 +0800848 }
849 catch (const std::exception& e)
850 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600851 error("Set attribute value error: {ERR_EXCEP}", "ERR_EXCEP", e.what());
John Wangd9659342020-02-27 16:46:05 +0800852 return PLDM_ERROR;
853 }
854
Tom Joseph7f839f92020-09-21 10:20:44 +0530855 setBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE, *destTable, updateBaseBIOSTable);
George Liu5c3192b2020-08-13 17:35:43 +0800856
Sagar Srinivascac0ebb2021-11-23 07:50:28 -0600857 traceBIOSUpdate(attrValueEntry, attrEntry, isBMC);
858
John Wangd9659342020-02-27 16:46:05 +0800859 return PLDM_SUCCESS;
860}
861
862void BIOSConfig::removeTables()
863{
864 try
865 {
866 fs::remove(tableDir / stringTableFile);
867 fs::remove(tableDir / attrTableFile);
868 fs::remove(tableDir / attrValueTableFile);
869 }
870 catch (const std::exception& e)
871 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600872 error("Remove the tables error: {ERR_EXCEP}", "ERR_EXCEP", e.what());
John Wangd9659342020-02-27 16:46:05 +0800873 }
874}
875
Sampa Misra46ece062020-03-18 07:17:44 -0500876void BIOSConfig::processBiosAttrChangeNotification(
877 const DbusChObjProperties& chProperties, uint32_t biosAttrIndex)
878{
879 const auto& dBusMap = biosAttributes[biosAttrIndex]->getDBusMap();
880 const auto& propertyName = dBusMap->propertyName;
881 const auto& attrName = biosAttributes[biosAttrIndex]->name;
882
883 const auto it = chProperties.find(propertyName);
884 if (it == chProperties.end())
885 {
886 return;
887 }
888
889 PropertyValue newPropVal = it->second;
890 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
891 if (!stringTable.has_value())
892 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600893 error("BIOS string table unavailable");
Sampa Misra46ece062020-03-18 07:17:44 -0500894 return;
895 }
896 BIOSStringTable biosStringTable(*stringTable);
897 uint16_t attrNameHdl{};
898 try
899 {
900 attrNameHdl = biosStringTable.findHandle(attrName);
901 }
Patrick Williams51330582021-10-06 12:48:56 -0500902 catch (const std::invalid_argument& e)
Sampa Misra46ece062020-03-18 07:17:44 -0500903 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600904 error("Could not find handle for BIOS string, ATTRIBUTE={ATTR_NAME}",
905 "ATTR_NAME", attrName.c_str());
Sampa Misra46ece062020-03-18 07:17:44 -0500906 return;
907 }
908
909 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
910 if (!attrTable.has_value())
911 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600912 error("Attribute table not present");
Sampa Misra46ece062020-03-18 07:17:44 -0500913 return;
914 }
915 const struct pldm_bios_attr_table_entry* tableEntry =
916 table::attribute::findByStringHandle(*attrTable, attrNameHdl);
917 if (tableEntry == nullptr)
918 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600919 error(
920 "Attribute not found in attribute table, name= {ATTR_NAME} name handle={ATTR_HANDLE}",
921 "ATTR_NAME", attrName.c_str(), "ATTR_HANDLE", attrNameHdl);
Sampa Misra46ece062020-03-18 07:17:44 -0500922 return;
923 }
924
925 auto [attrHdl, attrType, stringHdl] =
926 table::attribute::decodeHeader(tableEntry);
927
928 auto attrValueSrcTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
929
930 if (!attrValueSrcTable.has_value())
931 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600932 error("Attribute value table not present");
Sampa Misra46ece062020-03-18 07:17:44 -0500933 return;
934 }
935
936 Table newValue;
937 auto rc = biosAttributes[biosAttrIndex]->updateAttrVal(
938 newValue, attrHdl, attrType, newPropVal);
939 if (rc != PLDM_SUCCESS)
940 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600941 error(
942 "Could not update the attribute value table for attribute handle={ATTR_HANDLE} and type={ATTR_TYPE}",
943 "ATTR_HANDLE", attrHdl, "ATTR_TYPE", (uint32_t)attrType);
Sampa Misra46ece062020-03-18 07:17:44 -0500944 return;
945 }
946 auto destTable = table::attribute_value::updateTable(
947 *attrValueSrcTable, newValue.data(), newValue.size());
948 if (destTable.has_value())
949 {
950 storeTable(tableDir / attrValueTableFile, *destTable);
951 }
Sampa Misra0f262332021-02-15 00:13:51 -0600952
Sagar Srinivascac0ebb2021-11-23 07:50:28 -0600953 rc = setAttrValue(newValue.data(), newValue.size(), true, false);
Sampa Misra0f262332021-02-15 00:13:51 -0600954 if (rc != PLDM_SUCCESS)
955 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600956 error("could not setAttrValue on base bios table and dbus, rc = {RC}",
957 "RC", rc);
Sampa Misra0f262332021-02-15 00:13:51 -0600958 }
Sampa Misra46ece062020-03-18 07:17:44 -0500959}
960
George Liu1244acf2020-08-14 09:11:11 +0800961uint16_t BIOSConfig::findAttrHandle(const std::string& attrName)
962{
963 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
964 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
965
966 BIOSStringTable biosStringTable(*stringTable);
967 pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE> attrTableIter(
968 attrTable->data(), attrTable->size());
969 auto stringHandle = biosStringTable.findHandle(attrName);
970
971 for (auto entry : pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(
972 attrTable->data(), attrTable->size()))
973 {
974 auto header = table::attribute::decodeHeader(entry);
975 if (header.stringHandle == stringHandle)
976 {
977 return header.attrHandle;
978 }
979 }
980
981 throw std::invalid_argument("Unknow attribute Name");
982}
983
984void BIOSConfig::constructPendingAttribute(
985 const PendingAttributes& pendingAttributes)
986{
Tom Joseph7f839f92020-09-21 10:20:44 +0530987 std::vector<uint16_t> listOfHandles{};
988
George Liu1244acf2020-08-14 09:11:11 +0800989 for (auto& attribute : pendingAttributes)
990 {
991 std::string attributeName = attribute.first;
992 auto& [attributeType, attributevalue] = attribute.second;
993
994 auto iter = std::find_if(biosAttributes.begin(), biosAttributes.end(),
995 [&attributeName](const auto& attr) {
996 return attr->name == attributeName;
997 });
998
999 if (iter == biosAttributes.end())
1000 {
Riya Dixit49cfb132023-03-02 04:26:53 -06001001 error("Wrong attribute name, attributeName = {ATTR_NAME}",
1002 "ATTR_NAME", attributeName);
George Liu1244acf2020-08-14 09:11:11 +08001003 continue;
1004 }
1005
1006 Table attrValueEntry(sizeof(pldm_bios_attr_val_table_entry), 0);
1007 auto entry = reinterpret_cast<pldm_bios_attr_val_table_entry*>(
1008 attrValueEntry.data());
1009
1010 auto handler = findAttrHandle(attributeName);
1011 auto type =
1012 BIOSConfigManager::convertAttributeTypeFromString(attributeType);
1013
1014 if (type != BIOSConfigManager::AttributeType::Enumeration &&
1015 type != BIOSConfigManager::AttributeType::String &&
1016 type != BIOSConfigManager::AttributeType::Integer)
1017 {
Riya Dixit49cfb132023-03-02 04:26:53 -06001018 error("Attribute type not supported, attributeType = {ATTR_TYPE}",
1019 "ATTR_TYPE", attributeType);
George Liu1244acf2020-08-14 09:11:11 +08001020 continue;
1021 }
1022
George Liu4876c542022-06-08 15:59:54 +08001023 const auto [attrType, readonlyStatus, displayName, description,
1024 menuPath, currentValue, defaultValue, option] =
1025 baseBIOSTableMaps.at(attributeName);
1026
George Liu1244acf2020-08-14 09:11:11 +08001027 entry->attr_handle = htole16(handler);
George Liu4876c542022-06-08 15:59:54 +08001028
1029 // Need to verify that the current value has really changed
1030 if (attributeType == attrType && attributevalue != currentValue)
1031 {
1032 listOfHandles.emplace_back(htole16(handler));
1033 }
Tom Joseph7f839f92020-09-21 10:20:44 +05301034
George Liu1244acf2020-08-14 09:11:11 +08001035 (*iter)->generateAttributeEntry(attributevalue, attrValueEntry);
1036
Sagar Srinivascac0ebb2021-11-23 07:50:28 -06001037 setAttrValue(attrValueEntry.data(), attrValueEntry.size(), true);
Tom Joseph7f839f92020-09-21 10:20:44 +05301038 }
1039
1040 if (listOfHandles.size())
1041 {
1042#ifdef OEM_IBM
1043 auto rc = pldm::responder::platform::sendBiosAttributeUpdateEvent(
Sampa Misrac0c79482021-06-02 08:01:54 -05001044 eid, requester, listOfHandles, handler);
Tom Joseph7f839f92020-09-21 10:20:44 +05301045 if (rc != PLDM_SUCCESS)
1046 {
1047 return;
1048 }
1049#endif
George Liu1244acf2020-08-14 09:11:11 +08001050 }
1051}
1052
1053void BIOSConfig::listenPendingAttributes()
1054{
1055 constexpr auto objPath = "/xyz/openbmc_project/bios_config/manager";
1056 constexpr auto objInterface = "xyz.openbmc_project.BIOSConfig.Manager";
1057
1058 using namespace sdbusplus::bus::match::rules;
Patrick Williams84b790c2022-07-22 19:26:56 -05001059 auto updateBIOSMatch = std::make_unique<sdbusplus::bus::match_t>(
George Liu1244acf2020-08-14 09:11:11 +08001060 pldm::utils::DBusHandler::getBus(),
1061 propertiesChanged(objPath, objInterface),
Patrick Williams84b790c2022-07-22 19:26:56 -05001062 [this](sdbusplus::message_t& msg) {
George Liu1244acf2020-08-14 09:11:11 +08001063 constexpr auto propertyName = "PendingAttributes";
1064
1065 using Value =
1066 std::variant<std::string, PendingAttributes, BaseBIOSTable>;
1067 using Properties = std::map<DbusProp, Value>;
1068
1069 Properties props{};
1070 std::string intf;
1071 msg.read(intf, props);
1072
1073 auto valPropMap = props.find(propertyName);
1074 if (valPropMap == props.end())
1075 {
1076 return;
1077 }
1078
1079 PendingAttributes pendingAttributes =
1080 std::get<PendingAttributes>(valPropMap->second);
1081 this->constructPendingAttribute(pendingAttributes);
1082 });
1083
1084 biosAttrMatch.emplace_back(std::move(updateBIOSMatch));
1085}
1086
John Wangd9659342020-02-27 16:46:05 +08001087} // namespace bios
1088} // namespace responder
1089} // namespace pldm