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={ERR_EXCEP}", 532 "ERR_EXCEP", e.what()); 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={ERR_EXCEP}", 582 "ERR_EXCEP", e.what()); 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("Error constructing table entry for '{ATTR}': {ERROR}", 608 "ATTR", attr->name, "ERROR", e); 609 } 610 } 611 612 table::appendPadAndChecksum(attrTable); 613 table::appendPadAndChecksum(attrValueTable); 614 setBIOSTable(PLDM_BIOS_ATTR_TABLE, attrTable); 615 setBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE, attrValueTable); 616 } 617 618 std::optional<Table> BIOSConfig::buildAndStoreStringTable() 619 { 620 std::set<std::string> strings; 621 auto handler = [&strings](const Json& entry) { 622 strings.emplace(entry.at("attribute_name")); 623 }; 624 625 load(jsonDir / sysType / stringJsonFile, handler); 626 load(jsonDir / sysType / integerJsonFile, handler); 627 load(jsonDir / sysType / enumJsonFile, [&strings](const Json& entry) { 628 strings.emplace(entry.at("attribute_name")); 629 auto possibleValues = entry.at("possible_values"); 630 for (auto& pv : possibleValues) 631 { 632 strings.emplace(pv); 633 } 634 }); 635 636 if (strings.empty()) 637 { 638 return std::nullopt; 639 } 640 641 Table table; 642 for (const auto& elem : strings) 643 { 644 table::string::constructEntry(table, elem); 645 } 646 647 table::appendPadAndChecksum(table); 648 setBIOSTable(PLDM_BIOS_STRING_TABLE, table); 649 return table; 650 } 651 652 void BIOSConfig::storeTable(const fs::path& path, const Table& table) 653 { 654 BIOSTable biosTable(path.c_str()); 655 biosTable.store(table); 656 } 657 658 std::optional<Table> BIOSConfig::loadTable(const fs::path& path) 659 { 660 BIOSTable biosTable(path.c_str()); 661 if (biosTable.isEmpty()) 662 { 663 return std::nullopt; 664 } 665 666 Table table; 667 biosTable.load(table); 668 return table; 669 } 670 671 void BIOSConfig::load(const fs::path& filePath, ParseHandler handler) 672 { 673 std::ifstream file; 674 Json jsonConf; 675 if (fs::exists(filePath)) 676 { 677 try 678 { 679 file.open(filePath); 680 jsonConf = Json::parse(file); 681 auto entries = jsonConf.at("entries"); 682 for (auto& entry : entries) 683 { 684 try 685 { 686 handler(entry); 687 } 688 catch (const std::exception& e) 689 { 690 error( 691 "Failed to parse JSON config file(entry handler) : {JSON_PATH}, {ERR_EXCEP}", 692 "JSON_PATH", filePath.c_str(), "ERR_EXCEP", e.what()); 693 } 694 } 695 } 696 catch (const std::exception& e) 697 { 698 error("Failed to parse JSON config at '{PATH}': {ERROR}", "PATH", 699 filePath.c_str(), "ERROR", e); 700 } 701 } 702 } 703 704 std::string BIOSConfig::decodeStringFromStringEntry( 705 const pldm_bios_string_table_entry* stringEntry) 706 { 707 auto strLength = 708 pldm_bios_table_string_entry_decode_string_length(stringEntry); 709 std::vector<char> buffer(strLength + 1 /* sizeof '\0' */); 710 // Preconditions are upheld therefore no error check necessary 711 pldm_bios_table_string_entry_decode_string_check(stringEntry, buffer.data(), 712 buffer.size()); 713 return std::string(buffer.data(), buffer.data() + strLength); 714 } 715 716 std::string 717 BIOSConfig::displayStringHandle(uint16_t handle, uint8_t index, 718 const std::optional<Table>& attrTable, 719 const std::optional<Table>& stringTable) 720 { 721 auto attrEntry = pldm_bios_table_attr_find_by_handle( 722 attrTable->data(), attrTable->size(), handle); 723 uint8_t pvNum; 724 int rc = pldm_bios_table_attr_entry_enum_decode_pv_num_check(attrEntry, 725 &pvNum); 726 if (rc != PLDM_SUCCESS) 727 { 728 error( 729 "Failed to decode BIOS table possible values for attribute entry: {LIPBLDM_ERROR}", 730 "LIBPLDM_ERROR", rc); 731 throw std::runtime_error( 732 "Failed to decode BIOS table possible values for attribute entry"); 733 } 734 735 std::vector<uint16_t> pvHandls(pvNum); 736 // Preconditions are upheld therefore no error check necessary 737 pldm_bios_table_attr_entry_enum_decode_pv_hdls_check( 738 attrEntry, pvHandls.data(), pvHandls.size()); 739 740 std::string displayString = std::to_string(pvHandls[index]); 741 742 auto stringEntry = pldm_bios_table_string_find_by_handle( 743 stringTable->data(), stringTable->size(), pvHandls[index]); 744 745 auto decodedStr = decodeStringFromStringEntry(stringEntry); 746 747 return decodedStr + "(" + displayString + ")"; 748 } 749 750 void BIOSConfig::traceBIOSUpdate( 751 const pldm_bios_attr_val_table_entry* attrValueEntry, 752 const pldm_bios_attr_table_entry* attrEntry, bool isBMC) 753 { 754 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 755 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 756 757 auto [attrHandle, 758 attrType] = table::attribute_value::decodeHeader(attrValueEntry); 759 760 auto attrHeader = table::attribute::decodeHeader(attrEntry); 761 BIOSStringTable biosStringTable(*stringTable); 762 auto attrName = biosStringTable.findString(attrHeader.stringHandle); 763 764 switch (attrType) 765 { 766 case PLDM_BIOS_ENUMERATION: 767 case PLDM_BIOS_ENUMERATION_READ_ONLY: 768 { 769 auto count = pldm_bios_table_attr_value_entry_enum_decode_number( 770 attrValueEntry); 771 std::vector<uint8_t> handles(count); 772 pldm_bios_table_attr_value_entry_enum_decode_handles( 773 attrValueEntry, handles.data(), handles.size()); 774 775 for (uint8_t handle : handles) 776 { 777 auto nwVal = displayStringHandle(attrHandle, handle, attrTable, 778 stringTable); 779 auto chkBMC = isBMC ? "true" : "false"; 780 info( 781 "BIOS: {ATTR_NAME}, updated to value: {NEW_VAL}, by BMC: {CHK_BMC} ", 782 "ATTR_NAME", attrName, "NEW_VAL", nwVal, "CHK_BMC", chkBMC); 783 } 784 break; 785 } 786 case PLDM_BIOS_INTEGER: 787 case PLDM_BIOS_INTEGER_READ_ONLY: 788 { 789 auto value = 790 table::attribute_value::decodeIntegerEntry(attrValueEntry); 791 auto chkBMC = isBMC ? "true" : "false"; 792 info( 793 "BIOS: {ATTR_NAME}, updated to value: {UPDATED_VAL}, by BMC: {CHK_BMC}", 794 "ATTR_NAME", attrName, "UPDATED_VAL", value, "CHK_BMC", chkBMC); 795 break; 796 } 797 case PLDM_BIOS_STRING: 798 case PLDM_BIOS_STRING_READ_ONLY: 799 { 800 auto value = 801 table::attribute_value::decodeStringEntry(attrValueEntry); 802 auto chkBMC = isBMC ? "true" : "false"; 803 info( 804 "BIOS: {ATTR_NAME}, updated to value: {UPDATED_VAL}, by BMC: {CHK_BMC}", 805 "ATTR_NAME", attrName, "UPDATED_VAL", value, "CHK_BMC", chkBMC); 806 break; 807 } 808 default: 809 break; 810 }; 811 } 812 813 int BIOSConfig::checkAttrValueToUpdate( 814 const pldm_bios_attr_val_table_entry* attrValueEntry, 815 const pldm_bios_attr_table_entry* attrEntry, Table&) 816 817 { 818 auto [attrHandle, 819 attrType] = table::attribute_value::decodeHeader(attrValueEntry); 820 821 switch (attrType) 822 { 823 case PLDM_BIOS_ENUMERATION: 824 case PLDM_BIOS_ENUMERATION_READ_ONLY: 825 { 826 auto value = 827 table::attribute_value::decodeEnumEntry(attrValueEntry); 828 auto [pvHdls, 829 defIndex] = table::attribute::decodeEnumEntry(attrEntry); 830 if (!(value.size() == 1)) 831 { 832 return PLDM_ERROR_INVALID_LENGTH; 833 } 834 if (value[0] >= pvHdls.size()) 835 { 836 error("Enum: Illgeal index, Index = {ATTR_INDEX}", "ATTR_INDEX", 837 (int)value[0]); 838 return PLDM_ERROR_INVALID_DATA; 839 } 840 return PLDM_SUCCESS; 841 } 842 case PLDM_BIOS_INTEGER: 843 case PLDM_BIOS_INTEGER_READ_ONLY: 844 { 845 auto value = 846 table::attribute_value::decodeIntegerEntry(attrValueEntry); 847 auto [lower, upper, scalar, 848 def] = table::attribute::decodeIntegerEntry(attrEntry); 849 850 if (value < lower || value > upper) 851 { 852 error("Integer: out of bound, value = {ATTR_VALUE}", 853 "ATTR_VALUE", value); 854 return PLDM_ERROR_INVALID_DATA; 855 } 856 return PLDM_SUCCESS; 857 } 858 case PLDM_BIOS_STRING: 859 case PLDM_BIOS_STRING_READ_ONLY: 860 { 861 auto stringConf = table::attribute::decodeStringEntry(attrEntry); 862 auto value = 863 table::attribute_value::decodeStringEntry(attrValueEntry); 864 if (value.size() < stringConf.minLength || 865 value.size() > stringConf.maxLength) 866 { 867 error( 868 "String: Length error, string = {ATTR_VALUE} length {LEN}", 869 "ATTR_VALUE", value, "LEN", value.size()); 870 return PLDM_ERROR_INVALID_LENGTH; 871 } 872 return PLDM_SUCCESS; 873 } 874 default: 875 error("ReadOnly or Unspported type, type = {ATTR_TYPE}", 876 "ATTR_TYPE", attrType); 877 return PLDM_ERROR; 878 }; 879 } 880 881 int BIOSConfig::setAttrValue(const void* entry, size_t size, bool isBMC, 882 bool updateDBus, bool updateBaseBIOSTable) 883 { 884 auto attrValueTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 885 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 886 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 887 if (!attrValueTable || !attrTable || !stringTable) 888 { 889 return PLDM_BIOS_TABLE_UNAVAILABLE; 890 } 891 892 auto attrValueEntry = 893 reinterpret_cast<const pldm_bios_attr_val_table_entry*>(entry); 894 895 auto attrValHeader = table::attribute_value::decodeHeader(attrValueEntry); 896 897 auto attrEntry = table::attribute::findByHandle(*attrTable, 898 attrValHeader.attrHandle); 899 if (!attrEntry) 900 { 901 return PLDM_ERROR; 902 } 903 904 auto rc = checkAttrValueToUpdate(attrValueEntry, attrEntry, *stringTable); 905 if (rc != PLDM_SUCCESS) 906 { 907 return rc; 908 } 909 910 auto destTable = table::attribute_value::updateTable(*attrValueTable, entry, 911 size); 912 913 if (!destTable) 914 { 915 return PLDM_ERROR; 916 } 917 918 try 919 { 920 auto attrHeader = table::attribute::decodeHeader(attrEntry); 921 922 BIOSStringTable biosStringTable(*stringTable); 923 auto attrName = biosStringTable.findString(attrHeader.stringHandle); 924 auto iter = std::find_if( 925 biosAttributes.begin(), biosAttributes.end(), 926 [&attrName](const auto& attr) { return attr->name == attrName; }); 927 928 if (iter == biosAttributes.end()) 929 { 930 return PLDM_ERROR; 931 } 932 if (updateDBus) 933 { 934 (*iter)->setAttrValueOnDbus(attrValueEntry, attrEntry, 935 biosStringTable); 936 } 937 } 938 catch (const std::exception& e) 939 { 940 error("Set attribute value error: {ERR_EXCEP}", "ERR_EXCEP", e.what()); 941 return PLDM_ERROR; 942 } 943 944 setBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE, *destTable, updateBaseBIOSTable); 945 946 traceBIOSUpdate(attrValueEntry, attrEntry, isBMC); 947 948 return PLDM_SUCCESS; 949 } 950 951 void BIOSConfig::removeTables() 952 { 953 try 954 { 955 fs::remove(tableDir / stringTableFile); 956 fs::remove(tableDir / attrTableFile); 957 fs::remove(tableDir / attrValueTableFile); 958 } 959 catch (const std::exception& e) 960 { 961 error("Remove the tables error: {ERR_EXCEP}", "ERR_EXCEP", e.what()); 962 } 963 } 964 965 void BIOSConfig::processBiosAttrChangeNotification( 966 const DbusChObjProperties& chProperties, uint32_t biosAttrIndex) 967 { 968 const auto& dBusMap = biosAttributes[biosAttrIndex]->getDBusMap(); 969 const auto& propertyName = dBusMap->propertyName; 970 const auto& attrName = biosAttributes[biosAttrIndex]->name; 971 972 const auto it = chProperties.find(propertyName); 973 if (it == chProperties.end()) 974 { 975 return; 976 } 977 978 PropertyValue newPropVal = it->second; 979 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 980 if (!stringTable.has_value()) 981 { 982 error("BIOS string table unavailable"); 983 return; 984 } 985 BIOSStringTable biosStringTable(*stringTable); 986 uint16_t attrNameHdl{}; 987 try 988 { 989 attrNameHdl = biosStringTable.findHandle(attrName); 990 } 991 catch (const std::invalid_argument& e) 992 { 993 error("Missing handle for '{ATTR}': {ERROR}", "ATTR", attrName, "ERROR", 994 e); 995 return; 996 } 997 998 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 999 if (!attrTable.has_value()) 1000 { 1001 error("Attribute table not present"); 1002 return; 1003 } 1004 const struct pldm_bios_attr_table_entry* tableEntry = 1005 table::attribute::findByStringHandle(*attrTable, attrNameHdl); 1006 if (tableEntry == nullptr) 1007 { 1008 error( 1009 "Attribute not found in attribute table, name= {ATTR_NAME} name handle={ATTR_HANDLE}", 1010 "ATTR_NAME", attrName.c_str(), "ATTR_HANDLE", attrNameHdl); 1011 return; 1012 } 1013 1014 auto [attrHdl, attrType, 1015 stringHdl] = table::attribute::decodeHeader(tableEntry); 1016 1017 auto attrValueSrcTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 1018 1019 if (!attrValueSrcTable.has_value()) 1020 { 1021 error("Attribute value table not present"); 1022 return; 1023 } 1024 1025 Table newValue; 1026 auto rc = biosAttributes[biosAttrIndex]->updateAttrVal( 1027 newValue, attrHdl, attrType, newPropVal); 1028 if (rc != PLDM_SUCCESS) 1029 { 1030 error( 1031 "Could not update the attribute value table for attribute handle={ATTR_HANDLE} and type={ATTR_TYPE}", 1032 "ATTR_HANDLE", attrHdl, "ATTR_TYPE", (uint32_t)attrType); 1033 return; 1034 } 1035 auto destTable = table::attribute_value::updateTable( 1036 *attrValueSrcTable, newValue.data(), newValue.size()); 1037 if (destTable.has_value()) 1038 { 1039 storeTable(tableDir / attrValueTableFile, *destTable); 1040 } 1041 1042 rc = setAttrValue(newValue.data(), newValue.size(), true, false); 1043 if (rc != PLDM_SUCCESS) 1044 { 1045 error("could not setAttrValue on base bios table and dbus, rc = {RC}", 1046 "RC", rc); 1047 } 1048 } 1049 1050 uint16_t BIOSConfig::findAttrHandle(const std::string& attrName) 1051 { 1052 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 1053 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 1054 1055 BIOSStringTable biosStringTable(*stringTable); 1056 pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE> attrTableIter( 1057 attrTable->data(), attrTable->size()); 1058 auto stringHandle = biosStringTable.findHandle(attrName); 1059 1060 for (auto entry : pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE>( 1061 attrTable->data(), attrTable->size())) 1062 { 1063 auto header = table::attribute::decodeHeader(entry); 1064 if (header.stringHandle == stringHandle) 1065 { 1066 return header.attrHandle; 1067 } 1068 } 1069 1070 throw std::invalid_argument("Unknow attribute Name"); 1071 } 1072 1073 void BIOSConfig::constructPendingAttribute( 1074 const PendingAttributes& pendingAttributes) 1075 { 1076 std::vector<uint16_t> listOfHandles{}; 1077 1078 for (auto& attribute : pendingAttributes) 1079 { 1080 std::string attributeName = attribute.first; 1081 auto& [attributeType, attributevalue] = attribute.second; 1082 1083 auto iter = std::find_if(biosAttributes.begin(), biosAttributes.end(), 1084 [&attributeName](const auto& attr) { 1085 return attr->name == attributeName; 1086 }); 1087 1088 if (iter == biosAttributes.end()) 1089 { 1090 error("Wrong attribute name, attributeName = {ATTR_NAME}", 1091 "ATTR_NAME", attributeName); 1092 continue; 1093 } 1094 1095 Table attrValueEntry(sizeof(pldm_bios_attr_val_table_entry), 0); 1096 auto entry = reinterpret_cast<pldm_bios_attr_val_table_entry*>( 1097 attrValueEntry.data()); 1098 1099 auto handler = findAttrHandle(attributeName); 1100 auto type = 1101 BIOSConfigManager::convertAttributeTypeFromString(attributeType); 1102 1103 if (type != BIOSConfigManager::AttributeType::Enumeration && 1104 type != BIOSConfigManager::AttributeType::String && 1105 type != BIOSConfigManager::AttributeType::Integer) 1106 { 1107 error("Attribute type not supported, attributeType = {ATTR_TYPE}", 1108 "ATTR_TYPE", attributeType); 1109 continue; 1110 } 1111 1112 const auto [attrType, readonlyStatus, displayName, description, 1113 menuPath, currentValue, defaultValue, 1114 option] = baseBIOSTableMaps.at(attributeName); 1115 1116 entry->attr_handle = htole16(handler); 1117 1118 // Need to verify that the current value has really changed 1119 if (attributeType == attrType && attributevalue != currentValue) 1120 { 1121 listOfHandles.emplace_back(htole16(handler)); 1122 } 1123 1124 (*iter)->generateAttributeEntry(attributevalue, attrValueEntry); 1125 1126 setAttrValue(attrValueEntry.data(), attrValueEntry.size(), true); 1127 } 1128 1129 if (listOfHandles.size()) 1130 { 1131 #ifdef OEM_IBM 1132 auto rc = pldm::responder::platform::sendBiosAttributeUpdateEvent( 1133 eid, instanceIdDb, listOfHandles, handler); 1134 if (rc != PLDM_SUCCESS) 1135 { 1136 return; 1137 } 1138 #endif 1139 } 1140 } 1141 1142 void BIOSConfig::listenPendingAttributes() 1143 { 1144 constexpr auto objPath = "/xyz/openbmc_project/bios_config/manager"; 1145 constexpr auto objInterface = "xyz.openbmc_project.BIOSConfig.Manager"; 1146 1147 using namespace sdbusplus::bus::match::rules; 1148 auto updateBIOSMatch = std::make_unique<sdbusplus::bus::match_t>( 1149 pldm::utils::DBusHandler::getBus(), 1150 propertiesChanged(objPath, objInterface), 1151 [this](sdbusplus::message_t& msg) { 1152 constexpr auto propertyName = "PendingAttributes"; 1153 1154 using Value = 1155 std::variant<std::string, PendingAttributes, BaseBIOSTable>; 1156 using Properties = std::map<DbusProp, Value>; 1157 1158 Properties props{}; 1159 std::string intf; 1160 msg.read(intf, props); 1161 1162 auto valPropMap = props.find(propertyName); 1163 if (valPropMap == props.end()) 1164 { 1165 return; 1166 } 1167 1168 PendingAttributes pendingAttributes = 1169 std::get<PendingAttributes>(valPropMap->second); 1170 this->constructPendingAttribute(pendingAttributes); 1171 }); 1172 1173 biosAttrMatch.emplace_back(std::move(updateBIOSMatch)); 1174 } 1175 1176 } // namespace bios 1177 } // namespace responder 1178 } // namespace pldm 1179