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