#pragma once #include "external_storer_interface.hpp" #include "libbej/bej_decoder_json.hpp" #include "rde_dictionary_manager.hpp" #include #include #include 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 exStorer); /** * @brief Decode a RDE command. * * @param[in] rdeCommand - RDE command. * @param[in] type - RDE command type. * @return RdeDecodeStatus code. */ RdeDecodeStatus decodeRdeCommand(std::span 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 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 crcTable; /** * @brief Handles OperationInit request messages. * * @param[in] rdeCommand - RDE command. * @return RdeDecodeStatus */ RdeDecodeStatus operationInitRequest(std::span rdeCommand); /** * @brief Handles MultiPartReceive response messages. * * @param[in] rdeCommand - RDE command. * @return RdeDecodeStatus */ RdeDecodeStatus multiPartReceiveResp(std::span 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 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 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 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 rdeCommand, const MultipartReceiveResHeader* header, const uint8_t* data, uint32_t resourceId); }; } // namespace rde } // namespace bios_bmc_smm_error_logger