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 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 } // 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 hostTimePath = "/xyz/openbmc_project/time/host"; 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, hostTimePath, timeInterface); 79 80 auto method = bus.new_method_call(service.c_str(), hostTimePath, 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", hostTimePath), 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, 142 uint32_t /*transferHandle*/, 143 uint8_t /*transferOpFlag*/, uint8_t instanceID, 144 const char* biosJsonDir) 145 { 146 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES, 147 0); 148 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 149 150 if (BIOSStringTable.isEmpty()) 151 { // no persisted table, constructing fresh table and file 152 auto biosStrings = bios_parser::getStrings(biosJsonDir); 153 std::sort(biosStrings.begin(), biosStrings.end()); 154 // remove all duplicate strings received from bios json 155 biosStrings.erase(std::unique(biosStrings.begin(), biosStrings.end()), 156 biosStrings.end()); 157 size_t allStringsLen = 158 std::accumulate(biosStrings.begin(), biosStrings.end(), 0, 159 [](size_t sum, const std::string& elem) { 160 return sum + elem.size(); 161 }); 162 size_t sizeWithoutPad = 163 allStringsLen + 164 (biosStrings.size() * (sizeof(pldm_bios_string_table_entry) - 1)); 165 uint8_t padSize = utils::getNumPadBytes(sizeWithoutPad); 166 uint32_t stringTableSize{}; 167 uint32_t checkSum; 168 if (biosStrings.size()) 169 { 170 stringTableSize = sizeWithoutPad + padSize + sizeof(checkSum); 171 } 172 Table stringTable( 173 stringTableSize, 174 0); // initializing to 0 so that pad will be automatically added 175 auto tablePtr = reinterpret_cast<uint8_t*>(stringTable.data()); 176 for (const auto& elem : biosStrings) 177 { 178 auto stringPtr = 179 reinterpret_cast<struct pldm_bios_string_table_entry*>( 180 tablePtr); 181 182 stringPtr->string_handle = nextStringHandle(); 183 stringPtr->string_length = elem.length(); 184 memcpy(stringPtr->name, elem.c_str(), elem.length()); 185 tablePtr += sizeof(stringPtr->string_handle) + 186 sizeof(stringPtr->string_length); 187 tablePtr += elem.length(); 188 } 189 tablePtr += padSize; 190 191 if (stringTableSize) 192 { 193 // compute checksum 194 boost::crc_32_type result; 195 result.process_bytes(stringTable.data(), stringTableSize); 196 checkSum = result.checksum(); 197 std::copy_n(reinterpret_cast<uint8_t*>(&checkSum), sizeof(checkSum), 198 stringTable.data() + sizeWithoutPad + padSize); 199 BIOSStringTable.store(stringTable); 200 } 201 202 response.resize(sizeof(pldm_msg_hdr) + 203 PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES + 204 stringTableSize, 205 0); 206 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 207 size_t respPayloadLength = response.size(); 208 uint32_t nxtTransferHandle = 0; 209 uint8_t transferFlag = PLDM_START_AND_END; 210 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle, 211 transferFlag, stringTable.data(), 212 respPayloadLength, responsePtr); 213 } 214 else 215 { // persisted table present, constructing response 216 size_t respPayloadLength = response.size(); 217 uint32_t nxtTransferHandle = 0; 218 uint8_t transferFlag = PLDM_START_AND_END; 219 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle, 220 transferFlag, nullptr, respPayloadLength, 221 responsePtr); // filling up the header here 222 BIOSStringTable.load(response); 223 } 224 225 return response; 226 } 227 228 /** @brief Find the string handle from the BIOS string table given the name 229 * 230 * @param[in] name - name of the BIOS string 231 * @param[in] BIOSStringTable - the string table 232 * @return - uint16_t - handle of the string 233 */ 234 StringHandle findStringHandle(const std::string& name, 235 const BIOSTable& BIOSStringTable) 236 { 237 StringHandle hdl{}; 238 Response response; 239 BIOSStringTable.load(response); 240 241 auto tableData = response.data(); 242 size_t tableLen = response.size(); 243 auto tableEntry = 244 reinterpret_cast<struct pldm_bios_string_table_entry*>(response.data()); 245 while (1) 246 { 247 hdl = tableEntry->string_handle; 248 uint16_t len = tableEntry->string_length; 249 if (name.compare(0, name.length(), tableEntry->name, len) == 0) 250 { 251 break; 252 } 253 tableData += (sizeof(struct pldm_bios_string_table_entry) - 1) + len; 254 255 if (std::distance(tableData, response.data() + tableLen) <= 256 padChksumMax) 257 { 258 log<level::ERR>("Reached end of BIOS string table,did not find the " 259 "handle for the string", 260 entry("STRING=%s", name.c_str())); 261 elog<InternalFailure>(); 262 break; 263 } 264 265 tableEntry = 266 reinterpret_cast<struct pldm_bios_string_table_entry*>(tableData); 267 } 268 return hdl; 269 } 270 271 /** @brief Find the string name from the BIOS string table for a string handle 272 * 273 * @param[in] stringHdl - string handle 274 * @param[in] BIOSStringTable - the string table 275 * 276 * @return - std::string - name of the corresponding BIOS string 277 */ 278 std::string findStringName(StringHandle stringHdl, 279 const BIOSTable& BIOSStringTable) 280 { 281 std::string name; 282 Response response; 283 BIOSStringTable.load(response); 284 285 auto tableData = response.data(); 286 size_t tableLen = response.size(); 287 auto tableEntry = 288 reinterpret_cast<struct pldm_bios_string_table_entry*>(response.data()); 289 while (1) 290 { 291 StringHandle currHdl = tableEntry->string_handle; 292 uint16_t len = tableEntry->string_length; 293 if (currHdl == stringHdl) 294 { 295 name.resize(len); 296 memcpy(name.data(), tableEntry->name, len); 297 break; 298 } 299 tableData += (sizeof(struct pldm_bios_string_table_entry) - 1) + len; 300 301 if (std::distance(tableData, response.data() + tableLen) <= 302 padChksumMax) 303 { 304 log<level::ERR>("Reached end of BIOS string table,did not find " 305 "string name for handle", 306 entry("STRING_HANDLE=%d", stringHdl)); 307 break; 308 } 309 310 tableEntry = 311 reinterpret_cast<struct pldm_bios_string_table_entry*>(tableData); 312 } 313 return name; 314 } 315 316 namespace bios_type_enum 317 { 318 319 using namespace bios_parser::bios_enum; 320 321 /** @brief Find the indices into the array of the possible values of string 322 * handles for the current values.This is used in attribute value table 323 * 324 * @param[in] possiVals - vector of string handles comprising all the possible 325 * values for an attribute 326 * @param[in] currVals - vector of strings comprising all current values 327 * for an attribute 328 * @param[in] BIOSStringTable - the string table 329 * 330 * @return - std::vector<uint8_t> - indices into the array of the possible 331 * values of string handles 332 */ 333 std::vector<uint8_t> findStrIndices(PossibleValuesByHandle possiVals, 334 CurrentValues currVals, 335 const BIOSTable& BIOSStringTable) 336 { 337 std::vector<uint8_t> stringIndices; 338 339 for (const auto& currVal : currVals) 340 { 341 StringHandle curHdl; 342 try 343 { 344 curHdl = findStringHandle(currVal, BIOSStringTable); 345 } 346 catch (InternalFailure& e) 347 { 348 log<level::ERR>("Exception fetching handle for the string", 349 entry("STRING=%s", currVal.c_str())); 350 continue; 351 } 352 353 uint8_t i = 0; 354 for (auto possiHdl : possiVals) 355 { 356 if (possiHdl == curHdl) 357 { 358 stringIndices.push_back(i); 359 break; 360 } 361 i++; 362 } 363 } 364 return stringIndices; 365 } 366 367 /** @brief Find the indices into the array of the possible values of string 368 * handles for the default values. This is used in attribute table 369 * 370 * @param[in] possiVals - vector of strings comprising all the possible values 371 * for an attribute 372 * @param[in] defVals - vector of strings comprising all the default values 373 * for an attribute 374 * @return - std::vector<uint8_t> - indices into the array of the possible 375 * values of string 376 */ 377 std::vector<uint8_t> findDefaultValHandle(const PossibleValues& possiVals, 378 const DefaultValues& defVals) 379 { 380 std::vector<uint8_t> defHdls; 381 for (const auto& defs : defVals) 382 { 383 auto index = std::lower_bound(possiVals.begin(), possiVals.end(), defs); 384 if (index != possiVals.end()) 385 { 386 defHdls.push_back(index - possiVals.begin()); 387 } 388 } 389 390 return defHdls; 391 } 392 393 /** @brief Construct the attibute table for BIOS type Enumeration and 394 * Enumeration ReadOnly 395 * @param[in] BIOSStringTable - the string table 396 * @param[in] biosJsonDir - path where the BIOS json files are present 397 * @param[in,out] attributeTable - the attribute table 398 * 399 */ 400 void constructAttrTable(const BIOSTable& BIOSStringTable, 401 const char* biosJsonDir, Table& attributeTable) 402 { 403 setupValueLookup(biosJsonDir); 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 /** @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 * @param[in, out] attributeValueTable - the attribute value table 483 * 484 */ 485 void constructAttrValueTable(const BIOSTable& BIOSAttributeTable, 486 const BIOSTable& BIOSStringTable, 487 Table& attributeValueTable) 488 { 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; 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; 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 588 } // end namespace bios_type_enum 589 590 namespace bios_type_string 591 { 592 593 using namespace bios_parser::bios_string; 594 595 /** @brief Construct the attibute table for BIOS type String and 596 * String ReadOnly 597 * @param[in] BIOSStringTable - the string table 598 * @param[in] biosJsonDir - path where the BIOS json files are present 599 * @param[in,out] attributeTable - the attribute table 600 * 601 */ 602 void constructAttrTable(const BIOSTable& BIOSStringTable, 603 const char* biosJsonDir, Table& attributeTable) 604 { 605 auto rc = setupValueLookup(biosJsonDir); 606 if (rc == -1) 607 { 608 log<level::ERR>("Failed to parse entries in Json file"); 609 return; 610 } 611 const auto& attributeMap = getValues(); 612 StringHandle strHandle; 613 614 for (const auto& [key, value] : attributeMap) 615 { 616 try 617 { 618 strHandle = findStringHandle(key, BIOSStringTable); 619 } 620 catch (InternalFailure& e) 621 { 622 log<level::ERR>("Could not find handle for BIOS string", 623 entry("ATTRIBUTE=%s", key.c_str())); 624 continue; 625 } 626 627 const auto& [type, strType, minStrLen, maxStrLen, defaultStrLen, 628 defaultStr] = value; 629 uint8_t typeOfAttr = 630 type ? PLDM_BIOS_STRING_READ_ONLY : PLDM_BIOS_STRING; 631 632 BIOSTableRow stringAttrTable(bios_parser::bios_string::attrTableSize + 633 defaultStr.size()); 634 BIOSTableRow::iterator it = stringAttrTable.begin(); 635 auto attrPtr = reinterpret_cast<struct pldm_bios_attr_table_entry*>( 636 stringAttrTable.data()); 637 attrPtr->attr_handle = nextAttributeHandle(); 638 attrPtr->attr_type = typeOfAttr; 639 attrPtr->string_handle = strHandle; 640 641 std::advance(it, (sizeof(struct pldm_bios_attr_table_entry) - 1)); 642 std::copy_n(&strType, sizeof(uint8_t), it); 643 std::advance(it, sizeof(uint8_t)); 644 std::copy_n(reinterpret_cast<const uint8_t*>(&minStrLen), 645 sizeof(uint16_t), it); 646 std::advance(it, sizeof(uint16_t)); 647 std::copy_n(reinterpret_cast<const uint8_t*>(&maxStrLen), 648 sizeof(uint16_t), it); 649 std::advance(it, sizeof(uint16_t)); 650 std::copy_n(reinterpret_cast<const uint8_t*>(&defaultStrLen), 651 sizeof(uint16_t), it); 652 std::advance(it, sizeof(uint16_t)); 653 std::copy_n(defaultStr.data(), defaultStr.size(), it); 654 std::advance(it, defaultStr.size()); 655 656 attributeTable.insert(attributeTable.end(), stringAttrTable.begin(), 657 stringAttrTable.end()); 658 } 659 } 660 661 /** @brief Construct the attibute value table for BIOS type String and 662 * String ReadOnly 663 * 664 * @param[in] BIOSAttributeTable - the attribute table 665 * @param[in] BIOSStringTable - the string table 666 * @param[in, out] attributeValueTable - the attribute value table 667 * 668 */ 669 void constructAttrValueTable(const BIOSTable& BIOSAttributeTable, 670 const BIOSTable& BIOSStringTable, 671 Table& attributeValueTable) 672 { 673 Response response; 674 BIOSAttributeTable.load(response); 675 676 auto dataPtr = response.data(); 677 size_t tableLen = response.size(); 678 679 while (true) 680 { 681 auto attrPtr = 682 reinterpret_cast<struct pldm_bios_attr_table_entry*>(dataPtr); 683 uint16_t attrHdl = attrPtr->attr_handle; 684 uint8_t attrType = attrPtr->attr_type; 685 uint16_t stringHdl = attrPtr->string_handle; 686 dataPtr += (sizeof(struct pldm_bios_attr_table_entry) - 1); 687 // pass number of StringType, MinimumStringLength, MaximumStringLength 688 dataPtr += sizeof(uint8_t) + sizeof(uint16_t) + sizeof(uint16_t); 689 auto sizeDefaultStr = *(reinterpret_cast<uint16_t*>(dataPtr)); 690 // pass number of DefaultStringLength, DefaultString 691 dataPtr += sizeof(uint16_t) + sizeDefaultStr; 692 693 auto attrName = findStringName(stringHdl, BIOSStringTable); 694 if (attrName.empty()) 695 { 696 if (std::distance(dataPtr, response.data() + tableLen) <= 697 padChksumMax) 698 { 699 log<level::ERR>("Did not find string name for handle", 700 entry("STRING_HANDLE=%d", stringHdl)); 701 return; 702 } 703 continue; 704 } 705 706 uint16_t currStrLen = 0; 707 std::string currStr; 708 try 709 { 710 currStr = getAttrValue(attrName); 711 currStrLen = currStr.size(); 712 } 713 catch (const std::exception& e) 714 { 715 log<level::ERR>("getAttrValue returned error for attribute", 716 entry("NAME=%s", attrName.c_str()), 717 entry("ERROR=%s", e.what())); 718 if (std::distance(dataPtr, response.data() + tableLen) <= 719 padChksumMax) 720 { 721 return; 722 } 723 continue; 724 } 725 726 BIOSTableRow strAttrValTable( 727 bios_parser::bios_string::attrValueTableSize + currStrLen, 0); 728 BIOSTableRow::iterator it = strAttrValTable.begin(); 729 auto attrValPtr = 730 reinterpret_cast<struct pldm_bios_attr_val_table_entry*>( 731 strAttrValTable.data()); 732 attrValPtr->attr_handle = attrHdl; 733 attrValPtr->attr_type = attrType; 734 std::advance(it, (sizeof(pldm_bios_attr_val_table_entry) - 1)); 735 std::copy_n(reinterpret_cast<uint8_t*>(&currStrLen), sizeof(uint16_t), 736 it); 737 std::advance(it, sizeof(uint16_t)); 738 if (currStrLen) 739 { 740 std::copy_n(currStr.cbegin(), currStrLen, it); 741 std::advance(it, currStrLen); 742 } 743 744 attributeValueTable.insert(attributeValueTable.end(), 745 strAttrValTable.begin(), 746 strAttrValTable.end()); 747 748 if (std::distance(dataPtr, response.data() + tableLen) <= padChksumMax) 749 { 750 break; 751 } 752 } 753 } 754 755 } // end namespace bios_type_string 756 757 using typeHandler = 758 std::function<void(const BIOSTable& BIOSStringTable, 759 const char* biosJsonDir, Table& attributeTable)>; 760 std::map<BIOSJsonName, typeHandler> attrTypeHandlers{ 761 {bios_parser::bIOSEnumJson, bios_type_enum::constructAttrTable}, 762 {bios_parser::bIOSStrJson, bios_type_string::constructAttrTable}}; 763 764 using valueHandler = std::function<void(const BIOSTable& BIOSAttributeTable, 765 766 const BIOSTable& BIOSStringTable, 767 768 Table& attributeTable)>; 769 770 std::map<BIOSJsonName, valueHandler> attrValueHandlers{ 771 {bios_parser::bIOSEnumJson, bios_type_enum::constructAttrValueTable}, 772 {bios_parser::bIOSStrJson, bios_type_string::constructAttrValueTable}}; 773 774 /** @brief Construct the BIOS attribute table 775 * 776 * @param[in] BIOSAttributeTable - the attribute table 777 * @param[in] BIOSStringTable - the string table 778 * @param[in] transferHandle - transfer handle to identify part of transfer 779 * @param[in] transferOpFlag - flag to indicate which part of data being 780 * transferred 781 * @param[in] instanceID - instance ID to identify the command 782 * @param[in] biosJsonDir - path where the BIOS json files are present 783 */ 784 Response getBIOSAttributeTable(BIOSTable& BIOSAttributeTable, 785 const BIOSTable& BIOSStringTable, 786 uint32_t /*transferHandle*/, 787 uint8_t /*transferOpFlag*/, uint8_t instanceID, 788 const char* biosJsonDir) 789 { 790 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES, 791 0); 792 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 793 uint32_t nxtTransferHandle = 0; 794 uint8_t transferFlag = PLDM_START_AND_END; 795 796 if (BIOSAttributeTable.isEmpty()) 797 { // no persisted table, constructing fresh table and response 798 Table attributeTable; 799 fs::path dir(biosJsonDir); 800 801 for (auto it = attrTypeHandlers.begin(); it != attrTypeHandlers.end(); 802 it++) 803 { 804 fs::path file = dir / it->first; 805 if (fs::exists(file)) 806 { 807 it->second(BIOSStringTable, biosJsonDir, attributeTable); 808 } 809 } 810 811 if (attributeTable.empty()) 812 { // no available json file is found 813 encode_get_bios_table_resp(instanceID, PLDM_BIOS_TABLE_UNAVAILABLE, 814 nxtTransferHandle, transferFlag, nullptr, 815 response.size(), responsePtr); 816 return response; 817 } 818 819 // calculate pad 820 uint8_t padSize = utils::getNumPadBytes(attributeTable.size()); 821 std::vector<uint8_t> pad(padSize, 0); 822 if (padSize) 823 { 824 std::move(pad.begin(), pad.end(), 825 std::back_inserter(attributeTable)); 826 } 827 828 if (!attributeTable.empty()) 829 { 830 // compute checksum 831 boost::crc_32_type result; 832 size_t size = attributeTable.size(); 833 result.process_bytes(attributeTable.data(), size); 834 uint32_t checkSum = result.checksum(); 835 attributeTable.resize(size + sizeof(checkSum)); 836 std::copy_n(reinterpret_cast<uint8_t*>(&checkSum), sizeof(checkSum), 837 attributeTable.data() + size); 838 BIOSAttributeTable.store(attributeTable); 839 } 840 response.resize(sizeof(pldm_msg_hdr) + 841 PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES + 842 attributeTable.size()); 843 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 844 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle, 845 transferFlag, attributeTable.data(), 846 response.size(), responsePtr); 847 } 848 else 849 { // persisted table present, constructing response 850 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle, 851 transferFlag, nullptr, response.size(), 852 responsePtr); // filling up the header here 853 BIOSAttributeTable.load(response); 854 } 855 856 return response; 857 } 858 859 /** @brief Construct the BIOS attribute value table 860 * 861 * @param[in] BIOSAttributeValueTable - the attribute value table 862 * @param[in] BIOSAttributeTable - the attribute table 863 * @param[in] BIOSStringTable - the string table 864 * @param[in] transferHandle - transfer handle to identify part of transfer 865 * @param[in] transferOpFlag - flag to indicate which part of data being 866 * transferred 867 * @param[in] instanceID - instance ID to identify the command 868 */ 869 Response getBIOSAttributeValueTable(BIOSTable& BIOSAttributeValueTable, 870 const BIOSTable& BIOSAttributeTable, 871 const BIOSTable& BIOSStringTable, 872 uint32_t& /*transferHandle*/, 873 uint8_t& /*transferOpFlag*/, 874 uint8_t instanceID, const char* biosJsonDir) 875 { 876 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES, 877 0); 878 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 879 uint32_t nxtTransferHandle = 0; 880 uint8_t transferFlag = PLDM_START_AND_END; 881 size_t respPayloadLength{}; 882 883 if (BIOSAttributeValueTable.isEmpty()) 884 { // no persisted table, constructing fresh table and data 885 Table attributeValueTable; 886 fs::path dir(biosJsonDir); 887 888 for (auto it = attrValueHandlers.begin(); it != attrValueHandlers.end(); 889 it++) 890 { 891 fs::path file = dir / it->first; 892 if (fs::exists(file)) 893 { 894 it->second(BIOSAttributeTable, BIOSStringTable, 895 attributeValueTable); 896 } 897 } 898 899 if (attributeValueTable.empty()) 900 { // no available json file is found 901 encode_get_bios_table_resp(instanceID, PLDM_BIOS_TABLE_UNAVAILABLE, 902 nxtTransferHandle, transferFlag, nullptr, 903 response.size(), responsePtr); 904 return response; 905 } 906 // calculate pad 907 uint8_t padSize = utils::getNumPadBytes(attributeValueTable.size()); 908 std::vector<uint8_t> pad(padSize, 0); 909 if (padSize) 910 { 911 std::move(pad.begin(), pad.end(), 912 std::back_inserter(attributeValueTable)); 913 } 914 if (!attributeValueTable.empty()) 915 { 916 // compute checksum 917 boost::crc_32_type result; 918 result.process_bytes(attributeValueTable.data(), 919 attributeValueTable.size()); 920 uint32_t checkSum = result.checksum(); 921 size_t size = attributeValueTable.size(); 922 attributeValueTable.resize(size + sizeof(checkSum)); 923 std::copy_n(reinterpret_cast<uint8_t*>(&checkSum), sizeof(checkSum), 924 attributeValueTable.data() + size); 925 BIOSAttributeValueTable.store(attributeValueTable); 926 } 927 928 response.resize(sizeof(pldm_msg_hdr) + 929 PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES + 930 attributeValueTable.size()); 931 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 932 respPayloadLength = response.size(); 933 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle, 934 transferFlag, attributeValueTable.data(), 935 respPayloadLength, responsePtr); 936 } 937 else 938 { // persisted table present, constructing response 939 respPayloadLength = response.size(); 940 encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle, 941 transferFlag, nullptr, respPayloadLength, 942 responsePtr); // filling up the header here 943 BIOSAttributeValueTable.load(response); 944 } 945 946 return response; 947 } 948 949 Response getBIOSTable(const pldm_msg* request, size_t payloadLength) 950 { 951 fs::create_directory(BIOS_TABLES_DIR); 952 auto response = internal::buildBIOSTables(request, payloadLength, 953 BIOS_JSONS_DIR, BIOS_TABLES_DIR); 954 955 return response; 956 } 957 958 namespace bios 959 { 960 961 void registerHandlers() 962 { 963 registerHandler(PLDM_BIOS, PLDM_GET_DATE_TIME, std::move(getDateTime)); 964 registerHandler(PLDM_BIOS, PLDM_GET_BIOS_TABLE, std::move(getBIOSTable)); 965 } 966 967 namespace internal 968 { 969 970 Response buildBIOSTables(const pldm_msg* request, size_t payloadLength, 971 const char* biosJsonDir, const char* biosTablePath) 972 { 973 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES, 974 0); 975 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 976 977 uint32_t transferHandle{}; 978 uint8_t transferOpFlag{}; 979 uint8_t tableType{}; 980 981 auto rc = decode_get_bios_table_req(request, payloadLength, &transferHandle, 982 &transferOpFlag, &tableType); 983 if (rc == PLDM_SUCCESS) 984 { 985 BIOSTable BIOSStringTable( 986 ((std::string(biosTablePath) + "/stringTable")).c_str()); 987 BIOSTable BIOSAttributeTable( 988 ((std::string(biosTablePath) + "/attributeTable")).c_str()); 989 BIOSTable BIOSAttributeValueTable( 990 ((std::string(biosTablePath) + "/attributeValueTable")).c_str()); 991 switch (tableType) 992 { 993 case PLDM_BIOS_STRING_TABLE: 994 995 response = getBIOSStringTable( 996 BIOSStringTable, transferHandle, transferOpFlag, 997 request->hdr.instance_id, biosJsonDir); 998 break; 999 case PLDM_BIOS_ATTR_TABLE: 1000 1001 if (BIOSStringTable.isEmpty()) 1002 { 1003 rc = PLDM_BIOS_TABLE_UNAVAILABLE; 1004 } 1005 else 1006 { 1007 response = getBIOSAttributeTable( 1008 BIOSAttributeTable, BIOSStringTable, transferHandle, 1009 transferOpFlag, request->hdr.instance_id, biosJsonDir); 1010 } 1011 break; 1012 case PLDM_BIOS_ATTR_VAL_TABLE: 1013 if (BIOSAttributeTable.isEmpty()) 1014 { 1015 rc = PLDM_BIOS_TABLE_UNAVAILABLE; 1016 } 1017 else 1018 { 1019 response = getBIOSAttributeValueTable( 1020 BIOSAttributeValueTable, BIOSAttributeTable, 1021 BIOSStringTable, transferHandle, transferOpFlag, 1022 request->hdr.instance_id, biosJsonDir); 1023 } 1024 break; 1025 default: 1026 rc = PLDM_INVALID_BIOS_TABLE_TYPE; 1027 break; 1028 } 1029 } 1030 1031 if (rc != PLDM_SUCCESS) 1032 { 1033 uint32_t nxtTransferHandle{}; 1034 uint8_t transferFlag{}; 1035 size_t respPayloadLength{}; 1036 1037 encode_get_bios_table_resp(request->hdr.instance_id, rc, 1038 nxtTransferHandle, transferFlag, nullptr, 1039 respPayloadLength, responsePtr); 1040 } 1041 1042 return response; 1043 } 1044 1045 } // end namespace internal 1046 } // namespace bios 1047 1048 } // namespace responder 1049 } // namespace pldm 1050