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