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