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