blob: b596d3422f11d08db718424a8f0b2c5a4849a689 [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());
Matt Spinler386a61e2020-08-13 15:51:12 -0500233 case TestPELType::extendedUserDataSection:
234 data.insert(data.end(), extendedUserDataSection.begin(),
235 extendedUserDataSection.end());
Matt Spinlerd3335df2019-07-10 11:04:21 -0500236 }
237 return data;
238}
239
Matt Spinler454f6562020-07-07 11:22:47 -0500240std::vector<uint8_t> pelFactory(uint32_t id, char creatorID, uint8_t severity,
241 uint16_t actionFlags, size_t size)
242{
243 std::vector<uint8_t> data;
244 size_t offset = 0;
245
246 auto now = std::chrono::system_clock::now();
247 auto timestamp = getBCDTime(now);
248
249 // Start with the default Private Header, and modify it
250 data.insert(data.end(), privateHeaderSection.begin(),
251 privateHeaderSection.end());
252 data.at(creatorPHOffset) = creatorID;
253
254 // Modify the multibyte fields in it
255 Stream stream{data};
256 stream.offset(createTimestampPHOffset);
257 stream << timestamp;
258 stream.offset(commitTimestampPHOffset);
259 stream << timestamp;
260 stream.offset(plidPHOffset);
261 stream << id;
262 stream.offset(pelIDPHOffset);
263 stream << id;
264 stream.offset(obmcIDPHOffset);
265 stream << id + 500;
266
267 offset = data.size();
268
269 // User Header
270 data.insert(data.end(), userHeaderSection.begin(), userHeaderSection.end());
271 data.at(offset + sevUHOffset) = severity;
272 data.at(offset + actionFlagsUHOffset) = actionFlags >> 8;
273 data.at(offset + actionFlagsUHOffset + 1) = actionFlags;
274
275 // Use the default SRC, failing MTMS, and ext user Header sections
Matt Spinler6c081cc2020-08-05 13:25:54 -0500276 auto src = pelDataFactory(TestPELType::primarySRCSection2Callouts);
277
278 data.insert(data.end(), src.begin(), src.end());
Matt Spinler454f6562020-07-07 11:22:47 -0500279 data.insert(data.end(), failingMTMSSection.begin(),
280 failingMTMSSection.end());
281 data.insert(data.end(), ExtUserHeaderSection.begin(),
282 ExtUserHeaderSection.end());
283
284 data.at(sectionCountOffset) = 5;
285
286 // Require the size to be enough for all the above sections.
287 assert(size >= data.size());
288 assert(size <= 16384);
289
290 // Add a UserData section to get the size we need.
291 auto udSection = UserDataSection;
292 udSection.resize(size - data.size());
293
294 if (!udSection.empty())
295 {
296 // At least has to be 8B for the header
297 assert(udSection.size() >= 8);
298
299 // UD sections must be 4B aligned
300 assert(udSection.size() % 4 == 0);
301
302 // Set the new size in the section heder
303 Stream udStream{udSection};
304 udStream.offset(2);
305 udStream << static_cast<uint16_t>(udSection.size());
306
307 data.insert(data.end(), udSection.begin(), udSection.end());
308 data[sectionCountOffset]++;
309 }
310
311 assert(size == data.size());
312 return data;
313}
314
Matt Spinler6c9662c2019-10-09 11:27:20 -0500315std::vector<uint8_t> srcDataFactory(TestSRCType type)
316{
317 switch (type)
318 {
319 case TestSRCType::fruIdentityStructure:
320 return srcFRUIdentityCallout;
321
322 case TestSRCType::pceIdentityStructure:
323 return srcPCEIdentityCallout;
324
325 case TestSRCType::mruStructure:
326 return srcMRUCallout;
Matt Spinler32f13c92019-10-09 12:48:25 -0500327
328 case TestSRCType::calloutStructureA:
329 {
330 // Add just the FRU identity substructure to the base structure
331 std::vector<uint8_t> data{
332 0xFF, 0x28, 'H', 4, // size, flags, priority, LC length
333 'U', '4', '2', 0x00 // LC
334 };
335
336 data.insert(data.end(), srcFRUIdentityCallout.begin(),
337 srcFRUIdentityCallout.end());
338
339 // The final size
340 data[0] = data.size();
341 return data;
342 }
343 case TestSRCType::calloutStructureB:
344 {
345 // Add all 3 substructures to the base structure
346
347 std::vector<uint8_t> data{
348 0xFF, 0x2F, 'L', 8, // size, flags, priority, LC length
349 'U', '1', '2', '-', 'P', '1', 0x00, 0x00 // LC
350 };
351 data.insert(data.end(), srcFRUIdentityCallout.begin(),
352 srcFRUIdentityCallout.end());
353 data.insert(data.end(), srcPCEIdentityCallout.begin(),
354 srcPCEIdentityCallout.end());
355 data.insert(data.end(), srcMRUCallout.begin(), srcMRUCallout.end());
356
357 // The final size
358 data[0] = data.size();
359 return data;
360 }
Matt Spinlerf9bae182019-10-09 13:37:38 -0500361 case TestSRCType::calloutSection2Callouts:
362 {
363 std::vector<uint8_t> data{0xC0, 0x00, 0x00,
364 0x00}; // ID, flags, length in words
365
366 // Add 2 callouts
367 auto callout = srcDataFactory(TestSRCType::calloutStructureA);
368 data.insert(data.end(), callout.begin(), callout.end());
369
370 callout = srcDataFactory(TestSRCType::calloutStructureB);
371 data.insert(data.end(), callout.begin(), callout.end());
372
373 // Set the actual word length value at offset 2
374 Stream stream{data};
375 uint16_t wordLength = data.size() / 4;
376 stream.offset(2);
377 stream << wordLength;
378 stream.offset(0);
379
380 return data;
381 }
Matt Spinler6c9662c2019-10-09 11:27:20 -0500382 }
383 return {};
384}
385
Matt Spinlerd3335df2019-07-10 11:04:21 -0500386std::unique_ptr<std::vector<uint8_t>> readPELFile(const fs::path& path)
387{
388 std::ifstream file{path};
389
390 auto pel = std::make_unique<std::vector<uint8_t>>(
391 std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
392 return pel;
393}