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 Table attrTable, attrValueTable; 480 481 for (auto& attr : biosAttributes) 482 { 483 try 484 { 485 attr->constructEntry(biosStringTable, attrTable, attrValueTable); 486 } 487 catch (const std::exception& e) 488 { 489 std::cerr << "Construct Table Entry Error, AttributeName = " 490 << attr->name << std::endl; 491 } 492 } 493 494 table::appendPadAndChecksum(attrTable); 495 table::appendPadAndChecksum(attrValueTable); 496 setBIOSTable(PLDM_BIOS_ATTR_TABLE, attrTable); 497 setBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE, attrValueTable); 498 } 499 500 std::optional<Table> BIOSConfig::buildAndStoreStringTable() 501 { 502 std::set<std::string> strings; 503 auto handler = [&strings](const Json& entry) { 504 strings.emplace(entry.at("attribute_name")); 505 }; 506 507 load(jsonDir / stringJsonFile, handler); 508 load(jsonDir / integerJsonFile, handler); 509 load(jsonDir / enumJsonFile, [&strings](const Json& entry) { 510 strings.emplace(entry.at("attribute_name")); 511 auto possibleValues = entry.at("possible_values"); 512 for (auto& pv : possibleValues) 513 { 514 strings.emplace(pv); 515 } 516 }); 517 518 if (strings.empty()) 519 { 520 return std::nullopt; 521 } 522 523 Table table; 524 for (const auto& elem : strings) 525 { 526 table::string::constructEntry(table, elem); 527 } 528 529 table::appendPadAndChecksum(table); 530 setBIOSTable(PLDM_BIOS_STRING_TABLE, table); 531 return table; 532 } 533 534 void BIOSConfig::storeTable(const fs::path& path, const Table& table) 535 { 536 BIOSTable biosTable(path.c_str()); 537 biosTable.store(table); 538 } 539 540 std::optional<Table> BIOSConfig::loadTable(const fs::path& path) 541 { 542 BIOSTable biosTable(path.c_str()); 543 if (biosTable.isEmpty()) 544 { 545 return std::nullopt; 546 } 547 548 Table table; 549 biosTable.load(table); 550 return table; 551 } 552 553 void BIOSConfig::load(const fs::path& filePath, ParseHandler handler) 554 { 555 std::ifstream file; 556 Json jsonConf; 557 if (fs::exists(filePath)) 558 { 559 try 560 { 561 file.open(filePath); 562 jsonConf = Json::parse(file); 563 auto entries = jsonConf.at("entries"); 564 for (auto& entry : entries) 565 { 566 try 567 { 568 handler(entry); 569 } 570 catch (const std::exception& e) 571 { 572 std::cerr 573 << "Failed to parse JSON config file(entry handler) : " 574 << filePath.c_str() << ", " << e.what() << std::endl; 575 } 576 } 577 } 578 catch (const std::exception& e) 579 { 580 std::cerr << "Failed to parse JSON config file : " 581 << filePath.c_str() << std::endl; 582 } 583 } 584 } 585 586 int BIOSConfig::checkAttrValueToUpdate( 587 const pldm_bios_attr_val_table_entry* attrValueEntry, 588 const pldm_bios_attr_table_entry* attrEntry, Table&) 589 590 { 591 auto [attrHandle, attrType] = 592 table::attribute_value::decodeHeader(attrValueEntry); 593 594 switch (attrType) 595 { 596 case PLDM_BIOS_ENUMERATION: 597 { 598 auto value = 599 table::attribute_value::decodeEnumEntry(attrValueEntry); 600 auto [pvHdls, defIndex] = 601 table::attribute::decodeEnumEntry(attrEntry); 602 assert(value.size() == 1); 603 if (value[0] >= pvHdls.size()) 604 { 605 std::cerr << "Enum: Illgeal index, Index = " << (int)value[0] 606 << std::endl; 607 return PLDM_ERROR_INVALID_DATA; 608 } 609 610 return PLDM_SUCCESS; 611 } 612 case PLDM_BIOS_INTEGER: 613 { 614 auto value = 615 table::attribute_value::decodeIntegerEntry(attrValueEntry); 616 auto [lower, upper, scalar, def] = 617 table::attribute::decodeIntegerEntry(attrEntry); 618 619 if (value < lower || value > upper) 620 { 621 std::cerr << "Integer: out of bound, value = " << value 622 << std::endl; 623 return PLDM_ERROR_INVALID_DATA; 624 } 625 return PLDM_SUCCESS; 626 } 627 case PLDM_BIOS_STRING: 628 { 629 auto stringConf = table::attribute::decodeStringEntry(attrEntry); 630 auto value = 631 table::attribute_value::decodeStringEntry(attrValueEntry); 632 if (value.size() < stringConf.minLength || 633 value.size() > stringConf.maxLength) 634 { 635 std::cerr << "String: Length error, string = " << value 636 << " length = " << value.size() << std::endl; 637 return PLDM_ERROR_INVALID_LENGTH; 638 } 639 return PLDM_SUCCESS; 640 } 641 default: 642 std::cerr << "ReadOnly or Unspported type, type = " << attrType 643 << std::endl; 644 return PLDM_ERROR; 645 }; 646 } 647 648 int BIOSConfig::setAttrValue(const void* entry, size_t size, 649 bool updateBaseBIOSTable) 650 { 651 auto attrValueTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 652 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 653 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 654 if (!attrValueTable || !attrTable || !stringTable) 655 { 656 return PLDM_BIOS_TABLE_UNAVAILABLE; 657 } 658 659 auto attrValueEntry = 660 reinterpret_cast<const pldm_bios_attr_val_table_entry*>(entry); 661 662 auto attrValHeader = table::attribute_value::decodeHeader(attrValueEntry); 663 664 auto attrEntry = 665 table::attribute::findByHandle(*attrTable, attrValHeader.attrHandle); 666 if (!attrEntry) 667 { 668 return PLDM_ERROR; 669 } 670 671 auto rc = checkAttrValueToUpdate(attrValueEntry, attrEntry, *stringTable); 672 if (rc != PLDM_SUCCESS) 673 { 674 return rc; 675 } 676 677 auto destTable = 678 table::attribute_value::updateTable(*attrValueTable, entry, size); 679 680 if (!destTable) 681 { 682 return PLDM_ERROR; 683 } 684 685 try 686 { 687 auto attrHeader = table::attribute::decodeHeader(attrEntry); 688 689 BIOSStringTable biosStringTable(*stringTable); 690 auto attrName = biosStringTable.findString(attrHeader.stringHandle); 691 692 auto iter = std::find_if( 693 biosAttributes.begin(), biosAttributes.end(), 694 [&attrName](const auto& attr) { return attr->name == attrName; }); 695 696 if (iter == biosAttributes.end()) 697 { 698 return PLDM_ERROR; 699 } 700 (*iter)->setAttrValueOnDbus(attrValueEntry, attrEntry, biosStringTable); 701 } 702 catch (const std::exception& e) 703 { 704 std::cerr << "Set attribute value error: " << e.what() << std::endl; 705 return PLDM_ERROR; 706 } 707 708 setBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE, *destTable, updateBaseBIOSTable); 709 710 return PLDM_SUCCESS; 711 } 712 713 void BIOSConfig::removeTables() 714 { 715 try 716 { 717 fs::remove(tableDir / stringTableFile); 718 fs::remove(tableDir / attrTableFile); 719 fs::remove(tableDir / attrValueTableFile); 720 } 721 catch (const std::exception& e) 722 { 723 std::cerr << "Remove the tables error: " << e.what() << std::endl; 724 } 725 } 726 727 void BIOSConfig::processBiosAttrChangeNotification( 728 const DbusChObjProperties& chProperties, uint32_t biosAttrIndex) 729 { 730 const auto& dBusMap = biosAttributes[biosAttrIndex]->getDBusMap(); 731 const auto& propertyName = dBusMap->propertyName; 732 const auto& attrName = biosAttributes[biosAttrIndex]->name; 733 734 const auto it = chProperties.find(propertyName); 735 if (it == chProperties.end()) 736 { 737 return; 738 } 739 740 PropertyValue newPropVal = it->second; 741 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 742 if (!stringTable.has_value()) 743 { 744 std::cerr << "BIOS string table unavailable\n"; 745 return; 746 } 747 BIOSStringTable biosStringTable(*stringTable); 748 uint16_t attrNameHdl{}; 749 try 750 { 751 attrNameHdl = biosStringTable.findHandle(attrName); 752 } 753 catch (std::invalid_argument& e) 754 { 755 std::cerr << "Could not find handle for BIOS string, ATTRIBUTE=" 756 << attrName.c_str() << "\n"; 757 return; 758 } 759 760 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 761 if (!attrTable.has_value()) 762 { 763 std::cerr << "Attribute table not present\n"; 764 return; 765 } 766 const struct pldm_bios_attr_table_entry* tableEntry = 767 table::attribute::findByStringHandle(*attrTable, attrNameHdl); 768 if (tableEntry == nullptr) 769 { 770 std::cerr << "Attribute not found in attribute table, name= " 771 << attrName.c_str() << "name handle=" << attrNameHdl << "\n"; 772 return; 773 } 774 775 auto [attrHdl, attrType, stringHdl] = 776 table::attribute::decodeHeader(tableEntry); 777 778 auto attrValueSrcTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 779 780 if (!attrValueSrcTable.has_value()) 781 { 782 std::cerr << "Attribute value table not present\n"; 783 return; 784 } 785 786 Table newValue; 787 auto rc = biosAttributes[biosAttrIndex]->updateAttrVal( 788 newValue, attrHdl, attrType, newPropVal); 789 if (rc != PLDM_SUCCESS) 790 { 791 std::cerr << "Could not update the attribute value table for attribute " 792 "handle=" 793 << attrHdl << " and type=" << (uint32_t)attrType << "\n"; 794 return; 795 } 796 auto destTable = table::attribute_value::updateTable( 797 *attrValueSrcTable, newValue.data(), newValue.size()); 798 if (destTable.has_value()) 799 { 800 storeTable(tableDir / attrValueTableFile, *destTable); 801 } 802 } 803 804 uint16_t BIOSConfig::findAttrHandle(const std::string& attrName) 805 { 806 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 807 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 808 809 BIOSStringTable biosStringTable(*stringTable); 810 pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE> attrTableIter( 811 attrTable->data(), attrTable->size()); 812 auto stringHandle = biosStringTable.findHandle(attrName); 813 814 for (auto entry : pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE>( 815 attrTable->data(), attrTable->size())) 816 { 817 auto header = table::attribute::decodeHeader(entry); 818 if (header.stringHandle == stringHandle) 819 { 820 return header.attrHandle; 821 } 822 } 823 824 throw std::invalid_argument("Unknow attribute Name"); 825 } 826 827 void BIOSConfig::constructPendingAttribute( 828 const PendingAttributes& pendingAttributes) 829 { 830 std::vector<uint16_t> listOfHandles{}; 831 832 for (auto& attribute : pendingAttributes) 833 { 834 std::string attributeName = attribute.first; 835 auto& [attributeType, attributevalue] = attribute.second; 836 837 auto iter = std::find_if(biosAttributes.begin(), biosAttributes.end(), 838 [&attributeName](const auto& attr) { 839 return attr->name == attributeName; 840 }); 841 842 if (iter == biosAttributes.end()) 843 { 844 std::cerr << "Wrong attribute name, attributeName = " 845 << attributeName << std::endl; 846 continue; 847 } 848 849 Table attrValueEntry(sizeof(pldm_bios_attr_val_table_entry), 0); 850 auto entry = reinterpret_cast<pldm_bios_attr_val_table_entry*>( 851 attrValueEntry.data()); 852 853 auto handler = findAttrHandle(attributeName); 854 auto type = 855 BIOSConfigManager::convertAttributeTypeFromString(attributeType); 856 857 if (type != BIOSConfigManager::AttributeType::Enumeration && 858 type != BIOSConfigManager::AttributeType::String && 859 type != BIOSConfigManager::AttributeType::Integer) 860 { 861 std::cerr << "Attribute type not supported, attributeType = " 862 << attributeType << std::endl; 863 continue; 864 } 865 866 entry->attr_handle = htole16(handler); 867 listOfHandles.emplace_back(htole16(handler)); 868 869 (*iter)->generateAttributeEntry(attributevalue, attrValueEntry); 870 871 setAttrValue(attrValueEntry.data(), attrValueEntry.size(), false); 872 } 873 874 if (listOfHandles.size()) 875 { 876 #ifdef OEM_IBM 877 auto rc = pldm::responder::platform::sendBiosAttributeUpdateEvent( 878 fd, eid, requester, listOfHandles); 879 if (rc != PLDM_SUCCESS) 880 { 881 return; 882 } 883 #endif 884 updateBaseBIOSTableProperty(); 885 } 886 } 887 888 void BIOSConfig::listenPendingAttributes() 889 { 890 constexpr auto objPath = "/xyz/openbmc_project/bios_config/manager"; 891 constexpr auto objInterface = "xyz.openbmc_project.BIOSConfig.Manager"; 892 893 using namespace sdbusplus::bus::match::rules; 894 auto updateBIOSMatch = std::make_unique<sdbusplus::bus::match::match>( 895 pldm::utils::DBusHandler::getBus(), 896 propertiesChanged(objPath, objInterface), 897 [this](sdbusplus::message::message& msg) { 898 constexpr auto propertyName = "PendingAttributes"; 899 900 using Value = 901 std::variant<std::string, PendingAttributes, BaseBIOSTable>; 902 using Properties = std::map<DbusProp, Value>; 903 904 Properties props{}; 905 std::string intf; 906 msg.read(intf, props); 907 908 auto valPropMap = props.find(propertyName); 909 if (valPropMap == props.end()) 910 { 911 return; 912 } 913 914 PendingAttributes pendingAttributes = 915 std::get<PendingAttributes>(valPropMap->second); 916 this->constructPendingAttribute(pendingAttributes); 917 }); 918 919 biosAttrMatch.emplace_back(std::move(updateBIOSMatch)); 920 } 921 922 } // namespace bios 923 } // namespace responder 924 } // namespace pldm 925