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