blob: b31e26cf1e8419aa357a1d4664161665b841dbb6 [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"
Brandon Kim90ccfe82025-06-06 20:38:56 +00004// For local unit testing, remove "libbej/" prefix below
kasunatha3072872022-11-28 12:08:09 -08005#include "libbej/bej_decoder_json.hpp"
kasunathbac958d2022-06-07 18:15:24 -07006#include "rde_dictionary_manager.hpp"
7
8#include <cstdint>
9#include <span>
10#include <string_view>
11
12namespace bios_bmc_smm_error_logger
13{
14namespace rde
15{
16
17/**
18 * @brief Supported RDE commands.
19 *
20 * The values used are the same as what BIOS uses.
21 */
22enum 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 */
34enum class RdeDictTransferFlagState
35{
36 RdeStateIdle,
37 RdeStateStartRecvd,
38};
39
40/**
41 * @brief Status of RDE command processing.
42 */
43enum 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
kasunathaedea9f2022-12-05 11:17:26 -080061enum 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
72enum class RdeMultiReceiveTransferFlag : uint8_t
73{
74 RdeMRecFlagStart = 0,
75 RdeMRecFlagMiddle = 1,
76 RdeMRecFlagEnd = 2,
77 RdeMRecFlagStartAndEnd = 3,
78};
79
kasunathbac958d2022-06-07 18:15:24 -070080/**
kasunatha3072872022-11-28 12:08:09 -080081 * @brief RDEOperationInit response header.
82 *
83 * BIOS uses this header to send the BEJ encoded data.
84 */
85struct RdeOperationInitReqHeader
86{
87 uint32_t resourceID;
88 uint16_t operationID;
89 uint8_t operationType;
90
91 // OperationFlags bits
Patrick Williams589c1752023-10-20 11:20:01 -050092 uint8_t locatorValid:1;
93 uint8_t containsRequestPayload:1;
94 uint8_t containsCustomRequestParameters:1;
kasunatha3072872022-11-28 12:08:09 -080095
Patrick Williams589c1752023-10-20 11:20:01 -050096 uint8_t reserved:5;
kasunatha3072872022-11-28 12:08:09 -080097 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 */
107struct MultipartReceiveResHeader
108{
109 uint8_t completionCode;
110 uint8_t transferFlag;
111 uint32_t nextDataTransferHandle;
112 uint32_t dataLengthBytes;
113} __attribute__((__packed__));
114
115/**
kasunathbac958d2022-06-07 18:15:24 -0700116 * @brief Handles RDE messages from the BIOS - BMC circular buffer and updates
117 * ExternalStorer.
118 */
119class 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 */
Patrick Williams99cd49a2025-03-03 11:20:29 -0500267 RdeDecodeStatus handleFlagStartAndEnd(
268 std::span<const uint8_t> rdeCommand,
269 const MultipartReceiveResHeader* header, const uint8_t* data,
270 uint32_t resourceId);
kasunathbac958d2022-06-07 18:15:24 -0700271};
272
273} // namespace rde
274} // namespace bios_bmc_smm_error_logger