| #include "bios.hpp" |
| |
| #include "libpldmresponder/utils.hpp" |
| #include "xyz/openbmc_project/Common/error.hpp" |
| |
| #include <array> |
| #include <boost/crc.hpp> |
| #include <chrono> |
| #include <ctime> |
| #include <filesystem> |
| #include <memory> |
| #include <numeric> |
| #include <phosphor-logging/elog-errors.hpp> |
| #include <phosphor-logging/log.hpp> |
| #include <stdexcept> |
| #include <string> |
| #include <variant> |
| #include <vector> |
| |
| namespace fs = std::filesystem; |
| using namespace pldm::responder::bios; |
| using namespace bios_parser; |
| |
| constexpr auto stringTableFile = "stringTable"; |
| constexpr auto attrTableFile = "attributeTable"; |
| constexpr auto attrValTableFile = "attributeValueTable"; |
| |
| namespace pldm |
| { |
| |
| using namespace phosphor::logging; |
| using namespace sdbusplus::xyz::openbmc_project::Common::Error; |
| using EpochTimeUS = uint64_t; |
| using BIOSTableRow = std::vector<uint8_t>; |
| using BIOSJsonName = std::string; |
| |
| constexpr auto dbusProperties = "org.freedesktop.DBus.Properties"; |
| constexpr auto padChksumMax = 7; |
| |
| namespace responder |
| { |
| |
| namespace utils |
| { |
| |
| void epochToBCDTime(uint64_t timeSec, uint8_t& seconds, uint8_t& minutes, |
| uint8_t& hours, uint8_t& day, uint8_t& month, |
| uint16_t& year) |
| { |
| auto t = time_t(timeSec); |
| auto time = localtime(&t); |
| |
| seconds = decimalToBcd(time->tm_sec); |
| minutes = decimalToBcd(time->tm_min); |
| hours = decimalToBcd(time->tm_hour); |
| day = decimalToBcd(time->tm_mday); |
| month = |
| decimalToBcd(time->tm_mon + 1); // The number of months in the range |
| // 0 to 11.PLDM expects range 1 to 12 |
| year = decimalToBcd(time->tm_year + 1900); // The number of years since 1900 |
| } |
| |
| size_t getTableTotalsize(size_t sizeWithoutPad) |
| { |
| return sizeWithoutPad + pldm_bios_table_pad_checksum_size(sizeWithoutPad); |
| } |
| |
| void padAndChecksum(Table& table) |
| { |
| auto sizeWithoutPad = table.size(); |
| auto padAndChecksumSize = pldm_bios_table_pad_checksum_size(sizeWithoutPad); |
| table.resize(table.size() + padAndChecksumSize); |
| |
| pldm_bios_table_append_pad_checksum(table.data(), table.size(), |
| sizeWithoutPad); |
| } |
| |
| } // namespace utils |
| |
| namespace bios |
| { |
| |
| Handler::Handler() |
| { |
| try |
| { |
| fs::remove( |
| fs::path(std::string(BIOS_TABLES_DIR) + "/" + stringTableFile)); |
| fs::remove( |
| fs::path(std::string(BIOS_TABLES_DIR) + "/" + attrTableFile)); |
| fs::remove( |
| fs::path(std::string(BIOS_TABLES_DIR) + "/" + attrValTableFile)); |
| } |
| catch (const std::exception& e) |
| { |
| } |
| |
| handlers.emplace(PLDM_GET_DATE_TIME, |
| [this](const pldm_msg* request, size_t payloadLength) { |
| return this->getDateTime(request, payloadLength); |
| }); |
| handlers.emplace(PLDM_GET_BIOS_TABLE, |
| [this](const pldm_msg* request, size_t payloadLength) { |
| return this->getBIOSTable(request, payloadLength); |
| }); |
| handlers.emplace(PLDM_GET_BIOS_ATTRIBUTE_CURRENT_VALUE_BY_HANDLE, |
| [this](const pldm_msg* request, size_t payloadLength) { |
| return this->getBIOSAttributeCurrentValueByHandle( |
| request, payloadLength); |
| }); |
| } |
| |
| Response Handler::getDateTime(const pldm_msg* request, size_t /*payloadLength*/) |
| { |
| uint8_t seconds = 0; |
| uint8_t minutes = 0; |
| uint8_t hours = 0; |
| uint8_t day = 0; |
| uint8_t month = 0; |
| uint16_t year = 0; |
| |
| constexpr auto timeInterface = "xyz.openbmc_project.Time.EpochTime"; |
| constexpr auto hostTimePath = "/xyz/openbmc_project/time/host"; |
| Response response(sizeof(pldm_msg_hdr) + PLDM_GET_DATE_TIME_RESP_BYTES, 0); |
| auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); |
| std::variant<EpochTimeUS> value; |
| |
| auto bus = sdbusplus::bus::new_default(); |
| try |
| { |
| auto service = getService(bus, hostTimePath, timeInterface); |
| |
| auto method = bus.new_method_call(service.c_str(), hostTimePath, |
| dbusProperties, "Get"); |
| method.append(timeInterface, "Elapsed"); |
| |
| auto reply = bus.call(method); |
| reply.read(value); |
| } |
| |
| catch (std::exception& e) |
| { |
| log<level::ERR>("Error getting time", entry("PATH=%s", hostTimePath), |
| entry("TIME INTERACE=%s", timeInterface)); |
| |
| encode_get_date_time_resp(request->hdr.instance_id, PLDM_ERROR, seconds, |
| minutes, hours, day, month, year, |
| responsePtr); |
| return response; |
| } |
| |
| uint64_t timeUsec = std::get<EpochTimeUS>(value); |
| |
| uint64_t timeSec = std::chrono::duration_cast<std::chrono::seconds>( |
| std::chrono::microseconds(timeUsec)) |
| .count(); |
| |
| pldm::responder::utils::epochToBCDTime(timeSec, seconds, minutes, hours, |
| day, month, year); |
| |
| encode_get_date_time_resp(request->hdr.instance_id, PLDM_SUCCESS, seconds, |
| minutes, hours, day, month, year, responsePtr); |
| return response; |
| } |
| |
| /** @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 |
| */ |
| Response getBIOSStringTable(BIOSTable& BIOSStringTable, |
| uint32_t /*transferHandle*/, |
| uint8_t /*transferOpFlag*/, uint8_t instanceID) |
| |
| { |
| 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()) |
| { |
| encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, |
| 0, /* next transfer handle */ |
| PLDM_START_AND_END, nullptr, response.size(), |
| responsePtr); // filling up the header here |
| BIOSStringTable.load(response); |
| return response; |
| } |
| auto biosStrings = bios_parser::getStrings(); |
| 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 sizeWithoutPad = std::accumulate( |
| biosStrings.begin(), biosStrings.end(), 0, |
| [](size_t sum, const std::string& elem) { |
| return sum + |
| pldm_bios_table_string_entry_encode_length(elem.length()); |
| }); |
| |
| Table stringTable; |
| stringTable.reserve( |
| pldm::responder::utils::getTableTotalsize(sizeWithoutPad)); |
| |
| stringTable.resize(sizeWithoutPad); |
| auto tablePtr = stringTable.data(); |
| for (const auto& elem : biosStrings) |
| { |
| auto entry_length = |
| pldm_bios_table_string_entry_encode_length(elem.length()); |
| pldm_bios_table_string_entry_encode(tablePtr, sizeWithoutPad, |
| elem.c_str(), elem.length()); |
| tablePtr += entry_length; |
| sizeWithoutPad -= entry_length; |
| } |
| |
| pldm::responder::utils::padAndChecksum(stringTable); |
| BIOSStringTable.store(stringTable); |
| response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES + |
| stringTable.size(), |
| 0); |
| responsePtr = reinterpret_cast<pldm_msg*>(response.data()); |
| encode_get_bios_table_resp( |
| instanceID, PLDM_SUCCESS, 0 /* nxtTransferHandle */, PLDM_START_AND_END, |
| stringTable.data(), response.size(), responsePtr); |
| 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) |
| { |
| Table table; |
| BIOSStringTable.load(table); |
| auto stringEntry = pldm_bios_table_string_find_by_string( |
| table.data(), table.size(), name.c_str()); |
| if (stringEntry == nullptr) |
| { |
| 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>(); |
| } |
| |
| return pldm_bios_table_string_entry_decode_handle(stringEntry); |
| } |
| |
| /** @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) |
| { |
| Table table; |
| BIOSStringTable.load(table); |
| auto stringEntry = pldm_bios_table_string_find_by_handle( |
| table.data(), table.size(), stringHdl); |
| std::string name; |
| if (stringEntry == nullptr) |
| { |
| log<level::ERR>("Reached end of BIOS string table,did not find " |
| "string name for handle", |
| entry("STRING_HANDLE=%d", stringHdl)); |
| } |
| auto strLength = |
| pldm_bios_table_string_entry_decode_string_length(stringEntry); |
| name.resize(strLength); |
| pldm_bios_table_string_entry_decode_string(stringEntry, name.data(), |
| name.size()); |
| return name; |
| } |
| |
| namespace bios_type_enum |
| { |
| |
| using namespace bios_parser::bios_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 |
| * @param[in,out] attributeTable - the attribute table |
| * |
| */ |
| void constructAttrTable(const BIOSTable& BIOSStringTable, Table& attributeTable) |
| { |
| const auto& attributeMap = getValues(); |
| 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; |
| } |
| bool readOnly = (std::get<0>(value)); |
| 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); |
| auto entryLength = pldm_bios_table_attr_entry_enum_encode_length( |
| possiValsByHdl.size(), defValsByHdl.size()); |
| |
| auto attrTableSize = attributeTable.size(); |
| attributeTable.resize(attrTableSize + entryLength, 0); |
| struct pldm_bios_table_attr_entry_enum_info info = { |
| strHandle, |
| readOnly, |
| (uint8_t)possiValsByHdl.size(), |
| possiValsByHdl.data(), |
| (uint8_t)defValsByHdl.size(), |
| defValsByHdl.data(), |
| }; |
| pldm_bios_table_attr_entry_enum_encode( |
| attributeTable.data() + attrTableSize, entryLength, &info); |
| } |
| } |
| |
| void constructAttrValueEntry( |
| const struct pldm_bios_attr_table_entry* attrTableEntry, |
| const std::string& attrName, const BIOSTable& BIOSStringTable, |
| Table& attrValueTable) |
| { |
| CurrentValues currVals; |
| try |
| { |
| currVals = getAttrValue(attrName); |
| } |
| catch (const std::exception& e) |
| { |
| log<level::ERR>("getAttrValue returned error for attribute", |
| entry("NAME=%s", attrName.c_str()), |
| entry("ERROR=%s", e.what())); |
| return; |
| } |
| uint8_t pv_num = |
| pldm_bios_table_attr_entry_enum_decode_pv_num(attrTableEntry); |
| PossibleValuesByHandle pvHdls(pv_num, 0); |
| pldm_bios_table_attr_entry_enum_decode_pv_hdls(attrTableEntry, |
| pvHdls.data(), pv_num); |
| std::sort(currVals.begin(), currVals.end()); |
| |
| auto currValStrIndices = findStrIndices(pvHdls, currVals, BIOSStringTable); |
| |
| auto entryLength = pldm_bios_table_attr_value_entry_encode_enum_length( |
| currValStrIndices.size()); |
| auto tableSize = attrValueTable.size(); |
| attrValueTable.resize(tableSize + entryLength); |
| pldm_bios_table_attr_value_entry_encode_enum( |
| attrValueTable.data() + tableSize, entryLength, |
| attrTableEntry->attr_handle, attrTableEntry->attr_type, |
| currValStrIndices.size(), currValStrIndices.data()); |
| } |
| |
| } // end namespace bios_type_enum |
| |
| namespace bios_type_string |
| { |
| |
| using namespace bios_parser::bios_string; |
| |
| /** @brief Construct the attibute table for BIOS type String and |
| * String ReadOnly |
| * @param[in] BIOSStringTable - the string table |
| * @param[in] biosJsonDir - path where the BIOS json files are present |
| * @param[in,out] attributeTable - the attribute table |
| * |
| */ |
| void constructAttrTable(const BIOSTable& BIOSStringTable, Table& attributeTable) |
| { |
| const auto& attributeMap = getValues(); |
| 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; |
| } |
| |
| const auto& [readOnly, strType, minStrLen, maxStrLen, defaultStrLen, |
| defaultStr] = value; |
| auto entryLength = |
| pldm_bios_table_attr_entry_string_encode_length(defaultStrLen); |
| |
| struct pldm_bios_table_attr_entry_string_info info = { |
| strHandle, readOnly, strType, minStrLen, |
| maxStrLen, defaultStrLen, defaultStr.data(), |
| }; |
| auto attrTableSize = attributeTable.size(); |
| attributeTable.resize(attrTableSize + entryLength, 0); |
| pldm_bios_table_attr_entry_string_encode( |
| attributeTable.data() + attrTableSize, entryLength, &info); |
| } |
| } |
| |
| void constructAttrValueEntry(const pldm_bios_attr_table_entry* attrTableEntry, |
| const std::string& attrName, |
| const BIOSTable& BIOSStringTable, |
| Table& attrValueTable) |
| { |
| std::ignore = BIOSStringTable; |
| std::string currStr; |
| uint16_t currStrLen = 0; |
| try |
| { |
| currStr = getAttrValue(attrName); |
| currStrLen = currStr.size(); |
| } |
| catch (const std::exception& e) |
| { |
| log<level::ERR>("getAttrValue returned error for attribute", |
| entry("NAME=%s", attrName.c_str()), |
| entry("ERROR=%s", e.what())); |
| return; |
| } |
| auto entryLength = |
| pldm_bios_table_attr_value_entry_encode_string_length(currStrLen); |
| auto tableSize = attrValueTable.size(); |
| attrValueTable.resize(tableSize + entryLength); |
| pldm_bios_table_attr_value_entry_encode_string( |
| attrValueTable.data() + tableSize, entryLength, |
| attrTableEntry->attr_handle, attrTableEntry->attr_type, currStrLen, |
| currStr.c_str()); |
| } |
| |
| } // end namespace bios_type_string |
| |
| namespace bios_type_integer |
| { |
| |
| using namespace bios_parser::bios_integer; |
| |
| /** @brief Construct the attibute table for BIOS type Integer and |
| * Integer ReadOnly |
| * @param[in] BIOSStringTable - the string table |
| * @param[in,out] attributeTable - the attribute table |
| * |
| */ |
| void constructAttrTable(const BIOSTable& BIOSStringTable, Table& attributeTable) |
| { |
| const auto& attributeMap = getValues(); |
| 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; |
| } |
| |
| const auto& [readOnly, lowerBound, upperBound, scalarIncrement, |
| defaultValue] = value; |
| auto entryLength = pldm_bios_table_attr_entry_integer_encode_length(); |
| |
| struct pldm_bios_table_attr_entry_integer_info info = { |
| strHandle, readOnly, lowerBound, |
| upperBound, scalarIncrement, defaultValue, |
| }; |
| auto attrTableSize = attributeTable.size(); |
| attributeTable.resize(attrTableSize + entryLength, 0); |
| pldm_bios_table_attr_entry_integer_encode( |
| attributeTable.data() + attrTableSize, entryLength, &info); |
| } |
| } |
| |
| void constructAttrValueEntry(const pldm_bios_attr_table_entry* attrTableEntry, |
| const std::string& attrName, |
| const BIOSTable& BIOSStringTable, |
| Table& attrValueTable) |
| { |
| std::ignore = BIOSStringTable; |
| uint64_t currentValue; |
| try |
| { |
| currentValue = getAttrValue(attrName); |
| } |
| catch (const std::exception& e) |
| { |
| log<level::ERR>("Failed to get attribute value", |
| entry("NAME=%s", attrName.c_str()), |
| entry("ERROR=%s", e.what())); |
| return; |
| } |
| auto entryLength = pldm_bios_table_attr_value_entry_encode_integer_length(); |
| auto tableSize = attrValueTable.size(); |
| attrValueTable.resize(tableSize + entryLength); |
| pldm_bios_table_attr_value_entry_encode_integer( |
| attrValueTable.data() + tableSize, entryLength, |
| attrTableEntry->attr_handle, attrTableEntry->attr_type, currentValue); |
| } |
| |
| } // namespace bios_type_integer |
| |
| void traverseBIOSAttrTable(const Table& biosAttrTable, |
| AttrTableEntryHandler handler) |
| { |
| std::unique_ptr<pldm_bios_table_iter, decltype(&pldm_bios_table_iter_free)> |
| iter(pldm_bios_table_iter_create(biosAttrTable.data(), |
| biosAttrTable.size(), |
| PLDM_BIOS_ATTR_TABLE), |
| pldm_bios_table_iter_free); |
| while (!pldm_bios_table_iter_is_end(iter.get())) |
| { |
| auto table_entry = pldm_bios_table_iter_attr_entry_value(iter.get()); |
| try |
| { |
| handler(table_entry); |
| } |
| catch (const std::exception& e) |
| { |
| log<level::ERR>("handler fails when traversing BIOSAttrTable", |
| entry("ERROR=%s", e.what())); |
| } |
| pldm_bios_table_iter_next(iter.get()); |
| } |
| } |
| |
| using typeHandler = std::function<void(const BIOSTable& BIOSStringTable, |
| Table& attributeTable)>; |
| std::map<BIOSJsonName, typeHandler> attrTypeHandlers{ |
| {bios_parser::bIOSEnumJson, bios_type_enum::constructAttrTable}, |
| {bios_parser::bIOSStrJson, bios_type_string::constructAttrTable}, |
| {bios_parser::bIOSIntegerJson, bios_type_integer::constructAttrTable}, |
| }; |
| |
| /** @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; |
| |
| if (BIOSAttributeTable.isEmpty()) |
| { // no persisted table, constructing fresh table and response |
| Table attributeTable; |
| fs::path dir(biosJsonDir); |
| |
| for (auto it = attrTypeHandlers.begin(); it != attrTypeHandlers.end(); |
| it++) |
| { |
| fs::path file = dir / it->first; |
| if (fs::exists(file)) |
| { |
| it->second(BIOSStringTable, attributeTable); |
| } |
| } |
| |
| if (attributeTable.empty()) |
| { // no available json file is found |
| encode_get_bios_table_resp(instanceID, PLDM_BIOS_TABLE_UNAVAILABLE, |
| nxtTransferHandle, transferFlag, nullptr, |
| response.size(), responsePtr); |
| return response; |
| } |
| pldm::responder::utils::padAndChecksum(attributeTable); |
| 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()); |
| encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle, |
| transferFlag, attributeTable.data(), |
| response.size(), responsePtr); |
| } |
| else |
| { // persisted table present, constructing response |
| encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle, |
| transferFlag, nullptr, response.size(), |
| responsePtr); // filling up the header here |
| BIOSAttributeTable.load(response); |
| } |
| |
| return response; |
| } |
| |
| using AttrValTableEntryConstructHandler = |
| std::function<void(const struct pldm_bios_attr_table_entry* tableEntry, |
| const std::string& attrName, |
| const BIOSTable& BIOSStringTable, Table& table)>; |
| |
| using AttrType = uint8_t; |
| const std::map<AttrType, AttrValTableEntryConstructHandler> |
| AttrValTableConstructMap{ |
| {PLDM_BIOS_STRING, bios_type_string::constructAttrValueEntry}, |
| {PLDM_BIOS_STRING_READ_ONLY, bios_type_string::constructAttrValueEntry}, |
| {PLDM_BIOS_ENUMERATION, bios_type_enum::constructAttrValueEntry}, |
| {PLDM_BIOS_ENUMERATION_READ_ONLY, |
| bios_type_enum::constructAttrValueEntry}, |
| {PLDM_BIOS_INTEGER, bios_type_integer::constructAttrValueEntry}, |
| {PLDM_BIOS_INTEGER_READ_ONLY, |
| bios_type_integer::constructAttrValueEntry}, |
| }; |
| |
| void constructAttrValueTableEntry( |
| const struct pldm_bios_attr_table_entry* attrEntry, |
| const BIOSTable& BIOSStringTable, Table& attributeValueTable) |
| { |
| auto attrName = findStringName(attrEntry->string_handle, BIOSStringTable); |
| if (attrName.empty()) |
| { |
| log<level::ERR>("invalid string handle", |
| entry("STRING_HANDLE=%d", attrEntry->string_handle)); |
| return; |
| } |
| |
| AttrValTableConstructMap.at(attrEntry->attr_type)( |
| attrEntry, attrName, BIOSStringTable, attributeValueTable); |
| } |
| |
| /** @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 |
| */ |
| Response getBIOSAttributeValueTable(BIOSTable& BIOSAttributeValueTable, |
| const BIOSTable& BIOSAttributeTable, |
| const BIOSTable& BIOSStringTable, |
| uint32_t& /*transferHandle*/, |
| uint8_t& /*transferOpFlag*/, |
| uint8_t instanceID) |
| { |
| 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; |
| |
| if (!BIOSAttributeValueTable.isEmpty()) |
| { |
| encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle, |
| transferFlag, nullptr, response.size(), |
| responsePtr); // filling up the header here |
| BIOSAttributeValueTable.load(response); |
| return response; |
| } |
| |
| Table attributeValueTable; |
| Table attributeTable; |
| BIOSAttributeTable.load(attributeTable); |
| traverseBIOSAttrTable( |
| attributeTable, |
| [&BIOSStringTable, &attributeValueTable]( |
| const struct pldm_bios_attr_table_entry* tableEntry) { |
| constructAttrValueTableEntry(tableEntry, BIOSStringTable, |
| attributeValueTable); |
| }); |
| if (attributeValueTable.empty()) |
| { |
| encode_get_bios_table_resp(instanceID, PLDM_BIOS_TABLE_UNAVAILABLE, |
| nxtTransferHandle, transferFlag, nullptr, |
| response.size(), responsePtr); |
| return response; |
| } |
| pldm::responder::utils::padAndChecksum(attributeValueTable); |
| 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()); |
| encode_get_bios_table_resp(instanceID, PLDM_SUCCESS, nxtTransferHandle, |
| transferFlag, attributeValueTable.data(), |
| response.size(), responsePtr); |
| |
| return response; |
| } |
| |
| Response Handler::getBIOSTable(const pldm_msg* request, size_t payloadLength) |
| { |
| fs::create_directory(BIOS_TABLES_DIR); |
| auto response = internal::buildBIOSTables(request, payloadLength, |
| BIOS_JSONS_DIR, BIOS_TABLES_DIR); |
| |
| return response; |
| } |
| |
| Response Handler::getBIOSAttributeCurrentValueByHandle(const pldm_msg* request, |
| size_t payloadLength) |
| { |
| uint32_t transferHandle; |
| uint8_t transferOpFlag; |
| uint16_t attributeHandle; |
| |
| auto rc = decode_get_bios_attribute_current_value_by_handle_req( |
| request, payloadLength, &transferHandle, &transferOpFlag, |
| &attributeHandle); |
| if (rc != PLDM_SUCCESS) |
| { |
| return ccOnlyResponse(request, rc); |
| } |
| |
| fs::path tablesPath(BIOS_TABLES_DIR); |
| auto stringTablePath = tablesPath / stringTableFile; |
| BIOSTable BIOSStringTable(stringTablePath.c_str()); |
| auto attrTablePath = tablesPath / attrTableFile; |
| BIOSTable BIOSAttributeTable(attrTablePath.c_str()); |
| if (BIOSAttributeTable.isEmpty() || BIOSStringTable.isEmpty()) |
| { |
| return ccOnlyResponse(request, PLDM_BIOS_TABLE_UNAVAILABLE); |
| } |
| |
| auto attrValueTablePath = tablesPath / attrValTableFile; |
| BIOSTable BIOSAttributeValueTable(attrValueTablePath.c_str()); |
| |
| if (BIOSAttributeValueTable.isEmpty()) |
| { |
| Table attributeValueTable; |
| Table attributeTable; |
| BIOSAttributeTable.load(attributeTable); |
| traverseBIOSAttrTable( |
| attributeTable, |
| [&BIOSStringTable, &attributeValueTable]( |
| const struct pldm_bios_attr_table_entry* tableEntry) { |
| constructAttrValueTableEntry(tableEntry, BIOSStringTable, |
| attributeValueTable); |
| }); |
| if (attributeValueTable.empty()) |
| { |
| return ccOnlyResponse(request, PLDM_BIOS_TABLE_UNAVAILABLE); |
| } |
| pldm::responder::utils::padAndChecksum(attributeValueTable); |
| BIOSAttributeValueTable.store(attributeValueTable); |
| } |
| |
| Response table; |
| BIOSAttributeValueTable.load(table); |
| |
| auto entry = pldm_bios_table_attr_value_find_by_handle( |
| table.data(), table.size(), attributeHandle); |
| if (entry == nullptr) |
| { |
| return ccOnlyResponse(request, PLDM_INVALID_BIOS_ATTR_HANDLE); |
| } |
| |
| auto valueLength = pldm_bios_table_attr_value_entry_value_length(entry); |
| auto valuePtr = pldm_bios_table_attr_value_entry_value(entry); |
| Response response(sizeof(pldm_msg_hdr) + |
| PLDM_GET_BIOS_ATTR_CURR_VAL_BY_HANDLE_MIN_RESP_BYTES + |
| valueLength, |
| 0); |
| auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); |
| encode_get_bios_current_value_by_handle_resp( |
| request->hdr.instance_id, PLDM_SUCCESS, 0, PLDM_START_AND_END, valuePtr, |
| valueLength, responsePtr); |
| |
| return response; |
| } |
| |
| 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()); |
| |
| if (setupConfig(biosJsonDir) != 0) |
| { |
| encode_get_bios_table_resp( |
| request->hdr.instance_id, PLDM_BIOS_TABLE_UNAVAILABLE, |
| 0 /* nxtTransferHandle */, PLDM_START_AND_END, nullptr, |
| response.size(), responsePtr); |
| return response; |
| } |
| |
| 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) + "/" + stringTableFile).c_str()); |
| BIOSTable BIOSAttributeTable( |
| (std::string(biosTablePath) + "/" + attrTableFile).c_str()); |
| BIOSTable BIOSAttributeValueTable( |
| (std::string(biosTablePath) + "/" + attrValTableFile).c_str()); |
| switch (tableType) |
| { |
| case PLDM_BIOS_STRING_TABLE: |
| |
| response = getBIOSStringTable(BIOSStringTable, transferHandle, |
| transferOpFlag, |
| request->hdr.instance_id); |
| 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() || BIOSStringTable.isEmpty()) |
| { |
| rc = PLDM_BIOS_TABLE_UNAVAILABLE; |
| } |
| else |
| { |
| response = getBIOSAttributeValueTable( |
| BIOSAttributeValueTable, BIOSAttributeTable, |
| BIOSStringTable, transferHandle, transferOpFlag, |
| request->hdr.instance_id); |
| } |
| 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 |