blob: 59a8f0a5fc14c851a82d9f6f45f10d1c399ba482 [file] [log] [blame]
kasunathbac958d2022-06-07 18:15:24 -07001#pragma once
2
kasunathbac958d2022-06-07 18:15:24 -07003#include "external_storer_interface.hpp"
kasunatha3072872022-11-28 12:08:09 -08004#include "libbej/bej_decoder_json.hpp"
kasunathbac958d2022-06-07 18:15:24 -07005#include "rde_dictionary_manager.hpp"
6
7#include <cstdint>
8#include <span>
9#include <string_view>
10
11namespace bios_bmc_smm_error_logger
12{
13namespace rde
14{
15
16/**
17 * @brief Supported RDE commands.
18 *
19 * The values used are the same as what BIOS uses.
20 */
21enum 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 */
33enum class RdeDictTransferFlagState
34{
35 RdeStateIdle,
36 RdeStateStartRecvd,
37};
38
39/**
40 * @brief Status of RDE command processing.
41 */
42enum 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
kasunathaedea9f2022-12-05 11:17:26 -080060enum 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
71enum class RdeMultiReceiveTransferFlag : uint8_t
72{
73 RdeMRecFlagStart = 0,
74 RdeMRecFlagMiddle = 1,
75 RdeMRecFlagEnd = 2,
76 RdeMRecFlagStartAndEnd = 3,
77};
78
kasunathbac958d2022-06-07 18:15:24 -070079/**
kasunatha3072872022-11-28 12:08:09 -080080 * @brief RDEOperationInit response header.
81 *
82 * BIOS uses this header to send the BEJ encoded data.
83 */
84struct 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 */
106struct MultipartReceiveResHeader
107{
108 uint8_t completionCode;
109 uint8_t transferFlag;
110 uint32_t nextDataTransferHandle;
111 uint32_t dataLengthBytes;
112} __attribute__((__packed__));
113
114/**
kasunathbac958d2022-06-07 18:15:24 -0700115 * @brief Handles RDE messages from the BIOS - BMC circular buffer and updates
116 * ExternalStorer.
117 */
118class 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