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 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 // 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 } 92