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