1 #pragma once 2 3 #include "external_storer_interface.hpp" 4 // For local unit testing, remove "libbej/" prefix below 5 #include "libbej/bej_decoder_json.hpp" 6 #include "rde_dictionary_manager.hpp" 7 8 #include <cstdint> 9 #include <span> 10 #include <string_view> 11 12 namespace bios_bmc_smm_error_logger 13 { 14 namespace rde 15 { 16 17 /** 18 * @brief Supported RDE commands. 19 * 20 * The values used are the same as what BIOS uses. 21 */ 22 enum class RdeCommandType : char 23 { 24 // Used for RDE BEJ dictionary transfer. 25 RdeMultiPartReceiveResponse = 1, 26 // Used for RDE BEJ encoded data. 27 RdeOperationInitRequest = 2, 28 }; 29 30 /** 31 * @brief Used to keep track of RdeMultiPartReceiveResponse START flag 32 * reception. 33 */ 34 enum class RdeDictTransferFlagState 35 { 36 RdeStateIdle, 37 RdeStateStartRecvd, 38 }; 39 40 /** 41 * @brief Status of RDE command processing. 42 */ 43 enum class RdeDecodeStatus 44 { 45 RdeOk, 46 RdeInvalidCommand, 47 RdeUnsupportedOperation, 48 RdeNoDictionary, 49 RdePayloadOverflow, 50 RdeBejDecodingError, 51 RdeInvalidPktOrder, 52 RdeDictionaryError, 53 RdeFileCreationFailed, 54 RdeExternalStorerError, 55 // This implies that the stop flag has been received. 56 RdeInvalidChecksum, 57 // This implies that the checksum is correct. 58 RdeStopFlagReceived, 59 }; 60 61 enum class RdeOperationInitType : uint8_t 62 { 63 RdeOpInitOperationHead = 0, 64 RdeOpInitOperationRead = 1, 65 RdeOpInitOperationCreate = 2, 66 RdeOpInitOperationDelete = 3, 67 RdeOpInitOperationUpdate = 4, 68 RdeOpInitOperationReplace = 5, 69 RdeOpInitOperationAction = 6, 70 }; 71 72 enum class RdeMultiReceiveTransferFlag : uint8_t 73 { 74 RdeMRecFlagStart = 0, 75 RdeMRecFlagMiddle = 1, 76 RdeMRecFlagEnd = 2, 77 RdeMRecFlagStartAndEnd = 3, 78 }; 79 80 /** 81 * @brief RDEOperationInit response header. 82 * 83 * BIOS uses this header to send the BEJ encoded data. 84 */ 85 struct RdeOperationInitReqHeader 86 { 87 uint32_t resourceID; 88 uint16_t operationID; 89 uint8_t operationType; 90 91 // OperationFlags bits 92 uint8_t locatorValid:1; 93 uint8_t containsRequestPayload:1; 94 uint8_t containsCustomRequestParameters:1; 95 96 uint8_t reserved:5; 97 uint32_t sendDataTransferHandle; 98 uint8_t operationLocatorLength; 99 uint32_t requestPayloadLength; 100 } __attribute__((__packed__)); 101 102 /** 103 * @brief RDEMultipartReceive response header. 104 * 105 * BIOS uses this header to send the BEJ dictionary data. 106 */ 107 struct MultipartReceiveResHeader 108 { 109 uint8_t completionCode; 110 uint8_t transferFlag; 111 uint32_t nextDataTransferHandle; 112 uint32_t dataLengthBytes; 113 } __attribute__((__packed__)); 114 115 /** 116 * @brief Handles RDE messages from the BIOS - BMC circular buffer and updates 117 * ExternalStorer. 118 */ 119 class RdeCommandHandler 120 { 121 public: 122 /** 123 * @brief Constructor for RdeExternalStorer. 124 * 125 * @param[in] exStorer - valid ExternalStorerInterface. This class will take 126 * the ownership of this object. 127 */ 128 explicit RdeCommandHandler( 129 std::unique_ptr<ExternalStorerInterface> exStorer); 130 131 /** 132 * @brief Decode a RDE command. 133 * 134 * @param[in] rdeCommand - RDE command. 135 * @param[in] type - RDE command type. 136 * @return RdeDecodeStatus code. 137 */ 138 RdeDecodeStatus decodeRdeCommand(std::span<const uint8_t> rdeCommand, 139 RdeCommandType type); 140 141 /** 142 * @brief Get the number of complete dictionaries received. 143 * 144 * @return number of complete dictionaries. 145 */ 146 uint32_t getDictionaryCount(); 147 148 private: 149 /** 150 * @brief This keeps track of whether we received the dictionary start flag 151 * or not. 152 */ 153 RdeDictTransferFlagState flagState; 154 155 std::unique_ptr<ExternalStorerInterface> exStorer; 156 157 /** 158 * @brief We are using the prevDictResourceId to detect a new dictionary. 159 * 160 * BIOS-BMC buffer uses RdeMultiPartReceiveResponse START flag to indicate 161 * the first dictionary data chunk. BMC will not receive this flag at start 162 * of every new dictionary but only for the first data chunk. Therefore 163 * difference between resource ID is used to identify a new dictionary 164 * start. prevDictResourceId keeps track of the resource ID of the last 165 * dictionary data chunk. 166 */ 167 uint32_t prevDictResourceId; 168 169 DictionaryManager dictionaryManager; 170 libbej::BejDecoderJson decoder; 171 172 uint32_t crc; 173 std::array<uint32_t, UINT8_MAX + 1> crcTable; 174 175 /** 176 * @brief Handles OperationInit request messages. 177 * 178 * @param[in] rdeCommand - RDE command. 179 * @return RdeDecodeStatus 180 */ 181 RdeDecodeStatus operationInitRequest(std::span<const uint8_t> rdeCommand); 182 183 /** 184 * @brief Handles MultiPartReceive response messages. 185 * 186 * @param[in] rdeCommand - RDE command. 187 * @return RdeDecodeStatus 188 */ 189 RdeDecodeStatus multiPartReceiveResp(std::span<const uint8_t> rdeCommand); 190 191 /** 192 * @brief Initializes the CRC table. 193 */ 194 void calcCrcTable(); 195 196 /** 197 * @brief Update the existing CRC using the provided byte stream. 198 * 199 * According to the RDE BEJ specification: "32-bit CRC for the entire block 200 * of data (all parts concatenated together, excluding this checksum)". 201 * Therefore when calculating the CRC whole RDEMultipartReceive Response 202 * data packet is considered, not just the dictionary data contained within 203 * it. 204 * 205 * @param[in] stream - a byte stream. 206 */ 207 void updateCrc(std::span<const uint8_t> stream); 208 209 /** 210 * @brief Get the final checksum value. 211 * 212 * @return uint32_t - final checksum value. 213 */ 214 uint32_t finalChecksum(); 215 216 /** 217 * @brief Process received CRC field from a multi receive response command. 218 * END or START_AND_END flag should be set in the command. 219 * 220 * @param multiReceiveRespCmd - payload with a checksum field populated. 221 * @return RdeDecodeStatus 222 */ 223 RdeDecodeStatus handleCrc(std::span<const uint8_t> multiReceiveRespCmd); 224 225 /** 226 * @brief Handle dictionary data with flag Start. 227 * 228 * @param[in] header - RDE header portion of the RDE command. 229 * @param[in] data - data portion of the RDE command. 230 * @param[in] resourceId - PDR resource ID of the dictionary. 231 */ 232 void handleFlagStart(const MultipartReceiveResHeader* header, 233 const uint8_t* data, uint32_t resourceId); 234 235 /** 236 * @brief Handle dictionary data with flag Middle. 237 * 238 * @param[in] header - RDE header portion of the RDE command. 239 * @param[in] data - data portion of the RDE command. 240 * @param[in] resourceId - PDR resource ID of the dictionary. 241 * @return RdeDecodeStatus 242 */ 243 RdeDecodeStatus handleFlagMiddle(const MultipartReceiveResHeader* header, 244 const uint8_t* data, uint32_t resourceId); 245 /** 246 * @brief Handle dictionary data with flag End. 247 * 248 * @param[in] rdeCommand - RDE command. 249 * @param[in] header - RDE header portion of the RDE command. 250 * @param[in] data - data portion of the RDE command. 251 * @param[in] resourceId - PDR resource ID of the dictionary. 252 * @return RdeDecodeStatus 253 */ 254 RdeDecodeStatus handleFlagEnd(std::span<const uint8_t> rdeCommand, 255 const MultipartReceiveResHeader* header, 256 const uint8_t* data, uint32_t resourceId); 257 258 /** 259 * @brief Handle dictionary data with flag StartAndEnd. 260 * 261 * @param[in] rdeCommand - RDE command. 262 * @param[in] header - RDE header portion of the RDE command. 263 * @param[in] data - data portion of the RDE command. 264 * @param[in] resourceId - PDR resource ID of the dictionary. 265 * @return RdeDecodeStatus 266 */ 267 RdeDecodeStatus handleFlagStartAndEnd( 268 std::span<const uint8_t> rdeCommand, 269 const MultipartReceiveResHeader* header, const uint8_t* data, 270 uint32_t resourceId); 271 }; 272 273 } // namespace rde 274 } // namespace bios_bmc_smm_error_logger 275