blob: c7d7911b18c19f4731fc4017132aec026b06308e [file] [log] [blame]
Alexander Hansen40fb5492025-10-28 17:56:12 +01001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright 2019 IBM Corporation
3
Matt Spinlerd3335df2019-07-10 11:04:21 -05004#include "pel_utils.hpp"
5
6#include "extensions/openpower-pels/private_header.hpp"
Matt Spinler03c1d912019-07-10 14:12:15 -05007#include "extensions/openpower-pels/user_header.hpp"
Matt Spinlerd3335df2019-07-10 11:04:21 -05008
9#include <fstream>
10
11#include <gtest/gtest.h>
12
13namespace fs = std::filesystem;
14using namespace openpower::pels;
15
Matt Spinlercb6b0592019-07-16 15:58:51 -050016std::filesystem::path CleanLogID::pelIDFile{};
Matt Spinler89fa0822019-07-17 13:54:30 -050017std::filesystem::path CleanPELFiles::pelIDFile{};
18std::filesystem::path CleanPELFiles::repoPath{};
Matt Spinler367144c2019-09-19 15:33:52 -050019std::filesystem::path CleanPELFiles::registryPath{};
Matt Spinlercb6b0592019-07-16 15:58:51 -050020
Matt Spinler42828bd2019-10-11 10:39:30 -050021const std::vector<uint8_t> privateHeaderSection{
22 // section header
Patrick Williamsac1ba3f2023-05-10 07:50:16 -050023 0x50, 0x48, // ID 'PH'
24 0x00, 0x30, // Size
25 0x01, 0x02, // version, subtype
26 0x03, 0x04, // comp ID
Matt Spinlerd3335df2019-07-10 11:04:21 -050027
Matt Spinler42828bd2019-10-11 10:39:30 -050028 0x20, 0x30, 0x05, 0x09, 0x11, 0x1E, 0x1, 0x63, // create timestamp
Matt Spinlerd3335df2019-07-10 11:04:21 -050029 0x20, 0x31, 0x06, 0x0F, 0x09, 0x22, 0x3A, 0x00, // commit timestamp
Matt Spinler48c44db2020-08-25 12:47:13 -050030 0x4F, // creatorID 'O'
Matt Spinlerd3335df2019-07-10 11:04:21 -050031 0x00, // logtype
32 0x00, // reserved
33 0x02, // section count
34 0x90, 0x91, 0x92, 0x93, // OpenBMC log ID
35 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0, // creator version
36 0x50, 0x51, 0x52, 0x53, // plid
Matt Spinler454f6562020-07-07 11:22:47 -050037 0x80, 0x81, 0x82, 0x83}; // PEL ID
Matt Spinlerd3335df2019-07-10 11:04:21 -050038
Matt Spinler42828bd2019-10-11 10:39:30 -050039const std::vector<uint8_t> userHeaderSection{
40 // section header
Patrick Williamsac1ba3f2023-05-10 07:50:16 -050041 0x55, 0x48, // ID 'UH'
42 0x00, 0x18, // Size
43 0x01, 0x0A, // version, subtype
44 0x0B, 0x0C, // comp ID
Matt Spinler03c1d912019-07-10 14:12:15 -050045
Matt Spinler03c1d912019-07-10 14:12:15 -050046 0x10, 0x04, // subsystem, scope
47 0x20, 0x00, // severity, type
48 0x00, 0x00, 0x00, 0x00, // reserved
49 0x03, 0x04, // problem domain, vector
50 0x80, 0xC0, // action flags
51 0x00, 0x00, 0x00, 0x00 // reserved
Matt Spinlerd3335df2019-07-10 11:04:21 -050052};
53
Matt Spinler42828bd2019-10-11 10:39:30 -050054const std::vector<uint8_t> srcSectionNoCallouts{
Matt Spinlerf9bae182019-10-09 13:37:38 -050055
56 // Header
Matt Spinlerf1b46ff2020-01-22 14:10:04 -060057 'P', 'S', 0x00, 0x50, 0x01, 0x01, 0x02, 0x02,
Matt Spinlerf9bae182019-10-09 13:37:38 -050058
Matt Spinlerf9bae182019-10-09 13:37:38 -050059 0x02, 0x00, 0x00, // version, flags, reserved
60 0x09, 0x00, 0x00, // hex word count, reserved2B
61 0x00, 0x48, // SRC structure size
62
63 // Hex words 2 - 9
Matt Spinlerbd716f02019-10-15 10:54:11 -050064 0x02, 0x02, 0x02, 0x55, 0x03, 0x03, 0x03, 0x10, 0x04, 0x04, 0x04, 0x04,
Matt Spinlerf9bae182019-10-09 13:37:38 -050065 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07,
66 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09,
67 // ASCII string
68 'B', 'D', '8', 'D', '5', '6', '7', '8', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
69 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
70 ' ', ' '};
71
Matt Spinlerc63e2e82019-12-02 15:50:12 -060072const std::vector<uint8_t> failingMTMSSection{
Matt Spinler213e5c12019-10-11 10:57:49 -050073 // Header
74 0x4D, 0x54, 0x00, 0x1C, 0x01, 0x00, 0x20, 0x00,
75
76 'T', 'T', 'T', 'T', '-', 'M', 'M', 'M', '1', '2',
77 '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C'};
78
Matt Spinlerc63e2e82019-12-02 15:50:12 -060079const std::vector<uint8_t> UserDataSection{
Matt Spinler213e5c12019-10-11 10:57:49 -050080 // Header
81 0x55, 0x44, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00,
82
83 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
84
Matt Spinlerc63e2e82019-12-02 15:50:12 -060085const std::vector<uint8_t> ExtUserHeaderSection{
86 // Header
87 'E', 'H', 0x00, 0x60, 0x01, 0x00, 0x03, 0x04,
88
89 // MTMS
90 'T', 'T', 'T', 'T', '-', 'M', 'M', 'M', '1', '2', '3', '4', '5', '6', '7',
91 '8', '9', 'A', 'B', 'C',
92
93 // Server FW version
94 'S', 'E', 'R', 'V', 'E', 'R', '_', 'V', 'E', 'R', 'S', 'I', 'O', 'N', '\0',
95 '\0',
96
97 // Subsystem FW Version
98 'B', 'M', 'C', '_', 'V', 'E', 'R', 'S', 'I', 'O', 'N', '\0', '\0', '\0',
99 '\0', '\0',
100
101 0x00, 0x00, 0x00, 0x00, // Reserved
102 0x20, 0x25, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, // Ref time
103 0x00, 0x00, 0x00, // Reserved
104
105 // SymptomID length and symptom ID
106 20, 'B', 'D', '8', 'D', '4', '2', '0', '0', '_', '1', '2', '3', '4', '5',
107 '6', '7', '8', '\0', '\0', '\0'};
108
Matt Spinler42828bd2019-10-11 10:39:30 -0500109const std::vector<uint8_t> srcFRUIdentityCallout{
110 'I', 'D', 0x1C, 0x1D, // type, size, flags
111 '1', '2', '3', '4', // PN
112 '5', '6', '7', 0x00, 'A', 'A', 'A', 'A', // CCIN
113 '1', '2', '3', '4', '5', '6', '7', '8', // SN
114 '9', 'A', 'B', 'C'};
115
116const std::vector<uint8_t> srcPCEIdentityCallout{
117 'P', 'E', 0x24, 0x00, // type, size, flags
118 'T', 'T', 'T', 'T', '-', 'M', 'M', 'M', // MTM
119 '1', '2', '3', '4', '5', '6', '7', // SN
120 '8', '9', 'A', 'B', 'C', 'P', 'C', 'E', // Name + null padded
121 'N', 'A', 'M', 'E', '1', '2', 0x00, 0x00, 0x00};
122
123const std::vector<uint8_t> srcMRUCallout{
124 'M', 'R', 0x28, 0x04, // ID, size, flags
125 0x00, 0x00, 0x00, 0x00, // Reserved
126 0x00, 0x00, 0x00, 'H', // priority 0
127 0x01, 0x01, 0x01, 0x01, // MRU ID 0
128 0x00, 0x00, 0x00, 'M', // priority 1
129 0x02, 0x02, 0x02, 0x02, // MRU ID 1
130 0x00, 0x00, 0x00, 'L', // priority 2
131 0x03, 0x03, 0x03, 0x03, // MRU ID 2
132 0x00, 0x00, 0x00, 'H', // priority 3
133 0x04, 0x04, 0x04, 0x04, // MRU ID 3
134};
135
Matt Spinler386a61e2020-08-13 15:51:12 -0500136const std::vector<uint8_t> extendedUserDataSection{
137 // Header
138 0x45, 0x44, 0x00, 0x18, 0x01, 0x02, 0x20, 0x00,
139
140 // Creator ID 'O', and then data
141 0x4F, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
142 0x05, 0x0A, 0x0B, 0x0C};
143
Matt Spinler42828bd2019-10-11 10:39:30 -0500144constexpr size_t sectionCountOffset = 27;
Matt Spinler454f6562020-07-07 11:22:47 -0500145constexpr size_t createTimestampPHOffset = 8;
146constexpr size_t commitTimestampPHOffset = 16;
147constexpr size_t creatorPHOffset = 24;
148constexpr size_t obmcIDPHOffset = 28;
149constexpr size_t plidPHOffset = 40;
150constexpr size_t pelIDPHOffset = 44;
151constexpr size_t sevUHOffset = 10;
152constexpr size_t actionFlagsUHOffset = 18;
Matt Spinler42828bd2019-10-11 10:39:30 -0500153
154std::vector<uint8_t> pelDataFactory(TestPELType type)
Matt Spinlerd3335df2019-07-10 11:04:21 -0500155{
Matt Spinler42828bd2019-10-11 10:39:30 -0500156 std::vector<uint8_t> data;
157
Matt Spinlerd3335df2019-07-10 11:04:21 -0500158 switch (type)
159 {
Matt Spinler42828bd2019-10-11 10:39:30 -0500160 case TestPELType::pelSimple:
161 data.insert(data.end(), privateHeaderSection.begin(),
162 privateHeaderSection.end());
163 data.insert(data.end(), userHeaderSection.begin(),
164 userHeaderSection.end());
Matt Spinler213e5c12019-10-11 10:57:49 -0500165 data.insert(data.end(), srcSectionNoCallouts.begin(),
166 srcSectionNoCallouts.end());
167 data.insert(data.end(), failingMTMSSection.begin(),
168 failingMTMSSection.end());
169 data.insert(data.end(), UserDataSection.begin(),
170 UserDataSection.end());
Matt Spinlerc63e2e82019-12-02 15:50:12 -0600171 data.insert(data.end(), ExtUserHeaderSection.begin(),
172 ExtUserHeaderSection.end());
Matt Spinler386a61e2020-08-13 15:51:12 -0500173 data.insert(data.end(), extendedUserDataSection.begin(),
174 extendedUserDataSection.end());
175 data.at(sectionCountOffset) = 7;
Matt Spinlerd3335df2019-07-10 11:04:21 -0500176 break;
Matt Spinler42828bd2019-10-11 10:39:30 -0500177 case TestPELType::privateHeaderSection:
178 data.insert(data.end(), privateHeaderSection.begin(),
179 privateHeaderSection.end());
Matt Spinlerd3335df2019-07-10 11:04:21 -0500180 break;
Matt Spinler42828bd2019-10-11 10:39:30 -0500181 case TestPELType::userHeaderSection:
182 data.insert(data.end(), userHeaderSection.begin(),
183 userHeaderSection.end());
Matt Spinler03c1d912019-07-10 14:12:15 -0500184 break;
Matt Spinler42828bd2019-10-11 10:39:30 -0500185 case TestPELType::primarySRCSection:
186 data.insert(data.end(), srcSectionNoCallouts.begin(),
187 srcSectionNoCallouts.end());
188 break;
189 case TestPELType::primarySRCSection2Callouts:
190 {
191 // Start with the no-callouts SRC, and add the callouts section
192 // from above.
193 auto src = srcSectionNoCallouts;
194 auto callouts =
195 srcDataFactory(TestSRCType::calloutSection2Callouts);
196
197 src.insert(src.end(), callouts.begin(), callouts.end());
198
199 // Set the flag that says there are callouts
200 // One byte after the 8B header
201 src[8 + 1] |= 0x01;
202
203 // Set the new sizes
204 uint16_t size = src.size();
205 Stream stream{src};
206
207 stream.offset(2); // In the header
208 stream << size;
209
210 // In the SRC - the size field doesn't include the header
211 size -= 8;
212 stream.offset(8 + 6);
213 stream << size;
214
215 data.insert(data.end(), src.begin(), src.end());
216 break;
217 }
Matt Spinler213e5c12019-10-11 10:57:49 -0500218 case TestPELType::failingMTMSSection:
219 data.insert(data.end(), failingMTMSSection.begin(),
220 failingMTMSSection.end());
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500221 break;
Matt Spinler386a61e2020-08-13 15:51:12 -0500222 case TestPELType::extendedUserDataSection:
223 data.insert(data.end(), extendedUserDataSection.begin(),
224 extendedUserDataSection.end());
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500225 break;
Matt Spinlerd3335df2019-07-10 11:04:21 -0500226 }
227 return data;
228}
229
Matt Spinler454f6562020-07-07 11:22:47 -0500230std::vector<uint8_t> pelFactory(uint32_t id, char creatorID, uint8_t severity,
231 uint16_t actionFlags, size_t size)
232{
233 std::vector<uint8_t> data;
234 size_t offset = 0;
235
236 auto now = std::chrono::system_clock::now();
237 auto timestamp = getBCDTime(now);
238
239 // Start with the default Private Header, and modify it
240 data.insert(data.end(), privateHeaderSection.begin(),
241 privateHeaderSection.end());
242 data.at(creatorPHOffset) = creatorID;
243
244 // Modify the multibyte fields in it
245 Stream stream{data};
246 stream.offset(createTimestampPHOffset);
247 stream << timestamp;
248 stream.offset(commitTimestampPHOffset);
249 stream << timestamp;
250 stream.offset(plidPHOffset);
251 stream << id;
252 stream.offset(pelIDPHOffset);
253 stream << id;
254 stream.offset(obmcIDPHOffset);
255 stream << id + 500;
256
257 offset = data.size();
258
259 // User Header
260 data.insert(data.end(), userHeaderSection.begin(), userHeaderSection.end());
261 data.at(offset + sevUHOffset) = severity;
262 data.at(offset + actionFlagsUHOffset) = actionFlags >> 8;
263 data.at(offset + actionFlagsUHOffset + 1) = actionFlags;
264
265 // Use the default SRC, failing MTMS, and ext user Header sections
Matt Spinler6c081cc2020-08-05 13:25:54 -0500266 auto src = pelDataFactory(TestPELType::primarySRCSection2Callouts);
267
268 data.insert(data.end(), src.begin(), src.end());
Matt Spinler454f6562020-07-07 11:22:47 -0500269 data.insert(data.end(), failingMTMSSection.begin(),
270 failingMTMSSection.end());
271 data.insert(data.end(), ExtUserHeaderSection.begin(),
272 ExtUserHeaderSection.end());
273
274 data.at(sectionCountOffset) = 5;
275
276 // Require the size to be enough for all the above sections.
277 assert(size >= data.size());
278 assert(size <= 16384);
279
280 // Add a UserData section to get the size we need.
281 auto udSection = UserDataSection;
282 udSection.resize(size - data.size());
283
284 if (!udSection.empty())
285 {
286 // At least has to be 8B for the header
287 assert(udSection.size() >= 8);
288
289 // UD sections must be 4B aligned
290 assert(udSection.size() % 4 == 0);
291
292 // Set the new size in the section heder
293 Stream udStream{udSection};
294 udStream.offset(2);
295 udStream << static_cast<uint16_t>(udSection.size());
296
297 data.insert(data.end(), udSection.begin(), udSection.end());
298 data[sectionCountOffset]++;
299 }
300
301 assert(size == data.size());
302 return data;
303}
304
Matt Spinler6c9662c2019-10-09 11:27:20 -0500305std::vector<uint8_t> srcDataFactory(TestSRCType type)
306{
307 switch (type)
308 {
309 case TestSRCType::fruIdentityStructure:
310 return srcFRUIdentityCallout;
311
312 case TestSRCType::pceIdentityStructure:
313 return srcPCEIdentityCallout;
314
315 case TestSRCType::mruStructure:
316 return srcMRUCallout;
Matt Spinler32f13c92019-10-09 12:48:25 -0500317
318 case TestSRCType::calloutStructureA:
319 {
320 // Add just the FRU identity substructure to the base structure
321 std::vector<uint8_t> data{
322 0xFF, 0x28, 'H', 4, // size, flags, priority, LC length
323 'U', '4', '2', 0x00 // LC
324 };
325
326 data.insert(data.end(), srcFRUIdentityCallout.begin(),
327 srcFRUIdentityCallout.end());
328
329 // The final size
330 data[0] = data.size();
331 return data;
332 }
333 case TestSRCType::calloutStructureB:
334 {
335 // Add all 3 substructures to the base structure
336
337 std::vector<uint8_t> data{
338 0xFF, 0x2F, 'L', 8, // size, flags, priority, LC length
339 'U', '1', '2', '-', 'P', '1', 0x00, 0x00 // LC
340 };
341 data.insert(data.end(), srcFRUIdentityCallout.begin(),
342 srcFRUIdentityCallout.end());
343 data.insert(data.end(), srcPCEIdentityCallout.begin(),
344 srcPCEIdentityCallout.end());
345 data.insert(data.end(), srcMRUCallout.begin(), srcMRUCallout.end());
346
347 // The final size
348 data[0] = data.size();
349 return data;
350 }
Matt Spinlerf9bae182019-10-09 13:37:38 -0500351 case TestSRCType::calloutSection2Callouts:
352 {
353 std::vector<uint8_t> data{0xC0, 0x00, 0x00,
354 0x00}; // ID, flags, length in words
355
356 // Add 2 callouts
357 auto callout = srcDataFactory(TestSRCType::calloutStructureA);
358 data.insert(data.end(), callout.begin(), callout.end());
359
360 callout = srcDataFactory(TestSRCType::calloutStructureB);
361 data.insert(data.end(), callout.begin(), callout.end());
362
363 // Set the actual word length value at offset 2
364 Stream stream{data};
365 uint16_t wordLength = data.size() / 4;
366 stream.offset(2);
367 stream << wordLength;
368 stream.offset(0);
369
370 return data;
371 }
Matt Spinler6c9662c2019-10-09 11:27:20 -0500372 }
373 return {};
374}
375
Matt Spinlerd3335df2019-07-10 11:04:21 -0500376std::unique_ptr<std::vector<uint8_t>> readPELFile(const fs::path& path)
377{
378 std::ifstream file{path};
379
380 auto pel = std::make_unique<std::vector<uint8_t>>(
381 std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
382 return pel;
383}