1 /**
2  * Copyright © 2020 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "extended_user_data.hpp"
17 
18 #include "pel_types.hpp"
19 #ifdef PELTOOL
20 #include "user_data_json.hpp"
21 #endif
22 #include <phosphor-logging/log.hpp>
23 
24 #include <format>
25 
26 namespace openpower::pels
27 {
28 
29 using namespace phosphor::logging;
30 
31 void ExtendedUserData::unflatten(Stream& stream)
32 {
33     stream >> _header;
34 
35     if (_header.size <= SectionHeader::flattenedSize() + 4)
36     {
37         throw std::out_of_range(
38             std::format("ExtendedUserData::unflatten: SectionHeader::size {} "
39                         "too small",
40                         _header.size));
41     }
42 
43     size_t dataLength = _header.size - 4 - SectionHeader::flattenedSize();
44     _data.resize(dataLength);
45 
46     stream >> _creatorID >> _reserved1B >> _reserved2B >> _data;
47 }
48 
49 void ExtendedUserData::flatten(Stream& stream) const
50 {
51     stream << _header << _creatorID << _reserved1B << _reserved2B << _data;
52 }
53 
54 ExtendedUserData::ExtendedUserData(Stream& pel)
55 {
56     try
57     {
58         unflatten(pel);
59         validate();
60     }
61     catch (const std::exception& e)
62     {
63         log<level::ERR>(
64             std::format("Cannot unflatten ExtendedUserData section: {}",
65                         e.what())
66                 .c_str());
67         _valid = false;
68     }
69 }
70 
71 ExtendedUserData::ExtendedUserData(uint16_t componentID, uint8_t subType,
72                                    uint8_t version, uint8_t creatorID,
73                                    const std::vector<uint8_t>& data)
74 {
75     _header.id = static_cast<uint16_t>(SectionID::extUserData);
76     _header.version = version;
77     _header.subType = subType;
78     _header.componentID = componentID;
79 
80     _creatorID = creatorID;
81     _reserved1B = 0;
82     _reserved2B = 0;
83     _data = data;
84     _header.size = flattenedSize();
85     _valid = true;
86 }
87 
88 void ExtendedUserData::validate()
89 {
90     if (header().id != static_cast<uint16_t>(SectionID::extUserData))
91     {
92         log<level::ERR>(
93             std::format("Invalid ExtendedUserData section ID: {0:#x}",
94                         header().id)
95                 .c_str());
96         _valid = false;
97     }
98     else
99     {
100         _valid = true;
101     }
102 }
103 
104 std::optional<std::string>
105     ExtendedUserData::getJSON(uint8_t /*creatorID*/,
106                               const std::vector<std::string>& plugins
107                               [[maybe_unused]]) const
108 {
109     // Use the creator ID value from the section.
110 #ifdef PELTOOL
111     return user_data::getJSON(_header.componentID, _header.subType,
112                               _header.version, _data, _creatorID, plugins);
113 #endif
114     return std::nullopt;
115 }
116 
117 bool ExtendedUserData::shrink(size_t newSize)
118 {
119     // minimum size is 8B header + 4B of fields + 4B of data
120     if ((newSize < flattenedSize()) &&
121         (newSize >= (Section::flattenedSize() + 8)))
122     {
123         auto dataSize = newSize - Section::flattenedSize() - 4;
124 
125         // Ensure it's 4B aligned
126         _data.resize((dataSize / 4) * 4);
127         _header.size = flattenedSize();
128         return true;
129     }
130 
131     return false;
132 }
133 
134 } // namespace openpower::pels
135