1 /*++ @file
2   A simple FV stack so the SEC can extract the SEC Core from an
3   FV.
4 
5 Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 
8 **/
9 
10 #include <PiPei.h>
11 
12 
13 #define GET_OCCUPIED_SIZE(ActualSize, Alignment) \
14   (ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1))
15 
16 EFI_FFS_FILE_STATE
GetFileState(IN UINT8 ErasePolarity,IN EFI_FFS_FILE_HEADER * FfsHeader)17 GetFileState (
18   IN UINT8                ErasePolarity,
19   IN EFI_FFS_FILE_HEADER  *FfsHeader
20   )
21 /*++
22 
23 Routine Description:
24   Returns the highest bit set of the State field
25 
26 Arguments:
27   ErasePolarity   - Erase Polarity  as defined by EFI_FVB2_ERASE_POLARITY
28                     in the Attributes field.
29   FfsHeader       - Pointer to FFS File Header.
30 
31 Returns:
32   Returns the highest bit in the State field
33 
34 **/
35 {
36   EFI_FFS_FILE_STATE  FileState;
37   EFI_FFS_FILE_STATE  HighestBit;
38 
39   FileState = FfsHeader->State;
40 
41   if (ErasePolarity != 0) {
42     FileState = (EFI_FFS_FILE_STATE)~FileState;
43   }
44 
45   HighestBit = 0x80;
46   while (HighestBit != 0 && (HighestBit & FileState) == 0) {
47     HighestBit >>= 1;
48   }
49 
50   return HighestBit;
51 }
52 
53 UINT8
CalculateHeaderChecksum(IN EFI_FFS_FILE_HEADER * FileHeader)54 CalculateHeaderChecksum (
55   IN EFI_FFS_FILE_HEADER  *FileHeader
56   )
57 /*++
58 
59 Routine Description:
60   Calculates the checksum of the header of a file.
61 
62 Arguments:
63   FileHeader       - Pointer to FFS File Header.
64 
65 Returns:
66   Checksum of the header.
67 
68 **/
69 {
70   UINT8 *ptr;
71   UINTN Index;
72   UINT8 Sum;
73 
74   Sum = 0;
75   ptr = (UINT8 *) FileHeader;
76 
77   for (Index = 0; Index < sizeof (EFI_FFS_FILE_HEADER) - 3; Index += 4) {
78     Sum = (UINT8) (Sum + ptr[Index]);
79     Sum = (UINT8) (Sum + ptr[Index + 1]);
80     Sum = (UINT8) (Sum + ptr[Index + 2]);
81     Sum = (UINT8) (Sum + ptr[Index + 3]);
82   }
83 
84   for (; Index < sizeof (EFI_FFS_FILE_HEADER); Index++) {
85     Sum = (UINT8) (Sum + ptr[Index]);
86   }
87   //
88   // State field (since this indicates the different state of file).
89   //
90   Sum = (UINT8) (Sum - FileHeader->State);
91   //
92   // Checksum field of the file is not part of the header checksum.
93   //
94   Sum = (UINT8) (Sum - FileHeader->IntegrityCheck.Checksum.File);
95 
96   return Sum;
97 }
98 
99 EFI_STATUS
SecFfsFindNextFile(IN EFI_FV_FILETYPE SearchType,IN EFI_PEI_FV_HANDLE FvHandle,IN OUT EFI_PEI_FILE_HANDLE * FileHandle)100 SecFfsFindNextFile (
101   IN EFI_FV_FILETYPE             SearchType,
102   IN EFI_PEI_FV_HANDLE           FvHandle,
103   IN OUT EFI_PEI_FILE_HANDLE     *FileHandle
104   )
105 /*++
106 
107 Routine Description:
108     Given the input file pointer, search for the next matching file in the
109     FFS volume as defined by SearchType. The search starts from FileHeader inside
110     the Firmware Volume defined by FwVolHeader.
111 
112 Arguments:
113     SearchType - Filter to find only files of this type.
114                  Type EFI_FV_FILETYPE_ALL causes no filtering to be done.
115     FwVolHeader - Pointer to the FV header of the volume to search.
116                   This parameter must point to a valid FFS volume.
117     FileHeader  - Pointer to the current file from which to begin searching.
118                   This pointer will be updated upon return to reflect the file
119                   found.
120 
121 Returns:
122     EFI_NOT_FOUND - No files matching the search criteria were found
123     EFI_SUCCESS
124 
125 **/
126 {
127   EFI_FFS_FILE_HEADER *FfsFileHeader;
128   UINT32              FileLength;
129   UINT32              FileOccupiedSize;
130   UINT32              FileOffset;
131   UINT64              FvLength;
132   UINT8               ErasePolarity;
133   UINT8               FileState;
134   EFI_FIRMWARE_VOLUME_HEADER  *FwVolHeader;
135   EFI_FFS_FILE_HEADER         **FileHeader;
136 
137   //
138   // Convert the handle of FV to FV header for memory-mapped firmware volume
139   //
140   FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FvHandle;
141   FileHeader  = (EFI_FFS_FILE_HEADER **)FileHandle;
142 
143   FvLength = FwVolHeader->FvLength;
144   if (FwVolHeader->Attributes & EFI_FVB2_ERASE_POLARITY) {
145     ErasePolarity = 1;
146   } else {
147     ErasePolarity = 0;
148   }
149   //
150   // If FileHeader is not specified (NULL) start with the first file in the
151   // firmware volume.  Otherwise, start from the FileHeader.
152   //
153   if (*FileHeader == NULL) {
154     FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FwVolHeader + FwVolHeader->HeaderLength);
155   } else {
156     //
157     // Length is 24 bits wide so mask upper 8 bits
158     // FileLength is adjusted to FileOccupiedSize as it is 8 byte aligned.
159     //
160     FileLength        = *(UINT32 *) (*FileHeader)->Size & 0x00FFFFFF;
161     FileOccupiedSize  = GET_OCCUPIED_SIZE (FileLength, 8);
162     FfsFileHeader     = (EFI_FFS_FILE_HEADER *) ((UINT8 *) *FileHeader + FileOccupiedSize);
163   }
164 
165   FileOffset = (UINT32) ((UINT8 *) FfsFileHeader - (UINT8 *) FwVolHeader);
166 
167   while (FileOffset < (FvLength - sizeof (EFI_FFS_FILE_HEADER))) {
168     //
169     // Get FileState which is the highest bit of the State
170     //
171     FileState = GetFileState (ErasePolarity, FfsFileHeader);
172 
173     switch (FileState) {
174 
175     case EFI_FILE_HEADER_INVALID:
176       FileOffset += sizeof (EFI_FFS_FILE_HEADER);
177       FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER));
178       break;
179 
180     case EFI_FILE_DATA_VALID:
181     case EFI_FILE_MARKED_FOR_UPDATE:
182       if (CalculateHeaderChecksum (FfsFileHeader) == 0) {
183         FileLength        = *(UINT32 *) (FfsFileHeader->Size) & 0x00FFFFFF;
184         FileOccupiedSize  = GET_OCCUPIED_SIZE (FileLength, 8);
185 
186         if ((SearchType == FfsFileHeader->Type) || (SearchType == EFI_FV_FILETYPE_ALL)) {
187 
188           *FileHeader = FfsFileHeader;
189 
190           return EFI_SUCCESS;
191         }
192 
193         FileOffset += FileOccupiedSize;
194         FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsFileHeader + FileOccupiedSize);
195       } else {
196         return EFI_NOT_FOUND;
197       }
198       break;
199 
200     case EFI_FILE_DELETED:
201       FileLength        = *(UINT32 *) (FfsFileHeader->Size) & 0x00FFFFFF;
202       FileOccupiedSize  = GET_OCCUPIED_SIZE (FileLength, 8);
203       FileOffset += FileOccupiedSize;
204       FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsFileHeader + FileOccupiedSize);
205       break;
206 
207     default:
208       return EFI_NOT_FOUND;
209 
210     }
211   }
212 
213   return EFI_NOT_FOUND;
214 }
215 
216 EFI_STATUS
SecFfsFindSectionData(IN EFI_SECTION_TYPE SectionType,IN EFI_FFS_FILE_HEADER * FfsFileHeader,IN OUT VOID ** SectionData)217 SecFfsFindSectionData (
218   IN EFI_SECTION_TYPE      SectionType,
219   IN EFI_FFS_FILE_HEADER   *FfsFileHeader,
220   IN OUT VOID              **SectionData
221   )
222 /*++
223 
224 Routine Description:
225     Given the input file pointer, search for the next matching section in the
226     FFS volume.
227 
228 Arguments:
229     SearchType    - Filter to find only sections of this type.
230     FfsFileHeader - Pointer to the current file to search.
231     SectionData   - Pointer to the Section matching SectionType in FfsFileHeader.
232                      NULL if section not found
233 
234 Returns:
235     EFI_NOT_FOUND - No files matching the search criteria were found
236     EFI_SUCCESS
237 
238 **/
239 {
240   UINT32                    FileSize;
241   EFI_COMMON_SECTION_HEADER *Section;
242   UINT32                    SectionLength;
243   UINT32                    ParsedLength;
244 
245   //
246   // Size is 24 bits wide so mask upper 8 bits.
247   //    Does not include FfsFileHeader header size
248   // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned.
249   //
250   Section   = (EFI_COMMON_SECTION_HEADER *) (FfsFileHeader + 1);
251   FileSize  = *(UINT32 *) (FfsFileHeader->Size) & 0x00FFFFFF;
252   FileSize -= sizeof (EFI_FFS_FILE_HEADER);
253 
254   *SectionData  = NULL;
255   ParsedLength  = 0;
256   while (ParsedLength < FileSize) {
257     if (Section->Type == SectionType) {
258       *SectionData = (VOID *) (Section + 1);
259       return EFI_SUCCESS;
260     }
261     //
262     // Size is 24 bits wide so mask upper 8 bits.
263     // SectionLength is adjusted it is 4 byte aligned.
264     // Go to the next section
265     //
266     SectionLength = *(UINT32 *) Section->Size & 0x00FFFFFF;
267     SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
268 
269     ParsedLength += SectionLength;
270     Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + SectionLength);
271   }
272 
273   return EFI_NOT_FOUND;
274 }
275 
276