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), tableDir(tableDir), dbusHandler(dbusHandler), eid(eid), 49 instanceIdDb(instanceIdDb), handler(handler), 50 platformConfigHandler(platformConfigHandler), 51 requestPLDMServiceName(requestPLDMServiceName) 52 { 53 fs::create_directories(tableDir); 54 removeTables(); 55 56 #ifdef SYSTEM_SPECIFIC_BIOS_JSON 57 checkSystemTypeAvailability(); 58 #else 59 initBIOSAttributes(sysType, false); 60 #endif 61 62 listenPendingAttributes(); 63 } 64 65 void BIOSConfig::checkSystemTypeAvailability() 66 { 67 if (platformConfigHandler) 68 { 69 auto systemType = platformConfigHandler->getPlatformName(); 70 if (systemType.has_value()) 71 { 72 // Received System Type from Entity Manager 73 sysType = systemType.value(); 74 initBIOSAttributes(sysType, true); 75 } 76 else 77 { 78 platformConfigHandler->registerSystemTypeCallback( 79 std::bind(&BIOSConfig::initBIOSAttributes, this, 80 std::placeholders::_1, std::placeholders::_2)); 81 } 82 } 83 } 84 85 void BIOSConfig::initBIOSAttributes(const std::string& systemType, 86 bool registerService) 87 { 88 sysType = systemType; 89 fs::path dir{jsonDir / sysType}; 90 if (!fs::exists(dir)) 91 { 92 error("System specific bios attribute directory {DIR} does not exit", 93 "DIR", dir); 94 if (registerService) 95 { 96 requestPLDMServiceName(); 97 } 98 return; 99 } 100 constructAttributes(); 101 buildTables(); 102 if (registerService) 103 { 104 requestPLDMServiceName(); 105 } 106 } 107 108 void BIOSConfig::buildTables() 109 { 110 auto stringTable = buildAndStoreStringTable(); 111 if (stringTable) 112 { 113 buildAndStoreAttrTables(*stringTable); 114 } 115 } 116 117 std::optional<Table> BIOSConfig::getBIOSTable(pldm_bios_table_types tableType) 118 { 119 fs::path tablePath; 120 switch (tableType) 121 { 122 case PLDM_BIOS_STRING_TABLE: 123 tablePath = tableDir / stringTableFile; 124 break; 125 case PLDM_BIOS_ATTR_TABLE: 126 tablePath = tableDir / attrTableFile; 127 break; 128 case PLDM_BIOS_ATTR_VAL_TABLE: 129 tablePath = tableDir / attrValueTableFile; 130 break; 131 } 132 return loadTable(tablePath); 133 } 134 135 int BIOSConfig::setBIOSTable(uint8_t tableType, const Table& table, 136 bool updateBaseBIOSTable) 137 { 138 fs::path stringTablePath(tableDir / stringTableFile); 139 fs::path attrTablePath(tableDir / attrTableFile); 140 fs::path attrValueTablePath(tableDir / attrValueTableFile); 141 142 if (!pldm_bios_table_checksum(table.data(), table.size())) 143 { 144 return PLDM_INVALID_BIOS_TABLE_DATA_INTEGRITY_CHECK; 145 } 146 147 if (tableType == PLDM_BIOS_STRING_TABLE) 148 { 149 storeTable(stringTablePath, table); 150 } 151 else if (tableType == PLDM_BIOS_ATTR_TABLE) 152 { 153 BIOSTable biosStringTable(stringTablePath.c_str()); 154 if (biosStringTable.isEmpty()) 155 { 156 return PLDM_INVALID_BIOS_TABLE_TYPE; 157 } 158 159 auto rc = checkAttributeTable(table); 160 if (rc != PLDM_SUCCESS) 161 { 162 return rc; 163 } 164 165 storeTable(attrTablePath, table); 166 } 167 else if (tableType == PLDM_BIOS_ATTR_VAL_TABLE) 168 { 169 BIOSTable biosStringTable(stringTablePath.c_str()); 170 BIOSTable biosStringValueTable(attrTablePath.c_str()); 171 if (biosStringTable.isEmpty() || biosStringValueTable.isEmpty()) 172 { 173 return PLDM_INVALID_BIOS_TABLE_TYPE; 174 } 175 176 auto rc = checkAttributeValueTable(table); 177 if (rc != PLDM_SUCCESS) 178 { 179 return rc; 180 } 181 182 storeTable(attrValueTablePath, table); 183 } 184 else 185 { 186 return PLDM_INVALID_BIOS_TABLE_TYPE; 187 } 188 189 if ((tableType == PLDM_BIOS_ATTR_VAL_TABLE) && updateBaseBIOSTable) 190 { 191 updateBaseBIOSTableProperty(); 192 } 193 194 return PLDM_SUCCESS; 195 } 196 197 int BIOSConfig::checkAttributeTable(const Table& table) 198 { 199 using namespace pldm::bios::utils; 200 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 201 for (auto entry : 202 BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(table.data(), table.size())) 203 { 204 auto attrNameHandle = 205 pldm_bios_table_attr_entry_decode_string_handle(entry); 206 207 auto stringEnty = pldm_bios_table_string_find_by_handle( 208 stringTable->data(), stringTable->size(), attrNameHandle); 209 if (stringEnty == nullptr) 210 { 211 return PLDM_INVALID_BIOS_ATTR_HANDLE; 212 } 213 214 auto attrType = static_cast<pldm_bios_attribute_type>( 215 pldm_bios_table_attr_entry_decode_attribute_type(entry)); 216 217 switch (attrType) 218 { 219 case PLDM_BIOS_ENUMERATION: 220 case PLDM_BIOS_ENUMERATION_READ_ONLY: 221 { 222 uint8_t pvNum; 223 // Preconditions are upheld therefore no error check necessary 224 pldm_bios_table_attr_entry_enum_decode_pv_num(entry, &pvNum); 225 std::vector<uint16_t> pvHandls(pvNum); 226 // Preconditions are upheld therefore no error check necessary 227 pldm_bios_table_attr_entry_enum_decode_pv_hdls( 228 entry, pvHandls.data(), pvHandls.size()); 229 uint8_t defNum; 230 pldm_bios_table_attr_entry_enum_decode_def_num(entry, &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(stringEntry, buffer.data(), 323 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 = 353 [](uint16_t handle, 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( 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(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( 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(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 = 417 getValue(pvHandls[defIndices[i]], *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( 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 = 521 dbusHandler->getService(biosConfigPath, 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 = 574 bus.new_method_call(service.c_str(), biosObjPath, 575 "org.freedesktop.DBus.Properties", "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(stringEntry, buffer.data(), 720 buffer.size()); 721 return std::string(buffer.data(), buffer.data() + strLength); 722 } 723 724 std::string BIOSConfig::displayStringHandle( 725 uint16_t handle, uint8_t index, const std::optional<Table>& attrTable, 726 const std::optional<Table>& stringTable) 727 { 728 auto attrEntry = pldm_bios_table_attr_find_by_handle( 729 attrTable->data(), attrTable->size(), handle); 730 uint8_t pvNum; 731 int rc = pldm_bios_table_attr_entry_enum_decode_pv_num(attrEntry, &pvNum); 732 if (rc != PLDM_SUCCESS) 733 { 734 error( 735 "Failed to decode BIOS table possible values for attribute entry, response code '{RC}'", 736 "RC", rc); 737 throw std::runtime_error( 738 "Failed to decode BIOS table possible values for attribute entry"); 739 } 740 741 std::vector<uint16_t> pvHandls(pvNum); 742 // Preconditions are upheld therefore no error check necessary 743 pldm_bios_table_attr_entry_enum_decode_pv_hdls(attrEntry, pvHandls.data(), 744 pvHandls.size()); 745 746 std::string displayString = std::to_string(pvHandls[index]); 747 748 auto stringEntry = pldm_bios_table_string_find_by_handle( 749 stringTable->data(), stringTable->size(), pvHandls[index]); 750 751 auto decodedStr = decodeStringFromStringEntry(stringEntry); 752 753 return decodedStr + "(" + displayString + ")"; 754 } 755 756 void BIOSConfig::traceBIOSUpdate( 757 const pldm_bios_attr_val_table_entry* attrValueEntry, 758 const pldm_bios_attr_table_entry* attrEntry, bool isBMC) 759 { 760 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 761 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 762 763 auto [attrHandle, 764 attrType] = table::attribute_value::decodeHeader(attrValueEntry); 765 766 auto attrHeader = table::attribute::decodeHeader(attrEntry); 767 BIOSStringTable biosStringTable(*stringTable); 768 auto attrName = biosStringTable.findString(attrHeader.stringHandle); 769 770 switch (attrType) 771 { 772 case PLDM_BIOS_ENUMERATION: 773 case PLDM_BIOS_ENUMERATION_READ_ONLY: 774 { 775 auto count = pldm_bios_table_attr_value_entry_enum_decode_number( 776 attrValueEntry); 777 std::vector<uint8_t> handles(count); 778 pldm_bios_table_attr_value_entry_enum_decode_handles( 779 attrValueEntry, handles.data(), handles.size()); 780 781 for (uint8_t handle : handles) 782 { 783 auto nwVal = displayStringHandle(attrHandle, handle, attrTable, 784 stringTable); 785 auto chkBMC = isBMC ? "true" : "false"; 786 info( 787 "BIOS attribute '{ATTRIBUTE}' updated to value '{VALUE}' by BMC '{CHECK_BMC}'", 788 "ATTRIBUTE", attrName, "VALUE", nwVal, "CHECK_BMC", chkBMC); 789 } 790 break; 791 } 792 case PLDM_BIOS_INTEGER: 793 case PLDM_BIOS_INTEGER_READ_ONLY: 794 { 795 auto value = 796 table::attribute_value::decodeIntegerEntry(attrValueEntry); 797 auto chkBMC = isBMC ? "true" : "false"; 798 info( 799 "BIOS attribute '{ATTRIBUTE}' updated to value '{VALUE}' by BMC '{CHECK_BMC}'", 800 "ATTRIBUTE", attrName, "VALUE", value, "CHECK_BMC", chkBMC); 801 break; 802 } 803 case PLDM_BIOS_STRING: 804 case PLDM_BIOS_STRING_READ_ONLY: 805 { 806 auto value = 807 table::attribute_value::decodeStringEntry(attrValueEntry); 808 auto chkBMC = isBMC ? "true" : "false"; 809 info( 810 "BIOS attribute '{ATTRIBUTE}' updated to value '{VALUE}' by BMC '{CHECK_BMC}'", 811 "ATTRIBUTE", attrName, "VALUE", value, "CHECK_BMC", chkBMC); 812 break; 813 } 814 default: 815 break; 816 }; 817 } 818 819 int BIOSConfig::checkAttrValueToUpdate( 820 const pldm_bios_attr_val_table_entry* attrValueEntry, 821 const pldm_bios_attr_table_entry* attrEntry, Table&) 822 823 { 824 auto [attrHandle, 825 attrType] = table::attribute_value::decodeHeader(attrValueEntry); 826 827 switch (attrType) 828 { 829 case PLDM_BIOS_ENUMERATION: 830 case PLDM_BIOS_ENUMERATION_READ_ONLY: 831 { 832 auto value = 833 table::attribute_value::decodeEnumEntry(attrValueEntry); 834 auto [pvHdls, 835 defIndex] = table::attribute::decodeEnumEntry(attrEntry); 836 if (!(value.size() == 1)) 837 { 838 return PLDM_ERROR_INVALID_LENGTH; 839 } 840 if (value[0] >= pvHdls.size()) 841 { 842 error( 843 "Invalid index '{INDEX}' encountered for Enum type BIOS attribute", 844 "INDEX", value[0]); 845 return PLDM_ERROR_INVALID_DATA; 846 } 847 return PLDM_SUCCESS; 848 } 849 case PLDM_BIOS_INTEGER: 850 case PLDM_BIOS_INTEGER_READ_ONLY: 851 { 852 auto value = 853 table::attribute_value::decodeIntegerEntry(attrValueEntry); 854 auto [lower, upper, scalar, 855 def] = table::attribute::decodeIntegerEntry(attrEntry); 856 857 if (value < lower || value > upper) 858 { 859 error( 860 "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}'.", 861 "ATTRIBUTE_VALUE", value, "LOWER", lower, "UPPER", upper, 862 "SCALAR", scalar); 863 return PLDM_ERROR_INVALID_DATA; 864 } 865 return PLDM_SUCCESS; 866 } 867 case PLDM_BIOS_STRING: 868 case PLDM_BIOS_STRING_READ_ONLY: 869 { 870 auto stringConf = table::attribute::decodeStringEntry(attrEntry); 871 auto value = 872 table::attribute_value::decodeStringEntry(attrValueEntry); 873 if (value.size() < stringConf.minLength || 874 value.size() > stringConf.maxLength) 875 { 876 error( 877 "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}'", 878 "ATTRIBUTE_VALUE", value, "LENGTH", value.size(), "MIN_LEN", 879 stringConf.minLength, "MAX_LEN", stringConf.maxLength); 880 return PLDM_ERROR_INVALID_LENGTH; 881 } 882 return PLDM_SUCCESS; 883 } 884 default: 885 error("ReadOnly or Unsupported type '{TYPE}'", "TYPE", attrType); 886 return PLDM_ERROR; 887 }; 888 } 889 890 int BIOSConfig::setAttrValue(const void* entry, size_t size, bool isBMC, 891 bool updateDBus, bool updateBaseBIOSTable) 892 { 893 auto attrValueTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 894 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 895 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 896 if (!attrValueTable || !attrTable || !stringTable) 897 { 898 return PLDM_BIOS_TABLE_UNAVAILABLE; 899 } 900 901 auto attrValueEntry = 902 reinterpret_cast<const pldm_bios_attr_val_table_entry*>(entry); 903 904 auto attrValHeader = table::attribute_value::decodeHeader(attrValueEntry); 905 906 auto attrEntry = 907 table::attribute::findByHandle(*attrTable, attrValHeader.attrHandle); 908 if (!attrEntry) 909 { 910 return PLDM_ERROR; 911 } 912 913 auto rc = checkAttrValueToUpdate(attrValueEntry, attrEntry, *stringTable); 914 if (rc != PLDM_SUCCESS) 915 { 916 return rc; 917 } 918 919 auto destTable = 920 table::attribute_value::updateTable(*attrValueTable, entry, size); 921 922 if (!destTable) 923 { 924 return PLDM_ERROR; 925 } 926 927 try 928 { 929 auto attrHeader = table::attribute::decodeHeader(attrEntry); 930 931 BIOSStringTable biosStringTable(*stringTable); 932 auto attrName = biosStringTable.findString(attrHeader.stringHandle); 933 auto iter = std::find_if( 934 biosAttributes.begin(), biosAttributes.end(), 935 [&attrName](const auto& attr) { return attr->name == attrName; }); 936 937 if (iter == biosAttributes.end()) 938 { 939 return PLDM_ERROR; 940 } 941 if (updateDBus) 942 { 943 (*iter)->setAttrValueOnDbus(attrValueEntry, attrEntry, 944 biosStringTable); 945 } 946 } 947 catch (const std::exception& e) 948 { 949 error("Set attribute value error - {ERROR}", "ERROR", e); 950 return PLDM_ERROR; 951 } 952 953 setBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE, *destTable, updateBaseBIOSTable); 954 955 traceBIOSUpdate(attrValueEntry, attrEntry, isBMC); 956 957 return PLDM_SUCCESS; 958 } 959 960 void BIOSConfig::removeTables() 961 { 962 try 963 { 964 fs::remove(tableDir / stringTableFile); 965 fs::remove(tableDir / attrTableFile); 966 fs::remove(tableDir / attrValueTableFile); 967 } 968 catch (const std::exception& e) 969 { 970 error("Remove the tables error - {ERROR}", "ERROR", e); 971 } 972 } 973 974 void BIOSConfig::processBiosAttrChangeNotification( 975 const DbusChObjProperties& chProperties, uint32_t biosAttrIndex) 976 { 977 const auto& dBusMap = biosAttributes[biosAttrIndex]->getDBusMap(); 978 const auto& propertyName = dBusMap->propertyName; 979 const auto& attrName = biosAttributes[biosAttrIndex]->name; 980 981 const auto it = chProperties.find(propertyName); 982 if (it == chProperties.end()) 983 { 984 return; 985 } 986 987 PropertyValue newPropVal = it->second; 988 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 989 if (!stringTable.has_value()) 990 { 991 error("BIOS string table unavailable"); 992 return; 993 } 994 BIOSStringTable biosStringTable(*stringTable); 995 uint16_t attrNameHdl{}; 996 try 997 { 998 attrNameHdl = biosStringTable.findHandle(attrName); 999 } 1000 catch (const std::invalid_argument& e) 1001 { 1002 error( 1003 "Missing handle for attribute '{ATTRIBUTE}' in BIOS String Table, error - '{ERROR}'", 1004 "ATTRIBUTE", attrName, "ERROR", e); 1005 return; 1006 } 1007 1008 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 1009 if (!attrTable.has_value()) 1010 { 1011 error("BIOS Attribute table not present"); 1012 return; 1013 } 1014 const struct pldm_bios_attr_table_entry* tableEntry = 1015 table::attribute::findByStringHandle(*attrTable, attrNameHdl); 1016 if (tableEntry == nullptr) 1017 { 1018 error( 1019 "Failed to find attribute {ATTRIBUTE} in BIOS Attribute table with attribute handle '{ATTR_HANDLE}'", 1020 "ATTRIBUTE", attrName, "ATTR_HANDLE", attrNameHdl); 1021 return; 1022 } 1023 1024 auto [attrHdl, attrType, 1025 stringHdl] = table::attribute::decodeHeader(tableEntry); 1026 1027 auto attrValueSrcTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 1028 1029 if (!attrValueSrcTable.has_value()) 1030 { 1031 error("Attribute value table not present"); 1032 return; 1033 } 1034 1035 Table newValue; 1036 auto rc = biosAttributes[biosAttrIndex]->updateAttrVal( 1037 newValue, attrHdl, attrType, newPropVal); 1038 if (rc != PLDM_SUCCESS) 1039 { 1040 error( 1041 "Failed to update the attribute value table for attribute handle '{ATTR_HANDLE}' and attribute type '{TYPE}'", 1042 "ATTR_HANDLE", attrHdl, "TYPE", attrType); 1043 return; 1044 } 1045 auto destTable = table::attribute_value::updateTable( 1046 *attrValueSrcTable, newValue.data(), newValue.size()); 1047 if (destTable.has_value()) 1048 { 1049 storeTable(tableDir / attrValueTableFile, *destTable); 1050 } 1051 1052 rc = setAttrValue(newValue.data(), newValue.size(), true, false); 1053 if (rc != PLDM_SUCCESS) 1054 { 1055 error( 1056 "Failed to setAttrValue on base bios table and dbus, response code '{RC}'", 1057 "RC", rc); 1058 } 1059 } 1060 1061 uint16_t BIOSConfig::findAttrHandle(const std::string& attrName) 1062 { 1063 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 1064 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 1065 1066 BIOSStringTable biosStringTable(*stringTable); 1067 pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE> attrTableIter( 1068 attrTable->data(), attrTable->size()); 1069 auto stringHandle = biosStringTable.findHandle(attrName); 1070 1071 for (auto entry : pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE>( 1072 attrTable->data(), attrTable->size())) 1073 { 1074 auto header = table::attribute::decodeHeader(entry); 1075 if (header.stringHandle == stringHandle) 1076 { 1077 return header.attrHandle; 1078 } 1079 } 1080 1081 throw std::invalid_argument("Unknown attribute Name"); 1082 } 1083 1084 void BIOSConfig::constructPendingAttribute( 1085 const PendingAttributes& pendingAttributes) 1086 { 1087 std::vector<uint16_t> listOfHandles{}; 1088 1089 for (auto& attribute : pendingAttributes) 1090 { 1091 std::string attributeName = attribute.first; 1092 auto& [attributeType, attributevalue] = attribute.second; 1093 1094 auto iter = std::find_if(biosAttributes.begin(), biosAttributes.end(), 1095 [&attributeName](const auto& attr) { 1096 return attr->name == attributeName; 1097 }); 1098 1099 if (iter == biosAttributes.end()) 1100 { 1101 error("Wrong attribute name {NAME}", "NAME", attributeName); 1102 continue; 1103 } 1104 1105 Table attrValueEntry(sizeof(pldm_bios_attr_val_table_entry), 0); 1106 auto entry = reinterpret_cast<pldm_bios_attr_val_table_entry*>( 1107 attrValueEntry.data()); 1108 1109 auto handler = findAttrHandle(attributeName); 1110 auto type = 1111 BIOSConfigManager::convertAttributeTypeFromString(attributeType); 1112 1113 if (type != BIOSConfigManager::AttributeType::Enumeration && 1114 type != BIOSConfigManager::AttributeType::String && 1115 type != BIOSConfigManager::AttributeType::Integer) 1116 { 1117 error("Attribute type '{TYPE}' not supported", "TYPE", 1118 attributeType); 1119 continue; 1120 } 1121 1122 const auto [attrType, readonlyStatus, displayName, description, 1123 menuPath, currentValue, defaultValue, 1124 option] = baseBIOSTableMaps.at(attributeName); 1125 1126 entry->attr_handle = htole16(handler); 1127 1128 // Need to verify that the current value has really changed 1129 if (attributeType == attrType && attributevalue != currentValue) 1130 { 1131 listOfHandles.emplace_back(htole16(handler)); 1132 } 1133 1134 (*iter)->generateAttributeEntry(attributevalue, attrValueEntry); 1135 1136 setAttrValue(attrValueEntry.data(), attrValueEntry.size(), true); 1137 } 1138 1139 if (listOfHandles.size()) 1140 { 1141 #ifdef OEM_IBM 1142 auto rc = pldm::responder::platform::sendBiosAttributeUpdateEvent( 1143 eid, instanceIdDb, listOfHandles, handler); 1144 if (rc != PLDM_SUCCESS) 1145 { 1146 return; 1147 } 1148 #endif 1149 } 1150 } 1151 1152 void BIOSConfig::listenPendingAttributes() 1153 { 1154 constexpr auto objPath = "/xyz/openbmc_project/bios_config/manager"; 1155 constexpr auto objInterface = "xyz.openbmc_project.BIOSConfig.Manager"; 1156 1157 using namespace sdbusplus::bus::match::rules; 1158 auto updateBIOSMatch = std::make_unique<sdbusplus::bus::match_t>( 1159 pldm::utils::DBusHandler::getBus(), 1160 propertiesChanged(objPath, objInterface), 1161 [this](sdbusplus::message_t& msg) { 1162 constexpr auto propertyName = "PendingAttributes"; 1163 1164 using Value = 1165 std::variant<std::string, PendingAttributes, BaseBIOSTable>; 1166 using Properties = std::map<DbusProp, Value>; 1167 1168 Properties props{}; 1169 std::string intf; 1170 msg.read(intf, props); 1171 1172 auto valPropMap = props.find(propertyName); 1173 if (valPropMap == props.end()) 1174 { 1175 return; 1176 } 1177 1178 PendingAttributes pendingAttributes = 1179 std::get<PendingAttributes>(valPropMap->second); 1180 this->constructPendingAttribute(pendingAttributes); 1181 }); 1182 1183 biosAttrMatch.emplace_back(std::move(updateBIOSMatch)); 1184 } 1185 1186 } // namespace bios 1187 } // namespace responder 1188 } // namespace pldm 1189