| #include "bios_table.hpp" |
| |
| #include <libpldm/base.h> |
| #include <libpldm/bios_table.h> |
| #include <libpldm/utils.h> |
| |
| #include <phosphor-logging/lg2.hpp> |
| |
| #include <fstream> |
| |
| 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& e) |
| { |
| 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_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<char> 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<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_check( |
| table.data() + tableSize, entryLength, info); |
| if (rc != PLDM_SUCCESS) |
| { |
| lg2::error("Failed to encode BIOS table string entry: {LIBPLDM_ERROR}", |
| "LIBPLDM_ERROR", 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_check( |
| table.data() + tableSize, entryLength, info); |
| if (rc != PLDM_SUCCESS) |
| { |
| lg2::error( |
| "Failed to encode BIOS attribute table integer entry: {LIBPLDM_ERROR}", |
| "LIBPLDM_ERROR", 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_check( |
| entry, &defLength); |
| if (rc != PLDM_SUCCESS) |
| { |
| lg2::error( |
| "Failed to decode BIOS table string definition length: {LIBPLDM_ERROR}", |
| "LIBPLDM_ERROR", 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_check(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_check(entry, &pvNum); |
| if (rc != PLDM_SUCCESS) |
| { |
| lg2::error( |
| "Failed to decode the number of possible values for BIOS table enum entry: {LIBPLDM_ERROR}", |
| "LIBPLDM_ERROR", 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_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<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, |
| ¤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<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_check( |
| table.data() + tableSize, entryLength, attrHandle, attrType, strLen, |
| str.c_str()); |
| if (rc != PLDM_SUCCESS) |
| { |
| lg2::error( |
| "Failed to encode BIOS attribute table string entry: {LIBPLDM_ERROR}", |
| "LIBPLDM_ERROR", 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); |
| pldm_bios_table_attr_value_entry_encode_integer( |
| table.data() + tableSize, entryLength, attrHandle, attrType, value); |
| 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_check( |
| table.data() + tableSize, entryLength, attrHandle, attrType, |
| handleIndices.size(), handleIndices.data()); |
| if (rc != PLDM_SUCCESS) |
| { |
| lg2::error( |
| "Failed to encode BIOS attribute table enum entry: {LIBPLDM_ERROR}", |
| "LIBPLDM_ERROR", 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 |