xref: /openbmc/pldm/libpldmresponder/bios.cpp (revision 2ffe329e)
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