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