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