blob: d7e3e3959e018c2057ba01583ae609f4e553a238 [file] [log] [blame]
#include "bios_table.hpp"
#include <libpldm/base.h>
#include <libpldm/bios_table.h>
#include <libpldm/utils.h>
#include <phosphor-logging/lg2.hpp>
#include <fstream>
PHOSPHOR_LOG2_USING;
namespace pldm
{
namespace responder
{
namespace bios
{
BIOSTable::BIOSTable(const char* filePath) : filePath(filePath) {}
bool BIOSTable::isEmpty() const noexcept
{
bool empty = false;
try
{
empty = fs::is_empty(filePath);
}
catch (const fs::filesystem_error&)
{
return true;
}
return empty;
}
void BIOSTable::store(const Table& table)
{
std::ofstream stream(filePath.string(), std::ios::out | std::ios::binary);
stream.write(reinterpret_cast<const char*>(table.data()), table.size());
}
void BIOSTable::load(Response& response) const
{
auto currSize = response.size();
auto fileSize = fs::file_size(filePath);
response.resize(currSize + fileSize);
std::ifstream stream(filePath.string(), std::ios::in | std::ios::binary);
stream.read(reinterpret_cast<char*>(response.data() + currSize), fileSize);
}
BIOSStringTable::BIOSStringTable(const Table& stringTable) :
stringTable(stringTable)
{}
BIOSStringTable::BIOSStringTable(const BIOSTable& biosTable)
{
biosTable.load(stringTable);
}
std::string BIOSStringTable::findString(uint16_t handle) const
{
auto stringEntry = pldm_bios_table_string_find_by_handle(
stringTable.data(), stringTable.size(), handle);
if (stringEntry == nullptr)
{
throw std::invalid_argument("Invalid String Handle");
}
return table::string::decodeString(stringEntry);
}
uint16_t BIOSStringTable::findHandle(const std::string& name) const
{
auto stringEntry = pldm_bios_table_string_find_by_string(
stringTable.data(), stringTable.size(), name.c_str());
if (stringEntry == nullptr)
{
throw std::invalid_argument("Invalid String Name");
}
return table::string::decodeHandle(stringEntry);
}
namespace table
{
void appendPadAndChecksum(Table& table)
{
size_t payloadSize = table.size();
table.resize(payloadSize + pldm_bios_table_pad_checksum_size(payloadSize));
// No validation of return value as preconditions are satisfied
pldm_bios_table_append_pad_checksum(table.data(), table.size(),
&payloadSize);
}
namespace string
{
uint16_t decodeHandle(const pldm_bios_string_table_entry* entry)
{
return pldm_bios_table_string_entry_decode_handle(entry);
}
std::string decodeString(const pldm_bios_string_table_entry* entry)
{
auto strLength = pldm_bios_table_string_entry_decode_string_length(entry);
std::vector<char> buffer(strLength + 1 /* sizeof '\0' */);
// Preconditions are upheld therefore no error check necessary
pldm_bios_table_string_entry_decode_string(entry, buffer.data(),
buffer.size());
return std::string(buffer.data(), buffer.data() + strLength);
}
const pldm_bios_string_table_entry* constructEntry(Table& table,
const std::string& str)
{
auto tableSize = table.size();
auto entryLength = pldm_bios_table_string_entry_encode_length(str.length());
table.resize(tableSize + entryLength);
// Preconditions are upheld therefore no error check necessary
pldm_bios_table_string_entry_encode(table.data() + tableSize, entryLength,
str.c_str(), str.length());
return reinterpret_cast<pldm_bios_string_table_entry*>(table.data() +
tableSize);
}
} // namespace string
namespace attribute
{
TableHeader decodeHeader(const pldm_bios_attr_table_entry* entry)
{
auto attrHandle = pldm_bios_table_attr_entry_decode_attribute_handle(entry);
auto attrType = pldm_bios_table_attr_entry_decode_attribute_type(entry);
auto stringHandle = pldm_bios_table_attr_entry_decode_string_handle(entry);
return {attrHandle, attrType, stringHandle};
}
const pldm_bios_attr_table_entry* findByHandle(const Table& table,
uint16_t handle)
{
return pldm_bios_table_attr_find_by_handle(table.data(), table.size(),
handle);
}
const pldm_bios_attr_table_entry* findByStringHandle(const Table& table,
uint16_t handle)
{
return pldm_bios_table_attr_find_by_string_handle(table.data(),
table.size(), handle);
}
const pldm_bios_attr_table_entry*
constructStringEntry(Table& table,
pldm_bios_table_attr_entry_string_info* info)
{
auto entryLength =
pldm_bios_table_attr_entry_string_encode_length(info->def_length);
auto tableSize = table.size();
table.resize(tableSize + entryLength, 0);
int rc = pldm_bios_table_attr_entry_string_encode(table.data() + tableSize,
entryLength, info);
if (rc != PLDM_SUCCESS)
{
error("Failed to encode BIOS table string entry, response code '{RC}'",
"RC", rc);
throw std::runtime_error("Failed to encode BIOS table string entry");
}
return reinterpret_cast<pldm_bios_attr_table_entry*>(table.data() +
tableSize);
}
const pldm_bios_attr_table_entry*
constructIntegerEntry(Table& table,
pldm_bios_table_attr_entry_integer_info* info)
{
auto entryLength = pldm_bios_table_attr_entry_integer_encode_length();
auto tableSize = table.size();
table.resize(tableSize + entryLength, 0);
int rc = pldm_bios_table_attr_entry_integer_encode(table.data() + tableSize,
entryLength, info);
if (rc != PLDM_SUCCESS)
{
error(
"Failed to encode BIOS attribute table integer entry, response code '{RC}'",
"RC", rc);
throw std::runtime_error(
"Failed to encode BIOS attribute table integer entry");
}
return reinterpret_cast<pldm_bios_attr_table_entry*>(table.data() +
tableSize);
}
StringField decodeStringEntry(const pldm_bios_attr_table_entry* entry)
{
auto strType = pldm_bios_table_attr_entry_string_decode_string_type(entry);
auto minLength = pldm_bios_table_attr_entry_string_decode_min_length(entry);
auto maxLength = pldm_bios_table_attr_entry_string_decode_max_length(entry);
uint16_t defLength;
int rc = pldm_bios_table_attr_entry_string_decode_def_string_length(
entry, &defLength);
if (rc != PLDM_SUCCESS)
{
error(
"Failed to decode BIOS table string definition length, response code '{RC}'",
"RC", rc);
throw std::runtime_error(
"Failed to decode BIOS table string definitionlength");
}
std::vector<char> buffer(defLength + 1);
pldm_bios_table_attr_entry_string_decode_def_string(entry, buffer.data(),
buffer.size());
return {strType, minLength, maxLength, defLength,
std::string(buffer.data(), buffer.data() + defLength)};
}
IntegerField decodeIntegerEntry(const pldm_bios_attr_table_entry* entry)
{
uint64_t lower, upper, def;
uint32_t scalar;
pldm_bios_table_attr_entry_integer_decode(entry, &lower, &upper, &scalar,
&def);
return {lower, upper, scalar, def};
}
const pldm_bios_attr_table_entry*
constructEnumEntry(Table& table, pldm_bios_table_attr_entry_enum_info* info)
{
auto entryLength = pldm_bios_table_attr_entry_enum_encode_length(
info->pv_num, info->def_num);
auto tableSize = table.size();
table.resize(tableSize + entryLength, 0);
// Preconditions are upheld therefore no error check necessary
pldm_bios_table_attr_entry_enum_encode(table.data() + tableSize,
entryLength, info);
return reinterpret_cast<pldm_bios_attr_table_entry*>(table.data() +
tableSize);
}
EnumField decodeEnumEntry(const pldm_bios_attr_table_entry* entry)
{
uint8_t pvNum;
int rc = pldm_bios_table_attr_entry_enum_decode_pv_num(entry, &pvNum);
if (rc != PLDM_SUCCESS)
{
error(
"Failed to decode the number of possible values for BIOS table enum entry, response code '{RC}'",
"RC", rc);
throw std::runtime_error(
"Failed to decode the number of possible values for BIOS table enum entry");
}
std::vector<uint16_t> pvHdls(pvNum, 0);
// Preconditions are upheld therefore no error check necessary
pldm_bios_table_attr_entry_enum_decode_pv_hdls(entry, pvHdls.data(), pvNum);
// Preconditions are upheld therefore no error check necessary
uint8_t defNum;
pldm_bios_table_attr_entry_enum_decode_def_num(entry, &defNum);
std::vector<uint8_t> defIndices(defNum, 0);
pldm_bios_table_attr_entry_enum_decode_def_indices(entry, defIndices.data(),
defIndices.size());
return {pvHdls, defIndices};
}
} // namespace attribute
namespace attribute_value
{
TableHeader decodeHeader(const pldm_bios_attr_val_table_entry* entry)
{
auto handle =
pldm_bios_table_attr_value_entry_decode_attribute_handle(entry);
auto type = pldm_bios_table_attr_value_entry_decode_attribute_type(entry);
return {handle, type};
}
std::string decodeStringEntry(const pldm_bios_attr_val_table_entry* entry)
{
variable_field currentString{};
pldm_bios_table_attr_value_entry_string_decode_string(entry,
&currentString);
return std::string(currentString.ptr,
currentString.ptr + currentString.length);
}
uint64_t decodeIntegerEntry(const pldm_bios_attr_val_table_entry* entry)
{
return pldm_bios_table_attr_value_entry_integer_decode_cv(entry);
}
std::vector<uint8_t>
decodeEnumEntry(const pldm_bios_attr_val_table_entry* entry)
{
auto number = pldm_bios_table_attr_value_entry_enum_decode_number(entry);
std::vector<uint8_t> currHdls(number, 0);
pldm_bios_table_attr_value_entry_enum_decode_handles(entry, currHdls.data(),
currHdls.size());
return currHdls;
}
const pldm_bios_attr_val_table_entry*
constructStringEntry(Table& table, uint16_t attrHandle, uint8_t attrType,
const std::string& str)
{
auto strLen = str.size();
auto entryLength =
pldm_bios_table_attr_value_entry_encode_string_length(strLen);
auto tableSize = table.size();
table.resize(tableSize + entryLength);
int rc = pldm_bios_table_attr_value_entry_encode_string(
table.data() + tableSize, entryLength, attrHandle, attrType, strLen,
str.c_str());
if (rc != PLDM_SUCCESS)
{
error(
"Failed to encode BIOS attribute table string entry, response code '{RC}'",
"RC", rc);
throw std::runtime_error(
"Failed to encode BIOS attribute table string entry");
}
return reinterpret_cast<pldm_bios_attr_val_table_entry*>(table.data() +
tableSize);
}
const pldm_bios_attr_val_table_entry* constructIntegerEntry(Table& table,
uint16_t attrHandle,
uint8_t attrType,
uint64_t value)
{
auto entryLength = pldm_bios_table_attr_value_entry_encode_integer_length();
auto tableSize = table.size();
table.resize(tableSize + entryLength);
int rc = pldm_bios_table_attr_value_entry_encode_integer(
table.data() + tableSize, entryLength, attrHandle, attrType, value);
if (rc != PLDM_SUCCESS)
{
error(
"Failed to encode BIOS attribute table integer entry, response code '{RC}'",
"RC", rc);
throw std::runtime_error(
"Failed to encode BIOS attribute table integery entry");
}
return reinterpret_cast<pldm_bios_attr_val_table_entry*>(table.data() +
tableSize);
}
const pldm_bios_attr_val_table_entry*
constructEnumEntry(Table& table, uint16_t attrHandle, uint8_t attrType,
const std::vector<uint8_t>& handleIndices)
{
auto entryLength = pldm_bios_table_attr_value_entry_encode_enum_length(
handleIndices.size());
auto tableSize = table.size();
table.resize(tableSize + entryLength);
int rc = pldm_bios_table_attr_value_entry_encode_enum(
table.data() + tableSize, entryLength, attrHandle, attrType,
handleIndices.size(), handleIndices.data());
if (rc != PLDM_SUCCESS)
{
error(
"Failed to encode BIOS attribute table enum entry, response code '{RC}'",
"RC", rc);
throw std::runtime_error(
"Failed to encode BIOS attribute table enum entry");
}
return reinterpret_cast<pldm_bios_attr_val_table_entry*>(table.data() +
tableSize);
}
std::optional<Table> updateTable(const Table& table, const void* entry,
size_t size)
{
// Replace the old attribute with the new attribute, the size of table will
// change:
// sizeof(newTableBuffer) = srcTableSize + sizeof(newAttribute) -
// sizeof(oldAttribute) + pad(4-byte alignment, max =
// 3)
// For simplicity, we use
// sizeof(newTableBuffer) = srcTableSize + sizeof(newAttribute) + 3
size_t destBufferLength = table.size() + size + 3;
Table destTable(destBufferLength);
auto rc = pldm_bios_table_attr_value_copy_and_update(
table.data(), table.size(), destTable.data(), &destBufferLength, entry,
size);
if (rc != PLDM_SUCCESS)
{
return std::nullopt;
}
destTable.resize(destBufferLength);
return destTable;
}
} // namespace attribute_value
} // namespace table
} // namespace bios
} // namespace responder
} // namespace pldm