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