xref: /openbmc/bios-bmc-smm-error-logger/include/rde/rde_handler.hpp (revision 90ccfe879a68915e35f9f4d8de0ef94bf983249f)
1 #pragma once
2 
3 #include "external_storer_interface.hpp"
4 // For local unit testing, remove "libbej/" prefix below
5 #include "libbej/bej_decoder_json.hpp"
6 #include "rde_dictionary_manager.hpp"
7 
8 #include <cstdint>
9 #include <span>
10 #include <string_view>
11 
12 namespace bios_bmc_smm_error_logger
13 {
14 namespace rde
15 {
16 
17 /**
18  * @brief Supported RDE commands.
19  *
20  * The values used are the same as what BIOS uses.
21  */
22 enum 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  */
34 enum class RdeDictTransferFlagState
35 {
36     RdeStateIdle,
37     RdeStateStartRecvd,
38 };
39 
40 /**
41  * @brief Status of RDE command processing.
42  */
43 enum 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 
61 enum 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 
72 enum class RdeMultiReceiveTransferFlag : uint8_t
73 {
74     RdeMRecFlagStart = 0,
75     RdeMRecFlagMiddle = 1,
76     RdeMRecFlagEnd = 2,
77     RdeMRecFlagStartAndEnd = 3,
78 };
79 
80 /**
81  * @brief RDEOperationInit response header.
82  *
83  * BIOS uses this header to send the BEJ encoded data.
84  */
85 struct RdeOperationInitReqHeader
86 {
87     uint32_t resourceID;
88     uint16_t operationID;
89     uint8_t operationType;
90 
91     // OperationFlags bits
92     uint8_t locatorValid:1;
93     uint8_t containsRequestPayload:1;
94     uint8_t containsCustomRequestParameters:1;
95 
96     uint8_t reserved:5;
97     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  */
107 struct MultipartReceiveResHeader
108 {
109     uint8_t completionCode;
110     uint8_t transferFlag;
111     uint32_t nextDataTransferHandle;
112     uint32_t dataLengthBytes;
113 } __attribute__((__packed__));
114 
115 /**
116  * @brief Handles RDE messages from the BIOS - BMC circular buffer and updates
117  * ExternalStorer.
118  */
119 class 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      */
267     RdeDecodeStatus handleFlagStartAndEnd(
268         std::span<const uint8_t> rdeCommand,
269         const MultipartReceiveResHeader* header, const uint8_t* data,
270         uint32_t resourceId);
271 };
272 
273 } // namespace rde
274 } // namespace bios_bmc_smm_error_logger
275