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