blob: cf7a75f750425d7ac8f300791649dc91be1219c0 [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
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
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
148constexpr size_t sectionCountOffset = 27;
Matt Spinler454f6562020-07-07 11:22:47 -0500149constexpr size_t createTimestampPHOffset = 8;
150constexpr size_t commitTimestampPHOffset = 16;
151constexpr size_t creatorPHOffset = 24;
152constexpr size_t obmcIDPHOffset = 28;
153constexpr size_t plidPHOffset = 40;
154constexpr size_t pelIDPHOffset = 44;
155constexpr size_t sevUHOffset = 10;
156constexpr size_t actionFlagsUHOffset = 18;
Matt Spinler42828bd2019-10-11 10:39:30 -0500157
158std::vector<uint8_t> pelDataFactory(TestPELType type)
Matt Spinlerd3335df2019-07-10 11:04:21 -0500159{
Matt Spinler42828bd2019-10-11 10:39:30 -0500160 std::vector<uint8_t> data;
161
Matt Spinlerd3335df2019-07-10 11:04:21 -0500162 switch (type)
163 {
Matt Spinler42828bd2019-10-11 10:39:30 -0500164 case TestPELType::pelSimple:
165 data.insert(data.end(), privateHeaderSection.begin(),
166 privateHeaderSection.end());
167 data.insert(data.end(), userHeaderSection.begin(),
168 userHeaderSection.end());
Matt Spinler213e5c12019-10-11 10:57:49 -0500169 data.insert(data.end(), srcSectionNoCallouts.begin(),
170 srcSectionNoCallouts.end());
171 data.insert(data.end(), failingMTMSSection.begin(),
172 failingMTMSSection.end());
173 data.insert(data.end(), UserDataSection.begin(),
174 UserDataSection.end());
Matt Spinlerc63e2e82019-12-02 15:50:12 -0600175 data.insert(data.end(), ExtUserHeaderSection.begin(),
176 ExtUserHeaderSection.end());
177 data.at(sectionCountOffset) = 6;
Matt Spinlerd3335df2019-07-10 11:04:21 -0500178 break;
Matt Spinler42828bd2019-10-11 10:39:30 -0500179 case TestPELType::privateHeaderSection:
180 data.insert(data.end(), privateHeaderSection.begin(),
181 privateHeaderSection.end());
Matt Spinlerd3335df2019-07-10 11:04:21 -0500182 break;
Matt Spinler42828bd2019-10-11 10:39:30 -0500183 case TestPELType::userHeaderSection:
184 data.insert(data.end(), userHeaderSection.begin(),
185 userHeaderSection.end());
Matt Spinler03c1d912019-07-10 14:12:15 -0500186 break;
Matt Spinler42828bd2019-10-11 10:39:30 -0500187 case TestPELType::primarySRCSection:
188 data.insert(data.end(), srcSectionNoCallouts.begin(),
189 srcSectionNoCallouts.end());
190 break;
191 case TestPELType::primarySRCSection2Callouts:
192 {
193 // Start with the no-callouts SRC, and add the callouts section
194 // from above.
195 auto src = srcSectionNoCallouts;
196 auto callouts =
197 srcDataFactory(TestSRCType::calloutSection2Callouts);
198
199 src.insert(src.end(), callouts.begin(), callouts.end());
200
201 // Set the flag that says there are callouts
202 // One byte after the 8B header
203 src[8 + 1] |= 0x01;
204
205 // Set the new sizes
206 uint16_t size = src.size();
207 Stream stream{src};
208
209 stream.offset(2); // In the header
210 stream << size;
211
212 // In the SRC - the size field doesn't include the header
213 size -= 8;
214 stream.offset(8 + 6);
215 stream << size;
216
217 data.insert(data.end(), src.begin(), src.end());
218 break;
219 }
Matt Spinler213e5c12019-10-11 10:57:49 -0500220 case TestPELType::failingMTMSSection:
221 data.insert(data.end(), failingMTMSSection.begin(),
222 failingMTMSSection.end());
Matt Spinlerd3335df2019-07-10 11:04:21 -0500223 }
224 return data;
225}
226
Matt Spinler454f6562020-07-07 11:22:47 -0500227std::vector<uint8_t> pelFactory(uint32_t id, char creatorID, uint8_t severity,
228 uint16_t actionFlags, size_t size)
229{
230 std::vector<uint8_t> data;
231 size_t offset = 0;
232
233 auto now = std::chrono::system_clock::now();
234 auto timestamp = getBCDTime(now);
235
236 // Start with the default Private Header, and modify it
237 data.insert(data.end(), privateHeaderSection.begin(),
238 privateHeaderSection.end());
239 data.at(creatorPHOffset) = creatorID;
240
241 // Modify the multibyte fields in it
242 Stream stream{data};
243 stream.offset(createTimestampPHOffset);
244 stream << timestamp;
245 stream.offset(commitTimestampPHOffset);
246 stream << timestamp;
247 stream.offset(plidPHOffset);
248 stream << id;
249 stream.offset(pelIDPHOffset);
250 stream << id;
251 stream.offset(obmcIDPHOffset);
252 stream << id + 500;
253
254 offset = data.size();
255
256 // User Header
257 data.insert(data.end(), userHeaderSection.begin(), userHeaderSection.end());
258 data.at(offset + sevUHOffset) = severity;
259 data.at(offset + actionFlagsUHOffset) = actionFlags >> 8;
260 data.at(offset + actionFlagsUHOffset + 1) = actionFlags;
261
262 // Use the default SRC, failing MTMS, and ext user Header sections
263 data.insert(data.end(), srcSectionNoCallouts.begin(),
264 srcSectionNoCallouts.end());
265 data.insert(data.end(), failingMTMSSection.begin(),
266 failingMTMSSection.end());
267 data.insert(data.end(), ExtUserHeaderSection.begin(),
268 ExtUserHeaderSection.end());
269
270 data.at(sectionCountOffset) = 5;
271
272 // Require the size to be enough for all the above sections.
273 assert(size >= data.size());
274 assert(size <= 16384);
275
276 // Add a UserData section to get the size we need.
277 auto udSection = UserDataSection;
278 udSection.resize(size - data.size());
279
280 if (!udSection.empty())
281 {
282 // At least has to be 8B for the header
283 assert(udSection.size() >= 8);
284
285 // UD sections must be 4B aligned
286 assert(udSection.size() % 4 == 0);
287
288 // Set the new size in the section heder
289 Stream udStream{udSection};
290 udStream.offset(2);
291 udStream << static_cast<uint16_t>(udSection.size());
292
293 data.insert(data.end(), udSection.begin(), udSection.end());
294 data[sectionCountOffset]++;
295 }
296
297 assert(size == data.size());
298 return data;
299}
300
Matt Spinler6c9662c2019-10-09 11:27:20 -0500301std::vector<uint8_t> srcDataFactory(TestSRCType type)
302{
303 switch (type)
304 {
305 case TestSRCType::fruIdentityStructure:
306 return srcFRUIdentityCallout;
307
308 case TestSRCType::pceIdentityStructure:
309 return srcPCEIdentityCallout;
310
311 case TestSRCType::mruStructure:
312 return srcMRUCallout;
Matt Spinler32f13c92019-10-09 12:48:25 -0500313
314 case TestSRCType::calloutStructureA:
315 {
316 // Add just the FRU identity substructure to the base structure
317 std::vector<uint8_t> data{
318 0xFF, 0x28, 'H', 4, // size, flags, priority, LC length
319 'U', '4', '2', 0x00 // LC
320 };
321
322 data.insert(data.end(), srcFRUIdentityCallout.begin(),
323 srcFRUIdentityCallout.end());
324
325 // The final size
326 data[0] = data.size();
327 return data;
328 }
329 case TestSRCType::calloutStructureB:
330 {
331 // Add all 3 substructures to the base structure
332
333 std::vector<uint8_t> data{
334 0xFF, 0x2F, 'L', 8, // size, flags, priority, LC length
335 'U', '1', '2', '-', 'P', '1', 0x00, 0x00 // LC
336 };
337 data.insert(data.end(), srcFRUIdentityCallout.begin(),
338 srcFRUIdentityCallout.end());
339 data.insert(data.end(), srcPCEIdentityCallout.begin(),
340 srcPCEIdentityCallout.end());
341 data.insert(data.end(), srcMRUCallout.begin(), srcMRUCallout.end());
342
343 // The final size
344 data[0] = data.size();
345 return data;
346 }
Matt Spinlerf9bae182019-10-09 13:37:38 -0500347 case TestSRCType::calloutSection2Callouts:
348 {
349 std::vector<uint8_t> data{0xC0, 0x00, 0x00,
350 0x00}; // ID, flags, length in words
351
352 // Add 2 callouts
353 auto callout = srcDataFactory(TestSRCType::calloutStructureA);
354 data.insert(data.end(), callout.begin(), callout.end());
355
356 callout = srcDataFactory(TestSRCType::calloutStructureB);
357 data.insert(data.end(), callout.begin(), callout.end());
358
359 // Set the actual word length value at offset 2
360 Stream stream{data};
361 uint16_t wordLength = data.size() / 4;
362 stream.offset(2);
363 stream << wordLength;
364 stream.offset(0);
365
366 return data;
367 }
Matt Spinler6c9662c2019-10-09 11:27:20 -0500368 }
369 return {};
370}
371
Matt Spinlerd3335df2019-07-10 11:04:21 -0500372std::unique_ptr<std::vector<uint8_t>> readPELFile(const fs::path& path)
373{
374 std::ifstream file{path};
375
376 auto pel = std::make_unique<std::vector<uint8_t>>(
377 std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
378 return pel;
379}