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 30 using BIOSConfigManager = 31 sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager; 32 33 constexpr auto enumJsonFile = "enum_attrs.json"; 34 constexpr auto stringJsonFile = "string_attrs.json"; 35 constexpr auto integerJsonFile = "integer_attrs.json"; 36 37 constexpr auto stringTableFile = "stringTable"; 38 constexpr auto attrTableFile = "attributeTable"; 39 constexpr auto attrValueTableFile = "attributeValueTable"; 40 41 } // namespace 42 43 BIOSConfig::BIOSConfig( 44 const char* jsonDir, const char* tableDir, DBusHandler* const dbusHandler, 45 int fd, uint8_t eid, dbus_api::Requester* requester, 46 pldm::requester::Handler<pldm::requester::Request>* handler) : 47 jsonDir(jsonDir), 48 tableDir(tableDir), dbusHandler(dbusHandler), fd(fd), eid(eid), 49 requester(requester), handler(handler) 50 51 { 52 fs::create_directories(tableDir); 53 constructAttributes(); 54 listenPendingAttributes(); 55 } 56 57 void BIOSConfig::buildTables() 58 { 59 auto stringTable = buildAndStoreStringTable(); 60 if (stringTable) 61 { 62 buildAndStoreAttrTables(*stringTable); 63 } 64 } 65 66 std::optional<Table> BIOSConfig::getBIOSTable(pldm_bios_table_types tableType) 67 { 68 fs::path tablePath; 69 switch (tableType) 70 { 71 case PLDM_BIOS_STRING_TABLE: 72 tablePath = tableDir / stringTableFile; 73 break; 74 case PLDM_BIOS_ATTR_TABLE: 75 tablePath = tableDir / attrTableFile; 76 break; 77 case PLDM_BIOS_ATTR_VAL_TABLE: 78 tablePath = tableDir / attrValueTableFile; 79 break; 80 } 81 return loadTable(tablePath); 82 } 83 84 int BIOSConfig::setBIOSTable(uint8_t tableType, const Table& table, 85 bool updateBaseBIOSTable) 86 { 87 fs::path stringTablePath(tableDir / stringTableFile); 88 fs::path attrTablePath(tableDir / attrTableFile); 89 fs::path attrValueTablePath(tableDir / attrValueTableFile); 90 91 if (!pldm_bios_table_checksum(table.data(), table.size())) 92 { 93 return PLDM_INVALID_BIOS_TABLE_DATA_INTEGRITY_CHECK; 94 } 95 96 if (tableType == PLDM_BIOS_STRING_TABLE) 97 { 98 storeTable(stringTablePath, table); 99 } 100 else if (tableType == PLDM_BIOS_ATTR_TABLE) 101 { 102 BIOSTable biosStringTable(stringTablePath.c_str()); 103 if (biosStringTable.isEmpty()) 104 { 105 return PLDM_INVALID_BIOS_TABLE_TYPE; 106 } 107 108 auto rc = checkAttributeTable(table); 109 if (rc != PLDM_SUCCESS) 110 { 111 return rc; 112 } 113 114 storeTable(attrTablePath, table); 115 } 116 else if (tableType == PLDM_BIOS_ATTR_VAL_TABLE) 117 { 118 BIOSTable biosStringTable(stringTablePath.c_str()); 119 BIOSTable biosStringValueTable(attrTablePath.c_str()); 120 if (biosStringTable.isEmpty() || biosStringValueTable.isEmpty()) 121 { 122 return PLDM_INVALID_BIOS_TABLE_TYPE; 123 } 124 125 auto rc = checkAttributeValueTable(table); 126 if (rc != PLDM_SUCCESS) 127 { 128 return rc; 129 } 130 131 storeTable(attrValueTablePath, table); 132 } 133 else 134 { 135 return PLDM_INVALID_BIOS_TABLE_TYPE; 136 } 137 138 if ((tableType == PLDM_BIOS_ATTR_VAL_TABLE) && updateBaseBIOSTable) 139 { 140 std::cout << "setBIOSTable:: updateBaseBIOSTableProperty() " 141 << "\n"; 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 std::cerr << "failed to update BaseBIOSTable property, ERROR=" 457 << e.what() << "\n"; 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 std::cerr << "Failed to read BaseBIOSTable property, ERROR=" << e.what() 506 << "\n"; 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 std::cerr << "Construct Table Entry Error, AttributeName = " 532 << attr->name << std::endl; 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 std::cerr 615 << "Failed to parse JSON config file(entry handler) : " 616 << filePath.c_str() << ", " << e.what() << std::endl; 617 } 618 } 619 } 620 catch (const std::exception& e) 621 { 622 std::cerr << "Failed to parse JSON config file : " 623 << filePath.c_str() << std::endl; 624 } 625 } 626 } 627 628 int BIOSConfig::checkAttrValueToUpdate( 629 const pldm_bios_attr_val_table_entry* attrValueEntry, 630 const pldm_bios_attr_table_entry* attrEntry, Table&) 631 632 { 633 auto [attrHandle, attrType] = 634 table::attribute_value::decodeHeader(attrValueEntry); 635 636 switch (attrType) 637 { 638 case PLDM_BIOS_ENUMERATION: 639 { 640 auto value = 641 table::attribute_value::decodeEnumEntry(attrValueEntry); 642 auto [pvHdls, defIndex] = 643 table::attribute::decodeEnumEntry(attrEntry); 644 assert(value.size() == 1); 645 if (value[0] >= pvHdls.size()) 646 { 647 std::cerr << "Enum: Illgeal index, Index = " << (int)value[0] 648 << std::endl; 649 return PLDM_ERROR_INVALID_DATA; 650 } 651 652 return PLDM_SUCCESS; 653 } 654 case PLDM_BIOS_INTEGER: 655 { 656 auto value = 657 table::attribute_value::decodeIntegerEntry(attrValueEntry); 658 auto [lower, upper, scalar, def] = 659 table::attribute::decodeIntegerEntry(attrEntry); 660 661 if (value < lower || value > upper) 662 { 663 std::cerr << "Integer: out of bound, value = " << value 664 << std::endl; 665 return PLDM_ERROR_INVALID_DATA; 666 } 667 return PLDM_SUCCESS; 668 } 669 case PLDM_BIOS_STRING: 670 { 671 auto stringConf = table::attribute::decodeStringEntry(attrEntry); 672 auto value = 673 table::attribute_value::decodeStringEntry(attrValueEntry); 674 if (value.size() < stringConf.minLength || 675 value.size() > stringConf.maxLength) 676 { 677 std::cerr << "String: Length error, string = " << value 678 << " length = " << value.size() << std::endl; 679 return PLDM_ERROR_INVALID_LENGTH; 680 } 681 return PLDM_SUCCESS; 682 } 683 default: 684 std::cerr << "ReadOnly or Unspported type, type = " << attrType 685 << std::endl; 686 return PLDM_ERROR; 687 }; 688 } 689 690 int BIOSConfig::setAttrValue(const void* entry, size_t size, bool updateDBus, 691 bool updateBaseBIOSTable) 692 { 693 auto attrValueTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 694 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 695 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 696 if (!attrValueTable || !attrTable || !stringTable) 697 { 698 return PLDM_BIOS_TABLE_UNAVAILABLE; 699 } 700 701 auto attrValueEntry = 702 reinterpret_cast<const pldm_bios_attr_val_table_entry*>(entry); 703 704 auto attrValHeader = table::attribute_value::decodeHeader(attrValueEntry); 705 706 auto attrEntry = 707 table::attribute::findByHandle(*attrTable, attrValHeader.attrHandle); 708 if (!attrEntry) 709 { 710 return PLDM_ERROR; 711 } 712 713 auto rc = checkAttrValueToUpdate(attrValueEntry, attrEntry, *stringTable); 714 if (rc != PLDM_SUCCESS) 715 { 716 return rc; 717 } 718 719 auto destTable = 720 table::attribute_value::updateTable(*attrValueTable, entry, size); 721 722 if (!destTable) 723 { 724 return PLDM_ERROR; 725 } 726 727 try 728 { 729 auto attrHeader = table::attribute::decodeHeader(attrEntry); 730 731 BIOSStringTable biosStringTable(*stringTable); 732 auto attrName = biosStringTable.findString(attrHeader.stringHandle); 733 734 auto iter = std::find_if( 735 biosAttributes.begin(), biosAttributes.end(), 736 [&attrName](const auto& attr) { return attr->name == attrName; }); 737 738 if (iter == biosAttributes.end()) 739 { 740 return PLDM_ERROR; 741 } 742 if (updateDBus) 743 { 744 (*iter)->setAttrValueOnDbus(attrValueEntry, attrEntry, 745 biosStringTable); 746 } 747 } 748 catch (const std::exception& e) 749 { 750 std::cerr << "Set attribute value error: " << e.what() << std::endl; 751 return PLDM_ERROR; 752 } 753 754 setBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE, *destTable, updateBaseBIOSTable); 755 756 return PLDM_SUCCESS; 757 } 758 759 void BIOSConfig::removeTables() 760 { 761 try 762 { 763 fs::remove(tableDir / stringTableFile); 764 fs::remove(tableDir / attrTableFile); 765 fs::remove(tableDir / attrValueTableFile); 766 } 767 catch (const std::exception& e) 768 { 769 std::cerr << "Remove the tables error: " << e.what() << std::endl; 770 } 771 } 772 773 void BIOSConfig::processBiosAttrChangeNotification( 774 const DbusChObjProperties& chProperties, uint32_t biosAttrIndex) 775 { 776 const auto& dBusMap = biosAttributes[biosAttrIndex]->getDBusMap(); 777 const auto& propertyName = dBusMap->propertyName; 778 const auto& attrName = biosAttributes[biosAttrIndex]->name; 779 780 const auto it = chProperties.find(propertyName); 781 if (it == chProperties.end()) 782 { 783 return; 784 } 785 786 PropertyValue newPropVal = it->second; 787 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 788 if (!stringTable.has_value()) 789 { 790 std::cerr << "BIOS string table unavailable\n"; 791 return; 792 } 793 BIOSStringTable biosStringTable(*stringTable); 794 uint16_t attrNameHdl{}; 795 try 796 { 797 attrNameHdl = biosStringTable.findHandle(attrName); 798 } 799 catch (std::invalid_argument& e) 800 { 801 std::cerr << "Could not find handle for BIOS string, ATTRIBUTE=" 802 << attrName.c_str() << "\n"; 803 return; 804 } 805 806 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 807 if (!attrTable.has_value()) 808 { 809 std::cerr << "Attribute table not present\n"; 810 return; 811 } 812 const struct pldm_bios_attr_table_entry* tableEntry = 813 table::attribute::findByStringHandle(*attrTable, attrNameHdl); 814 if (tableEntry == nullptr) 815 { 816 std::cerr << "Attribute not found in attribute table, name= " 817 << attrName.c_str() << "name handle=" << attrNameHdl << "\n"; 818 return; 819 } 820 821 auto [attrHdl, attrType, stringHdl] = 822 table::attribute::decodeHeader(tableEntry); 823 824 auto attrValueSrcTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 825 826 if (!attrValueSrcTable.has_value()) 827 { 828 std::cerr << "Attribute value table not present\n"; 829 return; 830 } 831 832 Table newValue; 833 auto rc = biosAttributes[biosAttrIndex]->updateAttrVal( 834 newValue, attrHdl, attrType, newPropVal); 835 if (rc != PLDM_SUCCESS) 836 { 837 std::cerr << "Could not update the attribute value table for attribute " 838 "handle=" 839 << attrHdl << " and type=" << (uint32_t)attrType << "\n"; 840 return; 841 } 842 auto destTable = table::attribute_value::updateTable( 843 *attrValueSrcTable, newValue.data(), newValue.size()); 844 if (destTable.has_value()) 845 { 846 storeTable(tableDir / attrValueTableFile, *destTable); 847 } 848 849 rc = setAttrValue(newValue.data(), newValue.size(), false); 850 if (rc != PLDM_SUCCESS) 851 { 852 std::cerr << "could not setAttrValue on base bios table and dbus, rc = " 853 << rc << "\n"; 854 } 855 } 856 857 uint16_t BIOSConfig::findAttrHandle(const std::string& attrName) 858 { 859 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 860 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 861 862 BIOSStringTable biosStringTable(*stringTable); 863 pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE> attrTableIter( 864 attrTable->data(), attrTable->size()); 865 auto stringHandle = biosStringTable.findHandle(attrName); 866 867 for (auto entry : pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE>( 868 attrTable->data(), attrTable->size())) 869 { 870 auto header = table::attribute::decodeHeader(entry); 871 if (header.stringHandle == stringHandle) 872 { 873 return header.attrHandle; 874 } 875 } 876 877 throw std::invalid_argument("Unknow attribute Name"); 878 } 879 880 void BIOSConfig::constructPendingAttribute( 881 const PendingAttributes& pendingAttributes) 882 { 883 std::vector<uint16_t> listOfHandles{}; 884 885 for (auto& attribute : pendingAttributes) 886 { 887 std::string attributeName = attribute.first; 888 auto& [attributeType, attributevalue] = attribute.second; 889 890 auto iter = std::find_if(biosAttributes.begin(), biosAttributes.end(), 891 [&attributeName](const auto& attr) { 892 return attr->name == attributeName; 893 }); 894 895 if (iter == biosAttributes.end()) 896 { 897 std::cerr << "Wrong attribute name, attributeName = " 898 << attributeName << std::endl; 899 continue; 900 } 901 902 Table attrValueEntry(sizeof(pldm_bios_attr_val_table_entry), 0); 903 auto entry = reinterpret_cast<pldm_bios_attr_val_table_entry*>( 904 attrValueEntry.data()); 905 906 auto handler = findAttrHandle(attributeName); 907 auto type = 908 BIOSConfigManager::convertAttributeTypeFromString(attributeType); 909 910 if (type != BIOSConfigManager::AttributeType::Enumeration && 911 type != BIOSConfigManager::AttributeType::String && 912 type != BIOSConfigManager::AttributeType::Integer) 913 { 914 std::cerr << "Attribute type not supported, attributeType = " 915 << attributeType << std::endl; 916 continue; 917 } 918 919 entry->attr_handle = htole16(handler); 920 listOfHandles.emplace_back(htole16(handler)); 921 922 (*iter)->generateAttributeEntry(attributevalue, attrValueEntry); 923 924 setAttrValue(attrValueEntry.data(), attrValueEntry.size()); 925 } 926 927 if (listOfHandles.size()) 928 { 929 #ifdef OEM_IBM 930 auto rc = pldm::responder::platform::sendBiosAttributeUpdateEvent( 931 eid, requester, listOfHandles, handler); 932 if (rc != PLDM_SUCCESS) 933 { 934 return; 935 } 936 #endif 937 } 938 } 939 940 void BIOSConfig::listenPendingAttributes() 941 { 942 constexpr auto objPath = "/xyz/openbmc_project/bios_config/manager"; 943 constexpr auto objInterface = "xyz.openbmc_project.BIOSConfig.Manager"; 944 945 using namespace sdbusplus::bus::match::rules; 946 auto updateBIOSMatch = std::make_unique<sdbusplus::bus::match::match>( 947 pldm::utils::DBusHandler::getBus(), 948 propertiesChanged(objPath, objInterface), 949 [this](sdbusplus::message::message& msg) { 950 constexpr auto propertyName = "PendingAttributes"; 951 952 using Value = 953 std::variant<std::string, PendingAttributes, BaseBIOSTable>; 954 using Properties = std::map<DbusProp, Value>; 955 956 Properties props{}; 957 std::string intf; 958 msg.read(intf, props); 959 960 auto valPropMap = props.find(propertyName); 961 if (valPropMap == props.end()) 962 { 963 return; 964 } 965 966 PendingAttributes pendingAttributes = 967 std::get<PendingAttributes>(valPropMap->second); 968 this->constructPendingAttribute(pendingAttributes); 969 }); 970 971 biosAttrMatch.emplace_back(std::move(updateBIOSMatch)); 972 } 973 974 } // namespace bios 975 } // namespace responder 976 } // namespace pldm 977