blob: 4b637900a4d076a7df3f764caffd869b4d8156d6 [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
60/**
kasunatha3072872022-11-28 12:08:09 -080061 * @brief RDEOperationInit response header.
62 *
63 * BIOS uses this header to send the BEJ encoded data.
64 */
65struct RdeOperationInitReqHeader
66{
67 uint32_t resourceID;
68 uint16_t operationID;
69 uint8_t operationType;
70
71 // OperationFlags bits
72 uint8_t locatorValid : 1;
73 uint8_t containsRequestPayload : 1;
74 uint8_t containsCustomRequestParameters : 1;
75
76 uint8_t reserved : 5;
77 uint32_t sendDataTransferHandle;
78 uint8_t operationLocatorLength;
79 uint32_t requestPayloadLength;
80} __attribute__((__packed__));
81
82/**
83 * @brief RDEMultipartReceive response header.
84 *
85 * BIOS uses this header to send the BEJ dictionary data.
86 */
87struct MultipartReceiveResHeader
88{
89 uint8_t completionCode;
90 uint8_t transferFlag;
91 uint32_t nextDataTransferHandle;
92 uint32_t dataLengthBytes;
93} __attribute__((__packed__));
94
95/**
kasunathbac958d2022-06-07 18:15:24 -070096 * @brief Handles RDE messages from the BIOS - BMC circular buffer and updates
97 * ExternalStorer.
98 */
99class RdeCommandHandler
100{
101 public:
102 /**
103 * @brief Constructor for RdeExternalStorer.
104 *
105 * @param[in] exStorer - valid ExternalStorerInterface. This class will take
106 * the ownership of this object.
107 */
108 explicit RdeCommandHandler(
109 std::unique_ptr<ExternalStorerInterface> exStorer);
110
111 /**
112 * @brief Decode a RDE command.
113 *
114 * @param[in] rdeCommand - RDE command.
115 * @param[in] type - RDE command type.
116 * @return RdeDecodeStatus code.
117 */
118 RdeDecodeStatus decodeRdeCommand(std::span<const uint8_t> rdeCommand,
119 RdeCommandType type);
120
121 /**
122 * @brief Get the number of complete dictionaries received.
123 *
124 * @return number of complete dictionaries.
125 */
126 uint32_t getDictionaryCount();
127
128 private:
129 /**
130 * @brief This keeps track of whether we received the dictionary start flag
131 * or not.
132 */
133 RdeDictTransferFlagState flagState;
134
135 std::unique_ptr<ExternalStorerInterface> exStorer;
136
137 /**
138 * @brief We are using the prevDictResourceId to detect a new dictionary.
139 *
140 * BIOS-BMC buffer uses RdeMultiPartReceiveResponse START flag to indicate
141 * the first dictionary data chunk. BMC will not receive this flag at start
142 * of every new dictionary but only for the first data chunk. Therefore
143 * difference between resource ID is used to identify a new dictionary
144 * start. prevDictResourceId keeps track of the resource ID of the last
145 * dictionary data chunk.
146 */
147 uint32_t prevDictResourceId;
148
149 DictionaryManager dictionaryManager;
150 libbej::BejDecoderJson decoder;
151
152 uint32_t crc;
153 std::array<uint32_t, UINT8_MAX + 1> crcTable;
154
155 /**
156 * @brief Handles OperationInit request messages.
157 *
158 * @param[in] rdeCommand - RDE command.
159 * @return RdeDecodeStatus
160 */
161 RdeDecodeStatus operationInitRequest(std::span<const uint8_t> rdeCommand);
162
163 /**
164 * @brief Handles MultiPartReceive response messages.
165 *
166 * @param[in] rdeCommand - RDE command.
167 * @return RdeDecodeStatus
168 */
169 RdeDecodeStatus multiPartReceiveResp(std::span<const uint8_t> rdeCommand);
170
171 /**
172 * @brief Initializes the CRC table.
173 */
174 void calcCrcTable();
175
176 /**
177 * @brief Update the existing CRC using the provided byte stream.
178 *
179 * According to the RDE BEJ specification: "32-bit CRC for the entire block
180 * of data (all parts concatenated together, excluding this checksum)".
181 * Therefore when calculating the CRC whole RDEMultipartReceive Response
182 * data packet is considered, not just the dictionary data contained within
183 * it.
184 *
185 * @param[in] stream - a byte stream.
186 */
187 void updateCrc(std::span<const uint8_t> stream);
188
189 /**
190 * @brief Get the final checksum value.
191 *
192 * @return uint32_t - final checksum value.
193 */
194 uint32_t finalChecksum();
195
196 /**
197 * @brief Process received CRC field from a multi receive response command.
198 * END or START_AND_END flag should be set in the command.
199 *
200 * @param multiReceiveRespCmd - payload with a checksum field populated.
201 * @return RdeDecodeStatus
202 */
203 RdeDecodeStatus handleCrc(std::span<const uint8_t> multiReceiveRespCmd);
204
205 /**
206 * @brief Handle dictionary data with flag Start.
207 *
208 * @param[in] header - RDE header portion of the RDE command.
209 * @param[in] data - data portion of the RDE command.
210 * @param[in] resourceId - PDR resource ID of the dictionary.
211 */
212 void handleFlagStart(const MultipartReceiveResHeader* header,
213 const uint8_t* data, uint32_t resourceId);
214
215 /**
216 * @brief Handle dictionary data with flag Middle.
217 *
218 * @param[in] header - RDE header portion of the RDE command.
219 * @param[in] data - data portion of the RDE command.
220 * @param[in] resourceId - PDR resource ID of the dictionary.
221 * @return RdeDecodeStatus
222 */
223 RdeDecodeStatus handleFlagMiddle(const MultipartReceiveResHeader* header,
224 const uint8_t* data, uint32_t resourceId);
225 /**
226 * @brief Handle dictionary data with flag End.
227 *
228 * @param[in] rdeCommand - RDE command.
229 * @param[in] header - RDE header portion of the RDE command.
230 * @param[in] data - data portion of the RDE command.
231 * @param[in] resourceId - PDR resource ID of the dictionary.
232 * @return RdeDecodeStatus
233 */
234 RdeDecodeStatus handleFlagEnd(std::span<const uint8_t> rdeCommand,
235 const MultipartReceiveResHeader* header,
236 const uint8_t* data, uint32_t resourceId);
237
238 /**
239 * @brief Handle dictionary data with flag StartAndEnd.
240 *
241 * @param[in] rdeCommand - RDE command.
242 * @param[in] header - RDE header portion of the RDE command.
243 * @param[in] data - data portion of the RDE command.
244 * @param[in] resourceId - PDR resource ID of the dictionary.
245 * @return RdeDecodeStatus
246 */
247 RdeDecodeStatus
248 handleFlagStartAndEnd(std::span<const uint8_t> rdeCommand,
249 const MultipartReceiveResHeader* header,
250 const uint8_t* data, uint32_t resourceId);
251};
252
253} // namespace rde
254} // namespace bios_bmc_smm_error_logger