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 Callout::Callout(CalloutPriority priority, const std::string& locationCode,
89                  const std::string& partNumber, const std::string& ccin,
90                  const std::string& serialNumber,
91                  const std::vector<MRU::MRUCallout>& mrus)
92 {
93     _flags = calloutType | fruIdentIncluded;
94 
95     _priority = static_cast<uint8_t>(priority);
96 
97     setLocationCode(locationCode);
98 
99     _fruIdentity = std::make_unique<FRUIdentity>(partNumber, ccin,
100                                                  serialNumber);
101 
102     if (!mrus.empty())
103     {
104         _flags |= mruIncluded;
105         _mru = std::make_unique<MRU>(mrus);
106     }
107 
108     _size = flattenedSize();
109 }
110 
111 Callout::Callout(CalloutPriority priority, const std::string& procedure,
112                  CalloutValueType type)
113 {
114     _flags = calloutType | fruIdentIncluded;
115 
116     _priority = static_cast<uint8_t>(priority);
117 
118     _locationCodeSize = 0;
119 
120     _fruIdentity = std::make_unique<FRUIdentity>(procedure, type);
121 
122     _size = flattenedSize();
123 }
124 
125 Callout::Callout(CalloutPriority priority, const std::string& symbolicFRU,
126                  CalloutValueType type, const std::string& locationCode,
127                  bool trustedLocationCode)
128 {
129     _flags = calloutType | fruIdentIncluded;
130 
131     _priority = static_cast<uint8_t>(priority);
132 
133     setLocationCode(locationCode);
134 
135     _fruIdentity = std::make_unique<FRUIdentity>(symbolicFRU, type,
136                                                  trustedLocationCode);
137 
138     _size = flattenedSize();
139 }
140 
141 void Callout::setLocationCode(const std::string& locationCode)
142 {
143     if (locationCode.empty())
144     {
145         _locationCodeSize = 0;
146         return;
147     }
148 
149     std::copy(locationCode.begin(), locationCode.end(),
150               std::back_inserter(_locationCode));
151 
152     if (_locationCode.size() < locationCodeMaxSize)
153     {
154         // Add a NULL, and then pad to a 4B boundary
155         _locationCode.push_back('\0');
156 
157         while (_locationCode.size() % 4)
158         {
159             _locationCode.push_back('\0');
160         }
161     }
162     else
163     {
164         // Too big - truncate it and ensure it ends in a NULL.
165         _locationCode.resize(locationCodeMaxSize);
166         _locationCode.back() = '\0';
167     }
168 
169     _locationCodeSize = _locationCode.size();
170 }
171 
172 size_t Callout::flattenedSize() const
173 {
174     size_t size = sizeof(_size) + sizeof(_flags) + sizeof(_priority) +
175                   sizeof(_locationCodeSize) + _locationCodeSize;
176 
177     size += _fruIdentity ? _fruIdentity->flattenedSize() : 0;
178     size += _pceIdentity ? _pceIdentity->flattenedSize() : 0;
179     size += _mru ? _mru->flattenedSize() : 0;
180 
181     return size;
182 }
183 
184 void Callout::flatten(Stream& pel) const
185 {
186     pel << _size << _flags << _priority << _locationCodeSize;
187 
188     if (_locationCodeSize)
189     {
190         pel << _locationCode;
191     }
192 
193     if (_fruIdentity)
194     {
195         _fruIdentity->flatten(pel);
196     }
197 
198     if (_pceIdentity)
199     {
200         _pceIdentity->flatten(pel);
201     }
202     if (_mru)
203     {
204         _mru->flatten(pel);
205     }
206 }
207 
208 } // namespace src
209 } // namespace pels
210 } // namespace openpower
211