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