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) && !fs::is_symlink(dir)) 91 { 92 error("System specific bios attribute directory {DIR} does not exist", 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 if (oemBiosHandler) 526 { 527 oemBiosHandler->processOEMBaseBiosTable(baseBIOSTableMaps); 528 } 529 method.append(biosConfigInterface, biosConfigPropertyName, value); 530 bus.call_noreply(method, dbusTimeout); 531 } 532 catch (const std::exception& e) 533 { 534 error("Failed to update BaseBIOSTable property, error - {ERROR}", 535 "ERROR", e); 536 } 537 } 538 539 void BIOSConfig::constructAttributes() 540 { 541 info("Bios Attribute file path: {PATH}", "PATH", 542 (jsonDir / sysType / attributesJsonFile)); 543 load(jsonDir / sysType / attributesJsonFile, [this](const Json& entry) { 544 std::string attrType = entry.at("attribute_type"); 545 if (attrType == "string") 546 { 547 constructAttribute<BIOSStringAttribute>(entry); 548 } 549 else if (attrType == "integer") 550 { 551 constructAttribute<BIOSIntegerAttribute>(entry); 552 } 553 else if (attrType == "enum") 554 { 555 constructAttribute<BIOSEnumAttribute>(entry); 556 } 557 }); 558 } 559 560 void BIOSConfig::buildAndStoreAttrTables(const Table& stringTable) 561 { 562 BIOSStringTable biosStringTable(stringTable); 563 564 if (biosAttributes.empty()) 565 { 566 return; 567 } 568 569 BaseBIOSTable biosTable{}; 570 constexpr auto biosObjPath = "/xyz/openbmc_project/bios_config/manager"; 571 constexpr auto biosInterface = "xyz.openbmc_project.BIOSConfig.Manager"; 572 573 try 574 { 575 auto& bus = dbusHandler->getBus(); 576 auto service = dbusHandler->getService(biosObjPath, biosInterface); 577 auto method = 578 bus.new_method_call(service.c_str(), biosObjPath, 579 "org.freedesktop.DBus.Properties", "Get"); 580 method.append(biosInterface, "BaseBIOSTable"); 581 auto reply = bus.call(method, dbusTimeout); 582 std::variant<BaseBIOSTable> varBiosTable{}; 583 reply.read(varBiosTable); 584 biosTable = std::get<BaseBIOSTable>(varBiosTable); 585 } 586 // Failed to read the BaseBIOSTable, so update the BaseBIOSTable with the 587 // default values populated from the BIOS JSONs to keep PLDM and 588 // bios-settings-manager in sync 589 catch (const std::exception& e) 590 { 591 error("Failed to read BaseBIOSTable property, error - {ERROR}", "ERROR", 592 e); 593 } 594 595 Table attrTable, attrValueTable; 596 597 for (auto& attr : biosAttributes) 598 { 599 try 600 { 601 auto iter = biosTable.find(attr->name); 602 if (iter == biosTable.end()) 603 { 604 attr->constructEntry(biosStringTable, attrTable, attrValueTable, 605 std::nullopt); 606 } 607 else 608 { 609 attr->constructEntry( 610 biosStringTable, attrTable, attrValueTable, 611 std::get<static_cast<uint8_t>(Index::currentValue)>( 612 iter->second)); 613 } 614 } 615 catch (const std::exception& e) 616 { 617 error( 618 "Failed to construct table entry for attribute '{ATTRIBUTE}', error - {ERROR}", 619 "ATTRIBUTE", attr->name, "ERROR", e); 620 } 621 } 622 623 table::appendPadAndChecksum(attrTable); 624 table::appendPadAndChecksum(attrValueTable); 625 setBIOSTable(PLDM_BIOS_ATTR_TABLE, attrTable); 626 setBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE, attrValueTable); 627 } 628 629 std::optional<Table> BIOSConfig::buildAndStoreStringTable() 630 { 631 std::set<std::string> strings; 632 load(jsonDir / sysType / attributesJsonFile, [&strings](const Json& entry) { 633 if (entry.at("attribute_type") == "enum") 634 { 635 strings.emplace(entry.at("attribute_name")); 636 auto possibleValues = entry.at("possible_values"); 637 for (auto& pv : possibleValues) 638 { 639 strings.emplace(pv); 640 } 641 } 642 else 643 { 644 strings.emplace(entry.at("attribute_name")); 645 } 646 }); 647 648 if (strings.empty()) 649 { 650 return std::nullopt; 651 } 652 653 Table table; 654 for (const auto& elem : strings) 655 { 656 table::string::constructEntry(table, elem); 657 } 658 659 table::appendPadAndChecksum(table); 660 setBIOSTable(PLDM_BIOS_STRING_TABLE, table); 661 return table; 662 } 663 664 void BIOSConfig::storeTable(const fs::path& path, const Table& table) 665 { 666 BIOSTable biosTable(path.c_str()); 667 biosTable.store(table); 668 } 669 670 std::optional<Table> BIOSConfig::loadTable(const fs::path& path) 671 { 672 BIOSTable biosTable(path.c_str()); 673 if (biosTable.isEmpty()) 674 { 675 return std::nullopt; 676 } 677 678 Table table; 679 biosTable.load(table); 680 return table; 681 } 682 683 void BIOSConfig::load(const fs::path& filePath, ParseHandler handler) 684 { 685 std::ifstream file; 686 Json jsonConf; 687 if (fs::exists(filePath)) 688 { 689 try 690 { 691 file.open(filePath); 692 jsonConf = Json::parse(file); 693 auto entries = jsonConf.at("entries"); 694 for (auto& entry : entries) 695 { 696 try 697 { 698 handler(entry); 699 } 700 catch (const std::exception& e) 701 { 702 error( 703 "Failed to parse JSON config file at path '{PATH}', error - {ERROR}", 704 "PATH", filePath, "ERROR", e); 705 } 706 } 707 } 708 catch (const std::exception& e) 709 { 710 error("Failed to parse JSON config file '{PATH}', error - {ERROR}", 711 "PATH", filePath, "ERROR", e); 712 } 713 } 714 } 715 716 std::string BIOSConfig::decodeStringFromStringEntry( 717 const pldm_bios_string_table_entry* stringEntry) 718 { 719 auto strLength = 720 pldm_bios_table_string_entry_decode_string_length(stringEntry); 721 std::vector<char> buffer(strLength + 1 /* sizeof '\0' */); 722 // Preconditions are upheld therefore no error check necessary 723 pldm_bios_table_string_entry_decode_string(stringEntry, buffer.data(), 724 buffer.size()); 725 return std::string(buffer.data(), buffer.data() + strLength); 726 } 727 728 std::string BIOSConfig::displayStringHandle( 729 uint16_t handle, uint8_t index, const std::optional<Table>& attrTable, 730 const std::optional<Table>& stringTable) 731 { 732 auto attrEntry = pldm_bios_table_attr_find_by_handle( 733 attrTable->data(), attrTable->size(), handle); 734 uint8_t pvNum; 735 int rc = pldm_bios_table_attr_entry_enum_decode_pv_num(attrEntry, &pvNum); 736 if (rc != PLDM_SUCCESS) 737 { 738 error( 739 "Failed to decode BIOS table possible values for attribute entry, response code '{RC}'", 740 "RC", rc); 741 throw std::runtime_error( 742 "Failed to decode BIOS table possible values for attribute entry"); 743 } 744 745 std::vector<uint16_t> pvHandls(pvNum); 746 // Preconditions are upheld therefore no error check necessary 747 pldm_bios_table_attr_entry_enum_decode_pv_hdls(attrEntry, pvHandls.data(), 748 pvHandls.size()); 749 750 std::string displayString = std::to_string(pvHandls[index]); 751 752 auto stringEntry = pldm_bios_table_string_find_by_handle( 753 stringTable->data(), stringTable->size(), pvHandls[index]); 754 755 auto decodedStr = decodeStringFromStringEntry(stringEntry); 756 757 return decodedStr + "(" + displayString + ")"; 758 } 759 760 void BIOSConfig::traceBIOSUpdate( 761 const pldm_bios_attr_val_table_entry* attrValueEntry, 762 const pldm_bios_attr_table_entry* attrEntry, bool isBMC) 763 { 764 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 765 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 766 767 auto [attrHandle, 768 attrType] = table::attribute_value::decodeHeader(attrValueEntry); 769 770 auto attrHeader = table::attribute::decodeHeader(attrEntry); 771 BIOSStringTable biosStringTable(*stringTable); 772 auto attrName = biosStringTable.findString(attrHeader.stringHandle); 773 774 switch (attrType) 775 { 776 case PLDM_BIOS_ENUMERATION: 777 case PLDM_BIOS_ENUMERATION_READ_ONLY: 778 { 779 auto count = pldm_bios_table_attr_value_entry_enum_decode_number( 780 attrValueEntry); 781 std::vector<uint8_t> handles(count); 782 pldm_bios_table_attr_value_entry_enum_decode_handles( 783 attrValueEntry, handles.data(), handles.size()); 784 785 for (uint8_t handle : handles) 786 { 787 auto nwVal = displayStringHandle(attrHandle, handle, attrTable, 788 stringTable); 789 auto chkBMC = isBMC ? "true" : "false"; 790 info( 791 "BIOS attribute '{ATTRIBUTE}' updated to value '{VALUE}' by BMC '{CHECK_BMC}'", 792 "ATTRIBUTE", attrName, "VALUE", nwVal, "CHECK_BMC", chkBMC); 793 } 794 break; 795 } 796 case PLDM_BIOS_INTEGER: 797 case PLDM_BIOS_INTEGER_READ_ONLY: 798 { 799 auto value = 800 table::attribute_value::decodeIntegerEntry(attrValueEntry); 801 auto chkBMC = isBMC ? "true" : "false"; 802 info( 803 "BIOS attribute '{ATTRIBUTE}' updated to value '{VALUE}' by BMC '{CHECK_BMC}'", 804 "ATTRIBUTE", attrName, "VALUE", value, "CHECK_BMC", chkBMC); 805 break; 806 } 807 case PLDM_BIOS_STRING: 808 case PLDM_BIOS_STRING_READ_ONLY: 809 { 810 auto value = 811 table::attribute_value::decodeStringEntry(attrValueEntry); 812 auto chkBMC = isBMC ? "true" : "false"; 813 info( 814 "BIOS attribute '{ATTRIBUTE}' updated to value '{VALUE}' by BMC '{CHECK_BMC}'", 815 "ATTRIBUTE", attrName, "VALUE", value, "CHECK_BMC", chkBMC); 816 break; 817 } 818 default: 819 break; 820 }; 821 } 822 823 int BIOSConfig::checkAttrValueToUpdate( 824 const pldm_bios_attr_val_table_entry* attrValueEntry, 825 const pldm_bios_attr_table_entry* attrEntry, Table&) 826 827 { 828 auto [attrHandle, 829 attrType] = table::attribute_value::decodeHeader(attrValueEntry); 830 831 switch (attrType) 832 { 833 case PLDM_BIOS_ENUMERATION: 834 case PLDM_BIOS_ENUMERATION_READ_ONLY: 835 { 836 auto value = 837 table::attribute_value::decodeEnumEntry(attrValueEntry); 838 auto [pvHdls, 839 defIndex] = table::attribute::decodeEnumEntry(attrEntry); 840 if (!(value.size() == 1)) 841 { 842 return PLDM_ERROR_INVALID_LENGTH; 843 } 844 if (value[0] >= pvHdls.size()) 845 { 846 error( 847 "Invalid index '{INDEX}' encountered for Enum type BIOS attribute", 848 "INDEX", value[0]); 849 return PLDM_ERROR_INVALID_DATA; 850 } 851 return PLDM_SUCCESS; 852 } 853 case PLDM_BIOS_INTEGER: 854 case PLDM_BIOS_INTEGER_READ_ONLY: 855 { 856 auto value = 857 table::attribute_value::decodeIntegerEntry(attrValueEntry); 858 auto [lower, upper, scalar, 859 def] = table::attribute::decodeIntegerEntry(attrEntry); 860 861 if (value < lower || value > upper) 862 { 863 error( 864 "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}'.", 865 "ATTRIBUTE_VALUE", value, "LOWER", lower, "UPPER", upper, 866 "SCALAR", scalar); 867 return PLDM_ERROR_INVALID_DATA; 868 } 869 return PLDM_SUCCESS; 870 } 871 case PLDM_BIOS_STRING: 872 case PLDM_BIOS_STRING_READ_ONLY: 873 { 874 auto stringConf = table::attribute::decodeStringEntry(attrEntry); 875 auto value = 876 table::attribute_value::decodeStringEntry(attrValueEntry); 877 if (value.size() < stringConf.minLength || 878 value.size() > stringConf.maxLength) 879 { 880 error( 881 "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}'", 882 "ATTRIBUTE_VALUE", value, "LENGTH", value.size(), "MIN_LEN", 883 stringConf.minLength, "MAX_LEN", stringConf.maxLength); 884 return PLDM_ERROR_INVALID_LENGTH; 885 } 886 return PLDM_SUCCESS; 887 } 888 default: 889 error("ReadOnly or Unsupported type '{TYPE}'", "TYPE", attrType); 890 return PLDM_ERROR; 891 }; 892 } 893 894 int BIOSConfig::setAttrValue(const void* entry, size_t size, bool isBMC, 895 bool updateDBus, bool updateBaseBIOSTable) 896 { 897 auto attrValueTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 898 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 899 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 900 if (!attrValueTable || !attrTable || !stringTable) 901 { 902 return PLDM_BIOS_TABLE_UNAVAILABLE; 903 } 904 905 auto attrValueEntry = 906 reinterpret_cast<const pldm_bios_attr_val_table_entry*>(entry); 907 908 auto attrValHeader = table::attribute_value::decodeHeader(attrValueEntry); 909 910 auto attrEntry = 911 table::attribute::findByHandle(*attrTable, attrValHeader.attrHandle); 912 if (!attrEntry) 913 { 914 return PLDM_ERROR; 915 } 916 917 auto rc = checkAttrValueToUpdate(attrValueEntry, attrEntry, *stringTable); 918 if (rc != PLDM_SUCCESS) 919 { 920 return rc; 921 } 922 923 auto destTable = 924 table::attribute_value::updateTable(*attrValueTable, entry, size); 925 926 if (!destTable) 927 { 928 return PLDM_ERROR; 929 } 930 931 try 932 { 933 auto attrHeader = table::attribute::decodeHeader(attrEntry); 934 935 BIOSStringTable biosStringTable(*stringTable); 936 auto attrName = biosStringTable.findString(attrHeader.stringHandle); 937 auto iter = std::find_if( 938 biosAttributes.begin(), biosAttributes.end(), 939 [&attrName](const auto& attr) { return attr->name == attrName; }); 940 941 if (iter == biosAttributes.end()) 942 { 943 return PLDM_ERROR; 944 } 945 if (updateDBus) 946 { 947 (*iter)->setAttrValueOnDbus(attrValueEntry, attrEntry, 948 biosStringTable); 949 } 950 } 951 catch (const std::exception& e) 952 { 953 error("Set attribute value error - {ERROR}", "ERROR", e); 954 return PLDM_ERROR; 955 } 956 957 setBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE, *destTable, updateBaseBIOSTable); 958 959 traceBIOSUpdate(attrValueEntry, attrEntry, isBMC); 960 961 return PLDM_SUCCESS; 962 } 963 964 void BIOSConfig::removeTables() 965 { 966 try 967 { 968 fs::remove(tableDir / stringTableFile); 969 fs::remove(tableDir / attrTableFile); 970 fs::remove(tableDir / attrValueTableFile); 971 } 972 catch (const std::exception& e) 973 { 974 error("Remove the tables error - {ERROR}", "ERROR", e); 975 } 976 } 977 978 void BIOSConfig::processBiosAttrChangeNotification( 979 const DbusChObjProperties& chProperties, uint32_t biosAttrIndex) 980 { 981 const auto& dBusMap = biosAttributes[biosAttrIndex]->getDBusMap(); 982 const auto& propertyName = dBusMap->propertyName; 983 const auto& attrName = biosAttributes[biosAttrIndex]->name; 984 985 const auto it = chProperties.find(propertyName); 986 if (it == chProperties.end()) 987 { 988 return; 989 } 990 991 PropertyValue newPropVal = it->second; 992 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 993 if (!stringTable.has_value()) 994 { 995 error("BIOS string table unavailable"); 996 return; 997 } 998 BIOSStringTable biosStringTable(*stringTable); 999 uint16_t attrNameHdl{}; 1000 try 1001 { 1002 attrNameHdl = biosStringTable.findHandle(attrName); 1003 } 1004 catch (const std::invalid_argument& e) 1005 { 1006 error( 1007 "Missing handle for attribute '{ATTRIBUTE}' in BIOS String Table, error - '{ERROR}'", 1008 "ATTRIBUTE", attrName, "ERROR", e); 1009 return; 1010 } 1011 1012 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 1013 if (!attrTable.has_value()) 1014 { 1015 error("BIOS Attribute table not present"); 1016 return; 1017 } 1018 const struct pldm_bios_attr_table_entry* tableEntry = 1019 table::attribute::findByStringHandle(*attrTable, attrNameHdl); 1020 if (tableEntry == nullptr) 1021 { 1022 error( 1023 "Failed to find attribute {ATTRIBUTE} in BIOS Attribute table with attribute handle '{ATTR_HANDLE}'", 1024 "ATTRIBUTE", attrName, "ATTR_HANDLE", attrNameHdl); 1025 return; 1026 } 1027 1028 auto [attrHdl, attrType, 1029 stringHdl] = table::attribute::decodeHeader(tableEntry); 1030 1031 auto attrValueSrcTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 1032 1033 if (!attrValueSrcTable.has_value()) 1034 { 1035 error("Attribute value table not present"); 1036 return; 1037 } 1038 1039 Table newValue; 1040 auto rc = biosAttributes[biosAttrIndex]->updateAttrVal( 1041 newValue, attrHdl, attrType, newPropVal); 1042 if (rc != PLDM_SUCCESS) 1043 { 1044 error( 1045 "Failed to update the attribute value table for attribute handle '{ATTR_HANDLE}' and attribute type '{TYPE}'", 1046 "ATTR_HANDLE", attrHdl, "TYPE", attrType); 1047 return; 1048 } 1049 auto destTable = table::attribute_value::updateTable( 1050 *attrValueSrcTable, newValue.data(), newValue.size()); 1051 if (destTable.has_value()) 1052 { 1053 storeTable(tableDir / attrValueTableFile, *destTable); 1054 } 1055 1056 rc = setAttrValue(newValue.data(), newValue.size(), true, false); 1057 if (rc != PLDM_SUCCESS) 1058 { 1059 error( 1060 "Failed to setAttrValue on base bios table and dbus, response code '{RC}'", 1061 "RC", rc); 1062 } 1063 } 1064 1065 uint16_t BIOSConfig::findAttrHandle(const std::string& attrName) 1066 { 1067 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 1068 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 1069 1070 BIOSStringTable biosStringTable(*stringTable); 1071 pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE> attrTableIter( 1072 attrTable->data(), attrTable->size()); 1073 auto stringHandle = biosStringTable.findHandle(attrName); 1074 1075 for (auto entry : pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE>( 1076 attrTable->data(), attrTable->size())) 1077 { 1078 auto header = table::attribute::decodeHeader(entry); 1079 if (header.stringHandle == stringHandle) 1080 { 1081 return header.attrHandle; 1082 } 1083 } 1084 1085 throw std::invalid_argument("Unknown attribute Name"); 1086 } 1087 1088 void BIOSConfig::constructPendingAttribute( 1089 const PendingAttributes& pendingAttributes) 1090 { 1091 std::vector<uint16_t> listOfHandles{}; 1092 1093 for (auto& attribute : pendingAttributes) 1094 { 1095 std::string attributeName = attribute.first; 1096 auto& [attributeType, attributevalue] = attribute.second; 1097 1098 auto iter = std::find_if(biosAttributes.begin(), biosAttributes.end(), 1099 [&attributeName](const auto& attr) { 1100 return attr->name == attributeName; 1101 }); 1102 1103 if (iter == biosAttributes.end()) 1104 { 1105 error("Wrong attribute name {NAME}", "NAME", attributeName); 1106 continue; 1107 } 1108 1109 Table attrValueEntry(sizeof(pldm_bios_attr_val_table_entry), 0); 1110 auto entry = new (attrValueEntry.data()) pldm_bios_attr_val_table_entry; 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