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