1 /**
2  * Copyright © 2019 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 "callout.hpp"
17 
18 #include <phosphor-logging/log.hpp>
19 
20 namespace openpower
21 {
22 namespace pels
23 {
24 namespace src
25 {
26 
27 using namespace phosphor::logging;
28 
29 constexpr size_t locationCodeMaxSize = 80;
30 
31 Callout::Callout(Stream& pel)
32 {
33     pel >> _size >> _flags >> _priority >> _locationCodeSize;
34 
35     if (_locationCodeSize)
36     {
37         _locationCode.resize(_locationCodeSize);
38         pel >> _locationCode;
39     }
40 
41     size_t currentSize = 4 + _locationCodeSize;
42 
43     // Read in the substructures until the end of this structure.
44     // Any stream overflows will throw an exception up to the SRC constructor
45     while (_size > currentSize)
46     {
47         // Peek the type
48         uint16_t type = 0;
49         pel >> type;
50         pel.offset(pel.offset() - 2);
51 
52         switch (type)
53         {
54             case FRUIdentity::substructureType:
55             {
56                 _fruIdentity = std::make_unique<FRUIdentity>(pel);
57                 currentSize += _fruIdentity->flattenedSize();
58                 break;
59             }
60             case PCEIdentity::substructureType:
61             {
62                 _pceIdentity = std::make_unique<PCEIdentity>(pel);
63                 currentSize += _pceIdentity->flattenedSize();
64                 break;
65             }
66             case MRU::substructureType:
67             {
68                 _mru = std::make_unique<MRU>(pel);
69                 currentSize += _mru->flattenedSize();
70                 break;
71             }
72             default:
73                 log<level::ERR>("Invalid Callout subsection type",
74                                 entry("CALLOUT_TYPE=0x%X", type));
75                 throw std::runtime_error("Invalid Callout subsection type");
76                 break;
77         }
78     }
79 }
80 
81 Callout::Callout(CalloutPriority priority, const std::string& locationCode,
82                  const std::string& partNumber, const std::string& ccin,
83                  const std::string& serialNumber) :
84     Callout(priority, locationCode, partNumber, ccin, serialNumber,
85             std::vector<MRU::MRUCallout>{})
86 {
87 }
88 
89 Callout::Callout(CalloutPriority priority, const std::string& locationCode,
90                  const std::string& partNumber, const std::string& ccin,
91                  const std::string& serialNumber,
92                  const std::vector<MRU::MRUCallout>& mrus)
93 {
94     _flags = calloutType | fruIdentIncluded;
95 
96     _priority = static_cast<uint8_t>(priority);
97 
98     setLocationCode(locationCode);
99 
100     _fruIdentity =
101         std::make_unique<FRUIdentity>(partNumber, ccin, serialNumber);
102 
103     if (!mrus.empty())
104     {
105         _flags |= mruIncluded;
106         _mru = std::make_unique<MRU>(mrus);
107     }
108 
109     _size = flattenedSize();
110 }
111 
112 Callout::Callout(CalloutPriority priority, const std::string& procedure,
113                  CalloutValueType type)
114 {
115     _flags = calloutType | fruIdentIncluded;
116 
117     _priority = static_cast<uint8_t>(priority);
118 
119     _locationCodeSize = 0;
120 
121     _fruIdentity = std::make_unique<FRUIdentity>(procedure, type);
122 
123     _size = flattenedSize();
124 }
125 
126 Callout::Callout(CalloutPriority priority, const std::string& symbolicFRU,
127                  CalloutValueType type, const std::string& locationCode,
128                  bool trustedLocationCode)
129 {
130     _flags = calloutType | fruIdentIncluded;
131 
132     _priority = static_cast<uint8_t>(priority);
133 
134     setLocationCode(locationCode);
135 
136     _fruIdentity =
137         std::make_unique<FRUIdentity>(symbolicFRU, type, trustedLocationCode);
138 
139     _size = flattenedSize();
140 }
141 
142 void Callout::setLocationCode(const std::string& locationCode)
143 {
144     if (locationCode.empty())
145     {
146         _locationCodeSize = 0;
147         return;
148     }
149 
150     std::copy(locationCode.begin(), locationCode.end(),
151               std::back_inserter(_locationCode));
152 
153     if (_locationCode.size() < locationCodeMaxSize)
154     {
155         // Add a NULL, and then pad to a 4B boundary
156         _locationCode.push_back('\0');
157 
158         while (_locationCode.size() % 4)
159         {
160             _locationCode.push_back('\0');
161         }
162     }
163     else
164     {
165         // Too big - truncate it and ensure it ends in a NULL.
166         _locationCode.resize(locationCodeMaxSize);
167         _locationCode.back() = '\0';
168     }
169 
170     _locationCodeSize = _locationCode.size();
171 }
172 
173 size_t Callout::flattenedSize() const
174 {
175     size_t size = sizeof(_size) + sizeof(_flags) + sizeof(_priority) +
176                   sizeof(_locationCodeSize) + _locationCodeSize;
177 
178     size += _fruIdentity ? _fruIdentity->flattenedSize() : 0;
179     size += _pceIdentity ? _pceIdentity->flattenedSize() : 0;
180     size += _mru ? _mru->flattenedSize() : 0;
181 
182     return size;
183 }
184 
185 void Callout::flatten(Stream& pel) const
186 {
187     pel << _size << _flags << _priority << _locationCodeSize;
188 
189     if (_locationCodeSize)
190     {
191         pel << _locationCode;
192     }
193 
194     if (_fruIdentity)
195     {
196         _fruIdentity->flatten(pel);
197     }
198 
199     if (_pceIdentity)
200     {
201         _pceIdentity->flatten(pel);
202     }
203     if (_mru)
204     {
205         _mru->flatten(pel);
206     }
207 }
208 
209 } // namespace src
210 } // namespace pels
211 } // namespace openpower
212