1 #include "bios_config.hpp" 2 3 #include "bios_enum_attribute.hpp" 4 #include "bios_integer_attribute.hpp" 5 #include "bios_string_attribute.hpp" 6 #include "bios_table.hpp" 7 #include "common/bios_utils.hpp" 8 9 #include <phosphor-logging/lg2.hpp> 10 #include <xyz/openbmc_project/BIOSConfig/Manager/server.hpp> 11 12 #include <fstream> 13 #include <iostream> 14 15 #ifdef OEM_IBM 16 #include "oem/ibm/libpldmresponder/platform_oem_ibm.hpp" 17 #endif 18 19 PHOSPHOR_LOG2_USING; 20 21 using namespace pldm::utils; 22 23 namespace pldm 24 { 25 namespace responder 26 { 27 namespace bios 28 { 29 namespace 30 { 31 using BIOSConfigManager = 32 sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager; 33 34 constexpr auto enumJsonFile = "enum_attrs.json"; 35 constexpr auto stringJsonFile = "string_attrs.json"; 36 constexpr auto integerJsonFile = "integer_attrs.json"; 37 38 constexpr auto stringTableFile = "stringTable"; 39 constexpr auto attrTableFile = "attributeTable"; 40 constexpr auto attrValueTableFile = "attributeValueTable"; 41 42 } // namespace 43 44 BIOSConfig::BIOSConfig( 45 const char* jsonDir, const char* tableDir, DBusHandler* const dbusHandler, 46 int fd, uint8_t eid, pldm::InstanceIdDb* instanceIdDb, 47 pldm::requester::Handler<pldm::requester::Request>* handler) : 48 jsonDir(jsonDir), 49 tableDir(tableDir), dbusHandler(dbusHandler), fd(fd), eid(eid), 50 instanceIdDb(instanceIdDb), handler(handler) 51 52 { 53 fs::create_directories(tableDir); 54 constructAttributes(); 55 listenPendingAttributes(); 56 } 57 58 void BIOSConfig::buildTables() 59 { 60 auto stringTable = buildAndStoreStringTable(); 61 if (stringTable) 62 { 63 buildAndStoreAttrTables(*stringTable); 64 } 65 } 66 67 std::optional<Table> BIOSConfig::getBIOSTable(pldm_bios_table_types tableType) 68 { 69 fs::path tablePath; 70 switch (tableType) 71 { 72 case PLDM_BIOS_STRING_TABLE: 73 tablePath = tableDir / stringTableFile; 74 break; 75 case PLDM_BIOS_ATTR_TABLE: 76 tablePath = tableDir / attrTableFile; 77 break; 78 case PLDM_BIOS_ATTR_VAL_TABLE: 79 tablePath = tableDir / attrValueTableFile; 80 break; 81 } 82 return loadTable(tablePath); 83 } 84 85 int BIOSConfig::setBIOSTable(uint8_t tableType, const Table& table, 86 bool updateBaseBIOSTable) 87 { 88 fs::path stringTablePath(tableDir / stringTableFile); 89 fs::path attrTablePath(tableDir / attrTableFile); 90 fs::path attrValueTablePath(tableDir / attrValueTableFile); 91 92 if (!pldm_bios_table_checksum(table.data(), table.size())) 93 { 94 return PLDM_INVALID_BIOS_TABLE_DATA_INTEGRITY_CHECK; 95 } 96 97 if (tableType == PLDM_BIOS_STRING_TABLE) 98 { 99 storeTable(stringTablePath, table); 100 } 101 else if (tableType == PLDM_BIOS_ATTR_TABLE) 102 { 103 BIOSTable biosStringTable(stringTablePath.c_str()); 104 if (biosStringTable.isEmpty()) 105 { 106 return PLDM_INVALID_BIOS_TABLE_TYPE; 107 } 108 109 auto rc = checkAttributeTable(table); 110 if (rc != PLDM_SUCCESS) 111 { 112 return rc; 113 } 114 115 storeTable(attrTablePath, table); 116 } 117 else if (tableType == PLDM_BIOS_ATTR_VAL_TABLE) 118 { 119 BIOSTable biosStringTable(stringTablePath.c_str()); 120 BIOSTable biosStringValueTable(attrTablePath.c_str()); 121 if (biosStringTable.isEmpty() || biosStringValueTable.isEmpty()) 122 { 123 return PLDM_INVALID_BIOS_TABLE_TYPE; 124 } 125 126 auto rc = checkAttributeValueTable(table); 127 if (rc != PLDM_SUCCESS) 128 { 129 return rc; 130 } 131 132 storeTable(attrValueTablePath, table); 133 } 134 else 135 { 136 return PLDM_INVALID_BIOS_TABLE_TYPE; 137 } 138 139 if ((tableType == PLDM_BIOS_ATTR_VAL_TABLE) && updateBaseBIOSTable) 140 { 141 updateBaseBIOSTableProperty(); 142 } 143 144 return PLDM_SUCCESS; 145 } 146 147 int BIOSConfig::checkAttributeTable(const Table& table) 148 { 149 using namespace pldm::bios::utils; 150 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 151 for (auto entry : 152 BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(table.data(), table.size())) 153 { 154 auto attrNameHandle = 155 pldm_bios_table_attr_entry_decode_string_handle(entry); 156 157 auto stringEnty = pldm_bios_table_string_find_by_handle( 158 stringTable->data(), stringTable->size(), attrNameHandle); 159 if (stringEnty == nullptr) 160 { 161 return PLDM_INVALID_BIOS_ATTR_HANDLE; 162 } 163 164 auto attrType = static_cast<pldm_bios_attribute_type>( 165 pldm_bios_table_attr_entry_decode_attribute_type(entry)); 166 167 switch (attrType) 168 { 169 case PLDM_BIOS_ENUMERATION: 170 case PLDM_BIOS_ENUMERATION_READ_ONLY: 171 { 172 auto pvNum = 173 pldm_bios_table_attr_entry_enum_decode_pv_num(entry); 174 std::vector<uint16_t> pvHandls(pvNum); 175 pldm_bios_table_attr_entry_enum_decode_pv_hdls( 176 entry, pvHandls.data(), pvHandls.size()); 177 auto defNum = 178 pldm_bios_table_attr_entry_enum_decode_def_num(entry); 179 std::vector<uint8_t> defIndices(defNum); 180 pldm_bios_table_attr_entry_enum_decode_def_indices( 181 entry, defIndices.data(), defIndices.size()); 182 183 for (size_t i = 0; i < pvHandls.size(); i++) 184 { 185 auto stringEntry = pldm_bios_table_string_find_by_handle( 186 stringTable->data(), stringTable->size(), pvHandls[i]); 187 if (stringEntry == nullptr) 188 { 189 return PLDM_INVALID_BIOS_ATTR_HANDLE; 190 } 191 } 192 193 for (size_t i = 0; i < defIndices.size(); i++) 194 { 195 auto stringEntry = pldm_bios_table_string_find_by_handle( 196 stringTable->data(), stringTable->size(), 197 pvHandls[defIndices[i]]); 198 if (stringEntry == nullptr) 199 { 200 return PLDM_INVALID_BIOS_ATTR_HANDLE; 201 } 202 } 203 break; 204 } 205 case PLDM_BIOS_INTEGER: 206 case PLDM_BIOS_INTEGER_READ_ONLY: 207 case PLDM_BIOS_STRING: 208 case PLDM_BIOS_STRING_READ_ONLY: 209 case PLDM_BIOS_PASSWORD: 210 case PLDM_BIOS_PASSWORD_READ_ONLY: 211 break; 212 default: 213 return PLDM_INVALID_BIOS_ATTR_HANDLE; 214 } 215 } 216 217 return PLDM_SUCCESS; 218 } 219 220 int BIOSConfig::checkAttributeValueTable(const Table& table) 221 { 222 using namespace pldm::bios::utils; 223 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 224 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 225 226 baseBIOSTableMaps.clear(); 227 228 for (auto tableEntry : 229 BIOSTableIter<PLDM_BIOS_ATTR_VAL_TABLE>(table.data(), table.size())) 230 { 231 AttributeName attributeName{}; 232 AttributeType attributeType{}; 233 ReadonlyStatus readonlyStatus{}; 234 DisplayName displayName{}; 235 Description description{}; 236 MenuPath menuPath{}; 237 CurrentValue currentValue{}; 238 DefaultValue defaultValue{}; 239 Option options{}; 240 241 auto attrValueHandle = 242 pldm_bios_table_attr_value_entry_decode_attribute_handle( 243 tableEntry); 244 auto attrType = static_cast<pldm_bios_attribute_type>( 245 pldm_bios_table_attr_value_entry_decode_attribute_type(tableEntry)); 246 247 auto attrEntry = pldm_bios_table_attr_find_by_handle( 248 attrTable->data(), attrTable->size(), attrValueHandle); 249 if (attrEntry == nullptr) 250 { 251 return PLDM_INVALID_BIOS_ATTR_HANDLE; 252 } 253 auto attrHandle = 254 pldm_bios_table_attr_entry_decode_attribute_handle(attrEntry); 255 auto attrNameHandle = 256 pldm_bios_table_attr_entry_decode_string_handle(attrEntry); 257 258 auto stringEntry = pldm_bios_table_string_find_by_handle( 259 stringTable->data(), stringTable->size(), attrNameHandle); 260 if (stringEntry == nullptr) 261 { 262 return PLDM_INVALID_BIOS_ATTR_HANDLE; 263 } 264 auto strLength = 265 pldm_bios_table_string_entry_decode_string_length(stringEntry); 266 std::vector<char> buffer(strLength + 1 /* sizeof '\0' */); 267 pldm_bios_table_string_entry_decode_string(stringEntry, buffer.data(), 268 buffer.size()); 269 attributeName = std::string(buffer.data(), buffer.data() + strLength); 270 271 if (!biosAttributes.empty()) 272 { 273 readonlyStatus = 274 biosAttributes[attrHandle % biosAttributes.size()]->readOnly; 275 description = 276 biosAttributes[attrHandle % biosAttributes.size()]->helpText; 277 displayName = 278 biosAttributes[attrHandle % biosAttributes.size()]->displayName; 279 } 280 281 switch (attrType) 282 { 283 case PLDM_BIOS_ENUMERATION: 284 case PLDM_BIOS_ENUMERATION_READ_ONLY: 285 { 286 auto getValue = [](uint16_t handle, 287 const Table& table) -> std::string { 288 auto stringEntry = pldm_bios_table_string_find_by_handle( 289 table.data(), table.size(), handle); 290 291 auto strLength = 292 pldm_bios_table_string_entry_decode_string_length( 293 stringEntry); 294 std::vector<char> buffer(strLength + 1 /* sizeof '\0' */); 295 pldm_bios_table_string_entry_decode_string( 296 stringEntry, buffer.data(), buffer.size()); 297 298 return std::string(buffer.data(), 299 buffer.data() + strLength); 300 }; 301 302 attributeType = "xyz.openbmc_project.BIOSConfig.Manager." 303 "AttributeType.Enumeration"; 304 305 auto pvNum = 306 pldm_bios_table_attr_entry_enum_decode_pv_num(attrEntry); 307 std::vector<uint16_t> pvHandls(pvNum); 308 pldm_bios_table_attr_entry_enum_decode_pv_hdls( 309 attrEntry, pvHandls.data(), pvHandls.size()); 310 311 // get possible_value 312 for (size_t i = 0; i < pvHandls.size(); i++) 313 { 314 options.push_back( 315 std::make_tuple("xyz.openbmc_project.BIOSConfig." 316 "Manager.BoundType.OneOf", 317 getValue(pvHandls[i], *stringTable))); 318 } 319 320 auto count = 321 pldm_bios_table_attr_value_entry_enum_decode_number( 322 tableEntry); 323 std::vector<uint8_t> handles(count); 324 pldm_bios_table_attr_value_entry_enum_decode_handles( 325 tableEntry, handles.data(), handles.size()); 326 327 // get current_value 328 for (size_t i = 0; i < handles.size(); i++) 329 { 330 currentValue = getValue(pvHandls[handles[i]], *stringTable); 331 } 332 333 auto defNum = 334 pldm_bios_table_attr_entry_enum_decode_def_num(attrEntry); 335 std::vector<uint8_t> defIndices(defNum); 336 pldm_bios_table_attr_entry_enum_decode_def_indices( 337 attrEntry, defIndices.data(), defIndices.size()); 338 339 // get default_value 340 for (size_t i = 0; i < defIndices.size(); i++) 341 { 342 defaultValue = getValue(pvHandls[defIndices[i]], 343 *stringTable); 344 } 345 346 break; 347 } 348 case PLDM_BIOS_INTEGER: 349 case PLDM_BIOS_INTEGER_READ_ONLY: 350 { 351 attributeType = "xyz.openbmc_project.BIOSConfig.Manager." 352 "AttributeType.Integer"; 353 currentValue = static_cast<int64_t>( 354 pldm_bios_table_attr_value_entry_integer_decode_cv( 355 tableEntry)); 356 357 uint64_t lower, upper, def; 358 uint32_t scalar; 359 pldm_bios_table_attr_entry_integer_decode( 360 attrEntry, &lower, &upper, &scalar, &def); 361 options.push_back( 362 std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager." 363 "BoundType.LowerBound", 364 static_cast<int64_t>(lower))); 365 options.push_back( 366 std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager." 367 "BoundType.UpperBound", 368 static_cast<int64_t>(upper))); 369 options.push_back( 370 std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager." 371 "BoundType.ScalarIncrement", 372 static_cast<int64_t>(scalar))); 373 defaultValue = static_cast<int64_t>(def); 374 break; 375 } 376 case PLDM_BIOS_STRING: 377 case PLDM_BIOS_STRING_READ_ONLY: 378 { 379 attributeType = "xyz.openbmc_project.BIOSConfig.Manager." 380 "AttributeType.String"; 381 variable_field currentString; 382 pldm_bios_table_attr_value_entry_string_decode_string( 383 tableEntry, ¤tString); 384 currentValue = std::string( 385 reinterpret_cast<const char*>(currentString.ptr), 386 currentString.length); 387 auto min = pldm_bios_table_attr_entry_string_decode_min_length( 388 attrEntry); 389 auto max = pldm_bios_table_attr_entry_string_decode_max_length( 390 attrEntry); 391 auto def = 392 pldm_bios_table_attr_entry_string_decode_def_string_length( 393 attrEntry); 394 std::vector<char> defString(def + 1); 395 pldm_bios_table_attr_entry_string_decode_def_string( 396 attrEntry, defString.data(), defString.size()); 397 options.push_back( 398 std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager." 399 "BoundType.MinStringLength", 400 static_cast<int64_t>(min))); 401 options.push_back( 402 std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager." 403 "BoundType.MaxStringLength", 404 static_cast<int64_t>(max))); 405 defaultValue = defString.data(); 406 break; 407 } 408 case PLDM_BIOS_PASSWORD: 409 case PLDM_BIOS_PASSWORD_READ_ONLY: 410 { 411 attributeType = "xyz.openbmc_project.BIOSConfig.Manager." 412 "AttributeType.Password"; 413 break; 414 } 415 default: 416 return PLDM_INVALID_BIOS_ATTR_HANDLE; 417 } 418 baseBIOSTableMaps.emplace( 419 std::move(attributeName), 420 std::make_tuple(attributeType, readonlyStatus, displayName, 421 description, menuPath, currentValue, defaultValue, 422 std::move(options))); 423 } 424 425 return PLDM_SUCCESS; 426 } 427 428 void BIOSConfig::updateBaseBIOSTableProperty() 429 { 430 constexpr static auto biosConfigPath = 431 "/xyz/openbmc_project/bios_config/manager"; 432 constexpr static auto biosConfigInterface = 433 "xyz.openbmc_project.BIOSConfig.Manager"; 434 constexpr static auto biosConfigPropertyName = "BaseBIOSTable"; 435 constexpr static auto dbusProperties = "org.freedesktop.DBus.Properties"; 436 437 if (baseBIOSTableMaps.empty()) 438 { 439 return; 440 } 441 442 try 443 { 444 auto& bus = dbusHandler->getBus(); 445 auto service = dbusHandler->getService(biosConfigPath, 446 biosConfigInterface); 447 auto method = bus.new_method_call(service.c_str(), biosConfigPath, 448 dbusProperties, "Set"); 449 std::variant<BaseBIOSTable> value = baseBIOSTableMaps; 450 method.append(biosConfigInterface, biosConfigPropertyName, value); 451 bus.call_noreply(method); 452 } 453 catch (const std::exception& e) 454 { 455 error("failed to update BaseBIOSTable property, ERROR={ERR_EXCEP}", 456 "ERR_EXCEP", e.what()); 457 } 458 } 459 460 void BIOSConfig::constructAttributes() 461 { 462 load(jsonDir / stringJsonFile, [this](const Json& entry) { 463 constructAttribute<BIOSStringAttribute>(entry); 464 }); 465 load(jsonDir / integerJsonFile, [this](const Json& entry) { 466 constructAttribute<BIOSIntegerAttribute>(entry); 467 }); 468 load(jsonDir / enumJsonFile, [this](const Json& entry) { 469 constructAttribute<BIOSEnumAttribute>(entry); 470 }); 471 } 472 473 void BIOSConfig::buildAndStoreAttrTables(const Table& stringTable) 474 { 475 BIOSStringTable biosStringTable(stringTable); 476 477 if (biosAttributes.empty()) 478 { 479 return; 480 } 481 482 BaseBIOSTable biosTable{}; 483 constexpr auto biosObjPath = "/xyz/openbmc_project/bios_config/manager"; 484 constexpr auto biosInterface = "xyz.openbmc_project.BIOSConfig.Manager"; 485 486 try 487 { 488 auto& bus = dbusHandler->getBus(); 489 auto service = dbusHandler->getService(biosObjPath, biosInterface); 490 auto method = bus.new_method_call(service.c_str(), biosObjPath, 491 "org.freedesktop.DBus.Properties", 492 "Get"); 493 method.append(biosInterface, "BaseBIOSTable"); 494 auto reply = bus.call(method); 495 std::variant<BaseBIOSTable> varBiosTable{}; 496 reply.read(varBiosTable); 497 biosTable = std::get<BaseBIOSTable>(varBiosTable); 498 } 499 // Failed to read the BaseBIOSTable, so update the BaseBIOSTable with the 500 // default values populated from the BIOS JSONs to keep PLDM and 501 // bios-settings-manager in sync 502 catch (const std::exception& e) 503 { 504 error("Failed to read BaseBIOSTable property, ERROR={ERR_EXCEP}", 505 "ERR_EXCEP", e.what()); 506 } 507 508 Table attrTable, attrValueTable; 509 510 for (auto& attr : biosAttributes) 511 { 512 try 513 { 514 auto iter = biosTable.find(attr->name); 515 if (iter == biosTable.end()) 516 { 517 attr->constructEntry(biosStringTable, attrTable, attrValueTable, 518 std::nullopt); 519 } 520 else 521 { 522 attr->constructEntry( 523 biosStringTable, attrTable, attrValueTable, 524 std::get<static_cast<uint8_t>(Index::currentValue)>( 525 iter->second)); 526 } 527 } 528 catch (const std::exception& e) 529 { 530 error("Construct Table Entry Error, AttributeName = {ATTR_NAME}", 531 "ATTR_NAME", attr->name); 532 } 533 } 534 535 table::appendPadAndChecksum(attrTable); 536 table::appendPadAndChecksum(attrValueTable); 537 setBIOSTable(PLDM_BIOS_ATTR_TABLE, attrTable); 538 setBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE, attrValueTable); 539 } 540 541 std::optional<Table> BIOSConfig::buildAndStoreStringTable() 542 { 543 std::set<std::string> strings; 544 auto handler = [&strings](const Json& entry) { 545 strings.emplace(entry.at("attribute_name")); 546 }; 547 548 load(jsonDir / stringJsonFile, handler); 549 load(jsonDir / integerJsonFile, handler); 550 load(jsonDir / enumJsonFile, [&strings](const Json& entry) { 551 strings.emplace(entry.at("attribute_name")); 552 auto possibleValues = entry.at("possible_values"); 553 for (auto& pv : possibleValues) 554 { 555 strings.emplace(pv); 556 } 557 }); 558 559 if (strings.empty()) 560 { 561 return std::nullopt; 562 } 563 564 Table table; 565 for (const auto& elem : strings) 566 { 567 table::string::constructEntry(table, elem); 568 } 569 570 table::appendPadAndChecksum(table); 571 setBIOSTable(PLDM_BIOS_STRING_TABLE, table); 572 return table; 573 } 574 575 void BIOSConfig::storeTable(const fs::path& path, const Table& table) 576 { 577 BIOSTable biosTable(path.c_str()); 578 biosTable.store(table); 579 } 580 581 std::optional<Table> BIOSConfig::loadTable(const fs::path& path) 582 { 583 BIOSTable biosTable(path.c_str()); 584 if (biosTable.isEmpty()) 585 { 586 return std::nullopt; 587 } 588 589 Table table; 590 biosTable.load(table); 591 return table; 592 } 593 594 void BIOSConfig::load(const fs::path& filePath, ParseHandler handler) 595 { 596 std::ifstream file; 597 Json jsonConf; 598 if (fs::exists(filePath)) 599 { 600 try 601 { 602 file.open(filePath); 603 jsonConf = Json::parse(file); 604 auto entries = jsonConf.at("entries"); 605 for (auto& entry : entries) 606 { 607 try 608 { 609 handler(entry); 610 } 611 catch (const std::exception& e) 612 { 613 error( 614 "Failed to parse JSON config file(entry handler) : {JSON_PATH}, {ERR_EXCEP}", 615 "JSON_PATH", filePath.c_str(), "ERR_EXCEP", e.what()); 616 } 617 } 618 } 619 catch (const std::exception& e) 620 { 621 error("Failed to parse JSON config file : {JSON_PATH}", "JSON_PATH", 622 filePath.c_str()); 623 } 624 } 625 } 626 627 std::string BIOSConfig::decodeStringFromStringEntry( 628 const pldm_bios_string_table_entry* stringEntry) 629 { 630 auto strLength = 631 pldm_bios_table_string_entry_decode_string_length(stringEntry); 632 std::vector<char> buffer(strLength + 1 /* sizeof '\0' */); 633 pldm_bios_table_string_entry_decode_string(stringEntry, buffer.data(), 634 buffer.size()); 635 return std::string(buffer.data(), buffer.data() + strLength); 636 } 637 638 std::string 639 BIOSConfig::displayStringHandle(uint16_t handle, uint8_t index, 640 const std::optional<Table>& attrTable, 641 const std::optional<Table>& stringTable) 642 { 643 auto attrEntry = pldm_bios_table_attr_find_by_handle( 644 attrTable->data(), attrTable->size(), handle); 645 auto pvNum = pldm_bios_table_attr_entry_enum_decode_pv_num(attrEntry); 646 std::vector<uint16_t> pvHandls(pvNum); 647 pldm_bios_table_attr_entry_enum_decode_pv_hdls(attrEntry, pvHandls.data(), 648 pvHandls.size()); 649 650 std::string displayString = std::to_string(pvHandls[index]); 651 652 auto stringEntry = pldm_bios_table_string_find_by_handle( 653 stringTable->data(), stringTable->size(), pvHandls[index]); 654 655 auto decodedStr = decodeStringFromStringEntry(stringEntry); 656 657 return decodedStr + "(" + displayString + ")"; 658 } 659 660 void BIOSConfig::traceBIOSUpdate( 661 const pldm_bios_attr_val_table_entry* attrValueEntry, 662 const pldm_bios_attr_table_entry* attrEntry, bool isBMC) 663 { 664 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 665 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 666 667 auto [attrHandle, 668 attrType] = table::attribute_value::decodeHeader(attrValueEntry); 669 670 auto attrHeader = table::attribute::decodeHeader(attrEntry); 671 BIOSStringTable biosStringTable(*stringTable); 672 auto attrName = biosStringTable.findString(attrHeader.stringHandle); 673 674 switch (attrType) 675 { 676 case PLDM_BIOS_ENUMERATION: 677 case PLDM_BIOS_ENUMERATION_READ_ONLY: 678 { 679 auto count = pldm_bios_table_attr_value_entry_enum_decode_number( 680 attrValueEntry); 681 std::vector<uint8_t> handles(count); 682 pldm_bios_table_attr_value_entry_enum_decode_handles( 683 attrValueEntry, handles.data(), handles.size()); 684 685 for (uint8_t handle : handles) 686 { 687 auto nwVal = displayStringHandle(attrHandle, handle, attrTable, 688 stringTable); 689 auto chkBMC = isBMC ? "true" : "false"; 690 info( 691 "BIOS:{ATTR_NAME}, updated to value: {NEW_VAL}, by BMC: {CHK_BMC} ", 692 "ATTR_NAME", attrName, "NEW_VAL", nwVal, "CHK_BMC", chkBMC); 693 } 694 break; 695 } 696 case PLDM_BIOS_INTEGER: 697 case PLDM_BIOS_INTEGER_READ_ONLY: 698 { 699 auto value = 700 table::attribute_value::decodeIntegerEntry(attrValueEntry); 701 auto chkBMC = isBMC ? "true" : "false"; 702 info( 703 "BIOS: {ATTR_NAME}, updated to value: {UPDATED_VAL}, by BMC: {CHK_BMC}", 704 "ATTR_NAME", attrName, "UPDATED_VAL", value, "CHK_BMC", chkBMC); 705 break; 706 } 707 case PLDM_BIOS_STRING: 708 case PLDM_BIOS_STRING_READ_ONLY: 709 { 710 auto value = 711 table::attribute_value::decodeStringEntry(attrValueEntry); 712 auto chkBMC = isBMC ? "true" : "false"; 713 info( 714 "BIOS: {ATTR_NAME}, updated to value: {UPDATED_VAL}, by BMC: {CHK_BMC}", 715 "ATTR_NAME", attrName, "UPDATED_VAL", value, "CHK_BMC", chkBMC); 716 break; 717 } 718 default: 719 break; 720 }; 721 } 722 723 int BIOSConfig::checkAttrValueToUpdate( 724 const pldm_bios_attr_val_table_entry* attrValueEntry, 725 const pldm_bios_attr_table_entry* attrEntry, Table&) 726 727 { 728 auto [attrHandle, 729 attrType] = table::attribute_value::decodeHeader(attrValueEntry); 730 731 switch (attrType) 732 { 733 case PLDM_BIOS_ENUMERATION: 734 case PLDM_BIOS_ENUMERATION_READ_ONLY: 735 { 736 auto value = 737 table::attribute_value::decodeEnumEntry(attrValueEntry); 738 auto [pvHdls, 739 defIndex] = table::attribute::decodeEnumEntry(attrEntry); 740 if (!(value.size() == 1)) 741 { 742 return PLDM_ERROR_INVALID_LENGTH; 743 } 744 if (value[0] >= pvHdls.size()) 745 { 746 error("Enum: Illgeal index, Index = {ATTR_INDEX}", "ATTR_INDEX", 747 (int)value[0]); 748 return PLDM_ERROR_INVALID_DATA; 749 } 750 return PLDM_SUCCESS; 751 } 752 case PLDM_BIOS_INTEGER: 753 case PLDM_BIOS_INTEGER_READ_ONLY: 754 { 755 auto value = 756 table::attribute_value::decodeIntegerEntry(attrValueEntry); 757 auto [lower, upper, scalar, 758 def] = table::attribute::decodeIntegerEntry(attrEntry); 759 760 if (value < lower || value > upper) 761 { 762 error("Integer: out of bound, value = {ATTR_VALUE}", 763 "ATTR_VALUE", value); 764 return PLDM_ERROR_INVALID_DATA; 765 } 766 return PLDM_SUCCESS; 767 } 768 case PLDM_BIOS_STRING: 769 case PLDM_BIOS_STRING_READ_ONLY: 770 { 771 auto stringConf = table::attribute::decodeStringEntry(attrEntry); 772 auto value = 773 table::attribute_value::decodeStringEntry(attrValueEntry); 774 if (value.size() < stringConf.minLength || 775 value.size() > stringConf.maxLength) 776 { 777 error( 778 "String: Length error, string = {ATTR_VALUE} length {LEN}", 779 "ATTR_VALUE", value, "LEN", value.size()); 780 return PLDM_ERROR_INVALID_LENGTH; 781 } 782 return PLDM_SUCCESS; 783 } 784 default: 785 error("ReadOnly or Unspported type, type = {ATTR_TYPE}", 786 "ATTR_TYPE", attrType); 787 return PLDM_ERROR; 788 }; 789 } 790 791 int BIOSConfig::setAttrValue(const void* entry, size_t size, bool isBMC, 792 bool updateDBus, bool updateBaseBIOSTable) 793 { 794 auto attrValueTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 795 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 796 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 797 if (!attrValueTable || !attrTable || !stringTable) 798 { 799 return PLDM_BIOS_TABLE_UNAVAILABLE; 800 } 801 802 auto attrValueEntry = 803 reinterpret_cast<const pldm_bios_attr_val_table_entry*>(entry); 804 805 auto attrValHeader = table::attribute_value::decodeHeader(attrValueEntry); 806 807 auto attrEntry = table::attribute::findByHandle(*attrTable, 808 attrValHeader.attrHandle); 809 if (!attrEntry) 810 { 811 return PLDM_ERROR; 812 } 813 814 auto rc = checkAttrValueToUpdate(attrValueEntry, attrEntry, *stringTable); 815 if (rc != PLDM_SUCCESS) 816 { 817 return rc; 818 } 819 820 auto destTable = table::attribute_value::updateTable(*attrValueTable, entry, 821 size); 822 823 if (!destTable) 824 { 825 return PLDM_ERROR; 826 } 827 828 try 829 { 830 auto attrHeader = table::attribute::decodeHeader(attrEntry); 831 832 BIOSStringTable biosStringTable(*stringTable); 833 auto attrName = biosStringTable.findString(attrHeader.stringHandle); 834 auto iter = std::find_if(biosAttributes.begin(), biosAttributes.end(), 835 [&attrName](const auto& attr) { 836 return attr->name == attrName; 837 }); 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, 926 stringHdl] = 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, 1025 option] = 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, instanceIdDb, 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