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