]>
Commit | Line | Data |
---|---|---|
1e57a462 | 1 | /** @file\r |
2 | Implementation of the 6 PEI Ffs (FV) APIs in library form.\r | |
3402aac7 | 3 | \r |
1e57a462 | 4 | This code only knows about a FV if it has a EFI_HOB_TYPE_FV entry in the HOB list\r |
5 | \r | |
6 | Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r | |
3402aac7 | 7 | \r |
878b807a | 8 | SPDX-License-Identifier: BSD-2-Clause-Patent\r |
1e57a462 | 9 | \r |
10 | **/\r | |
11 | \r | |
12 | #include <PrePi.h>\r | |
13 | #include <Library/ExtractGuidedSectionLib.h>\r | |
14 | \r | |
1e57a462 | 15 | #define GET_OCCUPIED_SIZE(ActualSize, Alignment) \\r |
16 | (ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1))\r | |
17 | \r | |
1e57a462 | 18 | /**\r |
19 | Returns the highest bit set of the State field\r | |
3402aac7 | 20 | \r |
1e57a462 | 21 | @param ErasePolarity Erase Polarity as defined by EFI_FVB2_ERASE_POLARITY\r |
22 | in the Attributes field.\r | |
23 | @param FfsHeader Pointer to FFS File Header\r | |
3402aac7 | 24 | \r |
1e57a462 | 25 | \r |
26 | @retval the highest bit in the State field\r | |
27 | \r | |
28 | **/\r | |
29 | STATIC\r | |
30 | EFI_FFS_FILE_STATE\r | |
e7108d0e | 31 | GetFileState (\r |
1e57a462 | 32 | IN UINT8 ErasePolarity,\r |
33 | IN EFI_FFS_FILE_HEADER *FfsHeader\r | |
34 | )\r | |
35 | {\r | |
36 | EFI_FFS_FILE_STATE FileState;\r | |
37 | EFI_FFS_FILE_STATE HighestBit;\r | |
38 | \r | |
39 | FileState = FfsHeader->State;\r | |
40 | \r | |
41 | if (ErasePolarity != 0) {\r | |
e7108d0e | 42 | FileState = (EFI_FFS_FILE_STATE) ~FileState;\r |
1e57a462 | 43 | }\r |
44 | \r | |
45 | HighestBit = 0x80;\r | |
46 | while (HighestBit != 0 && (HighestBit & FileState) == 0) {\r | |
47 | HighestBit >>= 1;\r | |
48 | }\r | |
49 | \r | |
50 | return HighestBit;\r | |
3402aac7 | 51 | }\r |
1e57a462 | 52 | \r |
1e57a462 | 53 | /**\r |
54 | Calculates the checksum of the header of a file.\r | |
55 | The header is a zero byte checksum, so zero means header is good\r | |
3402aac7 | 56 | \r |
1e57a462 | 57 | @param FfsHeader Pointer to FFS File Header\r |
3402aac7 | 58 | \r |
1e57a462 | 59 | @retval Checksum of the header\r |
60 | \r | |
61 | **/\r | |
62 | STATIC\r | |
63 | UINT8\r | |
64 | CalculateHeaderChecksum (\r | |
65 | IN EFI_FFS_FILE_HEADER *FileHeader\r | |
66 | )\r | |
67 | {\r | |
e7108d0e MK |
68 | UINT8 *Ptr;\r |
69 | UINTN Index;\r | |
70 | UINT8 Sum;\r | |
3402aac7 | 71 | \r |
1e57a462 | 72 | Sum = 0;\r |
73 | Ptr = (UINT8 *)FileHeader;\r | |
74 | \r | |
e7108d0e | 75 | for (Index = 0; Index < sizeof (EFI_FFS_FILE_HEADER) - 3; Index += 4) {\r |
1e57a462 | 76 | Sum = (UINT8)(Sum + Ptr[Index]);\r |
77 | Sum = (UINT8)(Sum + Ptr[Index+1]);\r | |
78 | Sum = (UINT8)(Sum + Ptr[Index+2]);\r | |
79 | Sum = (UINT8)(Sum + Ptr[Index+3]);\r | |
80 | }\r | |
81 | \r | |
e7108d0e | 82 | for ( ; Index < sizeof (EFI_FFS_FILE_HEADER); Index++) {\r |
1e57a462 | 83 | Sum = (UINT8)(Sum + Ptr[Index]);\r |
84 | }\r | |
3402aac7 | 85 | \r |
1e57a462 | 86 | //\r |
3402aac7 | 87 | // State field (since this indicates the different state of file).\r |
1e57a462 | 88 | //\r |
89 | Sum = (UINT8)(Sum - FileHeader->State);\r | |
90 | //\r | |
91 | // Checksum field of the file is not part of the header checksum.\r | |
92 | //\r | |
93 | Sum = (UINT8)(Sum - FileHeader->IntegrityCheck.Checksum.File);\r | |
94 | \r | |
95 | return Sum;\r | |
96 | }\r | |
97 | \r | |
1e57a462 | 98 | /**\r |
99 | Given a FileHandle return the VolumeHandle\r | |
3402aac7 | 100 | \r |
1e57a462 | 101 | @param FileHandle File handle to look up\r |
102 | @param VolumeHandle Match for FileHandle\r | |
3402aac7 | 103 | \r |
1e57a462 | 104 | @retval TRUE VolumeHandle is valid\r |
105 | \r | |
106 | **/\r | |
107 | STATIC\r | |
108 | BOOLEAN\r | |
109 | EFIAPI\r | |
110 | FileHandleToVolume (\r | |
e7108d0e MK |
111 | IN EFI_PEI_FILE_HANDLE FileHandle,\r |
112 | OUT EFI_PEI_FV_HANDLE *VolumeHandle\r | |
1e57a462 | 113 | )\r |
114 | {\r | |
115 | EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r | |
116 | EFI_PEI_HOB_POINTERS Hob;\r | |
117 | \r | |
118 | Hob.Raw = GetHobList ();\r | |
119 | if (Hob.Raw == NULL) {\r | |
120 | return FALSE;\r | |
121 | }\r | |
3402aac7 | 122 | \r |
1e57a462 | 123 | do {\r |
124 | Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw);\r | |
125 | if (Hob.Raw != NULL) {\r | |
126 | FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(Hob.FirmwareVolume->BaseAddress);\r | |
e7108d0e MK |
127 | if (((UINT64)(UINTN)FileHandle > (UINT64)(UINTN)FwVolHeader) && \\r |
128 | ((UINT64)(UINTN)FileHandle <= ((UINT64)(UINTN)FwVolHeader + FwVolHeader->FvLength - 1)))\r | |
129 | {\r | |
1e57a462 | 130 | *VolumeHandle = (EFI_PEI_FV_HANDLE)FwVolHeader;\r |
131 | return TRUE;\r | |
132 | }\r | |
133 | \r | |
134 | Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, GET_NEXT_HOB (Hob));\r | |
135 | }\r | |
136 | } while (Hob.Raw != NULL);\r | |
3402aac7 | 137 | \r |
1e57a462 | 138 | return FALSE;\r |
139 | }\r | |
140 | \r | |
1e57a462 | 141 | /**\r |
142 | Given the input file pointer, search for the next matching file in the\r | |
143 | FFS volume as defined by SearchType. The search starts from FileHeader inside\r | |
144 | the Firmware Volume defined by FwVolHeader.\r | |
3402aac7 | 145 | \r |
1e57a462 | 146 | @param FileHandle File handle to look up\r |
147 | @param VolumeHandle Match for FileHandle\r | |
3402aac7 | 148 | \r |
1e57a462 | 149 | \r |
150 | **/\r | |
151 | EFI_STATUS\r | |
152 | FindFileEx (\r | |
e7108d0e MK |
153 | IN CONST EFI_PEI_FV_HANDLE FvHandle,\r |
154 | IN CONST EFI_GUID *FileName OPTIONAL,\r | |
155 | IN EFI_FV_FILETYPE SearchType,\r | |
156 | IN OUT EFI_PEI_FILE_HANDLE *FileHandle\r | |
1e57a462 | 157 | )\r |
158 | {\r | |
e7108d0e MK |
159 | EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r |
160 | EFI_FFS_FILE_HEADER **FileHeader;\r | |
161 | EFI_FFS_FILE_HEADER *FfsFileHeader;\r | |
162 | EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo;\r | |
163 | UINT32 FileLength;\r | |
164 | UINT32 FileOccupiedSize;\r | |
165 | UINT32 FileOffset;\r | |
166 | UINT64 FvLength;\r | |
167 | UINT8 ErasePolarity;\r | |
168 | UINT8 FileState;\r | |
1e57a462 | 169 | \r |
170 | FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FvHandle;\r | |
171 | FileHeader = (EFI_FFS_FILE_HEADER **)FileHandle;\r | |
172 | \r | |
173 | FvLength = FwVolHeader->FvLength;\r | |
174 | if (FwVolHeader->Attributes & EFI_FVB2_ERASE_POLARITY) {\r | |
175 | ErasePolarity = 1;\r | |
176 | } else {\r | |
177 | ErasePolarity = 0;\r | |
178 | }\r | |
179 | \r | |
180 | //\r | |
181 | // If FileHeader is not specified (NULL) or FileName is not NULL,\r | |
182 | // start with the first file in the firmware volume. Otherwise,\r | |
183 | // start from the FileHeader.\r | |
184 | //\r | |
185 | if ((*FileHeader == NULL) || (FileName != NULL)) {\r | |
186 | FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FwVolHeader + FwVolHeader->HeaderLength);\r | |
187 | if (FwVolHeader->ExtHeaderOffset != 0) {\r | |
188 | FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)(((UINT8 *)FwVolHeader) + FwVolHeader->ExtHeaderOffset);\r | |
e7108d0e | 189 | FfsFileHeader = (EFI_FFS_FILE_HEADER *)(((UINT8 *)FwVolExHeaderInfo) + FwVolExHeaderInfo->ExtHeaderSize);\r |
1e57a462 | 190 | }\r |
191 | } else {\r | |
192 | //\r | |
193 | // Length is 24 bits wide so mask upper 8 bits\r | |
194 | // FileLength is adjusted to FileOccupiedSize as it is 8 byte aligned.\r | |
195 | //\r | |
e7108d0e | 196 | FileLength = *(UINT32 *)(*FileHeader)->Size & 0x00FFFFFF;\r |
1e57a462 | 197 | FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);\r |
e7108d0e | 198 | FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)*FileHeader + FileOccupiedSize);\r |
1e57a462 | 199 | }\r |
3402aac7 | 200 | \r |
5a44a766 OM |
201 | // FFS files begin with a header that is aligned on an 8-byte boundary\r |
202 | FfsFileHeader = ALIGN_POINTER (FfsFileHeader, 8);\r | |
203 | \r | |
e7108d0e | 204 | FileOffset = (UINT32)((UINT8 *)FfsFileHeader - (UINT8 *)FwVolHeader);\r |
1e57a462 | 205 | ASSERT (FileOffset <= 0xFFFFFFFF);\r |
206 | \r | |
207 | while (FileOffset < (FvLength - sizeof (EFI_FFS_FILE_HEADER))) {\r | |
208 | //\r | |
3402aac7 | 209 | // Get FileState which is the highest bit of the State\r |
1e57a462 | 210 | //\r |
211 | FileState = GetFileState (ErasePolarity, FfsFileHeader);\r | |
212 | \r | |
213 | switch (FileState) {\r | |
e7108d0e MK |
214 | case EFI_FILE_HEADER_INVALID:\r |
215 | FileOffset += sizeof (EFI_FFS_FILE_HEADER);\r | |
216 | FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER));\r | |
217 | break;\r | |
218 | \r | |
219 | case EFI_FILE_DATA_VALID:\r | |
220 | case EFI_FILE_MARKED_FOR_UPDATE:\r | |
221 | if (CalculateHeaderChecksum (FfsFileHeader) != 0) {\r | |
222 | ASSERT (FALSE);\r | |
223 | *FileHeader = NULL;\r | |
224 | return EFI_NOT_FOUND;\r | |
225 | }\r | |
1e57a462 | 226 | \r |
e7108d0e MK |
227 | FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;\r |
228 | FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);\r | |
1e57a462 | 229 | \r |
e7108d0e MK |
230 | if (FileName != NULL) {\r |
231 | if (CompareGuid (&FfsFileHeader->Name, (EFI_GUID *)FileName)) {\r | |
232 | *FileHeader = FfsFileHeader;\r | |
233 | return EFI_SUCCESS;\r | |
234 | }\r | |
235 | } else if (((SearchType == FfsFileHeader->Type) || (SearchType == EFI_FV_FILETYPE_ALL)) &&\r | |
236 | (FfsFileHeader->Type != EFI_FV_FILETYPE_FFS_PAD))\r | |
237 | {\r | |
1e57a462 | 238 | *FileHeader = FfsFileHeader;\r |
239 | return EFI_SUCCESS;\r | |
240 | }\r | |
1e57a462 | 241 | \r |
e7108d0e MK |
242 | FileOffset += FileOccupiedSize;\r |
243 | FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize);\r | |
244 | break;\r | |
3402aac7 | 245 | \r |
e7108d0e MK |
246 | case EFI_FILE_DELETED:\r |
247 | FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;\r | |
248 | FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);\r | |
249 | FileOffset += FileOccupiedSize;\r | |
250 | FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize);\r | |
251 | break;\r | |
1e57a462 | 252 | \r |
e7108d0e MK |
253 | default:\r |
254 | *FileHeader = NULL;\r | |
255 | return EFI_NOT_FOUND;\r | |
3402aac7 | 256 | }\r |
1e57a462 | 257 | }\r |
258 | \r | |
1e57a462 | 259 | *FileHeader = NULL;\r |
3402aac7 | 260 | return EFI_NOT_FOUND;\r |
1e57a462 | 261 | }\r |
262 | \r | |
1e57a462 | 263 | /**\r |
264 | Go through the file to search SectionType section,\r | |
3402aac7 RC |
265 | when meeting an encapsuled section.\r |
266 | \r | |
1e57a462 | 267 | @param SectionType - Filter to find only section of this type.\r |
268 | @param Section - From where to search.\r | |
269 | @param SectionSize - The file size to search.\r | |
270 | @param OutputBuffer - Pointer to the section to search.\r | |
3402aac7 | 271 | \r |
1e57a462 | 272 | @retval EFI_SUCCESS\r |
273 | **/\r | |
274 | EFI_STATUS\r | |
275 | FfsProcessSection (\r | |
276 | IN EFI_SECTION_TYPE SectionType,\r | |
277 | IN EFI_COMMON_SECTION_HEADER *Section,\r | |
278 | IN UINTN SectionSize,\r | |
279 | OUT VOID **OutputBuffer\r | |
280 | )\r | |
281 | {\r | |
e7108d0e MK |
282 | EFI_STATUS Status;\r |
283 | UINT32 SectionLength;\r | |
284 | UINT32 ParsedLength;\r | |
285 | EFI_COMPRESSION_SECTION *CompressionSection;\r | |
286 | EFI_COMPRESSION_SECTION2 *CompressionSection2;\r | |
287 | UINT32 DstBufferSize;\r | |
288 | VOID *ScratchBuffer;\r | |
289 | UINT32 ScratchBufferSize;\r | |
290 | VOID *DstBuffer;\r | |
291 | UINT16 SectionAttribute;\r | |
292 | UINT32 AuthenticationStatus;\r | |
293 | CHAR8 *CompressedData;\r | |
294 | UINTN CompressedDataLength;\r | |
1e57a462 | 295 | \r |
296 | *OutputBuffer = NULL;\r | |
297 | ParsedLength = 0;\r | |
298 | Status = EFI_NOT_FOUND;\r | |
299 | while (ParsedLength < SectionSize) {\r | |
4efc8a40 MZ |
300 | if (IS_SECTION2 (Section)) {\r |
301 | ASSERT (SECTION2_SIZE (Section) > 0x00FFFFFF);\r | |
302 | }\r | |
303 | \r | |
1e57a462 | 304 | if (Section->Type == SectionType) {\r |
4efc8a40 | 305 | if (IS_SECTION2 (Section)) {\r |
e7108d0e | 306 | *OutputBuffer = (VOID *)((UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER2));\r |
4efc8a40 | 307 | } else {\r |
e7108d0e | 308 | *OutputBuffer = (VOID *)((UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER));\r |
4efc8a40 | 309 | }\r |
1e57a462 | 310 | \r |
311 | return EFI_SUCCESS;\r | |
312 | } else if ((Section->Type == EFI_SECTION_COMPRESSION) || (Section->Type == EFI_SECTION_GUID_DEFINED)) {\r | |
1e57a462 | 313 | if (Section->Type == EFI_SECTION_COMPRESSION) {\r |
4efc8a40 | 314 | if (IS_SECTION2 (Section)) {\r |
e7108d0e | 315 | CompressionSection2 = (EFI_COMPRESSION_SECTION2 *)Section;\r |
4efc8a40 MZ |
316 | SectionLength = SECTION2_SIZE (Section);\r |
317 | \r | |
318 | if (CompressionSection2->CompressionType != EFI_STANDARD_COMPRESSION) {\r | |
319 | return EFI_UNSUPPORTED;\r | |
320 | }\r | |
321 | \r | |
e7108d0e MK |
322 | CompressedData = (CHAR8 *)((EFI_COMPRESSION_SECTION2 *)Section + 1);\r |
323 | CompressedDataLength = (UINT32)SectionLength - sizeof (EFI_COMPRESSION_SECTION2);\r | |
4efc8a40 | 324 | } else {\r |
e7108d0e MK |
325 | CompressionSection = (EFI_COMPRESSION_SECTION *)Section;\r |
326 | SectionLength = SECTION_SIZE (Section);\r | |
4efc8a40 MZ |
327 | \r |
328 | if (CompressionSection->CompressionType != EFI_STANDARD_COMPRESSION) {\r | |
329 | return EFI_UNSUPPORTED;\r | |
330 | }\r | |
331 | \r | |
e7108d0e MK |
332 | CompressedData = (CHAR8 *)((EFI_COMPRESSION_SECTION *)Section + 1);\r |
333 | CompressedDataLength = (UINT32)SectionLength - sizeof (EFI_COMPRESSION_SECTION);\r | |
1e57a462 | 334 | }\r |
335 | \r | |
336 | Status = UefiDecompressGetInfo (\r | |
4efc8a40 MZ |
337 | CompressedData,\r |
338 | CompressedDataLength,\r | |
c1cdcab9 | 339 | &DstBufferSize,\r |
1e57a462 | 340 | &ScratchBufferSize\r |
341 | );\r | |
342 | } else if (Section->Type == EFI_SECTION_GUID_DEFINED) {\r | |
343 | Status = ExtractGuidedSectionGetInfo (\r | |
344 | Section,\r | |
c1cdcab9 | 345 | &DstBufferSize,\r |
1e57a462 | 346 | &ScratchBufferSize,\r |
347 | &SectionAttribute\r | |
348 | );\r | |
349 | }\r | |
3402aac7 | 350 | \r |
1e57a462 | 351 | if (EFI_ERROR (Status)) {\r |
352 | //\r | |
353 | // GetInfo failed\r | |
354 | //\r | |
a1878955 | 355 | DEBUG ((DEBUG_ERROR, "Decompress GetInfo Failed - %r\n", Status));\r |
1e57a462 | 356 | return EFI_NOT_FOUND;\r |
357 | }\r | |
e7108d0e | 358 | \r |
1e57a462 | 359 | //\r |
360 | // Allocate scratch buffer\r | |
361 | //\r | |
362 | ScratchBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));\r | |
363 | if (ScratchBuffer == NULL) {\r | |
364 | return EFI_OUT_OF_RESOURCES;\r | |
365 | }\r | |
e7108d0e | 366 | \r |
1e57a462 | 367 | //\r |
3402aac7 | 368 | // Allocate destination buffer, extra one page for adjustment\r |
1e57a462 | 369 | //\r |
370 | DstBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1);\r | |
371 | if (DstBuffer == NULL) {\r | |
372 | return EFI_OUT_OF_RESOURCES;\r | |
373 | }\r | |
e7108d0e | 374 | \r |
1e57a462 | 375 | //\r |
376 | // DstBuffer still is one section. Adjust DstBuffer offset, skip EFI section header\r | |
377 | // to make section data at page alignment.\r | |
378 | //\r | |
e7108d0e | 379 | if (IS_SECTION2 (Section)) {\r |
4efc8a40 | 380 | DstBuffer = (UINT8 *)DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER2);\r |
e7108d0e | 381 | } else {\r |
4efc8a40 | 382 | DstBuffer = (UINT8 *)DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER);\r |
e7108d0e MK |
383 | }\r |
384 | \r | |
1e57a462 | 385 | //\r |
386 | // Call decompress function\r | |
387 | //\r | |
388 | if (Section->Type == EFI_SECTION_COMPRESSION) {\r | |
4efc8a40 | 389 | if (IS_SECTION2 (Section)) {\r |
e7108d0e MK |
390 | CompressedData = (CHAR8 *)((EFI_COMPRESSION_SECTION2 *)Section + 1);\r |
391 | } else {\r | |
392 | CompressedData = (CHAR8 *)((EFI_COMPRESSION_SECTION *)Section + 1);\r | |
4efc8a40 MZ |
393 | }\r |
394 | \r | |
1e57a462 | 395 | Status = UefiDecompress (\r |
e7108d0e MK |
396 | CompressedData,\r |
397 | DstBuffer,\r | |
398 | ScratchBuffer\r | |
399 | );\r | |
1e57a462 | 400 | } else if (Section->Type == EFI_SECTION_GUID_DEFINED) {\r |
401 | Status = ExtractGuidedSectionDecode (\r | |
e7108d0e MK |
402 | Section,\r |
403 | &DstBuffer,\r | |
404 | ScratchBuffer,\r | |
405 | &AuthenticationStatus\r | |
406 | );\r | |
1e57a462 | 407 | }\r |
3402aac7 | 408 | \r |
1e57a462 | 409 | if (EFI_ERROR (Status)) {\r |
410 | //\r | |
411 | // Decompress failed\r | |
412 | //\r | |
a1878955 | 413 | DEBUG ((DEBUG_ERROR, "Decompress Failed - %r\n", Status));\r |
1e57a462 | 414 | return EFI_NOT_FOUND;\r |
415 | } else {\r | |
416 | return FfsProcessSection (\r | |
e7108d0e MK |
417 | SectionType,\r |
418 | DstBuffer,\r | |
419 | DstBufferSize,\r | |
420 | OutputBuffer\r | |
421 | );\r | |
422 | }\r | |
1e57a462 | 423 | }\r |
424 | \r | |
4efc8a40 MZ |
425 | if (IS_SECTION2 (Section)) {\r |
426 | SectionLength = SECTION2_SIZE (Section);\r | |
427 | } else {\r | |
428 | SectionLength = SECTION_SIZE (Section);\r | |
429 | }\r | |
e7108d0e | 430 | \r |
1e57a462 | 431 | //\r |
1e57a462 | 432 | // SectionLength is adjusted it is 4 byte aligned.\r |
433 | // Go to the next section\r | |
434 | //\r | |
1e57a462 | 435 | SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);\r |
436 | ASSERT (SectionLength != 0);\r | |
437 | ParsedLength += SectionLength;\r | |
e7108d0e | 438 | Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength);\r |
1e57a462 | 439 | }\r |
3402aac7 | 440 | \r |
1e57a462 | 441 | return EFI_NOT_FOUND;\r |
442 | }\r | |
443 | \r | |
1e57a462 | 444 | /**\r |
445 | This service enables discovery sections of a given type within a valid FFS file.\r | |
446 | \r | |
447 | @param SearchType The value of the section type to find.\r | |
448 | @param FfsFileHeader A pointer to the file header that contains the set of sections to\r | |
449 | be searched.\r | |
450 | @param SectionData A pointer to the discovered section, if successful.\r | |
451 | \r | |
452 | @retval EFI_SUCCESS The section was found.\r | |
453 | @retval EFI_NOT_FOUND The section was not found.\r | |
454 | \r | |
455 | **/\r | |
456 | EFI_STATUS\r | |
457 | EFIAPI\r | |
458 | FfsFindSectionData (\r | |
e7108d0e MK |
459 | IN EFI_SECTION_TYPE SectionType,\r |
460 | IN EFI_PEI_FILE_HANDLE FileHandle,\r | |
461 | OUT VOID **SectionData\r | |
1e57a462 | 462 | )\r |
463 | {\r | |
e7108d0e MK |
464 | EFI_FFS_FILE_HEADER *FfsFileHeader;\r |
465 | UINT32 FileSize;\r | |
466 | EFI_COMMON_SECTION_HEADER *Section;\r | |
1e57a462 | 467 | \r |
468 | FfsFileHeader = (EFI_FFS_FILE_HEADER *)(FileHandle);\r | |
469 | \r | |
470 | //\r | |
3402aac7 | 471 | // Size is 24 bits wide so mask upper 8 bits.\r |
1e57a462 | 472 | // Does not include FfsFileHeader header size\r |
473 | // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned.\r | |
474 | //\r | |
e7108d0e MK |
475 | Section = (EFI_COMMON_SECTION_HEADER *)(FfsFileHeader + 1);\r |
476 | FileSize = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;\r | |
1e57a462 | 477 | FileSize -= sizeof (EFI_FFS_FILE_HEADER);\r |
478 | \r | |
479 | return FfsProcessSection (\r | |
e7108d0e MK |
480 | SectionType,\r |
481 | Section,\r | |
482 | FileSize,\r | |
483 | SectionData\r | |
484 | );\r | |
1e57a462 | 485 | }\r |
486 | \r | |
1e57a462 | 487 | /**\r |
488 | This service enables discovery of additional firmware files.\r | |
489 | \r | |
490 | @param SearchType A filter to find files only of this type.\r | |
491 | @param FwVolHeader Pointer to the firmware volume header of the volume to search.\r | |
492 | This parameter must point to a valid FFS volume.\r | |
493 | @param FileHeader Pointer to the current file from which to begin searching.\r | |
494 | \r | |
495 | @retval EFI_SUCCESS The file was found.\r | |
496 | @retval EFI_NOT_FOUND The file was not found.\r | |
497 | @retval EFI_NOT_FOUND The header checksum was not zero.\r | |
498 | \r | |
499 | **/\r | |
500 | EFI_STATUS\r | |
501 | EFIAPI\r | |
502 | FfsFindNextFile (\r | |
e7108d0e MK |
503 | IN UINT8 SearchType,\r |
504 | IN EFI_PEI_FV_HANDLE VolumeHandle,\r | |
505 | IN OUT EFI_PEI_FILE_HANDLE *FileHandle\r | |
1e57a462 | 506 | )\r |
507 | {\r | |
508 | return FindFileEx (VolumeHandle, NULL, SearchType, FileHandle);\r | |
509 | }\r | |
510 | \r | |
1e57a462 | 511 | /**\r |
512 | This service enables discovery of additional firmware volumes.\r | |
513 | \r | |
514 | @param Instance This instance of the firmware volume to find. The value 0 is the\r | |
515 | Boot Firmware Volume (BFV).\r | |
516 | @param FwVolHeader Pointer to the firmware volume header of the volume to return.\r | |
517 | \r | |
518 | @retval EFI_SUCCESS The volume was found.\r | |
519 | @retval EFI_NOT_FOUND The volume was not found.\r | |
520 | \r | |
521 | **/\r | |
522 | EFI_STATUS\r | |
523 | EFIAPI\r | |
524 | FfsFindNextVolume (\r | |
e7108d0e MK |
525 | IN UINTN Instance,\r |
526 | IN OUT EFI_PEI_FV_HANDLE *VolumeHandle\r | |
1e57a462 | 527 | )\r |
528 | {\r | |
e7108d0e | 529 | EFI_PEI_HOB_POINTERS Hob;\r |
1e57a462 | 530 | \r |
531 | Hob.Raw = GetHobList ();\r | |
532 | if (Hob.Raw == NULL) {\r | |
533 | return EFI_NOT_FOUND;\r | |
534 | }\r | |
3402aac7 | 535 | \r |
1e57a462 | 536 | do {\r |
537 | Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw);\r | |
538 | if (Hob.Raw != NULL) {\r | |
539 | if (Instance-- == 0) {\r | |
540 | *VolumeHandle = (EFI_PEI_FV_HANDLE)(UINTN)(Hob.FirmwareVolume->BaseAddress);\r | |
541 | return EFI_SUCCESS;\r | |
542 | }\r | |
543 | \r | |
544 | Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, GET_NEXT_HOB (Hob));\r | |
545 | }\r | |
546 | } while (Hob.Raw != NULL);\r | |
3402aac7 | 547 | \r |
1e57a462 | 548 | return EFI_NOT_FOUND;\r |
1e57a462 | 549 | }\r |
550 | \r | |
1e57a462 | 551 | /**\r |
552 | Find a file in the volume by name\r | |
3402aac7 | 553 | \r |
1e57a462 | 554 | @param FileName A pointer to the name of the file to\r |
555 | find within the firmware volume.\r | |
556 | \r | |
557 | @param VolumeHandle The firmware volume to search FileHandle\r | |
558 | Upon exit, points to the found file's\r | |
559 | handle or NULL if it could not be found.\r | |
560 | \r | |
561 | @retval EFI_SUCCESS File was found.\r | |
562 | \r | |
563 | @retval EFI_NOT_FOUND File was not found.\r | |
564 | \r | |
565 | @retval EFI_INVALID_PARAMETER VolumeHandle or FileHandle or\r | |
566 | FileName was NULL.\r | |
567 | \r | |
568 | **/\r | |
569 | EFI_STATUS\r | |
3402aac7 | 570 | EFIAPI\r |
1e57a462 | 571 | FfsFindFileByName (\r |
e7108d0e MK |
572 | IN CONST EFI_GUID *FileName,\r |
573 | IN EFI_PEI_FV_HANDLE VolumeHandle,\r | |
574 | OUT EFI_PEI_FILE_HANDLE *FileHandle\r | |
1e57a462 | 575 | )\r |
576 | {\r | |
577 | EFI_STATUS Status;\r | |
e7108d0e | 578 | \r |
1e57a462 | 579 | if ((VolumeHandle == NULL) || (FileName == NULL) || (FileHandle == NULL)) {\r |
580 | return EFI_INVALID_PARAMETER;\r | |
581 | }\r | |
e7108d0e | 582 | \r |
1e57a462 | 583 | Status = FindFileEx (VolumeHandle, FileName, 0, FileHandle);\r |
584 | if (Status == EFI_NOT_FOUND) {\r | |
585 | *FileHandle = NULL;\r | |
586 | }\r | |
e7108d0e | 587 | \r |
1e57a462 | 588 | return Status;\r |
589 | }\r | |
590 | \r | |
1e57a462 | 591 | /**\r |
592 | Get information about the file by name.\r | |
593 | \r | |
594 | @param FileHandle Handle of the file.\r | |
595 | \r | |
596 | @param FileInfo Upon exit, points to the file's\r | |
597 | information.\r | |
598 | \r | |
599 | @retval EFI_SUCCESS File information returned.\r | |
3402aac7 | 600 | \r |
1e57a462 | 601 | @retval EFI_INVALID_PARAMETER If FileHandle does not\r |
602 | represent a valid file.\r | |
3402aac7 | 603 | \r |
1e57a462 | 604 | @retval EFI_INVALID_PARAMETER If FileInfo is NULL.\r |
3402aac7 | 605 | \r |
1e57a462 | 606 | **/\r |
607 | EFI_STATUS\r | |
3402aac7 | 608 | EFIAPI\r |
1e57a462 | 609 | FfsGetFileInfo (\r |
610 | IN EFI_PEI_FILE_HANDLE FileHandle,\r | |
611 | OUT EFI_FV_FILE_INFO *FileInfo\r | |
612 | )\r | |
613 | {\r | |
e7108d0e MK |
614 | UINT8 FileState;\r |
615 | UINT8 ErasePolarity;\r | |
616 | EFI_FFS_FILE_HEADER *FileHeader;\r | |
617 | EFI_PEI_FV_HANDLE VolumeHandle;\r | |
1e57a462 | 618 | \r |
619 | if ((FileHandle == NULL) || (FileInfo == NULL)) {\r | |
620 | return EFI_INVALID_PARAMETER;\r | |
621 | }\r | |
622 | \r | |
623 | VolumeHandle = 0;\r | |
624 | //\r | |
625 | // Retrieve the FirmwareVolume which the file resides in.\r | |
626 | //\r | |
e7108d0e | 627 | if (!FileHandleToVolume (FileHandle, &VolumeHandle)) {\r |
1e57a462 | 628 | return EFI_INVALID_PARAMETER;\r |
629 | }\r | |
630 | \r | |
e7108d0e | 631 | if (((EFI_FIRMWARE_VOLUME_HEADER *)VolumeHandle)->Attributes & EFI_FVB2_ERASE_POLARITY) {\r |
1e57a462 | 632 | ErasePolarity = 1;\r |
633 | } else {\r | |
634 | ErasePolarity = 0;\r | |
635 | }\r | |
636 | \r | |
637 | //\r | |
3402aac7 | 638 | // Get FileState which is the highest bit of the State\r |
1e57a462 | 639 | //\r |
e7108d0e | 640 | FileState = GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER *)FileHandle);\r |
1e57a462 | 641 | \r |
642 | switch (FileState) {\r | |
643 | case EFI_FILE_DATA_VALID:\r | |
644 | case EFI_FILE_MARKED_FOR_UPDATE:\r | |
3402aac7 | 645 | break;\r |
1e57a462 | 646 | default:\r |
647 | return EFI_INVALID_PARAMETER;\r | |
e7108d0e | 648 | }\r |
1e57a462 | 649 | \r |
650 | FileHeader = (EFI_FFS_FILE_HEADER *)FileHandle;\r | |
e7108d0e MK |
651 | CopyMem (&FileInfo->FileName, &FileHeader->Name, sizeof (EFI_GUID));\r |
652 | FileInfo->FileType = FileHeader->Type;\r | |
1e57a462 | 653 | FileInfo->FileAttributes = FileHeader->Attributes;\r |
e7108d0e MK |
654 | FileInfo->BufferSize = ((*(UINT32 *)FileHeader->Size) & 0x00FFFFFF) - sizeof (EFI_FFS_FILE_HEADER);\r |
655 | FileInfo->Buffer = (FileHeader + 1);\r | |
1e57a462 | 656 | return EFI_SUCCESS;\r |
657 | }\r | |
658 | \r | |
1e57a462 | 659 | /**\r |
660 | Get Information about the volume by name\r | |
661 | \r | |
662 | @param VolumeHandle Handle of the volume.\r | |
663 | \r | |
664 | @param VolumeInfo Upon exit, points to the volume's\r | |
665 | information.\r | |
666 | \r | |
667 | @retval EFI_SUCCESS File information returned.\r | |
3402aac7 | 668 | \r |
1e57a462 | 669 | @retval EFI_INVALID_PARAMETER If FileHandle does not\r |
670 | represent a valid file.\r | |
3402aac7 | 671 | \r |
1e57a462 | 672 | @retval EFI_INVALID_PARAMETER If FileInfo is NULL.\r |
673 | \r | |
674 | **/\r | |
675 | EFI_STATUS\r | |
3402aac7 | 676 | EFIAPI\r |
1e57a462 | 677 | FfsGetVolumeInfo (\r |
678 | IN EFI_PEI_FV_HANDLE VolumeHandle,\r | |
679 | OUT EFI_FV_INFO *VolumeInfo\r | |
680 | )\r | |
681 | {\r | |
e7108d0e MK |
682 | EFI_FIRMWARE_VOLUME_HEADER FwVolHeader;\r |
683 | EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo;\r | |
1e57a462 | 684 | \r |
685 | if (VolumeInfo == NULL) {\r | |
686 | return EFI_INVALID_PARAMETER;\r | |
687 | }\r | |
3402aac7 | 688 | \r |
1e57a462 | 689 | //\r |
3402aac7 RC |
690 | // VolumeHandle may not align at 8 byte,\r |
691 | // but FvLength is UINT64 type, which requires FvHeader align at least 8 byte.\r | |
1e57a462 | 692 | // So, Copy FvHeader into the local FvHeader structure.\r |
693 | //\r | |
694 | CopyMem (&FwVolHeader, VolumeHandle, sizeof (EFI_FIRMWARE_VOLUME_HEADER));\r | |
695 | //\r | |
696 | // Check Fv Image Signature\r | |
697 | //\r | |
698 | if (FwVolHeader.Signature != EFI_FVH_SIGNATURE) {\r | |
699 | return EFI_INVALID_PARAMETER;\r | |
700 | }\r | |
e7108d0e | 701 | \r |
1e57a462 | 702 | VolumeInfo->FvAttributes = FwVolHeader.Attributes;\r |
e7108d0e MK |
703 | VolumeInfo->FvStart = (VOID *)VolumeHandle;\r |
704 | VolumeInfo->FvSize = FwVolHeader.FvLength;\r | |
705 | CopyMem (&VolumeInfo->FvFormat, &FwVolHeader.FileSystemGuid, sizeof (EFI_GUID));\r | |
1e57a462 | 706 | \r |
707 | if (FwVolHeader.ExtHeaderOffset != 0) {\r | |
e7108d0e MK |
708 | FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)(((UINT8 *)VolumeHandle) + FwVolHeader.ExtHeaderOffset);\r |
709 | CopyMem (&VolumeInfo->FvName, &FwVolExHeaderInfo->FvName, sizeof (EFI_GUID));\r | |
1e57a462 | 710 | }\r |
e7108d0e | 711 | \r |
1e57a462 | 712 | return EFI_SUCCESS;\r |
713 | }\r | |
714 | \r | |
1e57a462 | 715 | /**\r |
716 | Search through every FV until you find a file of type FileType\r | |
717 | \r | |
91c38d4e | 718 | @param FileType File handle of a Fv type file.\r |
c6a72cd7 | 719 | @param Volumehandle On success Volume Handle of the match\r |
91c38d4e | 720 | @param FileHandle On success File Handle of the match\r |
3402aac7 | 721 | \r |
91c38d4e RC |
722 | @retval EFI_NOT_FOUND FV image can't be found.\r |
723 | @retval EFI_SUCCESS Successfully found FileType\r | |
1e57a462 | 724 | \r |
725 | **/\r | |
726 | EFI_STATUS\r | |
727 | EFIAPI\r | |
728 | FfsAnyFvFindFirstFile (\r | |
e7108d0e MK |
729 | IN EFI_FV_FILETYPE FileType,\r |
730 | OUT EFI_PEI_FV_HANDLE *VolumeHandle,\r | |
731 | OUT EFI_PEI_FILE_HANDLE *FileHandle\r | |
1e57a462 | 732 | )\r |
733 | {\r | |
e7108d0e MK |
734 | EFI_STATUS Status;\r |
735 | UINTN Instance;\r | |
1e57a462 | 736 | \r |
737 | //\r | |
738 | // Search every FV for the DXE Core\r | |
739 | //\r | |
740 | Instance = 0;\r | |
741 | *FileHandle = NULL;\r | |
742 | \r | |
e7108d0e | 743 | while (1) {\r |
1e57a462 | 744 | Status = FfsFindNextVolume (Instance++, VolumeHandle);\r |
e7108d0e | 745 | if (EFI_ERROR (Status)) {\r |
1e57a462 | 746 | break;\r |
747 | }\r | |
748 | \r | |
749 | Status = FfsFindNextFile (FileType, *VolumeHandle, FileHandle);\r | |
e7108d0e | 750 | if (!EFI_ERROR (Status)) {\r |
1e57a462 | 751 | break;\r |
752 | }\r | |
753 | }\r | |
3402aac7 | 754 | \r |
1e57a462 | 755 | return Status;\r |
756 | }\r | |
757 | \r | |
1e57a462 | 758 | /**\r |
759 | Get Fv image from the FV type file, then add FV & FV2 Hob.\r | |
760 | \r | |
91c38d4e | 761 | @param FileHandle File handle of a Fv type file.\r |
1e57a462 | 762 | \r |
763 | \r | |
91c38d4e RC |
764 | @retval EFI_NOT_FOUND FV image can't be found.\r |
765 | @retval EFI_SUCCESS Successfully to process it.\r | |
1e57a462 | 766 | \r |
767 | **/\r | |
768 | EFI_STATUS\r | |
769 | EFIAPI\r | |
770 | FfsProcessFvFile (\r | |
e7108d0e | 771 | IN EFI_PEI_FILE_HANDLE FvFileHandle\r |
1e57a462 | 772 | )\r |
773 | {\r | |
774 | EFI_STATUS Status;\r | |
775 | EFI_PEI_FV_HANDLE FvImageHandle;\r | |
776 | EFI_FV_INFO FvImageInfo;\r | |
777 | UINT32 FvAlignment;\r | |
778 | VOID *FvBuffer;\r | |
779 | EFI_PEI_HOB_POINTERS HobFv2;\r | |
780 | \r | |
e7108d0e | 781 | FvBuffer = NULL;\r |
1e57a462 | 782 | \r |
783 | //\r | |
784 | // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already\r | |
785 | // been extracted.\r | |
786 | //\r | |
787 | HobFv2.Raw = GetHobList ();\r | |
788 | while ((HobFv2.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobFv2.Raw)) != NULL) {\r | |
789 | if (CompareGuid (&(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name), &HobFv2.FirmwareVolume2->FileName)) {\r | |
790 | //\r | |
791 | // this FILE has been dispatched, it will not be dispatched again.\r | |
792 | //\r | |
793 | return EFI_SUCCESS;\r | |
794 | }\r | |
e7108d0e | 795 | \r |
1e57a462 | 796 | HobFv2.Raw = GET_NEXT_HOB (HobFv2);\r |
797 | }\r | |
798 | \r | |
799 | //\r | |
800 | // Find FvImage in FvFile\r | |
801 | //\r | |
802 | Status = FfsFindSectionData (EFI_SECTION_FIRMWARE_VOLUME_IMAGE, FvFileHandle, (VOID **)&FvImageHandle);\r | |
803 | if (EFI_ERROR (Status)) {\r | |
804 | return Status;\r | |
805 | }\r | |
3402aac7 | 806 | \r |
1e57a462 | 807 | //\r |
808 | // Collect FvImage Info.\r | |
809 | //\r | |
810 | ZeroMem (&FvImageInfo, sizeof (FvImageInfo));\r | |
811 | Status = FfsGetVolumeInfo (FvImageHandle, &FvImageInfo);\r | |
812 | ASSERT_EFI_ERROR (Status);\r | |
3402aac7 | 813 | \r |
1e57a462 | 814 | //\r |
815 | // FvAlignment must be more than 8 bytes required by FvHeader structure.\r | |
816 | //\r | |
817 | FvAlignment = 1 << ((FvImageInfo.FvAttributes & EFI_FVB2_ALIGNMENT) >> 16);\r | |
818 | if (FvAlignment < 8) {\r | |
819 | FvAlignment = 8;\r | |
820 | }\r | |
3402aac7 | 821 | \r |
1e57a462 | 822 | //\r |
823 | // Check FvImage\r | |
824 | //\r | |
e7108d0e MK |
825 | if ((UINTN)FvImageInfo.FvStart % FvAlignment != 0) {\r |
826 | FvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINT32)FvImageInfo.FvSize), FvAlignment);\r | |
1e57a462 | 827 | if (FvBuffer == NULL) {\r |
828 | return EFI_OUT_OF_RESOURCES;\r | |
829 | }\r | |
e7108d0e MK |
830 | \r |
831 | CopyMem (FvBuffer, FvImageInfo.FvStart, (UINTN)FvImageInfo.FvSize);\r | |
1e57a462 | 832 | //\r |
833 | // Update FvImageInfo after reload FvImage to new aligned memory\r | |
834 | //\r | |
e7108d0e | 835 | FfsGetVolumeInfo ((EFI_PEI_FV_HANDLE)FvBuffer, &FvImageInfo);\r |
1e57a462 | 836 | }\r |
837 | \r | |
1e57a462 | 838 | //\r |
c6a72cd7 | 839 | // Inform HOB consumer phase, i.e. DXE core, the existence of this FV\r |
1e57a462 | 840 | //\r |
e7108d0e | 841 | BuildFvHob ((EFI_PHYSICAL_ADDRESS)(UINTN)FvImageInfo.FvStart, FvImageInfo.FvSize);\r |
3402aac7 | 842 | \r |
1e57a462 | 843 | //\r |
844 | // Makes the encapsulated volume show up in DXE phase to skip processing of\r | |
845 | // encapsulated file again.\r | |
846 | //\r | |
847 | BuildFv2Hob (\r | |
e7108d0e | 848 | (EFI_PHYSICAL_ADDRESS)(UINTN)FvImageInfo.FvStart,\r |
1e57a462 | 849 | FvImageInfo.FvSize,\r |
850 | &FvImageInfo.FvName,\r | |
851 | &(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name)\r | |
852 | );\r | |
853 | \r | |
854 | return EFI_SUCCESS;\r | |
855 | }\r |