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