1 #include "bios_config.hpp" 2 3 #include "bios_enum_attribute.hpp" 4 #include "bios_integer_attribute.hpp" 5 #include "bios_string_attribute.hpp" 6 #include "bios_table.hpp" 7 #include "common/bios_utils.hpp" 8 9 #include <phosphor-logging/lg2.hpp> 10 #include <xyz/openbmc_project/BIOSConfig/Manager/server.hpp> 11 12 #include <filesystem> 13 #include <fstream> 14 15 #ifdef OEM_IBM 16 #include "oem/ibm/libpldmresponder/platform_oem_ibm.hpp" 17 #endif 18 19 PHOSPHOR_LOG2_USING; 20 21 using namespace pldm::utils; 22 23 namespace pldm 24 { 25 namespace responder 26 { 27 namespace bios 28 { 29 namespace 30 { 31 using BIOSConfigManager = 32 sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager; 33 34 constexpr auto attributesJsonFile = "bios_attrs.json"; 35 36 constexpr auto stringTableFile = "stringTable"; 37 constexpr auto attrTableFile = "attributeTable"; 38 constexpr auto attrValueTableFile = "attributeValueTable"; 39 40 } // namespace 41 42 BIOSConfig::BIOSConfig( 43 const char* jsonDir, const char* tableDir, DBusHandler* const dbusHandler, 44 int fd, uint8_t eid, pldm::InstanceIdDb* instanceIdDb, 45 pldm::requester::Handler<pldm::requester::Request>* handler, 46 pldm::responder::platform_config::Handler* platformConfigHandler, 47 pldm::responder::bios::Callback requestPLDMServiceName) : 48 jsonDir(jsonDir), 49 tableDir(tableDir), dbusHandler(dbusHandler), fd(fd), eid(eid), 50 instanceIdDb(instanceIdDb), handler(handler), 51 platformConfigHandler(platformConfigHandler), 52 requestPLDMServiceName(requestPLDMServiceName) 53 { 54 fs::create_directories(tableDir); 55 removeTables(); 56 57 #ifdef SYSTEM_SPECIFIC_BIOS_JSON 58 checkSystemTypeAvailability(); 59 #else 60 initBIOSAttributes(sysType, false); 61 #endif 62 63 listenPendingAttributes(); 64 } 65 66 void BIOSConfig::checkSystemTypeAvailability() 67 { 68 if (platformConfigHandler) 69 { 70 auto systemType = platformConfigHandler->getPlatformName(); 71 if (systemType.has_value()) 72 { 73 // Received System Type from Entity Manager 74 sysType = systemType.value(); 75 initBIOSAttributes(sysType, true); 76 } 77 else 78 { 79 platformConfigHandler->registerSystemTypeCallback( 80 std::bind(&BIOSConfig::initBIOSAttributes, this, 81 std::placeholders::_1, std::placeholders::_2)); 82 } 83 } 84 } 85 86 void BIOSConfig::initBIOSAttributes(const std::string& systemType, 87 bool registerService) 88 { 89 sysType = systemType; 90 fs::path dir{jsonDir / sysType}; 91 if (!fs::exists(dir)) 92 { 93 error("System specific bios attribute directory {DIR} does not exit", 94 "DIR", dir); 95 return; 96 } 97 constructAttributes(); 98 buildTables(); 99 if (registerService) 100 { 101 requestPLDMServiceName(); 102 } 103 } 104 105 void BIOSConfig::buildTables() 106 { 107 auto stringTable = buildAndStoreStringTable(); 108 if (stringTable) 109 { 110 buildAndStoreAttrTables(*stringTable); 111 } 112 } 113 114 std::optional<Table> BIOSConfig::getBIOSTable(pldm_bios_table_types tableType) 115 { 116 fs::path tablePath; 117 switch (tableType) 118 { 119 case PLDM_BIOS_STRING_TABLE: 120 tablePath = tableDir / stringTableFile; 121 break; 122 case PLDM_BIOS_ATTR_TABLE: 123 tablePath = tableDir / attrTableFile; 124 break; 125 case PLDM_BIOS_ATTR_VAL_TABLE: 126 tablePath = tableDir / attrValueTableFile; 127 break; 128 } 129 return loadTable(tablePath); 130 } 131 132 int BIOSConfig::setBIOSTable(uint8_t tableType, const Table& table, 133 bool updateBaseBIOSTable) 134 { 135 fs::path stringTablePath(tableDir / stringTableFile); 136 fs::path attrTablePath(tableDir / attrTableFile); 137 fs::path attrValueTablePath(tableDir / attrValueTableFile); 138 139 if (!pldm_bios_table_checksum(table.data(), table.size())) 140 { 141 return PLDM_INVALID_BIOS_TABLE_DATA_INTEGRITY_CHECK; 142 } 143 144 if (tableType == PLDM_BIOS_STRING_TABLE) 145 { 146 storeTable(stringTablePath, table); 147 } 148 else if (tableType == PLDM_BIOS_ATTR_TABLE) 149 { 150 BIOSTable biosStringTable(stringTablePath.c_str()); 151 if (biosStringTable.isEmpty()) 152 { 153 return PLDM_INVALID_BIOS_TABLE_TYPE; 154 } 155 156 auto rc = checkAttributeTable(table); 157 if (rc != PLDM_SUCCESS) 158 { 159 return rc; 160 } 161 162 storeTable(attrTablePath, table); 163 } 164 else if (tableType == PLDM_BIOS_ATTR_VAL_TABLE) 165 { 166 BIOSTable biosStringTable(stringTablePath.c_str()); 167 BIOSTable biosStringValueTable(attrTablePath.c_str()); 168 if (biosStringTable.isEmpty() || biosStringValueTable.isEmpty()) 169 { 170 return PLDM_INVALID_BIOS_TABLE_TYPE; 171 } 172 173 auto rc = checkAttributeValueTable(table); 174 if (rc != PLDM_SUCCESS) 175 { 176 return rc; 177 } 178 179 storeTable(attrValueTablePath, table); 180 } 181 else 182 { 183 return PLDM_INVALID_BIOS_TABLE_TYPE; 184 } 185 186 if ((tableType == PLDM_BIOS_ATTR_VAL_TABLE) && updateBaseBIOSTable) 187 { 188 updateBaseBIOSTableProperty(); 189 } 190 191 return PLDM_SUCCESS; 192 } 193 194 int BIOSConfig::checkAttributeTable(const Table& table) 195 { 196 using namespace pldm::bios::utils; 197 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 198 for (auto entry : 199 BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(table.data(), table.size())) 200 { 201 auto attrNameHandle = 202 pldm_bios_table_attr_entry_decode_string_handle(entry); 203 204 auto stringEnty = pldm_bios_table_string_find_by_handle( 205 stringTable->data(), stringTable->size(), attrNameHandle); 206 if (stringEnty == nullptr) 207 { 208 return PLDM_INVALID_BIOS_ATTR_HANDLE; 209 } 210 211 auto attrType = static_cast<pldm_bios_attribute_type>( 212 pldm_bios_table_attr_entry_decode_attribute_type(entry)); 213 214 switch (attrType) 215 { 216 case PLDM_BIOS_ENUMERATION: 217 case PLDM_BIOS_ENUMERATION_READ_ONLY: 218 { 219 uint8_t pvNum; 220 // Preconditions are upheld therefore no error check necessary 221 pldm_bios_table_attr_entry_enum_decode_pv_num_check(entry, 222 &pvNum); 223 std::vector<uint16_t> pvHandls(pvNum); 224 // Preconditions are upheld therefore no error check necessary 225 pldm_bios_table_attr_entry_enum_decode_pv_hdls_check( 226 entry, pvHandls.data(), pvHandls.size()); 227 uint8_t defNum; 228 pldm_bios_table_attr_entry_enum_decode_def_num_check(entry, 229 &defNum); 230 std::vector<uint8_t> defIndices(defNum); 231 pldm_bios_table_attr_entry_enum_decode_def_indices( 232 entry, defIndices.data(), defIndices.size()); 233 234 for (size_t i = 0; i < pvHandls.size(); i++) 235 { 236 auto stringEntry = pldm_bios_table_string_find_by_handle( 237 stringTable->data(), stringTable->size(), pvHandls[i]); 238 if (stringEntry == nullptr) 239 { 240 return PLDM_INVALID_BIOS_ATTR_HANDLE; 241 } 242 } 243 244 for (size_t i = 0; i < defIndices.size(); i++) 245 { 246 auto stringEntry = pldm_bios_table_string_find_by_handle( 247 stringTable->data(), stringTable->size(), 248 pvHandls[defIndices[i]]); 249 if (stringEntry == nullptr) 250 { 251 return PLDM_INVALID_BIOS_ATTR_HANDLE; 252 } 253 } 254 break; 255 } 256 case PLDM_BIOS_INTEGER: 257 case PLDM_BIOS_INTEGER_READ_ONLY: 258 case PLDM_BIOS_STRING: 259 case PLDM_BIOS_STRING_READ_ONLY: 260 case PLDM_BIOS_PASSWORD: 261 case PLDM_BIOS_PASSWORD_READ_ONLY: 262 break; 263 default: 264 return PLDM_INVALID_BIOS_ATTR_HANDLE; 265 } 266 } 267 268 return PLDM_SUCCESS; 269 } 270 271 int BIOSConfig::checkAttributeValueTable(const Table& table) 272 { 273 using namespace pldm::bios::utils; 274 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 275 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 276 277 baseBIOSTableMaps.clear(); 278 279 for (auto tableEntry : 280 BIOSTableIter<PLDM_BIOS_ATTR_VAL_TABLE>(table.data(), table.size())) 281 { 282 AttributeName attributeName{}; 283 AttributeType attributeType{}; 284 ReadonlyStatus readonlyStatus{}; 285 DisplayName displayName{}; 286 Description description{}; 287 MenuPath menuPath{}; 288 CurrentValue currentValue{}; 289 DefaultValue defaultValue{}; 290 std::vector<ValueDisplayName> valueDisplayNames; 291 std::map<uint16_t, std::vector<std::string>> valueDisplayNamesMap; 292 Option options{}; 293 294 auto attrValueHandle = 295 pldm_bios_table_attr_value_entry_decode_attribute_handle( 296 tableEntry); 297 auto attrType = static_cast<pldm_bios_attribute_type>( 298 pldm_bios_table_attr_value_entry_decode_attribute_type(tableEntry)); 299 300 auto attrEntry = pldm_bios_table_attr_find_by_handle( 301 attrTable->data(), attrTable->size(), attrValueHandle); 302 if (attrEntry == nullptr) 303 { 304 return PLDM_INVALID_BIOS_ATTR_HANDLE; 305 } 306 auto attrHandle = 307 pldm_bios_table_attr_entry_decode_attribute_handle(attrEntry); 308 auto attrNameHandle = 309 pldm_bios_table_attr_entry_decode_string_handle(attrEntry); 310 311 auto stringEntry = pldm_bios_table_string_find_by_handle( 312 stringTable->data(), stringTable->size(), attrNameHandle); 313 if (stringEntry == nullptr) 314 { 315 return PLDM_INVALID_BIOS_ATTR_HANDLE; 316 } 317 auto strLength = 318 pldm_bios_table_string_entry_decode_string_length(stringEntry); 319 std::vector<char> buffer(strLength + 1 /* sizeof '\0' */); 320 // Preconditions are upheld therefore no error check necessary 321 pldm_bios_table_string_entry_decode_string_check( 322 stringEntry, buffer.data(), buffer.size()); 323 324 attributeName = std::string(buffer.data(), buffer.data() + strLength); 325 326 if (!biosAttributes.empty()) 327 { 328 readonlyStatus = 329 biosAttributes[attrHandle % biosAttributes.size()]->readOnly; 330 description = 331 biosAttributes[attrHandle % biosAttributes.size()]->helpText; 332 displayName = 333 biosAttributes[attrHandle % biosAttributes.size()]->displayName; 334 valueDisplayNamesMap = 335 biosAttributes[attrHandle % biosAttributes.size()] 336 ->valueDisplayNamesMap; 337 } 338 339 switch (attrType) 340 { 341 case PLDM_BIOS_ENUMERATION: 342 case PLDM_BIOS_ENUMERATION_READ_ONLY: 343 { 344 if (valueDisplayNamesMap.contains(attrHandle)) 345 { 346 const std::vector<ValueDisplayName>& vdn = 347 valueDisplayNamesMap[attrHandle]; 348 valueDisplayNames.insert(valueDisplayNames.end(), 349 vdn.begin(), vdn.end()); 350 } 351 auto getValue = [](uint16_t handle, 352 const Table& table) -> std::string { 353 auto stringEntry = pldm_bios_table_string_find_by_handle( 354 table.data(), table.size(), handle); 355 356 auto strLength = 357 pldm_bios_table_string_entry_decode_string_length( 358 stringEntry); 359 std::vector<char> buffer(strLength + 1 /* sizeof '\0' */); 360 // Preconditions are upheld therefore no error check 361 // necessary 362 pldm_bios_table_string_entry_decode_string_check( 363 stringEntry, buffer.data(), buffer.size()); 364 365 return std::string(buffer.data(), 366 buffer.data() + strLength); 367 }; 368 369 attributeType = "xyz.openbmc_project.BIOSConfig.Manager." 370 "AttributeType.Enumeration"; 371 372 uint8_t pvNum; 373 // Preconditions are upheld therefore no error check necessary 374 pldm_bios_table_attr_entry_enum_decode_pv_num_check(attrEntry, 375 &pvNum); 376 std::vector<uint16_t> pvHandls(pvNum); 377 // Preconditions are upheld therefore no error check necessary 378 pldm_bios_table_attr_entry_enum_decode_pv_hdls_check( 379 attrEntry, pvHandls.data(), pvHandls.size()); 380 381 // get possible_value 382 for (size_t i = 0; i < pvHandls.size(); i++) 383 { 384 options.push_back( 385 std::make_tuple("xyz.openbmc_project.BIOSConfig." 386 "Manager.BoundType.OneOf", 387 getValue(pvHandls[i], *stringTable), 388 valueDisplayNames[i])); 389 } 390 391 auto count = 392 pldm_bios_table_attr_value_entry_enum_decode_number( 393 tableEntry); 394 std::vector<uint8_t> handles(count); 395 pldm_bios_table_attr_value_entry_enum_decode_handles( 396 tableEntry, handles.data(), handles.size()); 397 398 // get current_value 399 for (size_t i = 0; i < handles.size(); i++) 400 { 401 currentValue = getValue(pvHandls[handles[i]], *stringTable); 402 } 403 404 uint8_t defNum; 405 // Preconditions are upheld therefore no error check necessary 406 pldm_bios_table_attr_entry_enum_decode_def_num_check(attrEntry, 407 &defNum); 408 std::vector<uint8_t> defIndices(defNum); 409 pldm_bios_table_attr_entry_enum_decode_def_indices( 410 attrEntry, defIndices.data(), defIndices.size()); 411 412 // get default_value 413 for (size_t i = 0; i < defIndices.size(); i++) 414 { 415 defaultValue = getValue(pvHandls[defIndices[i]], 416 *stringTable); 417 } 418 419 break; 420 } 421 case PLDM_BIOS_INTEGER: 422 case PLDM_BIOS_INTEGER_READ_ONLY: 423 { 424 attributeType = "xyz.openbmc_project.BIOSConfig.Manager." 425 "AttributeType.Integer"; 426 currentValue = static_cast<int64_t>( 427 pldm_bios_table_attr_value_entry_integer_decode_cv( 428 tableEntry)); 429 430 uint64_t lower, upper, def; 431 uint32_t scalar; 432 pldm_bios_table_attr_entry_integer_decode( 433 attrEntry, &lower, &upper, &scalar, &def); 434 options.push_back(std::make_tuple( 435 "xyz.openbmc_project.BIOSConfig.Manager." 436 "BoundType.LowerBound", 437 static_cast<int64_t>(lower), attributeName)); 438 options.push_back(std::make_tuple( 439 "xyz.openbmc_project.BIOSConfig.Manager." 440 "BoundType.UpperBound", 441 static_cast<int64_t>(upper), attributeName)); 442 options.push_back(std::make_tuple( 443 "xyz.openbmc_project.BIOSConfig.Manager." 444 "BoundType.ScalarIncrement", 445 static_cast<int64_t>(scalar), attributeName)); 446 defaultValue = static_cast<int64_t>(def); 447 break; 448 } 449 case PLDM_BIOS_STRING: 450 case PLDM_BIOS_STRING_READ_ONLY: 451 { 452 attributeType = "xyz.openbmc_project.BIOSConfig.Manager." 453 "AttributeType.String"; 454 variable_field currentString; 455 pldm_bios_table_attr_value_entry_string_decode_string( 456 tableEntry, ¤tString); 457 currentValue = std::string( 458 reinterpret_cast<const char*>(currentString.ptr), 459 currentString.length); 460 auto min = pldm_bios_table_attr_entry_string_decode_min_length( 461 attrEntry); 462 auto max = pldm_bios_table_attr_entry_string_decode_max_length( 463 attrEntry); 464 uint16_t def; 465 // Preconditions are upheld therefore no error check necessary 466 pldm_bios_table_attr_entry_string_decode_def_string_length_check( 467 attrEntry, &def); 468 std::vector<char> defString(def + 1); 469 pldm_bios_table_attr_entry_string_decode_def_string( 470 attrEntry, defString.data(), defString.size()); 471 options.push_back( 472 std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager." 473 "BoundType.MinStringLength", 474 static_cast<int64_t>(min), attributeName)); 475 options.push_back( 476 std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager." 477 "BoundType.MaxStringLength", 478 static_cast<int64_t>(max), attributeName)); 479 defaultValue = defString.data(); 480 break; 481 } 482 case PLDM_BIOS_PASSWORD: 483 case PLDM_BIOS_PASSWORD_READ_ONLY: 484 { 485 attributeType = "xyz.openbmc_project.BIOSConfig.Manager." 486 "AttributeType.Password"; 487 break; 488 } 489 default: 490 return PLDM_INVALID_BIOS_ATTR_HANDLE; 491 } 492 baseBIOSTableMaps.emplace( 493 std::move(attributeName), 494 std::make_tuple(attributeType, readonlyStatus, displayName, 495 description, menuPath, currentValue, defaultValue, 496 std::move(options))); 497 } 498 499 return PLDM_SUCCESS; 500 } 501 502 void BIOSConfig::updateBaseBIOSTableProperty() 503 { 504 constexpr static auto biosConfigPath = 505 "/xyz/openbmc_project/bios_config/manager"; 506 constexpr static auto biosConfigInterface = 507 "xyz.openbmc_project.BIOSConfig.Manager"; 508 constexpr static auto biosConfigPropertyName = "BaseBIOSTable"; 509 constexpr static auto dbusProperties = "org.freedesktop.DBus.Properties"; 510 511 if (baseBIOSTableMaps.empty()) 512 { 513 return; 514 } 515 516 try 517 { 518 auto& bus = dbusHandler->getBus(); 519 auto service = dbusHandler->getService(biosConfigPath, 520 biosConfigInterface); 521 auto method = bus.new_method_call(service.c_str(), biosConfigPath, 522 dbusProperties, "Set"); 523 std::variant<BaseBIOSTable> value = baseBIOSTableMaps; 524 method.append(biosConfigInterface, biosConfigPropertyName, value); 525 bus.call_noreply(method, dbusTimeout); 526 } 527 catch (const std::exception& e) 528 { 529 error("Failed to update BaseBIOSTable property, error - {ERROR}", 530 "ERROR", e); 531 } 532 } 533 534 void BIOSConfig::constructAttributes() 535 { 536 info("Bios Attribute file path: {PATH}", "PATH", 537 (jsonDir / sysType / attributesJsonFile)); 538 load(jsonDir / sysType / attributesJsonFile, [this](const Json& entry) { 539 std::string attrType = entry.at("attribute_type"); 540 if (attrType == "string") 541 { 542 constructAttribute<BIOSStringAttribute>(entry); 543 } 544 else if (attrType == "integer") 545 { 546 constructAttribute<BIOSIntegerAttribute>(entry); 547 } 548 else if (attrType == "enum") 549 { 550 constructAttribute<BIOSEnumAttribute>(entry); 551 } 552 }); 553 } 554 555 void BIOSConfig::buildAndStoreAttrTables(const Table& stringTable) 556 { 557 BIOSStringTable biosStringTable(stringTable); 558 559 if (biosAttributes.empty()) 560 { 561 return; 562 } 563 564 BaseBIOSTable biosTable{}; 565 constexpr auto biosObjPath = "/xyz/openbmc_project/bios_config/manager"; 566 constexpr auto biosInterface = "xyz.openbmc_project.BIOSConfig.Manager"; 567 568 try 569 { 570 auto& bus = dbusHandler->getBus(); 571 auto service = dbusHandler->getService(biosObjPath, biosInterface); 572 auto method = bus.new_method_call(service.c_str(), biosObjPath, 573 "org.freedesktop.DBus.Properties", 574 "Get"); 575 method.append(biosInterface, "BaseBIOSTable"); 576 auto reply = bus.call(method, dbusTimeout); 577 std::variant<BaseBIOSTable> varBiosTable{}; 578 reply.read(varBiosTable); 579 biosTable = std::get<BaseBIOSTable>(varBiosTable); 580 } 581 // Failed to read the BaseBIOSTable, so update the BaseBIOSTable with the 582 // default values populated from the BIOS JSONs to keep PLDM and 583 // bios-settings-manager in sync 584 catch (const std::exception& e) 585 { 586 error("Failed to read BaseBIOSTable property, error - {ERROR}", "ERROR", 587 e); 588 } 589 590 Table attrTable, attrValueTable; 591 592 for (auto& attr : biosAttributes) 593 { 594 try 595 { 596 auto iter = biosTable.find(attr->name); 597 if (iter == biosTable.end()) 598 { 599 attr->constructEntry(biosStringTable, attrTable, attrValueTable, 600 std::nullopt); 601 } 602 else 603 { 604 attr->constructEntry( 605 biosStringTable, attrTable, attrValueTable, 606 std::get<static_cast<uint8_t>(Index::currentValue)>( 607 iter->second)); 608 } 609 } 610 catch (const std::exception& e) 611 { 612 error( 613 "Failed to construct table entry for attribute '{ATTRIBUTE}', error - {ERROR}", 614 "ATTRIBUTE", attr->name, "ERROR", e); 615 } 616 } 617 618 table::appendPadAndChecksum(attrTable); 619 table::appendPadAndChecksum(attrValueTable); 620 setBIOSTable(PLDM_BIOS_ATTR_TABLE, attrTable); 621 setBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE, attrValueTable); 622 } 623 624 std::optional<Table> BIOSConfig::buildAndStoreStringTable() 625 { 626 std::set<std::string> strings; 627 load(jsonDir / sysType / attributesJsonFile, [&strings](const Json& entry) { 628 if (entry.at("attribute_type") == "enum") 629 { 630 strings.emplace(entry.at("attribute_name")); 631 auto possibleValues = entry.at("possible_values"); 632 for (auto& pv : possibleValues) 633 { 634 strings.emplace(pv); 635 } 636 } 637 else 638 { 639 strings.emplace(entry.at("attribute_name")); 640 } 641 }); 642 643 if (strings.empty()) 644 { 645 return std::nullopt; 646 } 647 648 Table table; 649 for (const auto& elem : strings) 650 { 651 table::string::constructEntry(table, elem); 652 } 653 654 table::appendPadAndChecksum(table); 655 setBIOSTable(PLDM_BIOS_STRING_TABLE, table); 656 return table; 657 } 658 659 void BIOSConfig::storeTable(const fs::path& path, const Table& table) 660 { 661 BIOSTable biosTable(path.c_str()); 662 biosTable.store(table); 663 } 664 665 std::optional<Table> BIOSConfig::loadTable(const fs::path& path) 666 { 667 BIOSTable biosTable(path.c_str()); 668 if (biosTable.isEmpty()) 669 { 670 return std::nullopt; 671 } 672 673 Table table; 674 biosTable.load(table); 675 return table; 676 } 677 678 void BIOSConfig::load(const fs::path& filePath, ParseHandler handler) 679 { 680 std::ifstream file; 681 Json jsonConf; 682 if (fs::exists(filePath)) 683 { 684 try 685 { 686 file.open(filePath); 687 jsonConf = Json::parse(file); 688 auto entries = jsonConf.at("entries"); 689 for (auto& entry : entries) 690 { 691 try 692 { 693 handler(entry); 694 } 695 catch (const std::exception& e) 696 { 697 error( 698 "Failed to parse JSON config file at path '{PATH}', error - {ERROR}", 699 "PATH", filePath, "ERROR", e); 700 } 701 } 702 } 703 catch (const std::exception& e) 704 { 705 error("Failed to parse JSON config file '{PATH}', error - {ERROR}", 706 "PATH", filePath, "ERROR", e); 707 } 708 } 709 } 710 711 std::string BIOSConfig::decodeStringFromStringEntry( 712 const pldm_bios_string_table_entry* stringEntry) 713 { 714 auto strLength = 715 pldm_bios_table_string_entry_decode_string_length(stringEntry); 716 std::vector<char> buffer(strLength + 1 /* sizeof '\0' */); 717 // Preconditions are upheld therefore no error check necessary 718 pldm_bios_table_string_entry_decode_string_check(stringEntry, buffer.data(), 719 buffer.size()); 720 return std::string(buffer.data(), buffer.data() + strLength); 721 } 722 723 std::string 724 BIOSConfig::displayStringHandle(uint16_t handle, uint8_t index, 725 const std::optional<Table>& attrTable, 726 const std::optional<Table>& stringTable) 727 { 728 auto attrEntry = pldm_bios_table_attr_find_by_handle( 729 attrTable->data(), attrTable->size(), handle); 730 uint8_t pvNum; 731 int rc = pldm_bios_table_attr_entry_enum_decode_pv_num_check(attrEntry, 732 &pvNum); 733 if (rc != PLDM_SUCCESS) 734 { 735 error( 736 "Failed to decode BIOS table possible values for attribute entry, response code '{RC}'", 737 "RC", rc); 738 throw std::runtime_error( 739 "Failed to decode BIOS table possible values for attribute entry"); 740 } 741 742 std::vector<uint16_t> pvHandls(pvNum); 743 // Preconditions are upheld therefore no error check necessary 744 pldm_bios_table_attr_entry_enum_decode_pv_hdls_check( 745 attrEntry, pvHandls.data(), pvHandls.size()); 746 747 std::string displayString = std::to_string(pvHandls[index]); 748 749 auto stringEntry = pldm_bios_table_string_find_by_handle( 750 stringTable->data(), stringTable->size(), pvHandls[index]); 751 752 auto decodedStr = decodeStringFromStringEntry(stringEntry); 753 754 return decodedStr + "(" + displayString + ")"; 755 } 756 757 void BIOSConfig::traceBIOSUpdate( 758 const pldm_bios_attr_val_table_entry* attrValueEntry, 759 const pldm_bios_attr_table_entry* attrEntry, bool isBMC) 760 { 761 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 762 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 763 764 auto [attrHandle, 765 attrType] = table::attribute_value::decodeHeader(attrValueEntry); 766 767 auto attrHeader = table::attribute::decodeHeader(attrEntry); 768 BIOSStringTable biosStringTable(*stringTable); 769 auto attrName = biosStringTable.findString(attrHeader.stringHandle); 770 771 switch (attrType) 772 { 773 case PLDM_BIOS_ENUMERATION: 774 case PLDM_BIOS_ENUMERATION_READ_ONLY: 775 { 776 auto count = pldm_bios_table_attr_value_entry_enum_decode_number( 777 attrValueEntry); 778 std::vector<uint8_t> handles(count); 779 pldm_bios_table_attr_value_entry_enum_decode_handles( 780 attrValueEntry, handles.data(), handles.size()); 781 782 for (uint8_t handle : handles) 783 { 784 auto nwVal = displayStringHandle(attrHandle, handle, attrTable, 785 stringTable); 786 auto chkBMC = isBMC ? "true" : "false"; 787 info( 788 "BIOS attribute '{ATTRIBUTE}' updated to value '{VALUE}' by BMC '{CHECK_BMC}'", 789 "ATTRIBUTE", attrName, "VALUE", nwVal, "CHECK_BMC", chkBMC); 790 } 791 break; 792 } 793 case PLDM_BIOS_INTEGER: 794 case PLDM_BIOS_INTEGER_READ_ONLY: 795 { 796 auto value = 797 table::attribute_value::decodeIntegerEntry(attrValueEntry); 798 auto chkBMC = isBMC ? "true" : "false"; 799 info( 800 "BIOS attribute '{ATTRIBUTE}' updated to value '{VALUE}' by BMC '{CHECK_BMC}'", 801 "ATTRIBUTE", attrName, "VALUE", value, "CHECK_BMC", chkBMC); 802 break; 803 } 804 case PLDM_BIOS_STRING: 805 case PLDM_BIOS_STRING_READ_ONLY: 806 { 807 auto value = 808 table::attribute_value::decodeStringEntry(attrValueEntry); 809 auto chkBMC = isBMC ? "true" : "false"; 810 info( 811 "BIOS attribute '{ATTRIBUTE}' updated to value '{VALUE}' by BMC '{CHECK_BMC}'", 812 "ATTRIBUTE", attrName, "VALUE", value, "CHECK_BMC", chkBMC); 813 break; 814 } 815 default: 816 break; 817 }; 818 } 819 820 int BIOSConfig::checkAttrValueToUpdate( 821 const pldm_bios_attr_val_table_entry* attrValueEntry, 822 const pldm_bios_attr_table_entry* attrEntry, Table&) 823 824 { 825 auto [attrHandle, 826 attrType] = table::attribute_value::decodeHeader(attrValueEntry); 827 828 switch (attrType) 829 { 830 case PLDM_BIOS_ENUMERATION: 831 case PLDM_BIOS_ENUMERATION_READ_ONLY: 832 { 833 auto value = 834 table::attribute_value::decodeEnumEntry(attrValueEntry); 835 auto [pvHdls, 836 defIndex] = table::attribute::decodeEnumEntry(attrEntry); 837 if (!(value.size() == 1)) 838 { 839 return PLDM_ERROR_INVALID_LENGTH; 840 } 841 if (value[0] >= pvHdls.size()) 842 { 843 error( 844 "Invalid index '{INDEX}' encountered for Enum type BIOS attribute", 845 "INDEX", value[0]); 846 return PLDM_ERROR_INVALID_DATA; 847 } 848 return PLDM_SUCCESS; 849 } 850 case PLDM_BIOS_INTEGER: 851 case PLDM_BIOS_INTEGER_READ_ONLY: 852 { 853 auto value = 854 table::attribute_value::decodeIntegerEntry(attrValueEntry); 855 auto [lower, upper, scalar, 856 def] = table::attribute::decodeIntegerEntry(attrEntry); 857 858 if (value < lower || value > upper) 859 { 860 error( 861 "Out of range index '{ATTRIBUTE_VALUE}' encountered for Integer type BIOS attribute for the lower bound '{LOWER}', the upper bound '{UPPER}' and the scalar value '{SCALAR}'.", 862 "ATTRIBUTE_VALUE", value, "LOWER", lower, "UPPER", upper, 863 "SCALAR", scalar); 864 return PLDM_ERROR_INVALID_DATA; 865 } 866 return PLDM_SUCCESS; 867 } 868 case PLDM_BIOS_STRING: 869 case PLDM_BIOS_STRING_READ_ONLY: 870 { 871 auto stringConf = table::attribute::decodeStringEntry(attrEntry); 872 auto value = 873 table::attribute_value::decodeStringEntry(attrValueEntry); 874 if (value.size() < stringConf.minLength || 875 value.size() > stringConf.maxLength) 876 { 877 error( 878 "Invalid length '{LENGTH}' encountered for string type BIOS attribute value '{ATTRIBUTE_VALUE}' when minimum string entry length '{MIN_LEN}' and maximum string entry length '{MAX_LEN}'", 879 "ATTRIBUTE_VALUE", value, "LENGTH", value.size(), "MIN_LEN", 880 stringConf.minLength, "MAX_LEN", stringConf.maxLength); 881 return PLDM_ERROR_INVALID_LENGTH; 882 } 883 return PLDM_SUCCESS; 884 } 885 default: 886 error("ReadOnly or Unsupported type '{TYPE}'", "TYPE", attrType); 887 return PLDM_ERROR; 888 }; 889 } 890 891 int BIOSConfig::setAttrValue(const void* entry, size_t size, bool isBMC, 892 bool updateDBus, bool updateBaseBIOSTable) 893 { 894 auto attrValueTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 895 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 896 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 897 if (!attrValueTable || !attrTable || !stringTable) 898 { 899 return PLDM_BIOS_TABLE_UNAVAILABLE; 900 } 901 902 auto attrValueEntry = 903 reinterpret_cast<const pldm_bios_attr_val_table_entry*>(entry); 904 905 auto attrValHeader = table::attribute_value::decodeHeader(attrValueEntry); 906 907 auto attrEntry = table::attribute::findByHandle(*attrTable, 908 attrValHeader.attrHandle); 909 if (!attrEntry) 910 { 911 return PLDM_ERROR; 912 } 913 914 auto rc = checkAttrValueToUpdate(attrValueEntry, attrEntry, *stringTable); 915 if (rc != PLDM_SUCCESS) 916 { 917 return rc; 918 } 919 920 auto destTable = table::attribute_value::updateTable(*attrValueTable, entry, 921 size); 922 923 if (!destTable) 924 { 925 return PLDM_ERROR; 926 } 927 928 try 929 { 930 auto attrHeader = table::attribute::decodeHeader(attrEntry); 931 932 BIOSStringTable biosStringTable(*stringTable); 933 auto attrName = biosStringTable.findString(attrHeader.stringHandle); 934 auto iter = std::find_if( 935 biosAttributes.begin(), biosAttributes.end(), 936 [&attrName](const auto& attr) { return attr->name == attrName; }); 937 938 if (iter == biosAttributes.end()) 939 { 940 return PLDM_ERROR; 941 } 942 if (updateDBus) 943 { 944 (*iter)->setAttrValueOnDbus(attrValueEntry, attrEntry, 945 biosStringTable); 946 } 947 } 948 catch (const std::exception& e) 949 { 950 error("Set attribute value error - {ERROR}", "ERROR", e); 951 return PLDM_ERROR; 952 } 953 954 setBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE, *destTable, updateBaseBIOSTable); 955 956 traceBIOSUpdate(attrValueEntry, attrEntry, isBMC); 957 958 return PLDM_SUCCESS; 959 } 960 961 void BIOSConfig::removeTables() 962 { 963 try 964 { 965 fs::remove(tableDir / stringTableFile); 966 fs::remove(tableDir / attrTableFile); 967 fs::remove(tableDir / attrValueTableFile); 968 } 969 catch (const std::exception& e) 970 { 971 error("Remove the tables error - {ERROR}", "ERROR", e); 972 } 973 } 974 975 void BIOSConfig::processBiosAttrChangeNotification( 976 const DbusChObjProperties& chProperties, uint32_t biosAttrIndex) 977 { 978 const auto& dBusMap = biosAttributes[biosAttrIndex]->getDBusMap(); 979 const auto& propertyName = dBusMap->propertyName; 980 const auto& attrName = biosAttributes[biosAttrIndex]->name; 981 982 const auto it = chProperties.find(propertyName); 983 if (it == chProperties.end()) 984 { 985 return; 986 } 987 988 PropertyValue newPropVal = it->second; 989 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 990 if (!stringTable.has_value()) 991 { 992 error("BIOS string table unavailable"); 993 return; 994 } 995 BIOSStringTable biosStringTable(*stringTable); 996 uint16_t attrNameHdl{}; 997 try 998 { 999 attrNameHdl = biosStringTable.findHandle(attrName); 1000 } 1001 catch (const std::invalid_argument& e) 1002 { 1003 error( 1004 "Missing handle for attribute '{ATTRIBUTE}' in BIOS String Table, error - '{ERROR}'", 1005 "ATTRIBUTE", attrName, "ERROR", e); 1006 return; 1007 } 1008 1009 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 1010 if (!attrTable.has_value()) 1011 { 1012 error("BIOS Attribute table not present"); 1013 return; 1014 } 1015 const struct pldm_bios_attr_table_entry* tableEntry = 1016 table::attribute::findByStringHandle(*attrTable, attrNameHdl); 1017 if (tableEntry == nullptr) 1018 { 1019 error( 1020 "Failed to find attribute {ATTRIBUTE} in BIOS Attribute table with attribute handle '{ATTR_HANDLE}'", 1021 "ATTRIBUTE", attrName, "ATTR_HANDLE", attrNameHdl); 1022 return; 1023 } 1024 1025 auto [attrHdl, attrType, 1026 stringHdl] = table::attribute::decodeHeader(tableEntry); 1027 1028 auto attrValueSrcTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 1029 1030 if (!attrValueSrcTable.has_value()) 1031 { 1032 error("Attribute value table not present"); 1033 return; 1034 } 1035 1036 Table newValue; 1037 auto rc = biosAttributes[biosAttrIndex]->updateAttrVal( 1038 newValue, attrHdl, attrType, newPropVal); 1039 if (rc != PLDM_SUCCESS) 1040 { 1041 error( 1042 "Failed to update the attribute value table for attribute handle '{ATTR_HANDLE}' and attribute type '{TYPE}'", 1043 "ATTR_HANDLE", attrHdl, "TYPE", attrType); 1044 return; 1045 } 1046 auto destTable = table::attribute_value::updateTable( 1047 *attrValueSrcTable, newValue.data(), newValue.size()); 1048 if (destTable.has_value()) 1049 { 1050 storeTable(tableDir / attrValueTableFile, *destTable); 1051 } 1052 1053 rc = setAttrValue(newValue.data(), newValue.size(), true, false); 1054 if (rc != PLDM_SUCCESS) 1055 { 1056 error( 1057 "Failed to setAttrValue on base bios table and dbus, response code '{RC}'", 1058 "RC", rc); 1059 } 1060 } 1061 1062 uint16_t BIOSConfig::findAttrHandle(const std::string& attrName) 1063 { 1064 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 1065 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 1066 1067 BIOSStringTable biosStringTable(*stringTable); 1068 pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE> attrTableIter( 1069 attrTable->data(), attrTable->size()); 1070 auto stringHandle = biosStringTable.findHandle(attrName); 1071 1072 for (auto entry : pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE>( 1073 attrTable->data(), attrTable->size())) 1074 { 1075 auto header = table::attribute::decodeHeader(entry); 1076 if (header.stringHandle == stringHandle) 1077 { 1078 return header.attrHandle; 1079 } 1080 } 1081 1082 throw std::invalid_argument("Unknown attribute Name"); 1083 } 1084 1085 void BIOSConfig::constructPendingAttribute( 1086 const PendingAttributes& pendingAttributes) 1087 { 1088 std::vector<uint16_t> listOfHandles{}; 1089 1090 for (auto& attribute : pendingAttributes) 1091 { 1092 std::string attributeName = attribute.first; 1093 auto& [attributeType, attributevalue] = attribute.second; 1094 1095 auto iter = std::find_if(biosAttributes.begin(), biosAttributes.end(), 1096 [&attributeName](const auto& attr) { 1097 return attr->name == attributeName; 1098 }); 1099 1100 if (iter == biosAttributes.end()) 1101 { 1102 error("Wrong attribute name {NAME}", "NAME", attributeName); 1103 continue; 1104 } 1105 1106 Table attrValueEntry(sizeof(pldm_bios_attr_val_table_entry), 0); 1107 auto entry = reinterpret_cast<pldm_bios_attr_val_table_entry*>( 1108 attrValueEntry.data()); 1109 1110 auto handler = findAttrHandle(attributeName); 1111 auto type = 1112 BIOSConfigManager::convertAttributeTypeFromString(attributeType); 1113 1114 if (type != BIOSConfigManager::AttributeType::Enumeration && 1115 type != BIOSConfigManager::AttributeType::String && 1116 type != BIOSConfigManager::AttributeType::Integer) 1117 { 1118 error("Attribute type '{TYPE}' not supported", "TYPE", 1119 attributeType); 1120 continue; 1121 } 1122 1123 const auto [attrType, readonlyStatus, displayName, description, 1124 menuPath, currentValue, defaultValue, 1125 option] = baseBIOSTableMaps.at(attributeName); 1126 1127 entry->attr_handle = htole16(handler); 1128 1129 // Need to verify that the current value has really changed 1130 if (attributeType == attrType && attributevalue != currentValue) 1131 { 1132 listOfHandles.emplace_back(htole16(handler)); 1133 } 1134 1135 (*iter)->generateAttributeEntry(attributevalue, attrValueEntry); 1136 1137 setAttrValue(attrValueEntry.data(), attrValueEntry.size(), true); 1138 } 1139 1140 if (listOfHandles.size()) 1141 { 1142 #ifdef OEM_IBM 1143 auto rc = pldm::responder::platform::sendBiosAttributeUpdateEvent( 1144 eid, instanceIdDb, listOfHandles, handler); 1145 if (rc != PLDM_SUCCESS) 1146 { 1147 return; 1148 } 1149 #endif 1150 } 1151 } 1152 1153 void BIOSConfig::listenPendingAttributes() 1154 { 1155 constexpr auto objPath = "/xyz/openbmc_project/bios_config/manager"; 1156 constexpr auto objInterface = "xyz.openbmc_project.BIOSConfig.Manager"; 1157 1158 using namespace sdbusplus::bus::match::rules; 1159 auto updateBIOSMatch = std::make_unique<sdbusplus::bus::match_t>( 1160 pldm::utils::DBusHandler::getBus(), 1161 propertiesChanged(objPath, objInterface), 1162 [this](sdbusplus::message_t& msg) { 1163 constexpr auto propertyName = "PendingAttributes"; 1164 1165 using Value = 1166 std::variant<std::string, PendingAttributes, BaseBIOSTable>; 1167 using Properties = std::map<DbusProp, Value>; 1168 1169 Properties props{}; 1170 std::string intf; 1171 msg.read(intf, props); 1172 1173 auto valPropMap = props.find(propertyName); 1174 if (valPropMap == props.end()) 1175 { 1176 return; 1177 } 1178 1179 PendingAttributes pendingAttributes = 1180 std::get<PendingAttributes>(valPropMap->second); 1181 this->constructPendingAttribute(pendingAttributes); 1182 }); 1183 1184 biosAttrMatch.emplace_back(std::move(updateBIOSMatch)); 1185 } 1186 1187 } // namespace bios 1188 } // namespace responder 1189 } // namespace pldm 1190