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