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