#include "bios_table.hpp" #include #include #include #include #include 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(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(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_check(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 buffer(strLength + 1 /* sizeof '\0' */); // Preconditions are upheld therefore no error check necessary pldm_bios_table_string_entry_decode_string_check(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_check( table.data() + tableSize, entryLength, str.c_str(), str.length()); return reinterpret_cast(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_check( 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(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_check( 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(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_check( 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 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_check(table.data() + tableSize, entryLength, info); return reinterpret_cast(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_check(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 pvHdls(pvNum, 0); // Preconditions are upheld therefore no error check necessary pldm_bios_table_attr_entry_enum_decode_pv_hdls_check(entry, pvHdls.data(), pvNum); // Preconditions are upheld therefore no error check necessary uint8_t defNum; pldm_bios_table_attr_entry_enum_decode_def_num_check(entry, &defNum); std::vector 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, ¤tString); 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 decodeEnumEntry(const pldm_bios_attr_val_table_entry* entry) { auto number = pldm_bios_table_attr_value_entry_enum_decode_number(entry); std::vector 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_check( 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(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_check( 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(table.data() + tableSize); } const pldm_bios_attr_val_table_entry* constructEnumEntry(Table& table, uint16_t attrHandle, uint8_t attrType, const std::vector& 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_check( 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(table.data() + tableSize); } std::optional 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