blob: b9b46a6982d52d0fe7ba142a11e9887adcb7354b [file] [log] [blame]
Matt Spinler97f7abc2019-11-06 09:40:23 -06001/**
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 */
Matt Spinlerd3335df2019-07-10 11:04:21 -050016#include "pel_utils.hpp"
17
18#include "extensions/openpower-pels/private_header.hpp"
Matt Spinler03c1d912019-07-10 14:12:15 -050019#include "extensions/openpower-pels/user_header.hpp"
Matt Spinlerd3335df2019-07-10 11:04:21 -050020
21#include <fstream>
22
23#include <gtest/gtest.h>
24
25namespace fs = std::filesystem;
26using namespace openpower::pels;
27
Matt Spinlercb6b0592019-07-16 15:58:51 -050028std::filesystem::path CleanLogID::pelIDFile{};
Matt Spinler89fa0822019-07-17 13:54:30 -050029std::filesystem::path CleanPELFiles::pelIDFile{};
30std::filesystem::path CleanPELFiles::repoPath{};
Matt Spinler367144c2019-09-19 15:33:52 -050031std::filesystem::path CleanPELFiles::registryPath{};
Matt Spinlercb6b0592019-07-16 15:58:51 -050032
Matt Spinler42828bd2019-10-11 10:39:30 -050033const std::vector<uint8_t> privateHeaderSection{
34 // section header
Matt Spinlerd3335df2019-07-10 11:04:21 -050035 0x50, 0x48, // ID 'PH'
36 0x00, 0x30, // Size
37 0x01, 0x02, // version, subtype
38 0x03, 0x04, // comp ID
39
Matt Spinler42828bd2019-10-11 10:39:30 -050040 0x20, 0x30, 0x05, 0x09, 0x11, 0x1E, 0x1, 0x63, // create timestamp
Matt Spinlerd3335df2019-07-10 11:04:21 -050041 0x20, 0x31, 0x06, 0x0F, 0x09, 0x22, 0x3A, 0x00, // commit timestamp
Matt Spinler48c44db2020-08-25 12:47:13 -050042 0x4F, // creatorID 'O'
Matt Spinlerd3335df2019-07-10 11:04:21 -050043 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
Matt Spinler454f6562020-07-07 11:22:47 -050049 0x80, 0x81, 0x82, 0x83}; // PEL ID
Matt Spinlerd3335df2019-07-10 11:04:21 -050050
Matt Spinler42828bd2019-10-11 10:39:30 -050051const std::vector<uint8_t> userHeaderSection{
52 // section header
Matt Spinler03c1d912019-07-10 14:12:15 -050053 0x55, 0x48, // ID 'UH'
54 0x00, 0x18, // Size
55 0x01, 0x0A, // version, subtype
56 0x0B, 0x0C, // comp ID
57
Matt Spinler03c1d912019-07-10 14:12:15 -050058 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
Matt Spinlerd3335df2019-07-10 11:04:21 -050064};
65
Matt Spinler42828bd2019-10-11 10:39:30 -050066const std::vector<uint8_t> srcSectionNoCallouts{
Matt Spinlerf9bae182019-10-09 13:37:38 -050067
68 // Header
Matt Spinlerf1b46ff2020-01-22 14:10:04 -060069 'P', 'S', 0x00, 0x50, 0x01, 0x01, 0x02, 0x02,
Matt Spinlerf9bae182019-10-09 13:37:38 -050070
Matt Spinlerf9bae182019-10-09 13:37:38 -050071 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
Matt Spinlerbd716f02019-10-15 10:54:11 -050076 0x02, 0x02, 0x02, 0x55, 0x03, 0x03, 0x03, 0x10, 0x04, 0x04, 0x04, 0x04,
Matt Spinlerf9bae182019-10-09 13:37:38 -050077 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
Matt Spinlerc63e2e82019-12-02 15:50:12 -060084const std::vector<uint8_t> failingMTMSSection{
Matt Spinler213e5c12019-10-11 10:57:49 -050085 // 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
Matt Spinlerc63e2e82019-12-02 15:50:12 -060091const std::vector<uint8_t> UserDataSection{
Matt Spinler213e5c12019-10-11 10:57:49 -050092 // Header
93 0x55, 0x44, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00,
94
95 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
96
Matt Spinlerc63e2e82019-12-02 15:50:12 -060097const 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
Matt Spinler42828bd2019-10-11 10:39:30 -0500121const 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
128const 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
135const 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
Matt Spinler386a61e2020-08-13 15:51:12 -0500148const std::vector<uint8_t> extendedUserDataSection{
149 // Header
150 0x45, 0x44, 0x00, 0x18, 0x01, 0x02, 0x20, 0x00,
151
152 // Creator ID 'O', and then data
153 0x4F, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
154 0x05, 0x0A, 0x0B, 0x0C};
155
Matt Spinler42828bd2019-10-11 10:39:30 -0500156constexpr size_t sectionCountOffset = 27;
Matt Spinler454f6562020-07-07 11:22:47 -0500157constexpr size_t createTimestampPHOffset = 8;
158constexpr size_t commitTimestampPHOffset = 16;
159constexpr size_t creatorPHOffset = 24;
160constexpr size_t obmcIDPHOffset = 28;
161constexpr size_t plidPHOffset = 40;
162constexpr size_t pelIDPHOffset = 44;
163constexpr size_t sevUHOffset = 10;
164constexpr size_t actionFlagsUHOffset = 18;
Matt Spinler42828bd2019-10-11 10:39:30 -0500165
166std::vector<uint8_t> pelDataFactory(TestPELType type)
Matt Spinlerd3335df2019-07-10 11:04:21 -0500167{
Matt Spinler42828bd2019-10-11 10:39:30 -0500168 std::vector<uint8_t> data;
169
Matt Spinlerd3335df2019-07-10 11:04:21 -0500170 switch (type)
171 {
Matt Spinler42828bd2019-10-11 10:39:30 -0500172 case TestPELType::pelSimple:
173 data.insert(data.end(), privateHeaderSection.begin(),
174 privateHeaderSection.end());
175 data.insert(data.end(), userHeaderSection.begin(),
176 userHeaderSection.end());
Matt Spinler213e5c12019-10-11 10:57:49 -0500177 data.insert(data.end(), srcSectionNoCallouts.begin(),
178 srcSectionNoCallouts.end());
179 data.insert(data.end(), failingMTMSSection.begin(),
180 failingMTMSSection.end());
181 data.insert(data.end(), UserDataSection.begin(),
182 UserDataSection.end());
Matt Spinlerc63e2e82019-12-02 15:50:12 -0600183 data.insert(data.end(), ExtUserHeaderSection.begin(),
184 ExtUserHeaderSection.end());
Matt Spinler386a61e2020-08-13 15:51:12 -0500185 data.insert(data.end(), extendedUserDataSection.begin(),
186 extendedUserDataSection.end());
187 data.at(sectionCountOffset) = 7;
Matt Spinlerd3335df2019-07-10 11:04:21 -0500188 break;
Matt Spinler42828bd2019-10-11 10:39:30 -0500189 case TestPELType::privateHeaderSection:
190 data.insert(data.end(), privateHeaderSection.begin(),
191 privateHeaderSection.end());
Matt Spinlerd3335df2019-07-10 11:04:21 -0500192 break;
Matt Spinler42828bd2019-10-11 10:39:30 -0500193 case TestPELType::userHeaderSection:
194 data.insert(data.end(), userHeaderSection.begin(),
195 userHeaderSection.end());
Matt Spinler03c1d912019-07-10 14:12:15 -0500196 break;
Matt Spinler42828bd2019-10-11 10:39:30 -0500197 case TestPELType::primarySRCSection:
198 data.insert(data.end(), srcSectionNoCallouts.begin(),
199 srcSectionNoCallouts.end());
200 break;
201 case TestPELType::primarySRCSection2Callouts:
202 {
203 // Start with the no-callouts SRC, and add the callouts section
204 // from above.
205 auto src = srcSectionNoCallouts;
206 auto callouts =
207 srcDataFactory(TestSRCType::calloutSection2Callouts);
208
209 src.insert(src.end(), callouts.begin(), callouts.end());
210
211 // Set the flag that says there are callouts
212 // One byte after the 8B header
213 src[8 + 1] |= 0x01;
214
215 // Set the new sizes
216 uint16_t size = src.size();
217 Stream stream{src};
218
219 stream.offset(2); // In the header
220 stream << size;
221
222 // In the SRC - the size field doesn't include the header
223 size -= 8;
224 stream.offset(8 + 6);
225 stream << size;
226
227 data.insert(data.end(), src.begin(), src.end());
228 break;
229 }
Matt Spinler213e5c12019-10-11 10:57:49 -0500230 case TestPELType::failingMTMSSection:
231 data.insert(data.end(), failingMTMSSection.begin(),
232 failingMTMSSection.end());
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500233 break;
Matt Spinler386a61e2020-08-13 15:51:12 -0500234 case TestPELType::extendedUserDataSection:
235 data.insert(data.end(), extendedUserDataSection.begin(),
236 extendedUserDataSection.end());
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500237 break;
Matt Spinlerd3335df2019-07-10 11:04:21 -0500238 }
239 return data;
240}
241
Matt Spinler454f6562020-07-07 11:22:47 -0500242std::vector<uint8_t> pelFactory(uint32_t id, char creatorID, uint8_t severity,
243 uint16_t actionFlags, size_t size)
244{
245 std::vector<uint8_t> data;
246 size_t offset = 0;
247
248 auto now = std::chrono::system_clock::now();
249 auto timestamp = getBCDTime(now);
250
251 // Start with the default Private Header, and modify it
252 data.insert(data.end(), privateHeaderSection.begin(),
253 privateHeaderSection.end());
254 data.at(creatorPHOffset) = creatorID;
255
256 // Modify the multibyte fields in it
257 Stream stream{data};
258 stream.offset(createTimestampPHOffset);
259 stream << timestamp;
260 stream.offset(commitTimestampPHOffset);
261 stream << timestamp;
262 stream.offset(plidPHOffset);
263 stream << id;
264 stream.offset(pelIDPHOffset);
265 stream << id;
266 stream.offset(obmcIDPHOffset);
267 stream << id + 500;
268
269 offset = data.size();
270
271 // User Header
272 data.insert(data.end(), userHeaderSection.begin(), userHeaderSection.end());
273 data.at(offset + sevUHOffset) = severity;
274 data.at(offset + actionFlagsUHOffset) = actionFlags >> 8;
275 data.at(offset + actionFlagsUHOffset + 1) = actionFlags;
276
277 // Use the default SRC, failing MTMS, and ext user Header sections
Matt Spinler6c081cc2020-08-05 13:25:54 -0500278 auto src = pelDataFactory(TestPELType::primarySRCSection2Callouts);
279
280 data.insert(data.end(), src.begin(), src.end());
Matt Spinler454f6562020-07-07 11:22:47 -0500281 data.insert(data.end(), failingMTMSSection.begin(),
282 failingMTMSSection.end());
283 data.insert(data.end(), ExtUserHeaderSection.begin(),
284 ExtUserHeaderSection.end());
285
286 data.at(sectionCountOffset) = 5;
287
288 // Require the size to be enough for all the above sections.
289 assert(size >= data.size());
290 assert(size <= 16384);
291
292 // Add a UserData section to get the size we need.
293 auto udSection = UserDataSection;
294 udSection.resize(size - data.size());
295
296 if (!udSection.empty())
297 {
298 // At least has to be 8B for the header
299 assert(udSection.size() >= 8);
300
301 // UD sections must be 4B aligned
302 assert(udSection.size() % 4 == 0);
303
304 // Set the new size in the section heder
305 Stream udStream{udSection};
306 udStream.offset(2);
307 udStream << static_cast<uint16_t>(udSection.size());
308
309 data.insert(data.end(), udSection.begin(), udSection.end());
310 data[sectionCountOffset]++;
311 }
312
313 assert(size == data.size());
314 return data;
315}
316
Matt Spinler6c9662c2019-10-09 11:27:20 -0500317std::vector<uint8_t> srcDataFactory(TestSRCType type)
318{
319 switch (type)
320 {
321 case TestSRCType::fruIdentityStructure:
322 return srcFRUIdentityCallout;
323
324 case TestSRCType::pceIdentityStructure:
325 return srcPCEIdentityCallout;
326
327 case TestSRCType::mruStructure:
328 return srcMRUCallout;
Matt Spinler32f13c92019-10-09 12:48:25 -0500329
330 case TestSRCType::calloutStructureA:
331 {
332 // Add just the FRU identity substructure to the base structure
333 std::vector<uint8_t> data{
334 0xFF, 0x28, 'H', 4, // size, flags, priority, LC length
335 'U', '4', '2', 0x00 // LC
336 };
337
338 data.insert(data.end(), srcFRUIdentityCallout.begin(),
339 srcFRUIdentityCallout.end());
340
341 // The final size
342 data[0] = data.size();
343 return data;
344 }
345 case TestSRCType::calloutStructureB:
346 {
347 // Add all 3 substructures to the base structure
348
349 std::vector<uint8_t> data{
350 0xFF, 0x2F, 'L', 8, // size, flags, priority, LC length
351 'U', '1', '2', '-', 'P', '1', 0x00, 0x00 // LC
352 };
353 data.insert(data.end(), srcFRUIdentityCallout.begin(),
354 srcFRUIdentityCallout.end());
355 data.insert(data.end(), srcPCEIdentityCallout.begin(),
356 srcPCEIdentityCallout.end());
357 data.insert(data.end(), srcMRUCallout.begin(), srcMRUCallout.end());
358
359 // The final size
360 data[0] = data.size();
361 return data;
362 }
Matt Spinlerf9bae182019-10-09 13:37:38 -0500363 case TestSRCType::calloutSection2Callouts:
364 {
365 std::vector<uint8_t> data{0xC0, 0x00, 0x00,
366 0x00}; // ID, flags, length in words
367
368 // Add 2 callouts
369 auto callout = srcDataFactory(TestSRCType::calloutStructureA);
370 data.insert(data.end(), callout.begin(), callout.end());
371
372 callout = srcDataFactory(TestSRCType::calloutStructureB);
373 data.insert(data.end(), callout.begin(), callout.end());
374
375 // Set the actual word length value at offset 2
376 Stream stream{data};
377 uint16_t wordLength = data.size() / 4;
378 stream.offset(2);
379 stream << wordLength;
380 stream.offset(0);
381
382 return data;
383 }
Matt Spinler6c9662c2019-10-09 11:27:20 -0500384 }
385 return {};
386}
387
Matt Spinlerd3335df2019-07-10 11:04:21 -0500388std::unique_ptr<std::vector<uint8_t>> readPELFile(const fs::path& path)
389{
390 std::ifstream file{path};
391
392 auto pel = std::make_unique<std::vector<uint8_t>>(
393 std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
394 return pel;
395}