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