1 #pragma once
2 
3 #include "section.hpp"
4 #include "stream.hpp"
5 
6 namespace openpower::pels
7 {
8 
9 /**
10  * @class ExtendedUserData
11  *
12  * This represents the Extended User Data section in a PEL.  It is free form
13  * data that the creator knows the contents of.  The component ID, version, and
14  * sub-type fields in the section header are used to identify the format.
15  *
16  *  This section is used for one subsystem to add FFDC data to a PEL created
17  *  by another subsystem.  It is basically the same as a UserData section,
18  *  except it has the creator ID of the section creator stored in the section.
19  *
20  * The Section base class handles the section header structure that every
21  * PEL section has at offset zero.
22  */
23 class ExtendedUserData : public Section
24 {
25   public:
26     ExtendedUserData() = delete;
27     ~ExtendedUserData() = default;
28     ExtendedUserData(const ExtendedUserData&) = default;
29     ExtendedUserData& operator=(const ExtendedUserData&) = default;
30     ExtendedUserData(ExtendedUserData&&) = default;
31     ExtendedUserData& operator=(ExtendedUserData&&) = default;
32 
33     /**
34      * @brief Constructor
35      *
36      * Fills in this class's data fields from the stream.
37      *
38      * @param[in] pel - the PEL data stream
39      */
40     explicit ExtendedUserData(Stream& pel);
41 
42     /**
43      * @brief Constructor
44      *
45      * Create a valid ExtendedUserData object with the passed in data.
46      *
47      * The component ID, subtype, and version are used to identify
48      * the data to know which parser to call.
49      *
50      * @param[in] componentID - Component ID of the creator
51      * @param[in] subType - The type of user data
52      * @param[in] version - The version of the data
53      */
54     ExtendedUserData(uint16_t componentID, uint8_t subType, uint8_t version,
55                      uint8_t creatorID, const std::vector<uint8_t>& data);
56 
57     /**
58      * @brief Flatten the section into the stream
59      *
60      * @param[in] stream - The stream to write to
61      */
62     void flatten(Stream& stream) const override;
63 
64     /**
65      * @brief Returns the size of this section when flattened into a PEL
66      *
67      * @return size_t - the size of the section
68      */
69     size_t flattenedSize()
70     {
71         return Section::flattenedSize() + sizeof(_creatorID) +
72                sizeof(_reserved1B) + sizeof(_reserved2B) + _data.size();
73     }
74 
75     /**
76      * @brief Returns the section creator ID field.
77      *
78      * @return uint8_t - The creator ID
79      */
80     uint8_t creatorID() const
81     {
82         return _creatorID;
83     }
84 
85     /**
86      * @brief Returns the raw section data
87      *
88      * This doesn't include the creator ID.
89      *
90      * @return std::vector<uint8_t>&
91      */
92     const std::vector<uint8_t>& data() const
93     {
94         return _data;
95     }
96 
97     /**
98      * @brief Returns the section data updated with new data
99      *
100      * @param[in] subType - The type of user data
101      * @param[in] componentID - Component ID of the creator
102      * @param[in] newData - The new data
103      *
104      */
105     void updateDataSection(const uint8_t subType, const uint16_t componentId,
106                            const std::vector<uint8_t>& newData)
107     {
108         auto origDataSize = 0;
109 
110         if (newData.size() >= 4)
111         {
112             // Update component Id & subtype in section header of ED
113             _header.componentID = static_cast<uint16_t>(componentId);
114             _header.subType = static_cast<uint8_t>(subType);
115 
116             if (newData.size() > _data.size())
117             {
118                 // Don't allow section to get bigger
119                 origDataSize = _data.size();
120                 _data = newData;
121                 _data.resize(origDataSize);
122             }
123             else
124             {
125                 // Use shrink to handle 4B alignment and update the header size
126                 auto status =
127                     shrink(Section::flattenedSize() + 4 + newData.size());
128                 if (status)
129                 {
130                     origDataSize = _data.size();
131                     _data = newData;
132                     _data.resize(origDataSize);
133                 }
134             }
135         }
136     }
137 
138     /**
139      * @brief Get the section contents in JSON
140      *
141      * @param[in] creatorID - Creator Subsystem ID - unused (see the .cpp)
142      * @param[in] plugins - Vector of strings of plugins found in filesystem
143      *
144      * @return The JSON as a string if a parser was found,
145      *         otherwise std::nullopt.
146      */
147     std::optional<std::string>
148         getJSON(uint8_t creatorID,
149                 const std::vector<std::string>& plugins) const override;
150 
151     /**
152      * @brief Shrink the section
153      *
154      * The new size must be between the current size and the minimum
155      * size, which is 12 bytes.  If it isn't a 4 byte aligned value
156      * the code will do the aligning before the resize takes place.
157      *
158      * @param[in] newSize - The new size in bytes
159      *
160      * @return bool - true if successful, false else.
161      */
162     bool shrink(size_t newSize) override;
163 
164   private:
165     /**
166      * @brief Fills in the object from the stream data
167      *
168      * @param[in] stream - The stream to read from
169      */
170     void unflatten(Stream& stream);
171 
172     /**
173      * @brief Validates the section contents
174      *
175      * Updates _valid (in Section) with the results.
176      */
177     void validate() override;
178 
179     /**
180      * @brief The subsystem creator ID of the code that
181      *        created this section.
182      */
183     uint8_t _creatorID;
184 
185     /**
186      * @brief Reserved
187      */
188     uint8_t _reserved1B;
189 
190     /**
191      * @brief Reserved
192      */
193     uint16_t _reserved2B;
194 
195     /**
196      * @brief The section data
197      */
198     std::vector<uint8_t> _data;
199 };
200 
201 } // namespace openpower::pels
202