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