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