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