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