xref: /openbmc/phosphor-logging/test/openpower-pels/pel_utils.cpp (revision 40fb54935ce7367636a7156039396ee91cc4d5e2)
1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright 2019 IBM Corporation
3 
4 #include "pel_utils.hpp"
5 
6 #include "extensions/openpower-pels/private_header.hpp"
7 #include "extensions/openpower-pels/user_header.hpp"
8 
9 #include <fstream>
10 
11 #include <gtest/gtest.h>
12 
13 namespace fs = std::filesystem;
14 using namespace openpower::pels;
15 
16 std::filesystem::path CleanLogID::pelIDFile{};
17 std::filesystem::path CleanPELFiles::pelIDFile{};
18 std::filesystem::path CleanPELFiles::repoPath{};
19 std::filesystem::path CleanPELFiles::registryPath{};
20 
21 const std::vector<uint8_t> privateHeaderSection{
22     // section header
23     0x50, 0x48,                                     // ID 'PH'
24     0x00, 0x30,                                     // Size
25     0x01, 0x02,                                     // version, subtype
26     0x03, 0x04,                                     // comp ID
27 
28     0x20, 0x30, 0x05, 0x09, 0x11, 0x1E, 0x1,  0x63, // create timestamp
29     0x20, 0x31, 0x06, 0x0F, 0x09, 0x22, 0x3A, 0x00, // commit timestamp
30     0x4F,                                           // creatorID 'O'
31     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
37     0x80, 0x81, 0x82, 0x83};                        // PEL ID
38 
39 const std::vector<uint8_t> userHeaderSection{
40     // section header
41     0x55, 0x48,             // ID 'UH'
42     0x00, 0x18,             // Size
43     0x01, 0x0A,             // version, subtype
44     0x0B, 0x0C,             // comp ID
45 
46     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
52 };
53 
54 const std::vector<uint8_t> srcSectionNoCallouts{
55 
56     // Header
57     'P', 'S', 0x00, 0x50, 0x01, 0x01, 0x02, 0x02,
58 
59     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
64     0x02, 0x02, 0x02, 0x55, 0x03, 0x03, 0x03, 0x10, 0x04, 0x04, 0x04, 0x04,
65     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 
72 const std::vector<uint8_t> failingMTMSSection{
73     // 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 
79 const std::vector<uint8_t> UserDataSection{
80     // Header
81     0x55, 0x44, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00,
82 
83     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
84 
85 const 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 
109 const 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 
116 const 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 
123 const 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 
136 const 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 
144 constexpr size_t sectionCountOffset = 27;
145 constexpr size_t createTimestampPHOffset = 8;
146 constexpr size_t commitTimestampPHOffset = 16;
147 constexpr size_t creatorPHOffset = 24;
148 constexpr size_t obmcIDPHOffset = 28;
149 constexpr size_t plidPHOffset = 40;
150 constexpr size_t pelIDPHOffset = 44;
151 constexpr size_t sevUHOffset = 10;
152 constexpr size_t actionFlagsUHOffset = 18;
153 
pelDataFactory(TestPELType type)154 std::vector<uint8_t> pelDataFactory(TestPELType type)
155 {
156     std::vector<uint8_t> data;
157 
158     switch (type)
159     {
160         case TestPELType::pelSimple:
161             data.insert(data.end(), privateHeaderSection.begin(),
162                         privateHeaderSection.end());
163             data.insert(data.end(), userHeaderSection.begin(),
164                         userHeaderSection.end());
165             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());
171             data.insert(data.end(), ExtUserHeaderSection.begin(),
172                         ExtUserHeaderSection.end());
173             data.insert(data.end(), extendedUserDataSection.begin(),
174                         extendedUserDataSection.end());
175             data.at(sectionCountOffset) = 7;
176             break;
177         case TestPELType::privateHeaderSection:
178             data.insert(data.end(), privateHeaderSection.begin(),
179                         privateHeaderSection.end());
180             break;
181         case TestPELType::userHeaderSection:
182             data.insert(data.end(), userHeaderSection.begin(),
183                         userHeaderSection.end());
184             break;
185         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         }
218         case TestPELType::failingMTMSSection:
219             data.insert(data.end(), failingMTMSSection.begin(),
220                         failingMTMSSection.end());
221             break;
222         case TestPELType::extendedUserDataSection:
223             data.insert(data.end(), extendedUserDataSection.begin(),
224                         extendedUserDataSection.end());
225             break;
226     }
227     return data;
228 }
229 
pelFactory(uint32_t id,char creatorID,uint8_t severity,uint16_t actionFlags,size_t size)230 std::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
266     auto src = pelDataFactory(TestPELType::primarySRCSection2Callouts);
267 
268     data.insert(data.end(), src.begin(), src.end());
269     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 
srcDataFactory(TestSRCType type)305 std::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;
317 
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         }
351         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         }
372     }
373     return {};
374 }
375 
readPELFile(const fs::path & path)376 std::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 }
384