| #pragma once |
| |
| #include "external_storer_interface.hpp" |
| #include "libbej/bej_decoder_json.hpp" |
| #include "rde_dictionary_manager.hpp" |
| |
| #include <cstdint> |
| #include <span> |
| #include <string_view> |
| |
| namespace bios_bmc_smm_error_logger |
| { |
| namespace rde |
| { |
| |
| /** |
| * @brief Supported RDE commands. |
| * |
| * The values used are the same as what BIOS uses. |
| */ |
| enum class RdeCommandType : char |
| { |
| // Used for RDE BEJ dictionary transfer. |
| RdeMultiPartReceiveResponse = 1, |
| // Used for RDE BEJ encoded data. |
| RdeOperationInitRequest = 2, |
| }; |
| |
| /** |
| * @brief Used to keep track of RdeMultiPartReceiveResponse START flag |
| * reception. |
| */ |
| enum class RdeDictTransferFlagState |
| { |
| RdeStateIdle, |
| RdeStateStartRecvd, |
| }; |
| |
| /** |
| * @brief Status of RDE command processing. |
| */ |
| enum class RdeDecodeStatus |
| { |
| RdeOk, |
| RdeInvalidCommand, |
| RdeUnsupportedOperation, |
| RdeNoDictionary, |
| RdePayloadOverflow, |
| RdeBejDecodingError, |
| RdeInvalidPktOrder, |
| RdeDictionaryError, |
| RdeFileCreationFailed, |
| RdeExternalStorerError, |
| // This implies that the stop flag has been received. |
| RdeInvalidChecksum, |
| // This implies that the checksum is correct. |
| RdeStopFlagReceived, |
| }; |
| |
| enum class RdeOperationInitType : uint8_t |
| { |
| RdeOpInitOperationHead = 0, |
| RdeOpInitOperationRead = 1, |
| RdeOpInitOperationCreate = 2, |
| RdeOpInitOperationDelete = 3, |
| RdeOpInitOperationUpdate = 4, |
| RdeOpInitOperationReplace = 5, |
| RdeOpInitOperationAction = 6, |
| }; |
| |
| enum class RdeMultiReceiveTransferFlag : uint8_t |
| { |
| RdeMRecFlagStart = 0, |
| RdeMRecFlagMiddle = 1, |
| RdeMRecFlagEnd = 2, |
| RdeMRecFlagStartAndEnd = 3, |
| }; |
| |
| /** |
| * @brief RDEOperationInit response header. |
| * |
| * BIOS uses this header to send the BEJ encoded data. |
| */ |
| struct RdeOperationInitReqHeader |
| { |
| uint32_t resourceID; |
| uint16_t operationID; |
| uint8_t operationType; |
| |
| // OperationFlags bits |
| uint8_t locatorValid : 1; |
| uint8_t containsRequestPayload : 1; |
| uint8_t containsCustomRequestParameters : 1; |
| |
| uint8_t reserved : 5; |
| uint32_t sendDataTransferHandle; |
| uint8_t operationLocatorLength; |
| uint32_t requestPayloadLength; |
| } __attribute__((__packed__)); |
| |
| /** |
| * @brief RDEMultipartReceive response header. |
| * |
| * BIOS uses this header to send the BEJ dictionary data. |
| */ |
| struct MultipartReceiveResHeader |
| { |
| uint8_t completionCode; |
| uint8_t transferFlag; |
| uint32_t nextDataTransferHandle; |
| uint32_t dataLengthBytes; |
| } __attribute__((__packed__)); |
| |
| /** |
| * @brief Handles RDE messages from the BIOS - BMC circular buffer and updates |
| * ExternalStorer. |
| */ |
| class RdeCommandHandler |
| { |
| public: |
| /** |
| * @brief Constructor for RdeExternalStorer. |
| * |
| * @param[in] exStorer - valid ExternalStorerInterface. This class will take |
| * the ownership of this object. |
| */ |
| explicit RdeCommandHandler( |
| std::unique_ptr<ExternalStorerInterface> exStorer); |
| |
| /** |
| * @brief Decode a RDE command. |
| * |
| * @param[in] rdeCommand - RDE command. |
| * @param[in] type - RDE command type. |
| * @return RdeDecodeStatus code. |
| */ |
| RdeDecodeStatus decodeRdeCommand(std::span<const uint8_t> rdeCommand, |
| RdeCommandType type); |
| |
| /** |
| * @brief Get the number of complete dictionaries received. |
| * |
| * @return number of complete dictionaries. |
| */ |
| uint32_t getDictionaryCount(); |
| |
| private: |
| /** |
| * @brief This keeps track of whether we received the dictionary start flag |
| * or not. |
| */ |
| RdeDictTransferFlagState flagState; |
| |
| std::unique_ptr<ExternalStorerInterface> exStorer; |
| |
| /** |
| * @brief We are using the prevDictResourceId to detect a new dictionary. |
| * |
| * BIOS-BMC buffer uses RdeMultiPartReceiveResponse START flag to indicate |
| * the first dictionary data chunk. BMC will not receive this flag at start |
| * of every new dictionary but only for the first data chunk. Therefore |
| * difference between resource ID is used to identify a new dictionary |
| * start. prevDictResourceId keeps track of the resource ID of the last |
| * dictionary data chunk. |
| */ |
| uint32_t prevDictResourceId; |
| |
| DictionaryManager dictionaryManager; |
| libbej::BejDecoderJson decoder; |
| |
| uint32_t crc; |
| std::array<uint32_t, UINT8_MAX + 1> crcTable; |
| |
| /** |
| * @brief Handles OperationInit request messages. |
| * |
| * @param[in] rdeCommand - RDE command. |
| * @return RdeDecodeStatus |
| */ |
| RdeDecodeStatus operationInitRequest(std::span<const uint8_t> rdeCommand); |
| |
| /** |
| * @brief Handles MultiPartReceive response messages. |
| * |
| * @param[in] rdeCommand - RDE command. |
| * @return RdeDecodeStatus |
| */ |
| RdeDecodeStatus multiPartReceiveResp(std::span<const uint8_t> rdeCommand); |
| |
| /** |
| * @brief Initializes the CRC table. |
| */ |
| void calcCrcTable(); |
| |
| /** |
| * @brief Update the existing CRC using the provided byte stream. |
| * |
| * According to the RDE BEJ specification: "32-bit CRC for the entire block |
| * of data (all parts concatenated together, excluding this checksum)". |
| * Therefore when calculating the CRC whole RDEMultipartReceive Response |
| * data packet is considered, not just the dictionary data contained within |
| * it. |
| * |
| * @param[in] stream - a byte stream. |
| */ |
| void updateCrc(std::span<const uint8_t> stream); |
| |
| /** |
| * @brief Get the final checksum value. |
| * |
| * @return uint32_t - final checksum value. |
| */ |
| uint32_t finalChecksum(); |
| |
| /** |
| * @brief Process received CRC field from a multi receive response command. |
| * END or START_AND_END flag should be set in the command. |
| * |
| * @param multiReceiveRespCmd - payload with a checksum field populated. |
| * @return RdeDecodeStatus |
| */ |
| RdeDecodeStatus handleCrc(std::span<const uint8_t> multiReceiveRespCmd); |
| |
| /** |
| * @brief Handle dictionary data with flag Start. |
| * |
| * @param[in] header - RDE header portion of the RDE command. |
| * @param[in] data - data portion of the RDE command. |
| * @param[in] resourceId - PDR resource ID of the dictionary. |
| */ |
| void handleFlagStart(const MultipartReceiveResHeader* header, |
| const uint8_t* data, uint32_t resourceId); |
| |
| /** |
| * @brief Handle dictionary data with flag Middle. |
| * |
| * @param[in] header - RDE header portion of the RDE command. |
| * @param[in] data - data portion of the RDE command. |
| * @param[in] resourceId - PDR resource ID of the dictionary. |
| * @return RdeDecodeStatus |
| */ |
| RdeDecodeStatus handleFlagMiddle(const MultipartReceiveResHeader* header, |
| const uint8_t* data, uint32_t resourceId); |
| /** |
| * @brief Handle dictionary data with flag End. |
| * |
| * @param[in] rdeCommand - RDE command. |
| * @param[in] header - RDE header portion of the RDE command. |
| * @param[in] data - data portion of the RDE command. |
| * @param[in] resourceId - PDR resource ID of the dictionary. |
| * @return RdeDecodeStatus |
| */ |
| RdeDecodeStatus handleFlagEnd(std::span<const uint8_t> rdeCommand, |
| const MultipartReceiveResHeader* header, |
| const uint8_t* data, uint32_t resourceId); |
| |
| /** |
| * @brief Handle dictionary data with flag StartAndEnd. |
| * |
| * @param[in] rdeCommand - RDE command. |
| * @param[in] header - RDE header portion of the RDE command. |
| * @param[in] data - data portion of the RDE command. |
| * @param[in] resourceId - PDR resource ID of the dictionary. |
| * @return RdeDecodeStatus |
| */ |
| RdeDecodeStatus |
| handleFlagStartAndEnd(std::span<const uint8_t> rdeCommand, |
| const MultipartReceiveResHeader* header, |
| const uint8_t* data, uint32_t resourceId); |
| }; |
| |
| } // namespace rde |
| } // namespace bios_bmc_smm_error_logger |