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