blob: 625ca9135b6a40cb1f51b01d53859c9ca4db45be [file] [log] [blame]
Peter Foley21a1b5f2023-10-31 17:42:04 -04001/*
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)
23struct 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
36bool 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 // The MSB in the second byte of the MultiRecord header signals
60 // "End of list"
61 endOfList = fru[lastRecordStart + 1] & 0x80;
62 // Third byte in the MultiRecord header is the length
63 areaLength = fru[lastRecordStart + 2];
64 // This length is in bytes (not 8 bytes like other headers)
65 areaLength += 5; // The length omits the 5 byte header
66 if (!endOfList)
67 {
68 // Next MultiRecord header
69 lastRecordStart += areaLength;
70 }
71 }
72 }
73 else
74 {
75 // This FRU does not have a MultiRecord Area
76 // Get the length of the area in multiples of 8 bytes
77 if (lastWriteAddr > (lastRecordStart + 1))
78 {
79 // second byte in record area is the length
80 areaLength = fru[lastRecordStart + 1];
81 areaLength *= 8; // it is in multiples of 8 bytes
82 }
83 }
84 if (lastWriteAddr >= (areaLength + lastRecordStart))
85 {
86 atEnd = true;
87 }
88 }
89
90 return atEnd;
91}