xref: /openbmc/bios-bmc-smm-error-logger/include/rde/rde_handler.hpp (revision 99cd49a6901ae7596386df4c33fcde9df91d23e8)
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 handleFlagStartAndEnd(
267          std::span<const uint8_t> rdeCommand,
268          const MultipartReceiveResHeader* header, const uint8_t* data,
269          uint32_t resourceId);
270  };
271  
272  } // namespace rde
273  } // namespace bios_bmc_smm_error_logger
274