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