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 case PLDM_BIOS_ENUMERATION_READ_ONLY: 640 { 641 auto value = 642 table::attribute_value::decodeEnumEntry(attrValueEntry); 643 auto [pvHdls, defIndex] = 644 table::attribute::decodeEnumEntry(attrEntry); 645 assert(value.size() == 1); 646 if (value[0] >= pvHdls.size()) 647 { 648 std::cerr << "Enum: Illgeal index, Index = " << (int)value[0] 649 << std::endl; 650 return PLDM_ERROR_INVALID_DATA; 651 } 652 653 return PLDM_SUCCESS; 654 } 655 case PLDM_BIOS_INTEGER: 656 case PLDM_BIOS_INTEGER_READ_ONLY: 657 { 658 auto value = 659 table::attribute_value::decodeIntegerEntry(attrValueEntry); 660 auto [lower, upper, scalar, def] = 661 table::attribute::decodeIntegerEntry(attrEntry); 662 663 if (value < lower || value > upper) 664 { 665 std::cerr << "Integer: out of bound, value = " << value 666 << std::endl; 667 return PLDM_ERROR_INVALID_DATA; 668 } 669 return PLDM_SUCCESS; 670 } 671 case PLDM_BIOS_STRING: 672 case PLDM_BIOS_STRING_READ_ONLY: 673 { 674 auto stringConf = table::attribute::decodeStringEntry(attrEntry); 675 auto value = 676 table::attribute_value::decodeStringEntry(attrValueEntry); 677 if (value.size() < stringConf.minLength || 678 value.size() > stringConf.maxLength) 679 { 680 std::cerr << "String: Length error, string = " << value 681 << " length = " << value.size() << std::endl; 682 return PLDM_ERROR_INVALID_LENGTH; 683 } 684 return PLDM_SUCCESS; 685 } 686 default: 687 std::cerr << "ReadOnly or Unspported type, type = " << attrType 688 << std::endl; 689 return PLDM_ERROR; 690 }; 691 } 692 693 int BIOSConfig::setAttrValue(const void* entry, size_t size, bool updateDBus, 694 bool updateBaseBIOSTable) 695 { 696 auto attrValueTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 697 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 698 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 699 if (!attrValueTable || !attrTable || !stringTable) 700 { 701 return PLDM_BIOS_TABLE_UNAVAILABLE; 702 } 703 704 auto attrValueEntry = 705 reinterpret_cast<const pldm_bios_attr_val_table_entry*>(entry); 706 707 auto attrValHeader = table::attribute_value::decodeHeader(attrValueEntry); 708 709 auto attrEntry = 710 table::attribute::findByHandle(*attrTable, attrValHeader.attrHandle); 711 if (!attrEntry) 712 { 713 return PLDM_ERROR; 714 } 715 716 auto rc = checkAttrValueToUpdate(attrValueEntry, attrEntry, *stringTable); 717 if (rc != PLDM_SUCCESS) 718 { 719 return rc; 720 } 721 722 auto destTable = 723 table::attribute_value::updateTable(*attrValueTable, entry, size); 724 725 if (!destTable) 726 { 727 return PLDM_ERROR; 728 } 729 730 try 731 { 732 auto attrHeader = table::attribute::decodeHeader(attrEntry); 733 734 BIOSStringTable biosStringTable(*stringTable); 735 auto attrName = biosStringTable.findString(attrHeader.stringHandle); 736 737 auto iter = std::find_if( 738 biosAttributes.begin(), biosAttributes.end(), 739 [&attrName](const auto& attr) { return attr->name == attrName; }); 740 741 if (iter == biosAttributes.end()) 742 { 743 return PLDM_ERROR; 744 } 745 if (updateDBus) 746 { 747 (*iter)->setAttrValueOnDbus(attrValueEntry, attrEntry, 748 biosStringTable); 749 } 750 } 751 catch (const std::exception& e) 752 { 753 std::cerr << "Set attribute value error: " << e.what() << std::endl; 754 return PLDM_ERROR; 755 } 756 757 setBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE, *destTable, updateBaseBIOSTable); 758 759 return PLDM_SUCCESS; 760 } 761 762 void BIOSConfig::removeTables() 763 { 764 try 765 { 766 fs::remove(tableDir / stringTableFile); 767 fs::remove(tableDir / attrTableFile); 768 fs::remove(tableDir / attrValueTableFile); 769 } 770 catch (const std::exception& e) 771 { 772 std::cerr << "Remove the tables error: " << e.what() << std::endl; 773 } 774 } 775 776 void BIOSConfig::processBiosAttrChangeNotification( 777 const DbusChObjProperties& chProperties, uint32_t biosAttrIndex) 778 { 779 const auto& dBusMap = biosAttributes[biosAttrIndex]->getDBusMap(); 780 const auto& propertyName = dBusMap->propertyName; 781 const auto& attrName = biosAttributes[biosAttrIndex]->name; 782 783 const auto it = chProperties.find(propertyName); 784 if (it == chProperties.end()) 785 { 786 return; 787 } 788 789 PropertyValue newPropVal = it->second; 790 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 791 if (!stringTable.has_value()) 792 { 793 std::cerr << "BIOS string table unavailable\n"; 794 return; 795 } 796 BIOSStringTable biosStringTable(*stringTable); 797 uint16_t attrNameHdl{}; 798 try 799 { 800 attrNameHdl = biosStringTable.findHandle(attrName); 801 } 802 catch (const std::invalid_argument& e) 803 { 804 std::cerr << "Could not find handle for BIOS string, ATTRIBUTE=" 805 << attrName.c_str() << "\n"; 806 return; 807 } 808 809 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 810 if (!attrTable.has_value()) 811 { 812 std::cerr << "Attribute table not present\n"; 813 return; 814 } 815 const struct pldm_bios_attr_table_entry* tableEntry = 816 table::attribute::findByStringHandle(*attrTable, attrNameHdl); 817 if (tableEntry == nullptr) 818 { 819 std::cerr << "Attribute not found in attribute table, name= " 820 << attrName.c_str() << "name handle=" << attrNameHdl << "\n"; 821 return; 822 } 823 824 auto [attrHdl, attrType, stringHdl] = 825 table::attribute::decodeHeader(tableEntry); 826 827 auto attrValueSrcTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 828 829 if (!attrValueSrcTable.has_value()) 830 { 831 std::cerr << "Attribute value table not present\n"; 832 return; 833 } 834 835 Table newValue; 836 auto rc = biosAttributes[biosAttrIndex]->updateAttrVal( 837 newValue, attrHdl, attrType, newPropVal); 838 if (rc != PLDM_SUCCESS) 839 { 840 std::cerr << "Could not update the attribute value table for attribute " 841 "handle=" 842 << attrHdl << " and type=" << (uint32_t)attrType << "\n"; 843 return; 844 } 845 auto destTable = table::attribute_value::updateTable( 846 *attrValueSrcTable, newValue.data(), newValue.size()); 847 if (destTable.has_value()) 848 { 849 storeTable(tableDir / attrValueTableFile, *destTable); 850 } 851 852 rc = setAttrValue(newValue.data(), newValue.size(), false); 853 if (rc != PLDM_SUCCESS) 854 { 855 std::cerr << "could not setAttrValue on base bios table and dbus, rc = " 856 << rc << "\n"; 857 } 858 } 859 860 uint16_t BIOSConfig::findAttrHandle(const std::string& attrName) 861 { 862 auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE); 863 auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE); 864 865 BIOSStringTable biosStringTable(*stringTable); 866 pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE> attrTableIter( 867 attrTable->data(), attrTable->size()); 868 auto stringHandle = biosStringTable.findHandle(attrName); 869 870 for (auto entry : pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE>( 871 attrTable->data(), attrTable->size())) 872 { 873 auto header = table::attribute::decodeHeader(entry); 874 if (header.stringHandle == stringHandle) 875 { 876 return header.attrHandle; 877 } 878 } 879 880 throw std::invalid_argument("Unknow attribute Name"); 881 } 882 883 void BIOSConfig::constructPendingAttribute( 884 const PendingAttributes& pendingAttributes) 885 { 886 std::vector<uint16_t> listOfHandles{}; 887 888 for (auto& attribute : pendingAttributes) 889 { 890 std::string attributeName = attribute.first; 891 auto& [attributeType, attributevalue] = attribute.second; 892 893 auto iter = std::find_if(biosAttributes.begin(), biosAttributes.end(), 894 [&attributeName](const auto& attr) { 895 return attr->name == attributeName; 896 }); 897 898 if (iter == biosAttributes.end()) 899 { 900 std::cerr << "Wrong attribute name, attributeName = " 901 << attributeName << std::endl; 902 continue; 903 } 904 905 Table attrValueEntry(sizeof(pldm_bios_attr_val_table_entry), 0); 906 auto entry = reinterpret_cast<pldm_bios_attr_val_table_entry*>( 907 attrValueEntry.data()); 908 909 auto handler = findAttrHandle(attributeName); 910 auto type = 911 BIOSConfigManager::convertAttributeTypeFromString(attributeType); 912 913 if (type != BIOSConfigManager::AttributeType::Enumeration && 914 type != BIOSConfigManager::AttributeType::String && 915 type != BIOSConfigManager::AttributeType::Integer) 916 { 917 std::cerr << "Attribute type not supported, attributeType = " 918 << attributeType << std::endl; 919 continue; 920 } 921 922 entry->attr_handle = htole16(handler); 923 listOfHandles.emplace_back(htole16(handler)); 924 925 (*iter)->generateAttributeEntry(attributevalue, attrValueEntry); 926 927 setAttrValue(attrValueEntry.data(), attrValueEntry.size()); 928 } 929 930 if (listOfHandles.size()) 931 { 932 #ifdef OEM_IBM 933 auto rc = pldm::responder::platform::sendBiosAttributeUpdateEvent( 934 eid, requester, listOfHandles, handler); 935 if (rc != PLDM_SUCCESS) 936 { 937 return; 938 } 939 #endif 940 } 941 } 942 943 void BIOSConfig::listenPendingAttributes() 944 { 945 constexpr auto objPath = "/xyz/openbmc_project/bios_config/manager"; 946 constexpr auto objInterface = "xyz.openbmc_project.BIOSConfig.Manager"; 947 948 using namespace sdbusplus::bus::match::rules; 949 auto updateBIOSMatch = std::make_unique<sdbusplus::bus::match::match>( 950 pldm::utils::DBusHandler::getBus(), 951 propertiesChanged(objPath, objInterface), 952 [this](sdbusplus::message::message& msg) { 953 constexpr auto propertyName = "PendingAttributes"; 954 955 using Value = 956 std::variant<std::string, PendingAttributes, BaseBIOSTable>; 957 using Properties = std::map<DbusProp, Value>; 958 959 Properties props{}; 960 std::string intf; 961 msg.read(intf, props); 962 963 auto valPropMap = props.find(propertyName); 964 if (valPropMap == props.end()) 965 { 966 return; 967 } 968 969 PendingAttributes pendingAttributes = 970 std::get<PendingAttributes>(valPropMap->second); 971 this->constructPendingAttribute(pendingAttributes); 972 }); 973 974 biosAttrMatch.emplace_back(std::move(updateBIOSMatch)); 975 } 976 977 } // namespace bios 978 } // namespace responder 979 } // namespace pldm 980