xref: /openbmc/intel-ipmi-oem/src/fruutils.cpp (revision 0f1397f024ffd88ccd0a33e21ed5faa9e6182873)
1 /*
2 // Copyright (c) 2022-2023 Intel 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 */
16 
17 #include "fruutils.hpp"
18 
19 #include <algorithm>
20 #include <vector>
21 
22 #pragma pack(push, 1)
23 struct FRUHeader
24 {
25     uint8_t commonHeaderFormat;
26     uint8_t internalOffset;
27     uint8_t chassisOffset;
28     uint8_t boardOffset;
29     uint8_t productOffset;
30     uint8_t multiRecordOffset;
31     uint8_t pad;
32     uint8_t checksum;
33 };
34 #pragma pack(pop)
35 
validateBasicFruContent(const std::vector<uint8_t> & fru,size_t lastWriteAddr)36 bool validateBasicFruContent(const std::vector<uint8_t>& fru,
37                              size_t lastWriteAddr)
38 {
39     bool atEnd = false;
40 
41     if (fru.size() >= sizeof(FRUHeader))
42     {
43         const FRUHeader* header =
44             reinterpret_cast<const FRUHeader*>(fru.data());
45 
46         int areaLength = 0;
47         size_t lastRecordStart = std::max(
48             {header->internalOffset, header->chassisOffset, header->boardOffset,
49              header->productOffset, header->multiRecordOffset});
50         lastRecordStart *= 8; // header starts in are multiples of 8 bytes
51 
52         if (header->multiRecordOffset)
53         {
54             // This FRU has a MultiRecord Area
55             uint8_t endOfList = 0;
56             // Walk the MultiRecord headers until the last record
57             while (!endOfList)
58             {
59                 // Multi-Record Area Header size is of 5 bytes that keeps
60                 // information about the current record information. It also
61                 // contains offset information needed to find any additional
62                 // following records. So, All 5 bytes of Record Header should
63                 // not contain garbage values. Also, below check ensures that
64                 // the header is within the FRU size limits.
65                 if (lastRecordStart + 4 >= fru.size())
66                 {
67                     break;
68                 }
69                 // The MSB in the second byte of the MultiRecord header signals
70                 // "End of list"
71                 endOfList = fru[lastRecordStart + 1] & 0x80;
72                 // Third byte in the MultiRecord header is the length
73                 areaLength = fru[lastRecordStart + 2];
74                 // This length is in bytes (not 8 bytes like other headers)
75                 areaLength += 5; // The length omits the 5 byte header
76                 if (!endOfList)
77                 {
78                     // Next MultiRecord header
79                     lastRecordStart += areaLength;
80                 }
81             }
82         }
83         else
84         {
85             // This FRU does not have a MultiRecord Area
86             // Get the length of the area in multiples of 8 bytes
87             if (lastWriteAddr > (lastRecordStart + 1))
88             {
89                 // second byte in record area is the length
90                 areaLength = fru[lastRecordStart + 1];
91                 areaLength *= 8; // it is in multiples of 8 bytes
92             }
93         }
94         if (lastWriteAddr >= (areaLength + lastRecordStart))
95         {
96             atEnd = true;
97         }
98     }
99 
100     return atEnd;
101 }
102