pldmtool: Implement GetBIOSTable for the stringtable.

./pldmtool bios GetBIOSTable --help
get bios table
Usage: ./pldmtool bios GetBIOSTable [OPTIONS]

Options:
  -h,--help                   Print this help message and exit
  -t,--type ENUM:value in {StringTable->0,AttributeTable->1,AttributeValueTable->2} OR {0,1,2} REQUIRED
                              pldm bios table type

./pldmtool bios GetBIOSTable --type StringTable
Encode request successfully
Request Message:
08 01 80 03 01 20 00 00 00 01 00
Response Message:
08 01 00 03 01 00 00 00 00 00 05 00 00 07 00 41 6c 6c 6f 77 65 64 01 00 08 00 44 69 73 61 62 6c 65 64 02 00 07 00 45 6e 61 62 6c 65 64 03 00 0b 00 4e 6f 74 20 41 6c 6c 6f 77 65 64 04 00 04 00 50 65 72 6d 05 00 04 00 54 65 6d 70 06 00 10 00 70 76 6d 2d 66 77 2d 62 6f 6f 74 2d 73 69 64 65 07 00 16 00 70 76 6d 2d 69 6e 62 61 6e 64 2d 63 6f 64 65 2d 75 70 64 61 74 65 08 00 10 00 70 76 6d 2d 6f 73 2d 62 6f 6f 74 2d 73 69 64 65 09 00 15 00 70 76 6d 2d 70 63 69 65 2d 65 72 72 6f 72 2d 69 6e 6a 65 63 74 0a 00 10 00 70 76 6d 2d 73 75 72 76 65 69 6c 6c 61 6e 63 65 0b 00 0f 00 70 76 6d 2d 73 79 73 74 65 6d 2d 6e 61 6d 65 0c 00 0c 00 76 6d 69 2d 69 66 2d 63 6f 75 6e 74 00 18 b5 78 78
Parsed Response Msg:
BIOSStringHandle : BIOSString
0 : Allowed
1 : Disabled
2 : Enabled
3 : Not Allowed
4 : Perm
5 : Temp
6 : pvm-fw-boot-side
7 : pvm-inband-code-update
8 : pvm-os-boot-side
9 : pvm-pcie-error-inject
10 : pvm-surveillance
11 : pvm-system-name
12 : vmi-if-count

Signed-off-by: Sridevi Ramesh <sridevra@in.ibm.com>
Change-Id: Id1bc69ba3a2a045a252f795622e5a3183dfcb135
diff --git a/tool/pldm_bios_cmd.cpp b/tool/pldm_bios_cmd.cpp
index 0ff32bd..1fb9853 100644
--- a/tool/pldm_bios_cmd.cpp
+++ b/tool/pldm_bios_cmd.cpp
@@ -2,6 +2,7 @@
 
 #include "pldm_cmd_helper.hpp"
 
+#include "libpldm/bios_table.h"
 #include "libpldm/utils.h"
 
 namespace pldmtool
@@ -17,6 +18,12 @@
 
 std::vector<std::unique_ptr<CommandInterface>> commands;
 
+const std::map<const char*, pldm_bios_table_types> pldmBIOSTableTypes{
+    {"StringTable", PLDM_BIOS_STRING_TABLE},
+    {"AttributeTable", PLDM_BIOS_ATTR_TABLE},
+    {"AttributeValueTable", PLDM_BIOS_ATTR_VAL_TABLE},
+};
+
 } // namespace
 
 class GetDateTime : public CommandInterface
@@ -147,6 +154,121 @@
     uint64_t tmData;
 };
 
+class GetBIOSTable : public CommandInterface
+{
+  public:
+    ~GetBIOSTable() = default;
+    GetBIOSTable() = delete;
+    GetBIOSTable(const GetBIOSTable&) = delete;
+    GetBIOSTable(GetBIOSTable&&) = default;
+    GetBIOSTable& operator=(const GetBIOSTable&) = delete;
+    GetBIOSTable& operator=(GetBIOSTable&&) = default;
+
+    using CommandInterface::CommandInterface;
+
+    explicit GetBIOSTable(const char* type, const char* name, CLI::App* app) :
+        CommandInterface(type, name, app)
+    {
+        app->add_option("-t,--type", pldmBIOSTableType, "pldm bios table type")
+            ->required()
+            ->transform(
+                CLI::CheckedTransformer(pldmBIOSTableTypes, CLI::ignore_case));
+    }
+
+    std::pair<int, std::vector<uint8_t>> createRequestMsg() override
+    {
+        uint32_t nextTransferHandle = 32;
+
+        std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
+                                        PLDM_GET_BIOS_TABLE_REQ_BYTES);
+        auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+        auto rc = encode_get_bios_table_req(
+            PLDM_LOCAL_INSTANCE_ID, nextTransferHandle, PLDM_GET_FIRSTPART,
+            pldmBIOSTableType, request);
+        return {rc, requestMsg};
+    }
+
+    void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
+    {
+        uint8_t cc = 0, transferFlag = 0;
+        uint32_t nextTransferHandle = 0;
+        size_t bios_table_offset;
+
+        auto rc = decode_get_bios_table_resp(responsePtr, payloadLength, &cc,
+                                             &nextTransferHandle, &transferFlag,
+                                             &bios_table_offset);
+
+        if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
+        {
+            std::cerr << "Response Message Error: "
+                      << "rc=" << rc << ",cc=" << (int)cc << std::endl;
+            return;
+        }
+        auto tableData =
+            reinterpret_cast<char*>((responsePtr->payload) + bios_table_offset);
+        auto tableSize =
+            payloadLength - sizeof(nextTransferHandle) - sizeof(transferFlag);
+        printBIOSTable(tableData, tableSize, pldmBIOSTableType);
+    }
+
+  private:
+    pldm_bios_table_types pldmBIOSTableType;
+
+    void decodeStringTable(const void* tableData, size_t tableSize)
+    {
+        std::cout << "Parsed Response Msg: " << std::endl;
+        std::cout << "BIOSStringHandle : BIOSString" << std::endl;
+        std::string strTableData;
+        std::unique_ptr<pldm_bios_table_iter,
+                        decltype(&pldm_bios_table_iter_free)>
+            iter(pldm_bios_table_iter_create(tableData, tableSize,
+                                             PLDM_BIOS_STRING_TABLE),
+                 pldm_bios_table_iter_free);
+        while (!pldm_bios_table_iter_is_end(iter.get()))
+        {
+            try
+            {
+                auto tableEntry =
+                    pldm_bios_table_iter_string_entry_value(iter.get());
+                auto strLength =
+                    pldm_bios_table_string_entry_decode_string_length(
+                        tableEntry);
+                strTableData.resize(strLength + 1);
+                auto strHandle =
+                    pldm_bios_table_string_entry_decode_handle(tableEntry);
+                pldm_bios_table_string_entry_decode_string(
+                    tableEntry, strTableData.data(), strTableData.size());
+                std::cout << strHandle << " : " << strTableData << std::endl;
+            }
+            catch (const std::exception& e)
+            {
+                std::cerr
+                    << "handler fails when traversing BIOSStringTable, ERROR="
+                    << e.what() << "\n";
+            }
+            pldm_bios_table_iter_next(iter.get());
+        }
+    }
+    void printBIOSTable(const void* tableData, size_t tableSize,
+                        enum pldm_bios_table_types type)
+    {
+        if (!tableSize)
+        {
+            std::cerr << "Found table size null." << std::endl;
+            return;
+        }
+        switch (type)
+        {
+            case PLDM_BIOS_STRING_TABLE:
+                decodeStringTable(tableData, tableSize);
+                break;
+            default:
+                break;
+        }
+    }
+};
+
 void registerCommand(CLI::App& app)
 {
     auto bios = app.add_subcommand("bios", "bios type command");
@@ -159,6 +281,10 @@
         bios->add_subcommand("SetDateTime", "set host date time");
     commands.push_back(
         std::make_unique<SetDateTime>("bios", "setDateTime", setDateTime));
+
+    auto getBIOSTable = bios->add_subcommand("GetBIOSTable", "get bios table");
+    commands.push_back(
+        std::make_unique<GetBIOSTable>("bios", "GetBIOSTable", getBIOSTable));
 }
 
 } // namespace bios