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