blob: 59a8f0a5fc14c851a82d9f6f45f10d1c399ba482 [file] [log] [blame]
#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