GetBIOSTable responder implementation

This commit implements the GetBIOSTable responder handler
for the BIOS Enumeration type.
One of the tables among String table, Attribute table and Attribute
Value Table are created/fetched and sent to PLDM requester as response to
the command.

Tested:
Following are the tables constructed from the sample json file present at
"test/bios_jsons/enum_attrs.json"
-bash-4.2$ hexdump -C /tmp/AllBiosTables/stringTable
00000000  00 00 07 00 41 6c 6c 6f  77 65 64 01 00 10 00 43  |....Allowed....C|
00000010  6f 64 65 55 70 64 61 74  65 50 6f 6c 69 63 79 02  |odeUpdatePolicy.|
00000020  00 0a 00 43 6f 6e 63 75  72 72 65 6e 74 03 00 0a  |...Concurrent...|
00000030  00 44 69 73 72 75 70 74  69 76 65 04 00 0a 00 46  |.Disruptive....F|
00000040  57 42 6f 6f 74 53 69 64  65 05 00 0f 00 48 4d 43  |WBootSide....HMC|
00000050  4d 61 6e 61 67 65 64 53  74 61 74 65 06 00 10 00  |ManagedState....|
00000060  49 6e 62 61 6e 64 43 6f  64 65 55 70 64 61 74 65  |InbandCodeUpdate|
00000070  07 00 0a 00 4e 6f 74 41  6c 6c 6f 77 65 64 08 00  |....NotAllowed..|
00000080  03 00 4f 66 66 09 00 02  00 4f 6e 0a 00 04 00 50  |..Off....On....P|
00000090  65 72 6d 0b 00 04 00 54  65 6d 70 00 37 90 c0 da  |erm....Temp.7...|
000000a0
-bash-4.2$ hexdump -C /tmp/AllBiosTables/attributeTable
00000000  00 00 00 01 00 02 02 00  03 00 01 00 01 00 00 04  |................|
00000010  00 02 0a 00 0b 00 01 00  02 00 00 05 00 02 08 00  |................|
00000020  09 00 01 01 03 00 00 06  00 02 00 00 07 00 01 00  |................|
00000030  3b 85 69 a7                                       |;.i.|
00000034
-bash-4.2$ hexdump -C /tmp/AllBiosTables/attributeValueTable
00000000  00 00 00 01 00 00 00 00  d9 f6 42 58              |..........BX|
0000000c

Change-Id: I06aebcc2c2deea66e867fb775afa76a1e5d18dca
Signed-off-by: Sampa Misra <sampmisr@in.ibm.com>
diff --git a/libpldmresponder/Makefile.am b/libpldmresponder/Makefile.am
index 2f060df..948898f 100644
--- a/libpldmresponder/Makefile.am
+++ b/libpldmresponder/Makefile.am
@@ -3,11 +3,11 @@
 libpldmresponder_la_SOURCES = \
 	base.cpp \
 	utils.cpp \
-	bios.cpp \
+	bios_table.cpp \
 	effecters.cpp \
 	pdr.cpp \
-	bios_table.cpp \
-	bios_parser.cpp
+	bios_parser.cpp \
+	bios.cpp
 
 libpldmresponder_la_LIBADD = \
 	../libpldm/libpldm.la \
diff --git a/libpldmresponder/bios.cpp b/libpldmresponder/bios.cpp
index eab83dc..a899e62 100644
--- a/libpldmresponder/bios.cpp
+++ b/libpldmresponder/bios.cpp
@@ -5,37 +5,36 @@
 #include "xyz/openbmc_project/Common/error.hpp"
 
 #include <array>
+#include <boost/crc.hpp>
 #include <chrono>
 #include <ctime>
 #include <iostream>
+#include <numeric>
+#include <phosphor-logging/elog-errors.hpp>
 #include <phosphor-logging/log.hpp>
 #include <stdexcept>
 #include <string>
 #include <variant>
 #include <vector>
 
+using namespace pldm::responder::bios;
+using namespace bios_parser;
+using namespace bios_parser::bios_enum;
+
 namespace pldm
 {
 
 using namespace phosphor::logging;
-
+using namespace sdbusplus::xyz::openbmc_project::Common::Error;
 using EpochTimeUS = uint64_t;
+using BIOSTableRow = std::vector<uint8_t>;
 
 constexpr auto dbusProperties = "org.freedesktop.DBus.Properties";
+constexpr auto padChksumMax = 7;
 
 namespace responder
 {
 
-namespace bios
-{
-
-void registerHandlers()
-{
-    registerHandler(PLDM_BIOS, PLDM_GET_DATE_TIME, std::move(getDateTime));
-}
-
-} // namespace bios
-
 namespace utils
 {
 
@@ -110,5 +109,724 @@
     return response;
 }
 
+/** @brief Generate the next attribute handle
+ *
+ *  @return - uint16_t - next attribute handle
+ */
+AttributeHandle nextAttributeHandle()
+{
+    static AttributeHandle attrHdl = 0;
+    return attrHdl++;
+}
+
+/** @brief Generate the next string handle
+ *  *
+ *  @return - uint16_t - next string handle
+ */
+StringHandle nextStringHandle()
+{
+    static StringHandle strHdl = 0;
+    return strHdl++;
+}
+
+/** @brief Construct the BIOS string table
+ *
+ *  @param[in] BIOSStringTable - the string table
+ *  @param[in] transferHandle - transfer handle to identify part of transfer
+ *  @param[in] transferOpFlag - flag to indicate which part of data being
+ * transferred
+ *  @param[in] instanceID - instance ID to identify the command
+ *  @param[in] biosJsonDir - path where the BIOS json files are present
+ */
+Response getBIOSStringTable(BIOSTable& BIOSStringTable, uint32_t transferHandle,
+                            uint8_t transferOpFlag, uint8_t instanceID,
+                            const char* biosJsonDir)
+{
+    Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
+                      0);
+    auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+
+    if (BIOSStringTable.isEmpty())
+    { // no persisted table, constructing fresh table and file
+        auto biosStrings = bios_parser::getStrings(biosJsonDir);
+        std::sort(biosStrings.begin(), biosStrings.end());
+        // remove all duplicate strings received from bios json
+        biosStrings.erase(std::unique(biosStrings.begin(), biosStrings.end()),
+                          biosStrings.end());
+        size_t allStringsLen =
+            std::accumulate(biosStrings.begin(), biosStrings.end(), 0,
+                            [](size_t sum, const std::string& elem) {
+                                return sum + elem.size();
+                            });
+        size_t sizeWithoutPad =
+            allStringsLen +
+            (biosStrings.size() * (sizeof(pldm_bios_string_table_entry) - 1));
+        uint8_t padSize = utils::getNumPadBytes(sizeWithoutPad);
+        uint32_t stringTableSize{};
+        uint32_t checkSum;
+        if (biosStrings.size())
+        {
+            stringTableSize = sizeWithoutPad + padSize + sizeof(checkSum);
+        }
+        Table stringTable(
+            stringTableSize,
+            0); // initializing to 0 so that pad will be automatically added
+        auto tablePtr = reinterpret_cast<uint8_t*>(stringTable.data());
+        for (const auto& elem : biosStrings)
+        {
+            auto stringPtr =
+                reinterpret_cast<struct pldm_bios_string_table_entry*>(
+                    tablePtr);
+
+            stringPtr->string_handle = nextStringHandle();
+            stringPtr->string_length = elem.length();
+            memcpy(stringPtr->name, elem.c_str(), elem.length());
+            tablePtr += sizeof(stringPtr->string_handle) +
+                        sizeof(stringPtr->string_length);
+            tablePtr += elem.length();
+        }
+        tablePtr += padSize;
+
+        if (stringTableSize)
+        {
+            // compute checksum
+            boost::crc_32_type result;
+            result.process_bytes(stringTable.data(), stringTableSize);
+            checkSum = result.checksum();
+            std::copy_n(reinterpret_cast<uint8_t*>(&checkSum), sizeof(checkSum),
+                        stringTable.data() + sizeWithoutPad + padSize);
+            BIOSStringTable.store(stringTable);
+        }
+
+        response.resize(sizeof(pldm_msg_hdr) +
+                            PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
+                            stringTableSize,
+                        0);
+        responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+        size_t respPayloadLength = response.size();
+        uint32_t nxtTransferHandle = 0;
+        uint8_t transferFlag = PLDM_START_AND_END;
+        encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
+                                   transferFlag, stringTable.data(),
+                                   respPayloadLength, responsePtr);
+    }
+    else
+    { // persisted table present, constructing response
+        size_t respPayloadLength = response.size();
+        uint32_t nxtTransferHandle = 0;
+        uint8_t transferFlag = PLDM_START_AND_END;
+        encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
+                                   transferFlag, nullptr, respPayloadLength,
+                                   responsePtr); // filling up the header here
+        BIOSStringTable.load(response);
+    }
+
+    return response;
+}
+
+/** @brief Find the string handle from the BIOS string table given the name
+ *
+ *  @param[in] name - name of the BIOS string
+ *  @param[in] BIOSStringTable - the string table
+ *  @return - uint16_t - handle of the string
+ */
+StringHandle findStringHandle(const std::string& name,
+                              const BIOSTable& BIOSStringTable)
+{
+    StringHandle hdl{};
+    Response response;
+    BIOSStringTable.load(response);
+
+    auto tableData = response.data();
+    size_t tableLen = response.size();
+    auto tableEntry =
+        reinterpret_cast<struct pldm_bios_string_table_entry*>(response.data());
+    while (1)
+    {
+        hdl = tableEntry->string_handle;
+        uint16_t len = tableEntry->string_length;
+        if (memcmp(name.c_str(), tableEntry->name, len) == 0)
+        {
+            break;
+        }
+        tableData += (sizeof(struct pldm_bios_string_table_entry) - 1) + len;
+
+        if (std::distance(tableData, response.data() + tableLen) <=
+            padChksumMax)
+        {
+            log<level::ERR>("Reached end of BIOS string table,did not find the "
+                            "handle for the string",
+                            entry("STRING=%s", name.c_str()));
+            elog<InternalFailure>();
+            break;
+        }
+
+        tableEntry =
+            reinterpret_cast<struct pldm_bios_string_table_entry*>(tableData);
+    }
+    return hdl;
+}
+
+/** @brief Find the string name from the BIOS string table for a string handle
+ *
+ *  @param[in] stringHdl - string handle
+ *  @param[in] BIOSStringTable - the string table
+ *
+ *  @return - std::string - name of the corresponding BIOS string
+ */
+std::string findStringName(StringHandle stringHdl,
+                           const BIOSTable& BIOSStringTable)
+{
+    std::string name;
+    Response response;
+    BIOSStringTable.load(response);
+
+    auto tableData = response.data();
+    size_t tableLen = response.size();
+    auto tableEntry =
+        reinterpret_cast<struct pldm_bios_string_table_entry*>(response.data());
+    while (1)
+    {
+        StringHandle currHdl = tableEntry->string_handle;
+        uint16_t len = tableEntry->string_length;
+        if (currHdl == stringHdl)
+        {
+            name.resize(len);
+            memcpy(name.data(), tableEntry->name, len);
+            break;
+        }
+        tableData += (sizeof(struct pldm_bios_string_table_entry) - 1) + len;
+
+        if (std::distance(tableData, response.data() + tableLen) <=
+            padChksumMax)
+        {
+            log<level::ERR>("Reached end of BIOS string table,did not find "
+                            "string name for handle",
+                            entry("STRING_HANDLE=%d", stringHdl));
+            break;
+        }
+
+        tableEntry =
+            reinterpret_cast<struct pldm_bios_string_table_entry*>(tableData);
+    }
+    return name;
+}
+
+namespace bios_type_enum
+{
+
+/** @brief Find the indices  into the array of the possible values of string
+ *  handles for the current values.This is used in attribute value table
+ *
+ *  @param[in] possiVals - vector of string handles comprising all the possible
+ *                         values for an attribute
+ *  @param[in] currVals - vector of strings comprising all current values
+ *                        for an attribute
+ *  @param[in] BIOSStringTable - the string table
+ *
+ *  @return - std::vector<uint8_t> - indices into the array of the possible
+ *                                   values of string handles
+ */
+std::vector<uint8_t> findStrIndices(PossibleValuesByHandle possiVals,
+                                    CurrentValues currVals,
+                                    const BIOSTable& BIOSStringTable)
+{
+    std::vector<uint8_t> stringIndices;
+
+    for (const auto& currVal : currVals)
+    {
+        StringHandle curHdl;
+        try
+        {
+            curHdl = findStringHandle(currVal, BIOSStringTable);
+        }
+        catch (InternalFailure& e)
+        {
+            log<level::ERR>("Exception fetching handle for the string",
+                            entry("STRING=%s", currVal.c_str()));
+            continue;
+        }
+
+        uint8_t i = 0;
+        for (auto possiHdl : possiVals)
+        {
+            if (possiHdl == curHdl)
+            {
+                stringIndices.push_back(i);
+                break;
+            }
+            i++;
+        }
+    }
+    return stringIndices;
+}
+
+/** @brief Find the indices into the array of the possible values of string
+ *  handles for the default values. This is used in attribute table
+ *
+ *  @param[in] possiVals - vector of strings comprising all the possible values
+ *                         for an attribute
+ *  @param[in] defVals - vector of strings comprising all the default values
+ *                       for an attribute
+ *  @return - std::vector<uint8_t> - indices into the array of the possible
+ *                                   values of string
+ */
+std::vector<uint8_t> findDefaultValHandle(const PossibleValues& possiVals,
+                                          const DefaultValues& defVals)
+{
+    std::vector<uint8_t> defHdls;
+    for (const auto& defs : defVals)
+    {
+        auto index = std::lower_bound(possiVals.begin(), possiVals.end(), defs);
+        if (index != possiVals.end())
+        {
+            defHdls.push_back(index - possiVals.begin());
+        }
+    }
+
+    return defHdls;
+}
+
+/** @brief Construct the attibute table for BIOS type Enumeration and
+ *         Enumeration ReadOnly
+ *  @param[in] BIOSStringTable - the string table
+ *  @param[in] biosJsonDir - path where the BIOS json files are present
+ *
+ *  @return - Table - the attribute eenumeration table
+ */
+Table constructAttrTable(const BIOSTable& BIOSStringTable,
+                         const char* biosJsonDir)
+{
+    setupValueLookup(biosJsonDir);
+    const auto& attributeMap = getValues();
+    Table attributeTable;
+    StringHandle strHandle;
+
+    for (const auto& [key, value] : attributeMap)
+    {
+        try
+        {
+            strHandle = findStringHandle(key, BIOSStringTable);
+        }
+        catch (InternalFailure& e)
+        {
+            log<level::ERR>("Could not find handle for BIOS string",
+                            entry("ATTRIBUTE=%s", key.c_str()));
+            continue;
+        }
+        uint8_t typeOfAttr = (std::get<0>(value))
+                                 ? PLDM_BIOS_ENUMERATION_READ_ONLY
+                                 : PLDM_BIOS_ENUMERATION;
+        PossibleValues possiVals = std::get<1>(value);
+        DefaultValues defVals = std::get<2>(value);
+        // both the possible and default values are stored in sorted manner to
+        // ease in fetching back/comparison
+        std::sort(possiVals.begin(), possiVals.end());
+        std::sort(defVals.begin(), defVals.end());
+
+        std::vector<StringHandle> possiValsByHdl;
+        for (const auto& elem : possiVals)
+        {
+            try
+            {
+                auto hdl = findStringHandle(elem, BIOSStringTable);
+                possiValsByHdl.push_back(std::move(hdl));
+            }
+            catch (InternalFailure& e)
+            {
+                log<level::ERR>("Could not find handle for BIOS string",
+                                entry("STRING=%s", elem.c_str()));
+                continue;
+            }
+        }
+        auto defValsByHdl = findDefaultValHandle(possiVals, defVals);
+
+        BIOSTableRow enumAttrTable(
+            (sizeof(struct pldm_bios_attr_table_entry) - 1) + sizeof(uint8_t) +
+                possiValsByHdl.size() * sizeof(uint16_t) + sizeof(uint8_t) +
+                defValsByHdl.size() * sizeof(uint8_t),
+            0);
+        BIOSTableRow::iterator it = enumAttrTable.begin();
+        auto attrPtr = reinterpret_cast<struct pldm_bios_attr_table_entry*>(
+            enumAttrTable.data());
+        attrPtr->attr_handle = nextAttributeHandle();
+        attrPtr->attr_type = typeOfAttr;
+        attrPtr->string_handle = std::move(strHandle);
+        std::advance(it, (sizeof(struct pldm_bios_attr_table_entry) - 1));
+        uint8_t numPossibleVals = possiValsByHdl.size();
+        std::copy_n(&numPossibleVals, sizeof(numPossibleVals), it);
+        std::advance(it, sizeof(numPossibleVals));
+        std::copy_n(reinterpret_cast<uint8_t*>(possiValsByHdl.data()),
+                    sizeof(uint16_t) * possiValsByHdl.size(), it);
+        std::advance(
+            it, sizeof(uint16_t) *
+                    possiValsByHdl.size()); // possible val handle is uint16_t
+        uint8_t numDefaultVals = defValsByHdl.size();
+        std::copy_n(&numDefaultVals, sizeof(numDefaultVals), it);
+        std::advance(it, sizeof(numDefaultVals));
+        std::copy(defValsByHdl.begin(), defValsByHdl.end(), it);
+        std::advance(it, defValsByHdl.size());
+
+        std::move(enumAttrTable.begin(), enumAttrTable.end(),
+                  std::back_inserter(attributeTable));
+    }
+
+    return attributeTable;
+}
+
+/** @brief Construct the attibute value table for BIOS type Enumeration and
+ *  Enumeration ReadOnly
+ *
+ *  @param[in] BIOSAttributeTable - the attribute table
+ *  @param[in] BIOSStringTable - the string table
+ *
+ *  @return - Table - the attribute value table
+ */
+Table constructAttrValueTable(const BIOSTable& BIOSAttributeTable,
+                              const BIOSTable& BIOSStringTable)
+{
+    Table attributeValueTable;
+    Response response;
+    BIOSAttributeTable.load(response);
+
+    auto tableData = response.data();
+    size_t tableLen = response.size();
+    auto attrPtr =
+        reinterpret_cast<struct pldm_bios_attr_table_entry*>(response.data());
+
+    while (1)
+    {
+        uint16_t attrHdl = attrPtr->attr_handle;
+        uint8_t attrType = attrPtr->attr_type;
+        uint16_t stringHdl = attrPtr->string_handle;
+        tableData += (sizeof(struct pldm_bios_attr_table_entry) - 1);
+        uint8_t numPossiVals = *tableData;
+        tableData++; // pass number of possible values
+        PossibleValuesByHandle possiValsByHdl(numPossiVals, 0);
+        memcpy(possiValsByHdl.data(), tableData,
+               sizeof(uint16_t) * numPossiVals);
+        tableData += sizeof(uint16_t) * numPossiVals;
+        uint8_t numDefVals = *tableData;
+        tableData++;             // pass number of def vals
+        tableData += numDefVals; // pass all the def val indices
+
+        auto attrName = findStringName(stringHdl, BIOSStringTable);
+        if (attrName.empty())
+        {
+            if (std::distance(tableData, response.data() + tableLen) <=
+                padChksumMax)
+            {
+                log<level::ERR>("Did not find string name for handle",
+                                entry("STRING_HANDLE=%d", stringHdl));
+                return attributeValueTable;
+            }
+            attrPtr =
+                reinterpret_cast<struct pldm_bios_attr_table_entry*>(tableData);
+            continue;
+        }
+        CurrentValues currVals;
+        try
+        {
+            currVals = getAttrValue(attrName);
+        }
+        catch (const std::exception& e)
+        {
+            log<level::ERR>(
+                "constructAttrValueTable returned error for attribute",
+                entry("NAME=%s", attrName.c_str()),
+                entry("ERROR=%s", e.what()));
+            if (std::distance(tableData, response.data() + tableLen) <=
+                padChksumMax)
+            {
+                return attributeValueTable;
+            }
+
+            attrPtr =
+                reinterpret_cast<struct pldm_bios_attr_table_entry*>(tableData);
+            continue;
+        }
+        // sorting since the possible values are stored in sorted way
+        std::sort(currVals.begin(), currVals.end());
+        auto currValStrIndices =
+            findStrIndices(possiValsByHdl, currVals, BIOSStringTable);
+        // number of current values equals to the number of string handles
+        // received not the number of strings received from getAttrValue
+        uint8_t numCurrVals = currValStrIndices.size();
+
+        BIOSTableRow enumAttrValTable(
+            (sizeof(struct pldm_bios_attr_val_table_entry) - 1) +
+                sizeof(uint8_t) + numCurrVals * sizeof(uint8_t),
+            0);
+        BIOSTableRow::iterator it = enumAttrValTable.begin();
+        auto attrValPtr =
+            reinterpret_cast<struct pldm_bios_attr_val_table_entry*>(
+                enumAttrValTable.data());
+        attrValPtr->attr_handle = attrHdl;
+        attrValPtr->attr_type = attrType;
+        std::advance(it, (sizeof(pldm_bios_attr_val_table_entry) - 1));
+        std::copy_n(&numCurrVals, sizeof(numCurrVals), it);
+        std::advance(it, sizeof(numCurrVals));
+        if (numCurrVals)
+        {
+            std::copy(currValStrIndices.begin(), currValStrIndices.end(), it);
+            std::advance(it, currValStrIndices.size());
+        }
+        std::move(enumAttrValTable.begin(), enumAttrValTable.end(),
+                  std::back_inserter(attributeValueTable));
+
+        if (std::distance(tableData, response.data() + tableLen) <=
+            padChksumMax)
+        {
+            break;
+        }
+
+        attrPtr =
+            reinterpret_cast<struct pldm_bios_attr_table_entry*>(tableData);
+    }
+
+    return attributeValueTable;
+}
+
+} // end namespace bios_type_enum
+
+/** @brief Construct the BIOS attribute table
+ *
+ *  @param[in] BIOSAttributeTable - the attribute table
+ *  @param[in] BIOSStringTable - the string table
+ *  @param[in] transferHandle - transfer handle to identify part of transfer
+ *  @param[in] transferOpFlag - flag to indicate which part of data being
+ * transferred
+ *  @param[in] instanceID - instance ID to identify the command
+ *  @param[in] biosJsonDir - path where the BIOS json files are present
+ */
+Response getBIOSAttributeTable(BIOSTable& BIOSAttributeTable,
+                               const BIOSTable& BIOSStringTable,
+                               uint32_t transferHandle, uint8_t transferOpFlag,
+                               uint8_t instanceID, const char* biosJsonDir)
+{
+    Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
+                      0);
+    auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+    uint32_t nxtTransferHandle = 0;
+    uint8_t transferFlag = PLDM_START_AND_END;
+    size_t respPayloadLength{};
+
+    if (BIOSAttributeTable.isEmpty())
+    { // no persisted table, constructing fresh table and response
+        auto attributeTable =
+            bios_type_enum::constructAttrTable(BIOSStringTable, biosJsonDir);
+
+        // calculate pad
+        uint8_t padSize = utils::getNumPadBytes(attributeTable.size());
+        std::vector<uint8_t> pad(padSize, 0);
+        if (padSize)
+        {
+            std::move(pad.begin(), pad.end(),
+                      std::back_inserter(attributeTable));
+        }
+
+        if (!attributeTable.empty())
+        {
+            // compute checksum
+            boost::crc_32_type result;
+            size_t size = attributeTable.size();
+            result.process_bytes(attributeTable.data(), size);
+            uint32_t checkSum = result.checksum();
+            attributeTable.resize(size + sizeof(checkSum));
+            std::copy_n(reinterpret_cast<uint8_t*>(&checkSum), sizeof(checkSum),
+                        attributeTable.data() + size);
+            BIOSAttributeTable.store(attributeTable);
+        }
+        response.resize(sizeof(pldm_msg_hdr) +
+                        PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
+                        attributeTable.size());
+        responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+        respPayloadLength = response.size();
+        encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
+                                   transferFlag, attributeTable.data(),
+                                   respPayloadLength, responsePtr);
+    }
+    else
+    { // persisted table present, constructing response
+        respPayloadLength = response.size();
+        encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
+                                   transferFlag, nullptr, respPayloadLength,
+                                   responsePtr); // filling up the header here
+        BIOSAttributeTable.load(response);
+    }
+
+    return response;
+}
+
+/** @brief Construct the BIOS attribute value table
+ *
+ *  @param[in] BIOSAttributeValueTable - the attribute value table
+ *  @param[in] BIOSAttributeTable - the attribute table
+ *  @param[in] BIOSStringTable - the string table
+ *  @param[in] transferHandle - transfer handle to identify part of transfer
+ *  @param[in] transferOpFlag - flag to indicate which part of data being
+ * transferred
+ *  @param[in] instanceID - instance ID to identify the command
+ *  @param[in] biosJsonDir -  path where the BIOS json files are present
+ */
+Response getBIOSAttributeValueTable(BIOSTable& BIOSAttributeValueTable,
+                                    const BIOSTable& BIOSAttributeTable,
+                                    const BIOSTable& BIOSStringTable,
+                                    uint32_t& transferHandle,
+                                    uint8_t& transferOpFlag, uint8_t instanceID,
+                                    const char* biosJsonDir)
+{
+    Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
+                      0);
+    auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+    uint32_t nxtTransferHandle = 0;
+    uint8_t transferFlag = PLDM_START_AND_END;
+    size_t respPayloadLength{};
+
+    if (BIOSAttributeValueTable.isEmpty())
+    { // no persisted table, constructing fresh table and data
+        Table attributeValueTable = bios_type_enum::constructAttrValueTable(
+            BIOSAttributeTable, BIOSStringTable);
+        // calculate pad
+        uint8_t padSize = utils::getNumPadBytes(attributeValueTable.size());
+        std::vector<uint8_t> pad(padSize, 0);
+        if (padSize)
+        {
+            std::move(pad.begin(), pad.end(),
+                      std::back_inserter(attributeValueTable));
+        }
+        if (!attributeValueTable.empty())
+        {
+            // compute checksum
+            boost::crc_32_type result;
+            result.process_bytes(attributeValueTable.data(),
+                                 attributeValueTable.size());
+            uint32_t checkSum = result.checksum();
+            size_t size = attributeValueTable.size();
+            attributeValueTable.resize(size + sizeof(checkSum));
+            std::copy_n(reinterpret_cast<uint8_t*>(&checkSum), sizeof(checkSum),
+                        attributeValueTable.data() + size);
+            BIOSAttributeValueTable.store(attributeValueTable);
+        }
+
+        response.resize(sizeof(pldm_msg_hdr) +
+                        PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
+                        attributeValueTable.size());
+        responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+        respPayloadLength = response.size();
+        encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
+                                   transferFlag, attributeValueTable.data(),
+                                   respPayloadLength, responsePtr);
+    }
+    else
+    { // persisted table present, constructing response
+        respPayloadLength = response.size();
+        encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle,
+                                   transferFlag, nullptr, respPayloadLength,
+                                   responsePtr); // filling up the header here
+        BIOSAttributeValueTable.load(response);
+    }
+
+    return response;
+}
+
+Response getBIOSTable(const pldm_msg* request, size_t payloadLength)
+{
+    auto response = internal::buildBIOSTables(request, payloadLength,
+                                              BIOS_JSONS_DIR, BIOS_TABLES_DIR);
+
+    return response;
+}
+
+namespace bios
+{
+
+void registerHandlers()
+{
+    registerHandler(PLDM_BIOS, PLDM_GET_DATE_TIME, std::move(getDateTime));
+    registerHandler(PLDM_BIOS, PLDM_GET_BIOS_TABLE, std::move(getBIOSTable));
+}
+
+namespace internal
+{
+
+Response buildBIOSTables(const pldm_msg* request, size_t payloadLength,
+                         const char* biosJsonDir, const char* biosTablePath)
+{
+    Response response(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES,
+                      0);
+    auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+
+    uint32_t transferHandle{};
+    uint8_t transferOpFlag{};
+    uint8_t tableType{};
+
+    auto rc = decode_get_bios_table_req(request, payloadLength, &transferHandle,
+                                        &transferOpFlag, &tableType);
+    if (rc == PLDM_SUCCESS)
+    {
+        BIOSTable BIOSStringTable(
+            ((std::string(biosTablePath) + "/stringTable")).c_str());
+        BIOSTable BIOSAttributeTable(
+            ((std::string(biosTablePath) + "/attributeTable")).c_str());
+        BIOSTable BIOSAttributeValueTable(
+            ((std::string(biosTablePath) + "/attributeValueTable")).c_str());
+        switch (tableType)
+        {
+            case PLDM_BIOS_STRING_TABLE:
+
+                response = getBIOSStringTable(
+                    BIOSStringTable, transferHandle, transferOpFlag,
+                    request->hdr.instance_id, biosJsonDir);
+                break;
+            case PLDM_BIOS_ATTR_TABLE:
+
+                if (BIOSStringTable.isEmpty())
+                {
+                    rc = PLDM_BIOS_TABLE_UNAVAILABLE;
+                }
+                else
+                {
+                    response = getBIOSAttributeTable(
+                        BIOSAttributeTable, BIOSStringTable, transferHandle,
+                        transferOpFlag, request->hdr.instance_id, biosJsonDir);
+                }
+                break;
+            case PLDM_BIOS_ATTR_VAL_TABLE:
+                if (BIOSAttributeTable.isEmpty())
+                {
+                    rc = PLDM_BIOS_TABLE_UNAVAILABLE;
+                }
+                else
+                {
+                    response = getBIOSAttributeValueTable(
+                        BIOSAttributeValueTable, BIOSAttributeTable,
+                        BIOSStringTable, transferHandle, transferOpFlag,
+                        request->hdr.instance_id, biosJsonDir);
+                }
+                break;
+            default:
+                rc = PLDM_INVALID_BIOS_TABLE_TYPE;
+                break;
+        }
+    }
+
+    if (rc != PLDM_SUCCESS)
+    {
+        uint32_t nxtTransferHandle{};
+        uint8_t transferFlag{};
+        size_t respPayloadLength{};
+
+        encode_get_bios_table_resp(request->hdr.instance_id, rc,
+                                   nxtTransferHandle, transferFlag, nullptr,
+                                   respPayloadLength, responsePtr);
+    }
+
+    return response;
+}
+
+} // end namespace internal
+} // namespace bios
+
 } // namespace responder
 } // namespace pldm
diff --git a/libpldmresponder/bios.hpp b/libpldmresponder/bios.hpp
index 2befe24..9bb7d23 100644
--- a/libpldmresponder/bios.hpp
+++ b/libpldmresponder/bios.hpp
@@ -1,7 +1,13 @@
 #pragma once
 
+#include "config.h"
+
+#include "bios_parser.hpp"
+#include "bios_table.hpp"
+
 #include <stdint.h>
 
+#include <map>
 #include <vector>
 
 #include "libpldm/bios.h"
@@ -10,6 +16,9 @@
 {
 
 using Response = std::vector<uint8_t>;
+using AttributeHandle = uint16_t;
+using StringHandle = uint16_t;
+using PossibleValuesByHandle = std::vector<StringHandle>;
 
 namespace responder
 {
@@ -19,6 +28,21 @@
 /** @brief Register handlers for command from the platform spec
  */
 void registerHandlers();
+
+namespace internal
+{
+
+/** @brief Constructs all the BIOS Tables
+ *
+ *  @param[in] request - Request message
+ *  @param[in] payload_length - Request message payload length
+ *  @param[in] biosJsonDir - path to fetch the BIOS json files
+ *  @param[in] biosTablePath - path where the BIOS tables will be persisted
+ */
+Response buildBIOSTables(const pldm_msg* request, size_t payloadLength,
+                         const char* biosJsonDir, const char* biosTablePath);
+} // end namespace internal
+
 } // namespace bios
 
 /** @brief Handler for GetDateTime
@@ -28,6 +52,14 @@
  */
 Response getDateTime(const pldm_msg* request, size_t payloadLength);
 
+/** @brief Handler for GetBIOSTable
+ *
+ *  @param[in] request - Request message
+ *  @param[in] payload_length - Request message payload length
+ *  @param[return] Response - PLDM Response message
+ */
+Response getBIOSTable(const pldm_msg* request, size_t payloadLength);
+
 namespace utils
 {
 
diff --git a/libpldmresponder/utils.cpp b/libpldmresponder/utils.cpp
index 254b21a..766a183 100644
--- a/libpldmresponder/utils.cpp
+++ b/libpldmresponder/utils.cpp
@@ -47,5 +47,16 @@
     return mapperResponse.begin()->first;
 }
 
+namespace utils
+{
+
+uint8_t getNumPadBytes(uint32_t data)
+{
+    uint8_t pad;
+    pad = ((data % 4) ? (4 - data % 4) : 0);
+    return pad;
+} // end getNumPadBytes
+
+} // end namespace utils
 } // namespace responder
 } // namespace pldm
diff --git a/libpldmresponder/utils.hpp b/libpldmresponder/utils.hpp
index 39c7ed6..6891d81 100644
--- a/libpldmresponder/utils.hpp
+++ b/libpldmresponder/utils.hpp
@@ -46,6 +46,13 @@
     int fd = -1;
 };
 
+/** @brief Calculate the pad for PLDM data
+ *
+ *  @param[in] data - Length of the data
+ *  @return - uint8_t - number of pad bytes
+ */
+uint8_t getNumPadBytes(uint32_t data);
+
 } // namespace utils
 
 /**