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