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