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