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/configure.ac b/configure.ac
index e06f062..a73f03a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -91,6 +91,9 @@
AX_APPEND_COMPILE_FLAGS([-DVERBOSE], [CFLAGS])
])
+AC_DEFINE(BIOS_JSONS_DIR, "/etc/pldm/bios", [Directory housing the json files for BIOS tables])
+AC_DEFINE(BIOS_TABLES_DIR, "/var/lib/pldm/bios", [Directory housing actual BIOS tables])
+
# Create configured output
AC_CONFIG_FILES([Makefile libpldm/Makefile libpldmresponder/Makefile test/Makefile])
AC_CONFIG_FILES([libpldm/libpldm.pc])
diff --git a/libpldm/bios.c b/libpldm/bios.c
index 9664318..3027f6c 100644
--- a/libpldm/bios.c
+++ b/libpldm/bios.c
@@ -86,3 +86,65 @@
return PLDM_SUCCESS;
}
+
+int encode_get_bios_table_resp(uint8_t instance_id, uint8_t completion_code,
+ uint32_t next_transfer_handle,
+ uint8_t transfer_flag, uint8_t *table_data,
+ size_t payload_length, struct pldm_msg *msg)
+{
+ struct pldm_header_info header = {0};
+ int rc = PLDM_SUCCESS;
+
+ if (msg == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ struct pldm_get_bios_table_resp *response =
+ (struct pldm_get_bios_table_resp *)msg->payload;
+
+ response->completion_code = completion_code;
+ header.msg_type = PLDM_RESPONSE;
+ header.instance = instance_id;
+ header.pldm_type = PLDM_BIOS;
+ header.command = PLDM_GET_BIOS_TABLE;
+ if ((rc = pack_pldm_header(&header, &(msg->hdr))) > PLDM_SUCCESS) {
+ return rc;
+ }
+
+ if (response->completion_code == PLDM_SUCCESS) {
+
+ response->next_transfer_handle = htole32(next_transfer_handle);
+ response->transfer_flag = transfer_flag;
+ if (table_data != NULL &&
+ payload_length > (sizeof(struct pldm_msg_hdr) +
+ PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES)) {
+ memcpy(response->table_data, table_data,
+ payload_length -
+ (sizeof(struct pldm_msg_hdr) +
+ PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES));
+ }
+ }
+ return PLDM_SUCCESS;
+}
+
+int decode_get_bios_table_req(const struct pldm_msg *msg, size_t payload_length,
+ uint32_t *transfer_handle,
+ uint8_t *transfer_op_flag, uint8_t *table_type)
+{
+ if (msg == NULL || transfer_op_flag == NULL || table_type == NULL ||
+ transfer_handle == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (payload_length != PLDM_GET_BIOS_TABLE_REQ_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_get_bios_table_req *request =
+ (struct pldm_get_bios_table_req *)msg->payload;
+ *transfer_handle = le32toh(request->transfer_handle);
+ *transfer_op_flag = request->transfer_op_flag;
+ *table_type = request->table_type;
+
+ return PLDM_SUCCESS;
+}
diff --git a/libpldm/bios.h b/libpldm/bios.h
index 7030f5d..d8886c3 100644
--- a/libpldm/bios.h
+++ b/libpldm/bios.h
@@ -14,7 +14,18 @@
/* Response lengths are inclusive of completion code */
#define PLDM_GET_DATE_TIME_RESP_BYTES 8
-enum pldm_bios_commands { PLDM_GET_DATE_TIME = 0x0c };
+#define PLDM_GET_BIOS_TABLE_REQ_BYTES 6
+#define PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES 6
+
+enum pldm_bios_completion_codes {
+ PLDM_BIOS_TABLE_UNAVAILABLE = 0x83,
+ PLDM_INVALID_BIOS_TABLE_DATA_INTEGRITY_CHECK = 0x84,
+ PLDM_INVALID_BIOS_TABLE_TYPE = 0x85,
+};
+enum pldm_bios_commands {
+ PLDM_GET_BIOS_TABLE = 0x01,
+ PLDM_GET_DATE_TIME = 0x0c
+};
enum pldm_bios_table_types {
PLDM_BIOS_STRING_TABLE,
@@ -46,6 +57,38 @@
uint8_t value[1];
} __attribute__((packed));
+enum pldm_bios_attribute_type {
+ PLDM_BIOS_ENUMERATION = 0x0,
+ PLDM_BIOS_STRING = 0x1,
+ PLDM_BIOS_PASSWORD = 0x2,
+ PLDM_BIOS_INTEGER = 0x3,
+ PLDM_BIOS_ENUMERATION_READ_ONLY = 0x80,
+ PLDM_BIOS_STRING_READ_ONLY = 0x81,
+ PLDM_BIOS_PASSWORD_READ_ONLY = 0x82,
+ PLDM_BIOS_INTEGER_READ_ONLY = 0x83,
+};
+
+/** @struct pldm_get_bios_table_req
+ *
+ * structure representing GetBIOSTable request packet
+ */
+struct pldm_get_bios_table_req {
+ uint32_t transfer_handle;
+ uint8_t transfer_op_flag;
+ uint8_t table_type;
+} __attribute__((packed));
+
+/** @struct pldm_get_bios_table_resp
+ *
+ * structure representing GetBIOSTable response packet
+ */
+struct pldm_get_bios_table_resp {
+ uint8_t completion_code;
+ uint32_t next_transfer_handle;
+ uint8_t transfer_flag;
+ uint8_t table_data[1];
+} __attribute__((packed));
+
/** @struct pldm_get_date_time_resp
*
* Structure representing PLDM get date time response
@@ -118,6 +161,40 @@
uint8_t day, uint8_t month, uint16_t year,
struct pldm_msg *msg);
+/* GetBIOSTable */
+
+/** @brief Create a PLDM response message for GetBIOSTable
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - PLDM completion code
+ * @param[in] next_transfer_handle - handle to identify the next portion of the
+ * transfer
+ * @param[in] transfer_flag - To indicate what part of the transfer this
+ * response represents
+ * @param[in] table_data - BIOS Table type specific data
+ * @param[in] payload_length - Length of payload message
+ * @param[out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ */
+int encode_get_bios_table_resp(uint8_t instance_id, uint8_t completion_code,
+ uint32_t next_transfer_handle,
+ uint8_t transfer_flag, uint8_t *table_data,
+ size_t payload_length, struct pldm_msg *msg);
+
+/** @brief Decode GetBIOSTable request packet
+ *
+ * @param[in] msg - Request message
+ * @param[in] payload_length - Length of request message payload
+ * @param[out] transfer_handle - Handle to identify a BIOS table transfer
+ * @param[out] transfer_op_flag - Flag to indicate the start of a multipart
+ * transfer
+ * @param[out] table_type - BIOS table type
+ * @return pldm_completion_codes
+ */
+int decode_get_bios_table_req(const struct pldm_msg *msg, size_t payload_length,
+ uint32_t *transfer_handle,
+ uint8_t *transfer_op_flag, uint8_t *table_type);
+
#ifdef __cplusplus
}
#endif
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
/**
diff --git a/test/Makefile.am b/test/Makefile.am
index cc0d6c2..4b0acca 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -72,16 +72,21 @@
libpldmresponder_bios_test_CXXFLAGS = $(test_cxxflags)
libpldmresponder_bios_test_LDFLAGS = \
$(test_ldflags) \
- $(SDBUSPLUS_LIBS)
+ $(SDBUSPLUS_LIBS) \
+ -lstdc++fs
libpldmresponder_bios_test_LDADD = \
$(top_builddir)/pldmd-registration.o \
$(top_builddir)/libpldmresponder/libpldmresponder_la-bios.o \
- $(top_builddir)/libpldmresponder/libpldmresponder_la-bios_parser.o \
$(top_builddir)/libpldmresponder/libpldmresponder_la-utils.o \
+ $(top_builddir)/libpldmresponder/libpldmresponder_la-bios_table.o \
$(top_builddir)/libpldm/libpldm_la-base.o \
$(top_builddir)/libpldm/libpldm_la-bios.o \
+ $(top_builddir)/libpldmresponder/libpldmresponder_la-bios_parser.o \
$(CODE_COVERAGE_LIBS) \
- $(SDBUSPLUS_LIBS)
+ $(PHOSPHOR_LOGGING_LIBS) \
+ $(PHOSPHOR_DBUS_INTERFACES_LIBS) \
+ $(SDBUSPLUS_LIBS) \
+ -lstdc++fs
libpldmresponder_bios_test_SOURCES = \
libpldmresponder_bios_test.cpp
@@ -112,7 +117,7 @@
libpldmoemresponder_fileio_test_CXXFLAGS = $(test_cxxflags)
libpldmoemresponder_fileio_test_LDFLAGS = $(test_ldflags)
libpldmoemresponder_fileio_test_LDADD = \
- $(top_builddir)/pldmd-registration.o \
+ $(top_builddir)/pldmd-registration.o \
$(top_builddir)/libpldm/libpldm_la-base.o \
$(top_builddir)/oem/ibm/libpldm/libpldm_la-file_io.o \
$(top_builddir)/oem/ibm/libpldmresponder/libpldmresponder_la-file_io.o\
@@ -136,17 +141,20 @@
libpldmresponder_bios_table_test_CPPFLAGS = $(test_cppflags)
libpldmresponder_bios_table_test_CXXFLAGS = $(test_cxxflags)
libpldmresponder_bios_table_test_LDFLAGS = \
- $(test_ldflags) \
- $(SDBUSPLUS_LIBS)
+ $(test_ldflags) \
+ $(SDBUSPLUS_LIBS)
libpldmresponder_bios_table_test_LDADD = \
- $(top_builddir)/libpldmresponder/libpldmresponder_la-bios.o \
- $(top_builddir)/libpldmresponder/libpldmresponder_la-bios_table.o \
- $(top_builddir)/libpldmresponder/libpldmresponder_la-utils.o \
- $(top_builddir)/libpldm/libpldm_la-base.o \
- $(top_builddir)/libpldm/libpldm_la-bios.o \
+ $(top_builddir)/libpldmresponder/libpldmresponder_la-bios.o \
+ $(top_builddir)/libpldmresponder/libpldmresponder_la-bios_table.o \
+ $(top_builddir)/libpldmresponder/libpldmresponder_la-utils.o \
+ $(top_builddir)/libpldm/libpldm_la-base.o \
+ $(top_builddir)/libpldm/libpldm_la-bios.o \
+ $(top_builddir)/libpldmresponder/libpldmresponder_la-bios_parser.o \
$(top_builddir)/pldmd-registration.o \
- $(CODE_COVERAGE_LIBS) \
- $(SDBUSPLUS_LIBS) \
+ $(CODE_COVERAGE_LIBS) \
+ $(SDBUSPLUS_LIBS) \
+ $(PHOSPHOR_LOGGING_LIBS) \
+ $(PHOSPHOR_DBUS_INTERFACES_LIBS) \
-lstdc++fs
libpldmresponder_bios_table_test_SOURCES = \
libpldmresponder_bios_table_test.cpp
diff --git a/test/libpldm_bios_test.cpp b/test/libpldm_bios_test.cpp
index 495a0d2..aff5d6d 100644
--- a/test/libpldm_bios_test.cpp
+++ b/test/libpldm_bios_test.cpp
@@ -112,3 +112,97 @@
ASSERT_EQ(month, retMonth);
ASSERT_EQ(year, retYear);
}
+
+TEST(GetBIOSTable, testGoodEncodeResponse)
+{
+ std::array<uint8_t,
+ sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES + 4>
+ responseMsg{};
+ auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+ uint8_t completionCode = PLDM_SUCCESS;
+ uint32_t nextTransferHandle = 32;
+ uint8_t transferFlag = PLDM_START_AND_END;
+ std::array<uint8_t, 4> tableData{1, 2, 3, 4};
+
+ auto rc = encode_get_bios_table_resp(
+ 0, PLDM_SUCCESS, nextTransferHandle, transferFlag, tableData.data(),
+ sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES + 4,
+ response);
+ ASSERT_EQ(rc, PLDM_SUCCESS);
+
+ struct pldm_get_bios_table_resp* resp =
+ reinterpret_cast<struct pldm_get_bios_table_resp*>(response->payload);
+
+ ASSERT_EQ(completionCode, resp->completion_code);
+ ASSERT_EQ(nextTransferHandle, resp->next_transfer_handle);
+ ASSERT_EQ(transferFlag, resp->transfer_flag);
+ ASSERT_EQ(0, memcmp(tableData.data(), resp->table_data, tableData.size()));
+}
+
+TEST(GetBIOSTable, testBadEncodeResponse)
+{
+ uint32_t nextTransferHandle = 32;
+ uint8_t transferFlag = PLDM_START_AND_END;
+ std::array<uint8_t, 4> tableData{1, 2, 3, 4};
+
+ auto rc = encode_get_bios_table_resp(
+ 0, PLDM_SUCCESS, nextTransferHandle, transferFlag, tableData.data(),
+ sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES + 4, nullptr);
+ ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}
+
+TEST(GetBIOSTable, testGoodDecodeRequest)
+{
+ const auto hdr_size = sizeof(pldm_msg_hdr);
+ std::array<uint8_t, hdr_size + PLDM_GET_BIOS_TABLE_REQ_BYTES> requestMsg{};
+ uint32_t transferHandle = 31;
+ uint8_t transferOpFlag = PLDM_GET_FIRSTPART;
+ uint8_t tableType = PLDM_BIOS_ATTR_TABLE;
+ uint32_t retTransferHandle = 0;
+ uint8_t retTransferOpFlag = 0;
+ uint8_t retTableType = 0;
+
+ auto req = reinterpret_cast<pldm_msg*>(requestMsg.data());
+ struct pldm_get_bios_table_req* request =
+ reinterpret_cast<struct pldm_get_bios_table_req*>(req->payload);
+
+ request->transfer_handle = transferHandle;
+ request->transfer_op_flag = transferOpFlag;
+ request->table_type = tableType;
+
+ auto rc = decode_get_bios_table_req(req, requestMsg.size() - hdr_size,
+ &retTransferHandle, &retTransferOpFlag,
+ &retTableType);
+
+ ASSERT_EQ(rc, PLDM_SUCCESS);
+ ASSERT_EQ(transferHandle, retTransferHandle);
+ ASSERT_EQ(transferOpFlag, retTransferOpFlag);
+ ASSERT_EQ(tableType, retTableType);
+}
+
+TEST(GetBIOSTable, testBadDecodeRequest)
+{
+ const auto hdr_size = sizeof(pldm_msg_hdr);
+ std::array<uint8_t, hdr_size + PLDM_GET_BIOS_TABLE_REQ_BYTES> requestMsg{};
+ uint32_t transferHandle = 31;
+ uint8_t transferOpFlag = PLDM_GET_FIRSTPART;
+ uint8_t tableType = PLDM_BIOS_ATTR_TABLE;
+ uint32_t retTransferHandle = 0;
+ uint8_t retTransferOpFlag = 0;
+ uint8_t retTableType = 0;
+
+ auto req = reinterpret_cast<pldm_msg*>(requestMsg.data());
+ struct pldm_get_bios_table_req* request =
+ reinterpret_cast<struct pldm_get_bios_table_req*>(req->payload);
+
+ request->transfer_handle = transferHandle;
+ request->transfer_op_flag = transferOpFlag;
+ request->table_type = tableType;
+
+ auto rc = decode_get_bios_table_req(req, requestMsg.size() - hdr_size - 3,
+ &retTransferHandle, &retTransferOpFlag,
+ &retTableType);
+
+ ASSERT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
diff --git a/test/libpldmresponder_bios_test.cpp b/test/libpldmresponder_bios_test.cpp
index 6e404de..b5b207b 100644
--- a/test/libpldmresponder_bios_test.cpp
+++ b/test/libpldmresponder_bios_test.cpp
@@ -1,18 +1,24 @@
#include "libpldmresponder/bios.hpp"
#include "libpldmresponder/bios_parser.hpp"
+#include "libpldmresponder/bios_table.hpp"
#include <string.h>
#include <array>
#include <ctime>
+#include <filesystem>
#include "libpldm/base.h"
#include "libpldm/bios.h"
#include <gtest/gtest.h>
+using namespace pldm;
using namespace pldm::responder;
+using namespace pldm::responder::bios;
using namespace pldm::responder::utils;
+using namespace bios_parser;
+using namespace bios_parser::bios_enum;
TEST(epochToBCDTime, testTime)
{
@@ -67,15 +73,6 @@
TEST(getAttrValue, allScenarios)
{
using namespace bios_parser::bios_enum;
-
- // Invalid directory
- auto rc = setupValueLookup("./bios_json");
- ASSERT_EQ(rc, -1);
-
- // Initializes the lookup data structures
- rc = setupValueLookup("./bios_jsons");
- ASSERT_EQ(rc, 0);
-
// All the BIOS Strings in the BIOS JSON config files.
AttrValuesMap valueMap{
{"HMCManagedState", {false, {"On", "Off"}, {"On"}}},
@@ -84,6 +81,9 @@
{"CodeUpdatePolicy",
{false, {"Concurrent", "Disruptive"}, {"Concurrent"}}}};
+ auto rc = setupValueLookup("./bios_jsons");
+ ASSERT_EQ(rc, 0);
+
auto values = getValues();
ASSERT_EQ(valueMap == values, true);
@@ -94,3 +94,291 @@
// Invalid attribute name
ASSERT_THROW(getAttrValue("CodeUpdatePolic"), std::out_of_range);
}
+
+namespace fs = std::filesystem;
+class TestAllBIOSTables : public ::testing::Test
+{
+ public:
+ static void SetUpTestCase() // will execute once at the begining of all
+ // TestAllBIOSTables objects
+ {
+ char tmpdir[] = "/tmp/allBiosTables.XXXXXX";
+ biosPath = fs::path(mkdtemp(tmpdir));
+ }
+
+ static void TearDownTestCase() // will be executed once at th eend of all
+ // TestAllBIOSTables objects
+ {
+ fs::remove_all(biosPath);
+ }
+
+ static fs::path biosPath;
+};
+
+fs::path TestAllBIOSTables::biosPath;
+
+TEST_F(TestAllBIOSTables, GetBIOSTableTestBadRequest)
+{
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_REQ_BYTES>
+ requestPayload{};
+ auto request = reinterpret_cast<pldm_msg*>(requestPayload.data());
+ struct pldm_get_bios_table_req* req =
+ (struct pldm_get_bios_table_req*)request->payload;
+ req->transfer_handle = 9;
+ req->transfer_op_flag = PLDM_GET_FIRSTPART;
+ req->table_type = 0xFF;
+
+ size_t requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr);
+
+ auto response = internal::buildBIOSTables(request, requestPayloadLength,
+ "./bios_jsons", biosPath.c_str());
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+
+ struct pldm_get_bios_table_resp* resp =
+ reinterpret_cast<struct pldm_get_bios_table_resp*>(
+ responsePtr->payload);
+
+ ASSERT_EQ(PLDM_INVALID_BIOS_TABLE_TYPE, resp->completion_code);
+}
+
+TEST_F(TestAllBIOSTables, buildBIOSTablesTestBadRequest)
+{
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_REQ_BYTES>
+ requestPayload{};
+ auto request = reinterpret_cast<pldm_msg*>(requestPayload.data());
+ struct pldm_get_bios_table_req* req =
+ (struct pldm_get_bios_table_req*)request->payload;
+ req->transfer_handle = 9;
+ req->transfer_op_flag = PLDM_GET_FIRSTPART;
+ req->table_type = PLDM_BIOS_ATTR_VAL_TABLE;
+
+ size_t requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr);
+
+ auto response = internal::buildBIOSTables(request, requestPayloadLength,
+ "./bios_jsons", biosPath.c_str());
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ struct pldm_get_bios_table_resp* resp =
+ reinterpret_cast<struct pldm_get_bios_table_resp*>(
+ responsePtr->payload);
+ ASSERT_EQ(PLDM_BIOS_TABLE_UNAVAILABLE, resp->completion_code);
+
+ req->table_type = PLDM_BIOS_ATTR_TABLE;
+ response = internal::buildBIOSTables(request, requestPayloadLength,
+ "./bios_jsons", biosPath.c_str());
+ responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ resp = reinterpret_cast<struct pldm_get_bios_table_resp*>(
+ responsePtr->payload);
+ ASSERT_EQ(PLDM_BIOS_TABLE_UNAVAILABLE, resp->completion_code);
+}
+
+TEST_F(TestAllBIOSTables, GetBIOSStringTableTestGoodRequest)
+{
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_REQ_BYTES>
+ requestPayload{};
+ auto request = reinterpret_cast<pldm_msg*>(requestPayload.data());
+ struct pldm_get_bios_table_req* req =
+ (struct pldm_get_bios_table_req*)request->payload;
+ req->transfer_handle = 9;
+ req->transfer_op_flag = PLDM_GET_FIRSTPART;
+ req->table_type = PLDM_BIOS_STRING_TABLE;
+
+ Strings biosStrings = getStrings("./bios_jsons");
+ std::sort(biosStrings.begin(), biosStrings.end());
+ biosStrings.erase(std::unique(biosStrings.begin(), biosStrings.end()),
+ biosStrings.end());
+
+ size_t requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr);
+ uint8_t times = 0;
+ while (times < 2)
+ { // first time fresh table second time existing table
+ auto response = internal::buildBIOSTables(
+ request, requestPayloadLength, "./bios_jsons", biosPath.c_str());
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+
+ struct pldm_get_bios_table_resp* resp =
+ reinterpret_cast<struct pldm_get_bios_table_resp*>(
+ responsePtr->payload);
+
+ ASSERT_EQ(0, resp->completion_code);
+ ASSERT_EQ(0, resp->next_transfer_handle);
+ ASSERT_EQ(PLDM_START_AND_END, resp->transfer_flag);
+
+ uint16_t strLen = 0;
+ uint8_t* tableData = reinterpret_cast<uint8_t*>(resp->table_data);
+
+ for (auto elem : biosStrings)
+ {
+ struct pldm_bios_string_table_entry* ptr =
+ reinterpret_cast<struct pldm_bios_string_table_entry*>(
+ tableData);
+ strLen = ptr->string_length;
+ ASSERT_EQ(strLen, elem.size());
+ ASSERT_EQ(0, memcmp(elem.c_str(), ptr->name, strLen));
+ tableData += (sizeof(pldm_bios_string_table_entry) - 1) + strLen;
+
+ } // end for
+ times++;
+ }
+}
+
+TEST_F(TestAllBIOSTables, getBIOSAttributeTableTestGoodRequest)
+{
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_REQ_BYTES>
+ requestPayload{};
+ auto request = reinterpret_cast<pldm_msg*>(requestPayload.data());
+ struct pldm_get_bios_table_req* req =
+ (struct pldm_get_bios_table_req*)request->payload;
+ req->transfer_handle = 9;
+ req->transfer_op_flag = PLDM_GET_FIRSTPART;
+ req->table_type = PLDM_BIOS_ATTR_TABLE;
+
+ size_t requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr);
+
+ uint8_t times = 0;
+ while (times < 2)
+ { // first time fresh table second time existing table
+ auto response = internal::buildBIOSTables(
+ request, requestPayloadLength, "./bios_jsons", biosPath.c_str());
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+
+ struct pldm_get_bios_table_resp* resp =
+ reinterpret_cast<struct pldm_get_bios_table_resp*>(
+ responsePtr->payload);
+
+ ASSERT_EQ(0, resp->completion_code);
+ ASSERT_EQ(0, resp->next_transfer_handle);
+ ASSERT_EQ(PLDM_START_AND_END, resp->transfer_flag);
+
+ uint32_t attrTableLen =
+ response.size() - sizeof(pldm_msg_hdr) -
+ (sizeof(resp->completion_code) +
+ sizeof(resp->next_transfer_handle) + sizeof(resp->transfer_flag));
+ uint32_t traversed = 0;
+ uint16_t attrHdl = 0;
+ uint16_t stringHdl = 0;
+ uint8_t attrType = 0;
+ uint8_t numPosVals = 0;
+ uint8_t numDefVals = 0;
+ uint8_t defIndex = 0;
+
+ uint8_t* tableData = reinterpret_cast<uint8_t*>(resp->table_data);
+ while (1)
+ {
+ struct pldm_bios_attr_table_entry* ptr =
+ reinterpret_cast<struct pldm_bios_attr_table_entry*>(tableData);
+ attrHdl = ptr->attr_handle;
+ attrType = ptr->attr_type;
+ EXPECT_EQ(0, attrHdl);
+ EXPECT_EQ(PLDM_BIOS_ENUMERATION, attrType);
+ stringHdl = ptr->string_handle;
+ EXPECT_EQ(stringHdl, 1);
+ tableData += sizeof(attrHdl) + sizeof(attrType) + sizeof(stringHdl);
+ numPosVals = *tableData;
+ EXPECT_EQ(numPosVals, 2);
+ traversed += sizeof(attrHdl) + sizeof(attrType) + sizeof(stringHdl);
+ traversed += sizeof(numPosVals);
+ PossibleValuesByHandle possiVals;
+ tableData++;
+ uint16_t* temp = reinterpret_cast<uint16_t*>(tableData);
+ uint32_t i = 0;
+ while (i < numPosVals)
+ {
+ uint16_t val = *temp;
+ possiVals.push_back(val);
+ temp++;
+ i++;
+ }
+ EXPECT_EQ(possiVals.size(), 2);
+ tableData += numPosVals * sizeof(stringHdl);
+ traversed += numPosVals * sizeof(stringHdl);
+ numDefVals = *tableData;
+ EXPECT_EQ(numDefVals, 1);
+ tableData += numDefVals * sizeof(defIndex);
+ traversed += numDefVals + sizeof(numDefVals);
+
+ break; // test for first row only
+
+ if ((attrTableLen - traversed) < 8)
+ {
+ // reached pad
+ break;
+ }
+
+ } // end while
+ times++;
+ }
+
+} // end TEST
+
+TEST_F(TestAllBIOSTables, getBIOSAttributeValueTableTestGoodRequest)
+{
+ std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_REQ_BYTES>
+ requestPayload{};
+ auto request = reinterpret_cast<pldm_msg*>(requestPayload.data());
+ struct pldm_get_bios_table_req* req =
+ (struct pldm_get_bios_table_req*)request->payload;
+ req->transfer_handle = 9;
+ req->transfer_op_flag = PLDM_GET_FIRSTPART;
+ req->table_type = PLDM_BIOS_ATTR_VAL_TABLE;
+
+ std::string attrName("CodeUpdatePolicy");
+ CurrentValues currVals = getAttrValue(attrName);
+
+ size_t requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr);
+
+ uint8_t times = 0;
+ while (times < 2)
+ { // first time frest table second time existing table
+ auto response = internal::buildBIOSTables(
+ request, requestPayloadLength, "./bios_jsons", biosPath.c_str());
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+
+ struct pldm_get_bios_table_resp* resp =
+ reinterpret_cast<struct pldm_get_bios_table_resp*>(
+ responsePtr->payload);
+
+ ASSERT_EQ(0, resp->completion_code);
+ ASSERT_EQ(0, resp->next_transfer_handle);
+ ASSERT_EQ(PLDM_START_AND_END, resp->transfer_flag);
+
+ uint32_t attrValTableLen =
+ response.size() - sizeof(pldm_msg_hdr) -
+ (sizeof(resp->completion_code) +
+ sizeof(resp->next_transfer_handle) + sizeof(resp->transfer_flag));
+ uint32_t traversed = 0;
+ uint8_t* tableData = reinterpret_cast<uint8_t*>(resp->table_data);
+
+ uint16_t attrHdl;
+ uint8_t attrType;
+ uint8_t numCurrVals;
+ uint8_t currValStrIndex;
+
+ while (1)
+ {
+ struct pldm_bios_attr_val_table_entry* ptr =
+ reinterpret_cast<struct pldm_bios_attr_val_table_entry*>(
+ tableData);
+ attrHdl = ptr->attr_handle;
+ attrType = ptr->attr_type;
+ EXPECT_EQ(0, attrHdl);
+ EXPECT_EQ(PLDM_BIOS_ENUMERATION, attrType);
+ tableData += sizeof(attrHdl) + sizeof(attrType);
+ traversed += sizeof(attrHdl) + sizeof(attrType);
+ numCurrVals = *tableData;
+ EXPECT_EQ(1, numCurrVals);
+ tableData += sizeof(numCurrVals);
+ traversed += sizeof(numCurrVals);
+ currValStrIndex = *tableData;
+ EXPECT_EQ(0, currValStrIndex);
+ tableData += numCurrVals;
+ traversed += numCurrVals;
+ break; // testing for first row
+ if ((attrValTableLen - traversed) < 8)
+ {
+ break;
+ }
+ }
+ times++;
+ }
+
+} // end TEST