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