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