1 #include "bios.hpp" 2 3 #include "libpldmresponder/utils.hpp" 4 #include "xyz/openbmc_project/Common/error.hpp" 5 6 #include <array> 7 #include <boost/crc.hpp> 8 #include <chrono> 9 #include <ctime> 10 #include <filesystem> 11 #include <iostream> 12 #include <memory> 13 #include <numeric> 14 #include <stdexcept> 15 #include <string> 16 #include <variant> 17 #include <vector> 18 19 namespace fs = std::filesystem; 20 using namespace pldm::responder::bios; 21 using namespace bios_parser; 22 23 constexpr auto stringTableFile = "stringTable"; 24 constexpr auto attrTableFile = "attributeTable"; 25 constexpr auto attrValTableFile = "attributeValueTable"; 26 27 namespace pldm 28 { 29 30 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 31 using EpochTimeUS = uint64_t; 32 using BIOSTableRow = std::vector<uint8_t>; 33 using BIOSJsonName = std::string; 34 35 constexpr auto dbusProperties = "org.freedesktop.DBus.Properties"; 36 constexpr auto padChksumMax = 7; 37 38 namespace responder 39 { 40 41 namespace utils 42 { 43 44 void epochToBCDTime(uint64_t timeSec, uint8_t& seconds, uint8_t& minutes, 45 uint8_t& hours, uint8_t& day, uint8_t& month, 46 uint16_t& year) 47 { 48 auto t = time_t(timeSec); 49 auto time = localtime(&t); 50 51 seconds = decimalToBcd(time->tm_sec); 52 minutes = decimalToBcd(time->tm_min); 53 hours = decimalToBcd(time->tm_hour); 54 day = decimalToBcd(time->tm_mday); 55 month = 56 decimalToBcd(time->tm_mon + 1); // The number of months in the range 57 // 0 to 11.PLDM expects range 1 to 12 58 year = decimalToBcd(time->tm_year + 1900); // The number of years since 1900 59 } 60 61 size_t getTableTotalsize(size_t sizeWithoutPad) 62 { 63 return sizeWithoutPad + pldm_bios_table_pad_checksum_size(sizeWithoutPad); 64 } 65 66 void padAndChecksum(Table& table) 67 { 68 auto sizeWithoutPad = table.size(); 69 auto padAndChecksumSize = pldm_bios_table_pad_checksum_size(sizeWithoutPad); 70 table.resize(table.size() + padAndChecksumSize); 71 72 pldm_bios_table_append_pad_checksum(table.data(), table.size(), 73 sizeWithoutPad); 74 } 75 76 } // namespace utils 77 78 namespace bios 79 { 80 81 Handler::Handler() 82 { 83 try 84 { 85 fs::remove( 86 fs::path(std::string(BIOS_TABLES_DIR) + "/" + stringTableFile)); 87 fs::remove( 88 fs::path(std::string(BIOS_TABLES_DIR) + "/" + attrTableFile)); 89 fs::remove( 90 fs::path(std::string(BIOS_TABLES_DIR) + "/" + attrValTableFile)); 91 } 92 catch (const std::exception& e) 93 { 94 } 95 96 handlers.emplace(PLDM_GET_DATE_TIME, 97 [this](const pldm_msg* request, size_t payloadLength) { 98 return this->getDateTime(request, payloadLength); 99 }); 100 handlers.emplace(PLDM_GET_BIOS_TABLE, 101 [this](const pldm_msg* request, size_t payloadLength) { 102 return this->getBIOSTable(request, payloadLength); 103 }); 104 handlers.emplace(PLDM_GET_BIOS_ATTRIBUTE_CURRENT_VALUE_BY_HANDLE, 105 [this](const pldm_msg* request, size_t payloadLength) { 106 return this->getBIOSAttributeCurrentValueByHandle( 107 request, payloadLength); 108 }); 109 } 110 111 Response Handler::getDateTime(const pldm_msg* request, size_t /*payloadLength*/) 112 { 113 uint8_t seconds = 0; 114 uint8_t minutes = 0; 115 uint8_t hours = 0; 116 uint8_t day = 0; 117 uint8_t month = 0; 118 uint16_t year = 0; 119 120 constexpr auto timeInterface = "xyz.openbmc_project.Time.EpochTime"; 121 constexpr auto hostTimePath = "/xyz/openbmc_project/time/host"; 122 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_DATE_TIME_RESP_BYTES, 0); 123 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 124 std::variant<EpochTimeUS> value; 125 126 auto bus = sdbusplus::bus::new_default(); 127 try 128 { 129 auto service = getService(bus, hostTimePath, timeInterface); 130 131 auto method = bus.new_method_call(service.c_str(), hostTimePath, 132 dbusProperties, "Get"); 133 method.append(timeInterface, "Elapsed"); 134 135 auto reply = bus.call(method); 136 reply.read(value); 137 } 138 139 catch (std::exception& e) 140 { 141 std::cerr << "Error getting time, PATH=" << hostTimePath 142 << " TIME INTERACE=" << timeInterface << "\n"; 143 144 encode_get_date_time_resp(request->hdr.instance_id, PLDM_ERROR, seconds, 145 minutes, hours, day, month, year, 146 responsePtr); 147 return response; 148 } 149 150 uint64_t timeUsec = std::get<EpochTimeUS>(value); 151 152 uint64_t timeSec = std::chrono::duration_cast<std::chrono::seconds>( 153 std::chrono::microseconds(timeUsec)) 154 .count(); 155 156 pldm::responder::utils::epochToBCDTime(timeSec, seconds, minutes, hours, 157 day, month, year); 158 159 encode_get_date_time_resp(request->hdr.instance_id, PLDM_SUCCESS, seconds, 160 minutes, hours, day, month, year, responsePtr); 161 return response; 162 } 163 164 /** @brief Construct the BIOS string table 165 * 166 * @param[in] BIOSStringTable - the string table 167 * @param[in] transferHandle - transfer handle to identify part of transfer 168 * @param[in] transferOpFlag - flag to indicate which part of data being 169 * transferred 170 * @param[in] instanceID - instance ID to identify the command 171 */ 172 Response getBIOSStringTable(BIOSTable& BIOSStringTable, 173 uint32_t /*transferHandle*/, 174 uint8_t /*transferOpFlag*/, uint8_t instanceID) 175 176 { 177 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES, 178 0); 179 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 180 if (!BIOSStringTable.isEmpty()) 181 { 182 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, 183 0, /* next transfer handle */ 184 PLDM_START_AND_END, nullptr, response.size(), 185 responsePtr); // filling up the header here 186 BIOSStringTable.load(response); 187 return response; 188 } 189 auto biosStrings = bios_parser::getStrings(); 190 std::sort(biosStrings.begin(), biosStrings.end()); 191 // remove all duplicate strings received from bios json 192 biosStrings.erase(std::unique(biosStrings.begin(), biosStrings.end()), 193 biosStrings.end()); 194 195 size_t sizeWithoutPad = std::accumulate( 196 biosStrings.begin(), biosStrings.end(), 0, 197 [](size_t sum, const std::string& elem) { 198 return sum + 199 pldm_bios_table_string_entry_encode_length(elem.length()); 200 }); 201 202 Table stringTable; 203 stringTable.reserve( 204 pldm::responder::utils::getTableTotalsize(sizeWithoutPad)); 205 206 stringTable.resize(sizeWithoutPad); 207 auto tablePtr = stringTable.data(); 208 for (const auto& elem : biosStrings) 209 { 210 auto entry_length = 211 pldm_bios_table_string_entry_encode_length(elem.length()); 212 pldm_bios_table_string_entry_encode(tablePtr, sizeWithoutPad, 213 elem.c_str(), elem.length()); 214 tablePtr += entry_length; 215 sizeWithoutPad -= entry_length; 216 } 217 218 pldm::responder::utils::padAndChecksum(stringTable); 219 BIOSStringTable.store(stringTable); 220 response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES + 221 stringTable.size(), 222 0); 223 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 224 encode_get_bios_table_resp( 225 instanceID, PLDM_SUCCESS, 0 /* nxtTransferHandle */, PLDM_START_AND_END, 226 stringTable.data(), response.size(), responsePtr); 227 return response; 228 } 229 230 /** @brief Find the string handle from the BIOS string table given the name 231 * 232 * @param[in] name - name of the BIOS string 233 * @param[in] BIOSStringTable - the string table 234 * @return - uint16_t - handle of the string 235 */ 236 StringHandle findStringHandle(const std::string& name, 237 const BIOSTable& BIOSStringTable) 238 { 239 Table table; 240 BIOSStringTable.load(table); 241 auto stringEntry = pldm_bios_table_string_find_by_string( 242 table.data(), table.size(), name.c_str()); 243 if (stringEntry == nullptr) 244 { 245 std::cerr << "Reached end of BIOS string table,did not find the " 246 << "handle for the string, STRING=" << name.c_str() << "\n"; 247 throw InternalFailure(); 248 } 249 250 return pldm_bios_table_string_entry_decode_handle(stringEntry); 251 } 252 253 /** @brief Find the string name from the BIOS string table for a string handle 254 * 255 * @param[in] stringHdl - string handle 256 * @param[in] BIOSStringTable - the string table 257 * 258 * @return - std::string - name of the corresponding BIOS string 259 */ 260 std::string findStringName(StringHandle stringHdl, 261 const BIOSTable& BIOSStringTable) 262 { 263 Table table; 264 BIOSStringTable.load(table); 265 auto stringEntry = pldm_bios_table_string_find_by_handle( 266 table.data(), table.size(), stringHdl); 267 std::string name; 268 if (stringEntry == nullptr) 269 { 270 std::cerr << "Reached end of BIOS string table,did not find " 271 << "string name for handle, STRING_HANDLE=" << stringHdl 272 << "\n"; 273 } 274 auto strLength = 275 pldm_bios_table_string_entry_decode_string_length(stringEntry); 276 name.resize(strLength); 277 pldm_bios_table_string_entry_decode_string(stringEntry, name.data(), 278 name.size()); 279 return name; 280 } 281 282 namespace bios_type_enum 283 { 284 285 using namespace bios_parser::bios_enum; 286 287 /** @brief Find the indices into the array of the possible values of string 288 * handles for the current values.This is used in attribute value table 289 * 290 * @param[in] possiVals - vector of string handles comprising all the possible 291 * values for an attribute 292 * @param[in] currVals - vector of strings comprising all current values 293 * for an attribute 294 * @param[in] BIOSStringTable - the string table 295 * 296 * @return - std::vector<uint8_t> - indices into the array of the possible 297 * values of string handles 298 */ 299 std::vector<uint8_t> findStrIndices(PossibleValuesByHandle possiVals, 300 CurrentValues currVals, 301 const BIOSTable& BIOSStringTable) 302 { 303 std::vector<uint8_t> stringIndices; 304 305 for (const auto& currVal : currVals) 306 { 307 StringHandle curHdl; 308 try 309 { 310 curHdl = findStringHandle(currVal, BIOSStringTable); 311 } 312 catch (InternalFailure& e) 313 { 314 std::cerr << "Exception fetching handle for the string, STRING=" 315 << currVal.c_str() << "\n"; 316 continue; 317 } 318 319 uint8_t i = 0; 320 for (auto possiHdl : possiVals) 321 { 322 if (possiHdl == curHdl) 323 { 324 stringIndices.push_back(i); 325 break; 326 } 327 i++; 328 } 329 } 330 return stringIndices; 331 } 332 333 /** @brief Find the indices into the array of the possible values of string 334 * handles for the default values. This is used in attribute table 335 * 336 * @param[in] possiVals - vector of strings comprising all the possible values 337 * for an attribute 338 * @param[in] defVals - vector of strings comprising all the default values 339 * for an attribute 340 * @return - std::vector<uint8_t> - indices into the array of the possible 341 * values of string 342 */ 343 std::vector<uint8_t> findDefaultValHandle(const PossibleValues& possiVals, 344 const DefaultValues& defVals) 345 { 346 std::vector<uint8_t> defHdls; 347 for (const auto& defs : defVals) 348 { 349 auto index = std::lower_bound(possiVals.begin(), possiVals.end(), defs); 350 if (index != possiVals.end()) 351 { 352 defHdls.push_back(index - possiVals.begin()); 353 } 354 } 355 356 return defHdls; 357 } 358 359 /** @brief Construct the attibute table for BIOS type Enumeration and 360 * Enumeration ReadOnly 361 * @param[in] BIOSStringTable - the string table 362 * @param[in] biosJsonDir - path where the BIOS json files are present 363 * @param[in,out] attributeTable - the attribute table 364 * 365 */ 366 void constructAttrTable(const BIOSTable& BIOSStringTable, Table& attributeTable) 367 { 368 const auto& attributeMap = getValues(); 369 StringHandle strHandle; 370 371 for (const auto& [key, value] : attributeMap) 372 { 373 try 374 { 375 strHandle = findStringHandle(key, BIOSStringTable); 376 } 377 catch (InternalFailure& e) 378 { 379 std::cerr << "Could not find handle for BIOS string, ATTRIBUTE=" 380 << key.c_str() << "\n"; 381 continue; 382 } 383 bool readOnly = (std::get<0>(value)); 384 PossibleValues possiVals = std::get<1>(value); 385 DefaultValues defVals = std::get<2>(value); 386 // both the possible and default values are stored in sorted manner to 387 // ease in fetching back/comparison 388 std::sort(possiVals.begin(), possiVals.end()); 389 std::sort(defVals.begin(), defVals.end()); 390 391 std::vector<StringHandle> possiValsByHdl; 392 for (const auto& elem : possiVals) 393 { 394 try 395 { 396 auto hdl = findStringHandle(elem, BIOSStringTable); 397 possiValsByHdl.push_back(std::move(hdl)); 398 } 399 catch (InternalFailure& e) 400 { 401 std::cerr << "Could not find handle for BIOS string, STRING=" 402 << elem.c_str() << "\n"; 403 continue; 404 } 405 } 406 auto defValsByHdl = findDefaultValHandle(possiVals, defVals); 407 auto entryLength = pldm_bios_table_attr_entry_enum_encode_length( 408 possiValsByHdl.size(), defValsByHdl.size()); 409 410 auto attrTableSize = attributeTable.size(); 411 attributeTable.resize(attrTableSize + entryLength, 0); 412 struct pldm_bios_table_attr_entry_enum_info info = { 413 strHandle, 414 readOnly, 415 (uint8_t)possiValsByHdl.size(), 416 possiValsByHdl.data(), 417 (uint8_t)defValsByHdl.size(), 418 defValsByHdl.data(), 419 }; 420 pldm_bios_table_attr_entry_enum_encode( 421 attributeTable.data() + attrTableSize, entryLength, &info); 422 } 423 } 424 425 void constructAttrValueEntry( 426 const struct pldm_bios_attr_table_entry* attrTableEntry, 427 const std::string& attrName, const BIOSTable& BIOSStringTable, 428 Table& attrValueTable) 429 { 430 CurrentValues currVals; 431 try 432 { 433 currVals = getAttrValue(attrName); 434 } 435 catch (const std::exception& e) 436 { 437 std::cerr << "getAttrValue returned error for attribute, NAME=" 438 << attrName.c_str() << " ERROR=" << e.what() << "\n"; 439 return; 440 } 441 uint8_t pv_num = 442 pldm_bios_table_attr_entry_enum_decode_pv_num(attrTableEntry); 443 PossibleValuesByHandle pvHdls(pv_num, 0); 444 pldm_bios_table_attr_entry_enum_decode_pv_hdls(attrTableEntry, 445 pvHdls.data(), pv_num); 446 std::sort(currVals.begin(), currVals.end()); 447 448 auto currValStrIndices = findStrIndices(pvHdls, currVals, BIOSStringTable); 449 450 auto entryLength = pldm_bios_table_attr_value_entry_encode_enum_length( 451 currValStrIndices.size()); 452 auto tableSize = attrValueTable.size(); 453 attrValueTable.resize(tableSize + entryLength); 454 pldm_bios_table_attr_value_entry_encode_enum( 455 attrValueTable.data() + tableSize, entryLength, 456 attrTableEntry->attr_handle, attrTableEntry->attr_type, 457 currValStrIndices.size(), currValStrIndices.data()); 458 } 459 460 } // end namespace bios_type_enum 461 462 namespace bios_type_string 463 { 464 465 using namespace bios_parser::bios_string; 466 467 /** @brief Construct the attibute table for BIOS type String and 468 * String ReadOnly 469 * @param[in] BIOSStringTable - the string table 470 * @param[in] biosJsonDir - path where the BIOS json files are present 471 * @param[in,out] attributeTable - the attribute table 472 * 473 */ 474 void constructAttrTable(const BIOSTable& BIOSStringTable, Table& attributeTable) 475 { 476 const auto& attributeMap = getValues(); 477 StringHandle strHandle; 478 for (const auto& [key, value] : attributeMap) 479 { 480 try 481 { 482 strHandle = findStringHandle(key, BIOSStringTable); 483 } 484 catch (InternalFailure& e) 485 { 486 std::cerr << "Could not find handle for BIOS string, ATTRIBUTE=" 487 << key.c_str() << "\n"; 488 continue; 489 } 490 491 const auto& [readOnly, strType, minStrLen, maxStrLen, defaultStrLen, 492 defaultStr] = value; 493 auto entryLength = 494 pldm_bios_table_attr_entry_string_encode_length(defaultStrLen); 495 496 struct pldm_bios_table_attr_entry_string_info info = { 497 strHandle, readOnly, strType, minStrLen, 498 maxStrLen, defaultStrLen, defaultStr.data(), 499 }; 500 auto attrTableSize = attributeTable.size(); 501 attributeTable.resize(attrTableSize + entryLength, 0); 502 pldm_bios_table_attr_entry_string_encode( 503 attributeTable.data() + attrTableSize, entryLength, &info); 504 } 505 } 506 507 void constructAttrValueEntry(const pldm_bios_attr_table_entry* attrTableEntry, 508 const std::string& attrName, 509 const BIOSTable& BIOSStringTable, 510 Table& attrValueTable) 511 { 512 std::ignore = BIOSStringTable; 513 std::string currStr; 514 uint16_t currStrLen = 0; 515 try 516 { 517 currStr = getAttrValue(attrName); 518 currStrLen = currStr.size(); 519 } 520 catch (const std::exception& e) 521 { 522 std::cerr << "getAttrValue returned error for attribute, NAME=" 523 << attrName.c_str() << " ERROR=" << e.what() << "\n"; 524 return; 525 } 526 auto entryLength = 527 pldm_bios_table_attr_value_entry_encode_string_length(currStrLen); 528 auto tableSize = attrValueTable.size(); 529 attrValueTable.resize(tableSize + entryLength); 530 pldm_bios_table_attr_value_entry_encode_string( 531 attrValueTable.data() + tableSize, entryLength, 532 attrTableEntry->attr_handle, attrTableEntry->attr_type, currStrLen, 533 currStr.c_str()); 534 } 535 536 } // end namespace bios_type_string 537 538 namespace bios_type_integer 539 { 540 541 using namespace bios_parser::bios_integer; 542 543 /** @brief Construct the attibute table for BIOS type Integer and 544 * Integer ReadOnly 545 * @param[in] BIOSStringTable - the string table 546 * @param[in,out] attributeTable - the attribute table 547 * 548 */ 549 void constructAttrTable(const BIOSTable& BIOSStringTable, Table& attributeTable) 550 { 551 const auto& attributeMap = getValues(); 552 StringHandle strHandle; 553 for (const auto& [key, value] : attributeMap) 554 { 555 try 556 { 557 strHandle = findStringHandle(key, BIOSStringTable); 558 } 559 catch (InternalFailure& e) 560 { 561 std::cerr << "Could not find handle for BIOS string, ATTRIBUTE=" 562 << key.c_str() << "\n"; 563 continue; 564 } 565 566 const auto& [readOnly, lowerBound, upperBound, scalarIncrement, 567 defaultValue] = value; 568 auto entryLength = pldm_bios_table_attr_entry_integer_encode_length(); 569 570 struct pldm_bios_table_attr_entry_integer_info info = { 571 strHandle, readOnly, lowerBound, 572 upperBound, scalarIncrement, defaultValue, 573 }; 574 auto attrTableSize = attributeTable.size(); 575 attributeTable.resize(attrTableSize + entryLength, 0); 576 pldm_bios_table_attr_entry_integer_encode( 577 attributeTable.data() + attrTableSize, entryLength, &info); 578 } 579 } 580 581 void constructAttrValueEntry(const pldm_bios_attr_table_entry* attrTableEntry, 582 const std::string& attrName, 583 const BIOSTable& BIOSStringTable, 584 Table& attrValueTable) 585 { 586 std::ignore = BIOSStringTable; 587 uint64_t currentValue; 588 try 589 { 590 currentValue = getAttrValue(attrName); 591 } 592 catch (const std::exception& e) 593 { 594 std::cerr << "Failed to get attribute value, NAME=" << attrName.c_str() 595 << " ERROR=" << e.what() << "\n"; 596 return; 597 } 598 auto entryLength = pldm_bios_table_attr_value_entry_encode_integer_length(); 599 auto tableSize = attrValueTable.size(); 600 attrValueTable.resize(tableSize + entryLength); 601 pldm_bios_table_attr_value_entry_encode_integer( 602 attrValueTable.data() + tableSize, entryLength, 603 attrTableEntry->attr_handle, attrTableEntry->attr_type, currentValue); 604 } 605 606 } // namespace bios_type_integer 607 608 void traverseBIOSAttrTable(const Table& biosAttrTable, 609 AttrTableEntryHandler handler) 610 { 611 std::unique_ptr<pldm_bios_table_iter, decltype(&pldm_bios_table_iter_free)> 612 iter(pldm_bios_table_iter_create(biosAttrTable.data(), 613 biosAttrTable.size(), 614 PLDM_BIOS_ATTR_TABLE), 615 pldm_bios_table_iter_free); 616 while (!pldm_bios_table_iter_is_end(iter.get())) 617 { 618 auto table_entry = pldm_bios_table_iter_attr_entry_value(iter.get()); 619 try 620 { 621 handler(table_entry); 622 } 623 catch (const std::exception& e) 624 { 625 std::cerr << "handler fails when traversing BIOSAttrTable, ERROR=" 626 << e.what() << "\n"; 627 } 628 pldm_bios_table_iter_next(iter.get()); 629 } 630 } 631 632 using typeHandler = std::function<void(const BIOSTable& BIOSStringTable, 633 Table& attributeTable)>; 634 std::map<BIOSJsonName, typeHandler> attrTypeHandlers{ 635 {bios_parser::bIOSEnumJson, bios_type_enum::constructAttrTable}, 636 {bios_parser::bIOSStrJson, bios_type_string::constructAttrTable}, 637 {bios_parser::bIOSIntegerJson, bios_type_integer::constructAttrTable}, 638 }; 639 640 /** @brief Construct the BIOS attribute table 641 * 642 * @param[in] BIOSAttributeTable - the attribute table 643 * @param[in] BIOSStringTable - the string table 644 * @param[in] transferHandle - transfer handle to identify part of transfer 645 * @param[in] transferOpFlag - flag to indicate which part of data being 646 * transferred 647 * @param[in] instanceID - instance ID to identify the command 648 * @param[in] biosJsonDir - path where the BIOS json files are present 649 */ 650 Response getBIOSAttributeTable(BIOSTable& BIOSAttributeTable, 651 const BIOSTable& BIOSStringTable, 652 uint32_t /*transferHandle*/, 653 uint8_t /*transferOpFlag*/, uint8_t instanceID, 654 const char* biosJsonDir) 655 { 656 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES, 657 0); 658 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 659 uint32_t nxtTransferHandle = 0; 660 uint8_t transferFlag = PLDM_START_AND_END; 661 662 if (BIOSAttributeTable.isEmpty()) 663 { // no persisted table, constructing fresh table and response 664 Table attributeTable; 665 fs::path dir(biosJsonDir); 666 667 for (auto it = attrTypeHandlers.begin(); it != attrTypeHandlers.end(); 668 it++) 669 { 670 fs::path file = dir / it->first; 671 if (fs::exists(file)) 672 { 673 it->second(BIOSStringTable, attributeTable); 674 } 675 } 676 677 if (attributeTable.empty()) 678 { // no available json file is found 679 encode_get_bios_table_resp(instanceID, PLDM_BIOS_TABLE_UNAVAILABLE, 680 nxtTransferHandle, transferFlag, nullptr, 681 response.size(), responsePtr); 682 return response; 683 } 684 pldm::responder::utils::padAndChecksum(attributeTable); 685 BIOSAttributeTable.store(attributeTable); 686 response.resize(sizeof(pldm_msg_hdr) + 687 PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES + 688 attributeTable.size()); 689 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 690 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle, 691 transferFlag, attributeTable.data(), 692 response.size(), responsePtr); 693 } 694 else 695 { // persisted table present, constructing response 696 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle, 697 transferFlag, nullptr, response.size(), 698 responsePtr); // filling up the header here 699 BIOSAttributeTable.load(response); 700 } 701 702 return response; 703 } 704 705 using AttrValTableEntryConstructHandler = 706 std::function<void(const struct pldm_bios_attr_table_entry* tableEntry, 707 const std::string& attrName, 708 const BIOSTable& BIOSStringTable, Table& table)>; 709 710 using AttrType = uint8_t; 711 const std::map<AttrType, AttrValTableEntryConstructHandler> 712 AttrValTableConstructMap{ 713 {PLDM_BIOS_STRING, bios_type_string::constructAttrValueEntry}, 714 {PLDM_BIOS_STRING_READ_ONLY, bios_type_string::constructAttrValueEntry}, 715 {PLDM_BIOS_ENUMERATION, bios_type_enum::constructAttrValueEntry}, 716 {PLDM_BIOS_ENUMERATION_READ_ONLY, 717 bios_type_enum::constructAttrValueEntry}, 718 {PLDM_BIOS_INTEGER, bios_type_integer::constructAttrValueEntry}, 719 {PLDM_BIOS_INTEGER_READ_ONLY, 720 bios_type_integer::constructAttrValueEntry}, 721 }; 722 723 void constructAttrValueTableEntry( 724 const struct pldm_bios_attr_table_entry* attrEntry, 725 const BIOSTable& BIOSStringTable, Table& attributeValueTable) 726 { 727 auto attrName = findStringName(attrEntry->string_handle, BIOSStringTable); 728 if (attrName.empty()) 729 { 730 std::cerr << "invalid string handle, STRING_HANDLE=" 731 << attrEntry->string_handle << "\n"; 732 return; 733 } 734 735 AttrValTableConstructMap.at(attrEntry->attr_type)( 736 attrEntry, attrName, BIOSStringTable, attributeValueTable); 737 } 738 739 /** @brief Construct the BIOS attribute value table 740 * 741 * @param[in] BIOSAttributeValueTable - the attribute value table 742 * @param[in] BIOSAttributeTable - the attribute table 743 * @param[in] BIOSStringTable - the string table 744 * @param[in] transferHandle - transfer handle to identify part of transfer 745 * @param[in] transferOpFlag - flag to indicate which part of data being 746 * transferred 747 * @param[in] instanceID - instance ID to identify the command 748 */ 749 Response getBIOSAttributeValueTable(BIOSTable& BIOSAttributeValueTable, 750 const BIOSTable& BIOSAttributeTable, 751 const BIOSTable& BIOSStringTable, 752 uint32_t& /*transferHandle*/, 753 uint8_t& /*transferOpFlag*/, 754 uint8_t instanceID) 755 { 756 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES, 757 0); 758 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 759 uint32_t nxtTransferHandle = 0; 760 uint8_t transferFlag = PLDM_START_AND_END; 761 762 if (!BIOSAttributeValueTable.isEmpty()) 763 { 764 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle, 765 transferFlag, nullptr, response.size(), 766 responsePtr); // filling up the header here 767 BIOSAttributeValueTable.load(response); 768 return response; 769 } 770 771 Table attributeValueTable; 772 Table attributeTable; 773 BIOSAttributeTable.load(attributeTable); 774 traverseBIOSAttrTable( 775 attributeTable, 776 [&BIOSStringTable, &attributeValueTable]( 777 const struct pldm_bios_attr_table_entry* tableEntry) { 778 constructAttrValueTableEntry(tableEntry, BIOSStringTable, 779 attributeValueTable); 780 }); 781 if (attributeValueTable.empty()) 782 { 783 encode_get_bios_table_resp(instanceID, PLDM_BIOS_TABLE_UNAVAILABLE, 784 nxtTransferHandle, transferFlag, nullptr, 785 response.size(), responsePtr); 786 return response; 787 } 788 pldm::responder::utils::padAndChecksum(attributeValueTable); 789 BIOSAttributeValueTable.store(attributeValueTable); 790 791 response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES + 792 attributeValueTable.size()); 793 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 794 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle, 795 transferFlag, attributeValueTable.data(), 796 response.size(), responsePtr); 797 798 return response; 799 } 800 801 Response Handler::getBIOSTable(const pldm_msg* request, size_t payloadLength) 802 { 803 fs::create_directory(BIOS_TABLES_DIR); 804 auto response = internal::buildBIOSTables(request, payloadLength, 805 BIOS_JSONS_DIR, BIOS_TABLES_DIR); 806 807 return response; 808 } 809 810 Response Handler::getBIOSAttributeCurrentValueByHandle(const pldm_msg* request, 811 size_t payloadLength) 812 { 813 uint32_t transferHandle; 814 uint8_t transferOpFlag; 815 uint16_t attributeHandle; 816 817 auto rc = decode_get_bios_attribute_current_value_by_handle_req( 818 request, payloadLength, &transferHandle, &transferOpFlag, 819 &attributeHandle); 820 if (rc != PLDM_SUCCESS) 821 { 822 return ccOnlyResponse(request, rc); 823 } 824 825 fs::path tablesPath(BIOS_TABLES_DIR); 826 auto stringTablePath = tablesPath / stringTableFile; 827 BIOSTable BIOSStringTable(stringTablePath.c_str()); 828 auto attrTablePath = tablesPath / attrTableFile; 829 BIOSTable BIOSAttributeTable(attrTablePath.c_str()); 830 if (BIOSAttributeTable.isEmpty() || BIOSStringTable.isEmpty()) 831 { 832 return ccOnlyResponse(request, PLDM_BIOS_TABLE_UNAVAILABLE); 833 } 834 835 auto attrValueTablePath = tablesPath / attrValTableFile; 836 BIOSTable BIOSAttributeValueTable(attrValueTablePath.c_str()); 837 838 if (BIOSAttributeValueTable.isEmpty()) 839 { 840 Table attributeValueTable; 841 Table attributeTable; 842 BIOSAttributeTable.load(attributeTable); 843 traverseBIOSAttrTable( 844 attributeTable, 845 [&BIOSStringTable, &attributeValueTable]( 846 const struct pldm_bios_attr_table_entry* tableEntry) { 847 constructAttrValueTableEntry(tableEntry, BIOSStringTable, 848 attributeValueTable); 849 }); 850 if (attributeValueTable.empty()) 851 { 852 return ccOnlyResponse(request, PLDM_BIOS_TABLE_UNAVAILABLE); 853 } 854 pldm::responder::utils::padAndChecksum(attributeValueTable); 855 BIOSAttributeValueTable.store(attributeValueTable); 856 } 857 858 Response table; 859 BIOSAttributeValueTable.load(table); 860 861 auto entry = pldm_bios_table_attr_value_find_by_handle( 862 table.data(), table.size(), attributeHandle); 863 if (entry == nullptr) 864 { 865 return ccOnlyResponse(request, PLDM_INVALID_BIOS_ATTR_HANDLE); 866 } 867 868 auto valueLength = pldm_bios_table_attr_value_entry_value_length(entry); 869 auto valuePtr = pldm_bios_table_attr_value_entry_value(entry); 870 Response response(sizeof(pldm_msg_hdr) + 871 PLDM_GET_BIOS_ATTR_CURR_VAL_BY_HANDLE_MIN_RESP_BYTES + 872 valueLength, 873 0); 874 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 875 encode_get_bios_current_value_by_handle_resp( 876 request->hdr.instance_id, PLDM_SUCCESS, 0, PLDM_START_AND_END, valuePtr, 877 valueLength, responsePtr); 878 879 return response; 880 } 881 882 namespace internal 883 { 884 885 Response buildBIOSTables(const pldm_msg* request, size_t payloadLength, 886 const char* biosJsonDir, const char* biosTablePath) 887 { 888 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES, 889 0); 890 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 891 892 if (setupConfig(biosJsonDir) != 0) 893 { 894 encode_get_bios_table_resp( 895 request->hdr.instance_id, PLDM_BIOS_TABLE_UNAVAILABLE, 896 0 /* nxtTransferHandle */, PLDM_START_AND_END, nullptr, 897 response.size(), responsePtr); 898 return response; 899 } 900 901 uint32_t transferHandle{}; 902 uint8_t transferOpFlag{}; 903 uint8_t tableType{}; 904 905 auto rc = decode_get_bios_table_req(request, payloadLength, &transferHandle, 906 &transferOpFlag, &tableType); 907 if (rc == PLDM_SUCCESS) 908 { 909 BIOSTable BIOSStringTable( 910 (std::string(biosTablePath) + "/" + stringTableFile).c_str()); 911 BIOSTable BIOSAttributeTable( 912 (std::string(biosTablePath) + "/" + attrTableFile).c_str()); 913 BIOSTable BIOSAttributeValueTable( 914 (std::string(biosTablePath) + "/" + attrValTableFile).c_str()); 915 switch (tableType) 916 { 917 case PLDM_BIOS_STRING_TABLE: 918 919 response = getBIOSStringTable(BIOSStringTable, transferHandle, 920 transferOpFlag, 921 request->hdr.instance_id); 922 break; 923 case PLDM_BIOS_ATTR_TABLE: 924 925 if (BIOSStringTable.isEmpty()) 926 { 927 rc = PLDM_BIOS_TABLE_UNAVAILABLE; 928 } 929 else 930 { 931 response = getBIOSAttributeTable( 932 BIOSAttributeTable, BIOSStringTable, transferHandle, 933 transferOpFlag, request->hdr.instance_id, biosJsonDir); 934 } 935 break; 936 case PLDM_BIOS_ATTR_VAL_TABLE: 937 if (BIOSAttributeTable.isEmpty() || BIOSStringTable.isEmpty()) 938 { 939 rc = PLDM_BIOS_TABLE_UNAVAILABLE; 940 } 941 else 942 { 943 response = getBIOSAttributeValueTable( 944 BIOSAttributeValueTable, BIOSAttributeTable, 945 BIOSStringTable, transferHandle, transferOpFlag, 946 request->hdr.instance_id); 947 } 948 break; 949 default: 950 rc = PLDM_INVALID_BIOS_TABLE_TYPE; 951 break; 952 } 953 } 954 955 if (rc != PLDM_SUCCESS) 956 { 957 uint32_t nxtTransferHandle{}; 958 uint8_t transferFlag{}; 959 size_t respPayloadLength{}; 960 961 encode_get_bios_table_resp(request->hdr.instance_id, rc, 962 nxtTransferHandle, transferFlag, nullptr, 963 respPayloadLength, responsePtr); 964 } 965 966 return response; 967 } 968 969 } // end namespace internal 970 } // namespace bios 971 972 } // namespace responder 973 } // namespace pldm 974