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 "pel_utils.hpp" 17 18 #include "extensions/openpower-pels/private_header.hpp" 19 #include "extensions/openpower-pels/user_header.hpp" 20 21 #include <fstream> 22 23 #include <gtest/gtest.h> 24 25 namespace fs = std::filesystem; 26 using namespace openpower::pels; 27 28 std::filesystem::path CleanLogID::pelIDFile{}; 29 std::filesystem::path CleanPELFiles::pelIDFile{}; 30 std::filesystem::path CleanPELFiles::repoPath{}; 31 std::filesystem::path CleanPELFiles::registryPath{}; 32 33 const std::vector<uint8_t> privateHeaderSection{ 34 // section header 35 0x50, 0x48, // ID 'PH' 36 0x00, 0x30, // Size 37 0x01, 0x02, // version, subtype 38 0x03, 0x04, // comp ID 39 40 0x20, 0x30, 0x05, 0x09, 0x11, 0x1E, 0x1, 0x63, // create timestamp 41 0x20, 0x31, 0x06, 0x0F, 0x09, 0x22, 0x3A, 0x00, // commit timestamp 42 0xAA, // creatorID 43 0x00, // logtype 44 0x00, // reserved 45 0x02, // section count 46 0x90, 0x91, 0x92, 0x93, // OpenBMC log ID 47 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0, // creator version 48 0x50, 0x51, 0x52, 0x53, // plid 49 0x80, 0x81, 0x82, 0x83}; 50 51 const std::vector<uint8_t> userHeaderSection{ 52 // section header 53 0x55, 0x48, // ID 'UH' 54 0x00, 0x18, // Size 55 0x01, 0x0A, // version, subtype 56 0x0B, 0x0C, // comp ID 57 58 0x10, 0x04, // subsystem, scope 59 0x20, 0x00, // severity, type 60 0x00, 0x00, 0x00, 0x00, // reserved 61 0x03, 0x04, // problem domain, vector 62 0x80, 0xC0, // action flags 63 0x00, 0x00, 0x00, 0x00 // reserved 64 }; 65 66 const std::vector<uint8_t> srcSectionNoCallouts{ 67 68 // Header 69 'P', 'S', 0x00, 0x50, 0x01, 0x01, 0x02, 0x02, 70 71 0x02, 0x00, 0x00, // version, flags, reserved 72 0x09, 0x00, 0x00, // hex word count, reserved2B 73 0x00, 0x48, // SRC structure size 74 75 // Hex words 2 - 9 76 0x02, 0x02, 0x02, 0x55, 0x03, 0x03, 0x03, 0x10, 0x04, 0x04, 0x04, 0x04, 77 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 78 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 79 // ASCII string 80 'B', 'D', '8', 'D', '5', '6', '7', '8', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 81 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 82 ' ', ' '}; 83 84 const std::vector<uint8_t> failingMTMSSection{ 85 // Header 86 0x4D, 0x54, 0x00, 0x1C, 0x01, 0x00, 0x20, 0x00, 87 88 'T', 'T', 'T', 'T', '-', 'M', 'M', 'M', '1', '2', 89 '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C'}; 90 91 const std::vector<uint8_t> UserDataSection{ 92 // Header 93 0x55, 0x44, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 94 95 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; 96 97 const std::vector<uint8_t> ExtUserHeaderSection{ 98 // Header 99 'E', 'H', 0x00, 0x60, 0x01, 0x00, 0x03, 0x04, 100 101 // MTMS 102 'T', 'T', 'T', 'T', '-', 'M', 'M', 'M', '1', '2', '3', '4', '5', '6', '7', 103 '8', '9', 'A', 'B', 'C', 104 105 // Server FW version 106 'S', 'E', 'R', 'V', 'E', 'R', '_', 'V', 'E', 'R', 'S', 'I', 'O', 'N', '\0', 107 '\0', 108 109 // Subsystem FW Version 110 'B', 'M', 'C', '_', 'V', 'E', 'R', 'S', 'I', 'O', 'N', '\0', '\0', '\0', 111 '\0', '\0', 112 113 0x00, 0x00, 0x00, 0x00, // Reserved 114 0x20, 0x25, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, // Ref time 115 0x00, 0x00, 0x00, // Reserved 116 117 // SymptomID length and symptom ID 118 20, 'B', 'D', '8', 'D', '4', '2', '0', '0', '_', '1', '2', '3', '4', '5', 119 '6', '7', '8', '\0', '\0', '\0'}; 120 121 const std::vector<uint8_t> srcFRUIdentityCallout{ 122 'I', 'D', 0x1C, 0x1D, // type, size, flags 123 '1', '2', '3', '4', // PN 124 '5', '6', '7', 0x00, 'A', 'A', 'A', 'A', // CCIN 125 '1', '2', '3', '4', '5', '6', '7', '8', // SN 126 '9', 'A', 'B', 'C'}; 127 128 const std::vector<uint8_t> srcPCEIdentityCallout{ 129 'P', 'E', 0x24, 0x00, // type, size, flags 130 'T', 'T', 'T', 'T', '-', 'M', 'M', 'M', // MTM 131 '1', '2', '3', '4', '5', '6', '7', // SN 132 '8', '9', 'A', 'B', 'C', 'P', 'C', 'E', // Name + null padded 133 'N', 'A', 'M', 'E', '1', '2', 0x00, 0x00, 0x00}; 134 135 const std::vector<uint8_t> srcMRUCallout{ 136 'M', 'R', 0x28, 0x04, // ID, size, flags 137 0x00, 0x00, 0x00, 0x00, // Reserved 138 0x00, 0x00, 0x00, 'H', // priority 0 139 0x01, 0x01, 0x01, 0x01, // MRU ID 0 140 0x00, 0x00, 0x00, 'M', // priority 1 141 0x02, 0x02, 0x02, 0x02, // MRU ID 1 142 0x00, 0x00, 0x00, 'L', // priority 2 143 0x03, 0x03, 0x03, 0x03, // MRU ID 2 144 0x00, 0x00, 0x00, 'H', // priority 3 145 0x04, 0x04, 0x04, 0x04, // MRU ID 3 146 }; 147 148 constexpr size_t sectionCountOffset = 27; 149 150 std::vector<uint8_t> pelDataFactory(TestPELType type) 151 { 152 std::vector<uint8_t> data; 153 154 switch (type) 155 { 156 case TestPELType::pelSimple: 157 data.insert(data.end(), privateHeaderSection.begin(), 158 privateHeaderSection.end()); 159 data.insert(data.end(), userHeaderSection.begin(), 160 userHeaderSection.end()); 161 data.insert(data.end(), srcSectionNoCallouts.begin(), 162 srcSectionNoCallouts.end()); 163 data.insert(data.end(), failingMTMSSection.begin(), 164 failingMTMSSection.end()); 165 data.insert(data.end(), UserDataSection.begin(), 166 UserDataSection.end()); 167 data.insert(data.end(), ExtUserHeaderSection.begin(), 168 ExtUserHeaderSection.end()); 169 data.at(sectionCountOffset) = 6; 170 break; 171 case TestPELType::privateHeaderSection: 172 data.insert(data.end(), privateHeaderSection.begin(), 173 privateHeaderSection.end()); 174 break; 175 case TestPELType::userHeaderSection: 176 data.insert(data.end(), userHeaderSection.begin(), 177 userHeaderSection.end()); 178 break; 179 case TestPELType::primarySRCSection: 180 data.insert(data.end(), srcSectionNoCallouts.begin(), 181 srcSectionNoCallouts.end()); 182 break; 183 case TestPELType::primarySRCSection2Callouts: 184 { 185 // Start with the no-callouts SRC, and add the callouts section 186 // from above. 187 auto src = srcSectionNoCallouts; 188 auto callouts = 189 srcDataFactory(TestSRCType::calloutSection2Callouts); 190 191 src.insert(src.end(), callouts.begin(), callouts.end()); 192 193 // Set the flag that says there are callouts 194 // One byte after the 8B header 195 src[8 + 1] |= 0x01; 196 197 // Set the new sizes 198 uint16_t size = src.size(); 199 Stream stream{src}; 200 201 stream.offset(2); // In the header 202 stream << size; 203 204 // In the SRC - the size field doesn't include the header 205 size -= 8; 206 stream.offset(8 + 6); 207 stream << size; 208 209 data.insert(data.end(), src.begin(), src.end()); 210 break; 211 } 212 case TestPELType::failingMTMSSection: 213 data.insert(data.end(), failingMTMSSection.begin(), 214 failingMTMSSection.end()); 215 } 216 return data; 217 } 218 219 std::vector<uint8_t> srcDataFactory(TestSRCType type) 220 { 221 switch (type) 222 { 223 case TestSRCType::fruIdentityStructure: 224 return srcFRUIdentityCallout; 225 226 case TestSRCType::pceIdentityStructure: 227 return srcPCEIdentityCallout; 228 229 case TestSRCType::mruStructure: 230 return srcMRUCallout; 231 232 case TestSRCType::calloutStructureA: 233 { 234 // Add just the FRU identity substructure to the base structure 235 std::vector<uint8_t> data{ 236 0xFF, 0x28, 'H', 4, // size, flags, priority, LC length 237 'U', '4', '2', 0x00 // LC 238 }; 239 240 data.insert(data.end(), srcFRUIdentityCallout.begin(), 241 srcFRUIdentityCallout.end()); 242 243 // The final size 244 data[0] = data.size(); 245 return data; 246 } 247 case TestSRCType::calloutStructureB: 248 { 249 // Add all 3 substructures to the base structure 250 251 std::vector<uint8_t> data{ 252 0xFF, 0x2F, 'L', 8, // size, flags, priority, LC length 253 'U', '1', '2', '-', 'P', '1', 0x00, 0x00 // LC 254 }; 255 data.insert(data.end(), srcFRUIdentityCallout.begin(), 256 srcFRUIdentityCallout.end()); 257 data.insert(data.end(), srcPCEIdentityCallout.begin(), 258 srcPCEIdentityCallout.end()); 259 data.insert(data.end(), srcMRUCallout.begin(), srcMRUCallout.end()); 260 261 // The final size 262 data[0] = data.size(); 263 return data; 264 } 265 case TestSRCType::calloutSection2Callouts: 266 { 267 std::vector<uint8_t> data{0xC0, 0x00, 0x00, 268 0x00}; // ID, flags, length in words 269 270 // Add 2 callouts 271 auto callout = srcDataFactory(TestSRCType::calloutStructureA); 272 data.insert(data.end(), callout.begin(), callout.end()); 273 274 callout = srcDataFactory(TestSRCType::calloutStructureB); 275 data.insert(data.end(), callout.begin(), callout.end()); 276 277 // Set the actual word length value at offset 2 278 Stream stream{data}; 279 uint16_t wordLength = data.size() / 4; 280 stream.offset(2); 281 stream << wordLength; 282 stream.offset(0); 283 284 return data; 285 } 286 } 287 return {}; 288 } 289 290 std::unique_ptr<std::vector<uint8_t>> readPELFile(const fs::path& path) 291 { 292 std::ifstream file{path}; 293 294 auto pel = std::make_unique<std::vector<uint8_t>>( 295 std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()); 296 return pel; 297 } 298