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(entry, &pvNum); 226 std::vector<uint16_t> pvHandls(pvNum); 227 // Preconditions are upheld therefore no error check necessary 228 pldm_bios_table_attr_entry_enum_decode_pv_hdls_check( 229 entry, pvHandls.data(), pvHandls.size()); 230 uint8_t defNum; 231 pldm_bios_table_attr_entry_enum_decode_def_num(entry, &defNum); 232 std::vector<uint8_t> defIndices(defNum); 233 pldm_bios_table_attr_entry_enum_decode_def_indices( 234 entry, defIndices.data(), defIndices.size()); 235 236 for (size_t i = 0; i < pvHandls.size(); i++) 237 { 238 auto stringEntry = pldm_bios_table_string_find_by_handle( 239 stringTable->data(), stringTable->size(), pvHandls[i]); 240 if (stringEntry == nullptr) 241 { 242 return PLDM_INVALID_BIOS_ATTR_HANDLE; 243 } 244 } 245 246 for (size_t i = 0; i < defIndices.size(); i++) 247 { 248 auto stringEntry = pldm_bios_table_string_find_by_handle( 249 stringTable->data(), stringTable->size(), 250 pvHandls[defIndices[i]]); 251 if (stringEntry == nullptr) 252 { 253 return PLDM_INVALID_BIOS_ATTR_HANDLE; 254 } 255 } 256 break; 257 } 258 case PLDM_BIOS_INTEGER: 259 case PLDM_BIOS_INTEGER_READ_ONLY: 260 case PLDM_BIOS_STRING: 261 case PLDM_BIOS_STRING_READ_ONLY: 262 case PLDM_BIOS_PASSWORD: 263 case PLDM_BIOS_PASSWORD_READ_ONLY: 264 break; 265 default: 266 return PLDM_INVALID_BIOS_ATTR_HANDLE; 267 } 268 } 269 270 return PLDM_SUCCESS; 271 } 272 273 int BIOSConfig::checkAttributeValueTable(const Table& table) 274 { 275 using namespace pldm::bios::utils; 276 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 277 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 278 279 baseBIOSTableMaps.clear(); 280 281 for (auto tableEntry : 282 BIOSTableIter<PLDM_BIOS_ATTR_VAL_TABLE>(table.data(), table.size())) 283 { 284 AttributeName attributeName{}; 285 AttributeType attributeType{}; 286 ReadonlyStatus readonlyStatus{}; 287 DisplayName displayName{}; 288 Description description{}; 289 MenuPath menuPath{}; 290 CurrentValue currentValue{}; 291 DefaultValue defaultValue{}; 292 std::vector<ValueDisplayName> valueDisplayNames; 293 std::map<uint16_t, std::vector<std::string>> valueDisplayNamesMap; 294 Option options{}; 295 296 auto attrValueHandle = 297 pldm_bios_table_attr_value_entry_decode_attribute_handle( 298 tableEntry); 299 auto attrType = static_cast<pldm_bios_attribute_type>( 300 pldm_bios_table_attr_value_entry_decode_attribute_type(tableEntry)); 301 302 auto attrEntry = pldm_bios_table_attr_find_by_handle( 303 attrTable->data(), attrTable->size(), attrValueHandle); 304 if (attrEntry == nullptr) 305 { 306 return PLDM_INVALID_BIOS_ATTR_HANDLE; 307 } 308 auto attrHandle = 309 pldm_bios_table_attr_entry_decode_attribute_handle(attrEntry); 310 auto attrNameHandle = 311 pldm_bios_table_attr_entry_decode_string_handle(attrEntry); 312 313 auto stringEntry = pldm_bios_table_string_find_by_handle( 314 stringTable->data(), stringTable->size(), attrNameHandle); 315 if (stringEntry == nullptr) 316 { 317 return PLDM_INVALID_BIOS_ATTR_HANDLE; 318 } 319 auto strLength = 320 pldm_bios_table_string_entry_decode_string_length(stringEntry); 321 std::vector<char> buffer(strLength + 1 /* sizeof '\0' */); 322 // Preconditions are upheld therefore no error check necessary 323 pldm_bios_table_string_entry_decode_string(stringEntry, buffer.data(), 324 buffer.size()); 325 326 attributeName = std::string(buffer.data(), buffer.data() + strLength); 327 328 if (!biosAttributes.empty()) 329 { 330 readonlyStatus = 331 biosAttributes[attrHandle % biosAttributes.size()]->readOnly; 332 description = 333 biosAttributes[attrHandle % biosAttributes.size()]->helpText; 334 displayName = 335 biosAttributes[attrHandle % biosAttributes.size()]->displayName; 336 valueDisplayNamesMap = 337 biosAttributes[attrHandle % biosAttributes.size()] 338 ->valueDisplayNamesMap; 339 } 340 341 switch (attrType) 342 { 343 case PLDM_BIOS_ENUMERATION: 344 case PLDM_BIOS_ENUMERATION_READ_ONLY: 345 { 346 if (valueDisplayNamesMap.contains(attrHandle)) 347 { 348 const std::vector<ValueDisplayName>& vdn = 349 valueDisplayNamesMap[attrHandle]; 350 valueDisplayNames.insert(valueDisplayNames.end(), 351 vdn.begin(), vdn.end()); 352 } 353 auto getValue = [](uint16_t handle, 354 const Table& table) -> std::string { 355 auto stringEntry = pldm_bios_table_string_find_by_handle( 356 table.data(), table.size(), handle); 357 358 auto strLength = 359 pldm_bios_table_string_entry_decode_string_length( 360 stringEntry); 361 std::vector<char> buffer(strLength + 1 /* sizeof '\0' */); 362 // Preconditions are upheld therefore no error check 363 // necessary 364 pldm_bios_table_string_entry_decode_string( 365 stringEntry, buffer.data(), buffer.size()); 366 367 return std::string(buffer.data(), 368 buffer.data() + strLength); 369 }; 370 371 attributeType = "xyz.openbmc_project.BIOSConfig.Manager." 372 "AttributeType.Enumeration"; 373 374 uint8_t pvNum; 375 // Preconditions are upheld therefore no error check necessary 376 pldm_bios_table_attr_entry_enum_decode_pv_num(attrEntry, 377 &pvNum); 378 std::vector<uint16_t> pvHandls(pvNum); 379 // Preconditions are upheld therefore no error check necessary 380 pldm_bios_table_attr_entry_enum_decode_pv_hdls_check( 381 attrEntry, pvHandls.data(), pvHandls.size()); 382 383 // get possible_value 384 for (size_t i = 0; i < pvHandls.size(); i++) 385 { 386 options.push_back( 387 std::make_tuple("xyz.openbmc_project.BIOSConfig." 388 "Manager.BoundType.OneOf", 389 getValue(pvHandls[i], *stringTable), 390 valueDisplayNames[i])); 391 } 392 393 auto count = 394 pldm_bios_table_attr_value_entry_enum_decode_number( 395 tableEntry); 396 std::vector<uint8_t> handles(count); 397 pldm_bios_table_attr_value_entry_enum_decode_handles( 398 tableEntry, handles.data(), handles.size()); 399 400 // get current_value 401 for (size_t i = 0; i < handles.size(); i++) 402 { 403 currentValue = getValue(pvHandls[handles[i]], *stringTable); 404 } 405 406 uint8_t defNum; 407 // Preconditions are upheld therefore no error check necessary 408 pldm_bios_table_attr_entry_enum_decode_def_num(attrEntry, 409 &defNum); 410 std::vector<uint8_t> defIndices(defNum); 411 pldm_bios_table_attr_entry_enum_decode_def_indices( 412 attrEntry, defIndices.data(), defIndices.size()); 413 414 // get default_value 415 for (size_t i = 0; i < defIndices.size(); i++) 416 { 417 defaultValue = getValue(pvHandls[defIndices[i]], 418 *stringTable); 419 } 420 421 break; 422 } 423 case PLDM_BIOS_INTEGER: 424 case PLDM_BIOS_INTEGER_READ_ONLY: 425 { 426 attributeType = "xyz.openbmc_project.BIOSConfig.Manager." 427 "AttributeType.Integer"; 428 currentValue = static_cast<int64_t>( 429 pldm_bios_table_attr_value_entry_integer_decode_cv( 430 tableEntry)); 431 432 uint64_t lower, upper, def; 433 uint32_t scalar; 434 pldm_bios_table_attr_entry_integer_decode( 435 attrEntry, &lower, &upper, &scalar, &def); 436 options.push_back(std::make_tuple( 437 "xyz.openbmc_project.BIOSConfig.Manager." 438 "BoundType.LowerBound", 439 static_cast<int64_t>(lower), attributeName)); 440 options.push_back(std::make_tuple( 441 "xyz.openbmc_project.BIOSConfig.Manager." 442 "BoundType.UpperBound", 443 static_cast<int64_t>(upper), attributeName)); 444 options.push_back(std::make_tuple( 445 "xyz.openbmc_project.BIOSConfig.Manager." 446 "BoundType.ScalarIncrement", 447 static_cast<int64_t>(scalar), attributeName)); 448 defaultValue = static_cast<int64_t>(def); 449 break; 450 } 451 case PLDM_BIOS_STRING: 452 case PLDM_BIOS_STRING_READ_ONLY: 453 { 454 attributeType = "xyz.openbmc_project.BIOSConfig.Manager." 455 "AttributeType.String"; 456 variable_field currentString; 457 pldm_bios_table_attr_value_entry_string_decode_string( 458 tableEntry, ¤tString); 459 currentValue = std::string( 460 reinterpret_cast<const char*>(currentString.ptr), 461 currentString.length); 462 auto min = pldm_bios_table_attr_entry_string_decode_min_length( 463 attrEntry); 464 auto max = pldm_bios_table_attr_entry_string_decode_max_length( 465 attrEntry); 466 uint16_t def; 467 // Preconditions are upheld therefore no error check necessary 468 pldm_bios_table_attr_entry_string_decode_def_string_length_check( 469 attrEntry, &def); 470 std::vector<char> defString(def + 1); 471 pldm_bios_table_attr_entry_string_decode_def_string( 472 attrEntry, defString.data(), defString.size()); 473 options.push_back( 474 std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager." 475 "BoundType.MinStringLength", 476 static_cast<int64_t>(min), attributeName)); 477 options.push_back( 478 std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager." 479 "BoundType.MaxStringLength", 480 static_cast<int64_t>(max), attributeName)); 481 defaultValue = defString.data(); 482 break; 483 } 484 case PLDM_BIOS_PASSWORD: 485 case PLDM_BIOS_PASSWORD_READ_ONLY: 486 { 487 attributeType = "xyz.openbmc_project.BIOSConfig.Manager." 488 "AttributeType.Password"; 489 break; 490 } 491 default: 492 return PLDM_INVALID_BIOS_ATTR_HANDLE; 493 } 494 baseBIOSTableMaps.emplace( 495 std::move(attributeName), 496 std::make_tuple(attributeType, readonlyStatus, displayName, 497 description, menuPath, currentValue, defaultValue, 498 std::move(options))); 499 } 500 501 return PLDM_SUCCESS; 502 } 503 504 void BIOSConfig::updateBaseBIOSTableProperty() 505 { 506 constexpr static auto biosConfigPath = 507 "/xyz/openbmc_project/bios_config/manager"; 508 constexpr static auto biosConfigInterface = 509 "xyz.openbmc_project.BIOSConfig.Manager"; 510 constexpr static auto biosConfigPropertyName = "BaseBIOSTable"; 511 constexpr static auto dbusProperties = "org.freedesktop.DBus.Properties"; 512 513 if (baseBIOSTableMaps.empty()) 514 { 515 return; 516 } 517 518 try 519 { 520 auto& bus = dbusHandler->getBus(); 521 auto service = dbusHandler->getService(biosConfigPath, 522 biosConfigInterface); 523 auto method = bus.new_method_call(service.c_str(), biosConfigPath, 524 dbusProperties, "Set"); 525 std::variant<BaseBIOSTable> value = baseBIOSTableMaps; 526 method.append(biosConfigInterface, biosConfigPropertyName, value); 527 bus.call_noreply(method, dbusTimeout); 528 } 529 catch (const std::exception& e) 530 { 531 error("Failed to update BaseBIOSTable property, error - {ERROR}", 532 "ERROR", e); 533 } 534 } 535 536 void BIOSConfig::constructAttributes() 537 { 538 info("Bios Attribute file path: {PATH}", "PATH", 539 (jsonDir / sysType / attributesJsonFile)); 540 load(jsonDir / sysType / attributesJsonFile, [this](const Json& entry) { 541 std::string attrType = entry.at("attribute_type"); 542 if (attrType == "string") 543 { 544 constructAttribute<BIOSStringAttribute>(entry); 545 } 546 else if (attrType == "integer") 547 { 548 constructAttribute<BIOSIntegerAttribute>(entry); 549 } 550 else if (attrType == "enum") 551 { 552 constructAttribute<BIOSEnumAttribute>(entry); 553 } 554 }); 555 } 556 557 void BIOSConfig::buildAndStoreAttrTables(const Table& stringTable) 558 { 559 BIOSStringTable biosStringTable(stringTable); 560 561 if (biosAttributes.empty()) 562 { 563 return; 564 } 565 566 BaseBIOSTable biosTable{}; 567 constexpr auto biosObjPath = "/xyz/openbmc_project/bios_config/manager"; 568 constexpr auto biosInterface = "xyz.openbmc_project.BIOSConfig.Manager"; 569 570 try 571 { 572 auto& bus = dbusHandler->getBus(); 573 auto service = dbusHandler->getService(biosObjPath, biosInterface); 574 auto method = bus.new_method_call(service.c_str(), biosObjPath, 575 "org.freedesktop.DBus.Properties", 576 "Get"); 577 method.append(biosInterface, "BaseBIOSTable"); 578 auto reply = bus.call(method, dbusTimeout); 579 std::variant<BaseBIOSTable> varBiosTable{}; 580 reply.read(varBiosTable); 581 biosTable = std::get<BaseBIOSTable>(varBiosTable); 582 } 583 // Failed to read the BaseBIOSTable, so update the BaseBIOSTable with the 584 // default values populated from the BIOS JSONs to keep PLDM and 585 // bios-settings-manager in sync 586 catch (const std::exception& e) 587 { 588 error("Failed to read BaseBIOSTable property, error - {ERROR}", "ERROR", 589 e); 590 } 591 592 Table attrTable, attrValueTable; 593 594 for (auto& attr : biosAttributes) 595 { 596 try 597 { 598 auto iter = biosTable.find(attr->name); 599 if (iter == biosTable.end()) 600 { 601 attr->constructEntry(biosStringTable, attrTable, attrValueTable, 602 std::nullopt); 603 } 604 else 605 { 606 attr->constructEntry( 607 biosStringTable, attrTable, attrValueTable, 608 std::get<static_cast<uint8_t>(Index::currentValue)>( 609 iter->second)); 610 } 611 } 612 catch (const std::exception& e) 613 { 614 error( 615 "Failed to construct table entry for attribute '{ATTRIBUTE}', error - {ERROR}", 616 "ATTRIBUTE", attr->name, "ERROR", e); 617 } 618 } 619 620 table::appendPadAndChecksum(attrTable); 621 table::appendPadAndChecksum(attrValueTable); 622 setBIOSTable(PLDM_BIOS_ATTR_TABLE, attrTable); 623 setBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE, attrValueTable); 624 } 625 626 std::optional<Table> BIOSConfig::buildAndStoreStringTable() 627 { 628 std::set<std::string> strings; 629 load(jsonDir / sysType / attributesJsonFile, [&strings](const Json& entry) { 630 if (entry.at("attribute_type") == "enum") 631 { 632 strings.emplace(entry.at("attribute_name")); 633 auto possibleValues = entry.at("possible_values"); 634 for (auto& pv : possibleValues) 635 { 636 strings.emplace(pv); 637 } 638 } 639 else 640 { 641 strings.emplace(entry.at("attribute_name")); 642 } 643 }); 644 645 if (strings.empty()) 646 { 647 return std::nullopt; 648 } 649 650 Table table; 651 for (const auto& elem : strings) 652 { 653 table::string::constructEntry(table, elem); 654 } 655 656 table::appendPadAndChecksum(table); 657 setBIOSTable(PLDM_BIOS_STRING_TABLE, table); 658 return table; 659 } 660 661 void BIOSConfig::storeTable(const fs::path& path, const Table& table) 662 { 663 BIOSTable biosTable(path.c_str()); 664 biosTable.store(table); 665 } 666 667 std::optional<Table> BIOSConfig::loadTable(const fs::path& path) 668 { 669 BIOSTable biosTable(path.c_str()); 670 if (biosTable.isEmpty()) 671 { 672 return std::nullopt; 673 } 674 675 Table table; 676 biosTable.load(table); 677 return table; 678 } 679 680 void BIOSConfig::load(const fs::path& filePath, ParseHandler handler) 681 { 682 std::ifstream file; 683 Json jsonConf; 684 if (fs::exists(filePath)) 685 { 686 try 687 { 688 file.open(filePath); 689 jsonConf = Json::parse(file); 690 auto entries = jsonConf.at("entries"); 691 for (auto& entry : entries) 692 { 693 try 694 { 695 handler(entry); 696 } 697 catch (const std::exception& e) 698 { 699 error( 700 "Failed to parse JSON config file at path '{PATH}', error - {ERROR}", 701 "PATH", filePath, "ERROR", e); 702 } 703 } 704 } 705 catch (const std::exception& e) 706 { 707 error("Failed to parse JSON config file '{PATH}', error - {ERROR}", 708 "PATH", filePath, "ERROR", e); 709 } 710 } 711 } 712 713 std::string BIOSConfig::decodeStringFromStringEntry( 714 const pldm_bios_string_table_entry* stringEntry) 715 { 716 auto strLength = 717 pldm_bios_table_string_entry_decode_string_length(stringEntry); 718 std::vector<char> buffer(strLength + 1 /* sizeof '\0' */); 719 // Preconditions are upheld therefore no error check necessary 720 pldm_bios_table_string_entry_decode_string(stringEntry, buffer.data(), 721 buffer.size()); 722 return std::string(buffer.data(), buffer.data() + strLength); 723 } 724 725 std::string 726 BIOSConfig::displayStringHandle(uint16_t handle, uint8_t index, 727 const std::optional<Table>& attrTable, 728 const std::optional<Table>& stringTable) 729 { 730 auto attrEntry = pldm_bios_table_attr_find_by_handle( 731 attrTable->data(), attrTable->size(), handle); 732 uint8_t pvNum; 733 int rc = pldm_bios_table_attr_entry_enum_decode_pv_num(attrEntry, &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