]>
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 | |
c673216f MX |
267 | @param SectionType - Filter to find only section of this type.\r |
268 | @param SectionCheckHook - A hook which can check if the section is the target one.\r | |
269 | @param Section - From where to search.\r | |
270 | @param SectionSize - The file size to search.\r | |
271 | @param OutputBuffer - Pointer to the section to search.\r | |
3402aac7 | 272 | \r |
1e57a462 | 273 | @retval EFI_SUCCESS\r |
274 | **/\r | |
275 | EFI_STATUS\r | |
276 | FfsProcessSection (\r | |
277 | IN EFI_SECTION_TYPE SectionType,\r | |
c673216f | 278 | IN FFS_CHECK_SECTION_HOOK SectionCheckHook,\r |
1e57a462 | 279 | IN EFI_COMMON_SECTION_HEADER *Section,\r |
280 | IN UINTN SectionSize,\r | |
281 | OUT VOID **OutputBuffer\r | |
282 | )\r | |
283 | {\r | |
e7108d0e MK |
284 | EFI_STATUS Status;\r |
285 | UINT32 SectionLength;\r | |
286 | UINT32 ParsedLength;\r | |
287 | EFI_COMPRESSION_SECTION *CompressionSection;\r | |
288 | EFI_COMPRESSION_SECTION2 *CompressionSection2;\r | |
289 | UINT32 DstBufferSize;\r | |
290 | VOID *ScratchBuffer;\r | |
291 | UINT32 ScratchBufferSize;\r | |
292 | VOID *DstBuffer;\r | |
293 | UINT16 SectionAttribute;\r | |
294 | UINT32 AuthenticationStatus;\r | |
295 | CHAR8 *CompressedData;\r | |
6777e673 | 296 | UINT32 CompressedDataLength;\r |
c673216f | 297 | BOOLEAN Found;\r |
1e57a462 | 298 | \r |
c673216f | 299 | Found = FALSE;\r |
1e57a462 | 300 | *OutputBuffer = NULL;\r |
301 | ParsedLength = 0;\r | |
302 | Status = EFI_NOT_FOUND;\r | |
303 | while (ParsedLength < SectionSize) {\r | |
4efc8a40 MZ |
304 | if (IS_SECTION2 (Section)) {\r |
305 | ASSERT (SECTION2_SIZE (Section) > 0x00FFFFFF);\r | |
306 | }\r | |
307 | \r | |
1e57a462 | 308 | if (Section->Type == SectionType) {\r |
c673216f MX |
309 | if (SectionCheckHook != NULL) {\r |
310 | Found = SectionCheckHook (Section) == EFI_SUCCESS;\r | |
4efc8a40 | 311 | } else {\r |
c673216f | 312 | Found = TRUE;\r |
4efc8a40 | 313 | }\r |
1e57a462 | 314 | \r |
c673216f MX |
315 | if (Found) {\r |
316 | if (IS_SECTION2 (Section)) {\r | |
317 | *OutputBuffer = (VOID *)((UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER2));\r | |
318 | } else {\r | |
319 | *OutputBuffer = (VOID *)((UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER));\r | |
320 | }\r | |
321 | \r | |
322 | return EFI_SUCCESS;\r | |
323 | } else {\r | |
324 | goto CheckNextSection;\r | |
325 | }\r | |
1e57a462 | 326 | } else if ((Section->Type == EFI_SECTION_COMPRESSION) || (Section->Type == EFI_SECTION_GUID_DEFINED)) {\r |
1e57a462 | 327 | if (Section->Type == EFI_SECTION_COMPRESSION) {\r |
4efc8a40 | 328 | if (IS_SECTION2 (Section)) {\r |
e7108d0e | 329 | CompressionSection2 = (EFI_COMPRESSION_SECTION2 *)Section;\r |
4efc8a40 MZ |
330 | SectionLength = SECTION2_SIZE (Section);\r |
331 | \r | |
332 | if (CompressionSection2->CompressionType != EFI_STANDARD_COMPRESSION) {\r | |
333 | return EFI_UNSUPPORTED;\r | |
334 | }\r | |
335 | \r | |
e7108d0e | 336 | CompressedData = (CHAR8 *)((EFI_COMPRESSION_SECTION2 *)Section + 1);\r |
6777e673 | 337 | CompressedDataLength = SectionLength - sizeof (EFI_COMPRESSION_SECTION2);\r |
4efc8a40 | 338 | } else {\r |
e7108d0e MK |
339 | CompressionSection = (EFI_COMPRESSION_SECTION *)Section;\r |
340 | SectionLength = SECTION_SIZE (Section);\r | |
4efc8a40 MZ |
341 | \r |
342 | if (CompressionSection->CompressionType != EFI_STANDARD_COMPRESSION) {\r | |
343 | return EFI_UNSUPPORTED;\r | |
344 | }\r | |
345 | \r | |
e7108d0e | 346 | CompressedData = (CHAR8 *)((EFI_COMPRESSION_SECTION *)Section + 1);\r |
6777e673 | 347 | CompressedDataLength = SectionLength - sizeof (EFI_COMPRESSION_SECTION);\r |
1e57a462 | 348 | }\r |
349 | \r | |
350 | Status = UefiDecompressGetInfo (\r | |
4efc8a40 MZ |
351 | CompressedData,\r |
352 | CompressedDataLength,\r | |
c1cdcab9 | 353 | &DstBufferSize,\r |
1e57a462 | 354 | &ScratchBufferSize\r |
355 | );\r | |
356 | } else if (Section->Type == EFI_SECTION_GUID_DEFINED) {\r | |
357 | Status = ExtractGuidedSectionGetInfo (\r | |
358 | Section,\r | |
c1cdcab9 | 359 | &DstBufferSize,\r |
1e57a462 | 360 | &ScratchBufferSize,\r |
361 | &SectionAttribute\r | |
362 | );\r | |
363 | }\r | |
3402aac7 | 364 | \r |
1e57a462 | 365 | if (EFI_ERROR (Status)) {\r |
366 | //\r | |
367 | // GetInfo failed\r | |
368 | //\r | |
a1878955 | 369 | DEBUG ((DEBUG_ERROR, "Decompress GetInfo Failed - %r\n", Status));\r |
1e57a462 | 370 | return EFI_NOT_FOUND;\r |
371 | }\r | |
e7108d0e | 372 | \r |
1e57a462 | 373 | //\r |
374 | // Allocate scratch buffer\r | |
375 | //\r | |
376 | ScratchBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));\r | |
377 | if (ScratchBuffer == NULL) {\r | |
378 | return EFI_OUT_OF_RESOURCES;\r | |
379 | }\r | |
e7108d0e | 380 | \r |
1e57a462 | 381 | //\r |
3402aac7 | 382 | // Allocate destination buffer, extra one page for adjustment\r |
1e57a462 | 383 | //\r |
384 | DstBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1);\r | |
385 | if (DstBuffer == NULL) {\r | |
386 | return EFI_OUT_OF_RESOURCES;\r | |
387 | }\r | |
e7108d0e | 388 | \r |
1e57a462 | 389 | //\r |
390 | // DstBuffer still is one section. Adjust DstBuffer offset, skip EFI section header\r | |
391 | // to make section data at page alignment.\r | |
392 | //\r | |
e7108d0e | 393 | if (IS_SECTION2 (Section)) {\r |
4efc8a40 | 394 | DstBuffer = (UINT8 *)DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER2);\r |
e7108d0e | 395 | } else {\r |
4efc8a40 | 396 | DstBuffer = (UINT8 *)DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER);\r |
e7108d0e MK |
397 | }\r |
398 | \r | |
1e57a462 | 399 | //\r |
400 | // Call decompress function\r | |
401 | //\r | |
402 | if (Section->Type == EFI_SECTION_COMPRESSION) {\r | |
4efc8a40 | 403 | if (IS_SECTION2 (Section)) {\r |
e7108d0e MK |
404 | CompressedData = (CHAR8 *)((EFI_COMPRESSION_SECTION2 *)Section + 1);\r |
405 | } else {\r | |
406 | CompressedData = (CHAR8 *)((EFI_COMPRESSION_SECTION *)Section + 1);\r | |
4efc8a40 MZ |
407 | }\r |
408 | \r | |
1e57a462 | 409 | Status = UefiDecompress (\r |
e7108d0e MK |
410 | CompressedData,\r |
411 | DstBuffer,\r | |
412 | ScratchBuffer\r | |
413 | );\r | |
1e57a462 | 414 | } else if (Section->Type == EFI_SECTION_GUID_DEFINED) {\r |
415 | Status = ExtractGuidedSectionDecode (\r | |
e7108d0e MK |
416 | Section,\r |
417 | &DstBuffer,\r | |
418 | ScratchBuffer,\r | |
419 | &AuthenticationStatus\r | |
420 | );\r | |
1e57a462 | 421 | }\r |
3402aac7 | 422 | \r |
1e57a462 | 423 | if (EFI_ERROR (Status)) {\r |
424 | //\r | |
425 | // Decompress failed\r | |
426 | //\r | |
a1878955 | 427 | DEBUG ((DEBUG_ERROR, "Decompress Failed - %r\n", Status));\r |
1e57a462 | 428 | return EFI_NOT_FOUND;\r |
429 | } else {\r | |
430 | return FfsProcessSection (\r | |
e7108d0e | 431 | SectionType,\r |
c673216f | 432 | SectionCheckHook,\r |
e7108d0e MK |
433 | DstBuffer,\r |
434 | DstBufferSize,\r | |
435 | OutputBuffer\r | |
436 | );\r | |
437 | }\r | |
1e57a462 | 438 | }\r |
439 | \r | |
c673216f | 440 | CheckNextSection:\r |
4efc8a40 MZ |
441 | if (IS_SECTION2 (Section)) {\r |
442 | SectionLength = SECTION2_SIZE (Section);\r | |
443 | } else {\r | |
444 | SectionLength = SECTION_SIZE (Section);\r | |
445 | }\r | |
e7108d0e | 446 | \r |
1e57a462 | 447 | //\r |
1e57a462 | 448 | // SectionLength is adjusted it is 4 byte aligned.\r |
449 | // Go to the next section\r | |
450 | //\r | |
1e57a462 | 451 | SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);\r |
452 | ASSERT (SectionLength != 0);\r | |
453 | ParsedLength += SectionLength;\r | |
e7108d0e | 454 | Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength);\r |
1e57a462 | 455 | }\r |
3402aac7 | 456 | \r |
1e57a462 | 457 | return EFI_NOT_FOUND;\r |
458 | }\r | |
459 | \r | |
1e57a462 | 460 | /**\r |
461 | This service enables discovery sections of a given type within a valid FFS file.\r | |
462 | \r | |
463 | @param SearchType The value of the section type to find.\r | |
464 | @param FfsFileHeader A pointer to the file header that contains the set of sections to\r | |
465 | be searched.\r | |
466 | @param SectionData A pointer to the discovered section, if successful.\r | |
467 | \r | |
468 | @retval EFI_SUCCESS The section was found.\r | |
469 | @retval EFI_NOT_FOUND The section was not found.\r | |
470 | \r | |
471 | **/\r | |
472 | EFI_STATUS\r | |
473 | EFIAPI\r | |
474 | FfsFindSectionData (\r | |
c673216f MX |
475 | IN EFI_SECTION_TYPE SectionType,\r |
476 | IN FFS_CHECK_SECTION_HOOK SectionCheckHook,\r | |
477 | IN EFI_PEI_FILE_HANDLE FileHandle,\r | |
478 | OUT VOID **SectionData\r | |
1e57a462 | 479 | )\r |
480 | {\r | |
e7108d0e MK |
481 | EFI_FFS_FILE_HEADER *FfsFileHeader;\r |
482 | UINT32 FileSize;\r | |
483 | EFI_COMMON_SECTION_HEADER *Section;\r | |
1e57a462 | 484 | \r |
485 | FfsFileHeader = (EFI_FFS_FILE_HEADER *)(FileHandle);\r | |
486 | \r | |
487 | //\r | |
3402aac7 | 488 | // Size is 24 bits wide so mask upper 8 bits.\r |
1e57a462 | 489 | // Does not include FfsFileHeader header size\r |
490 | // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned.\r | |
491 | //\r | |
e7108d0e MK |
492 | Section = (EFI_COMMON_SECTION_HEADER *)(FfsFileHeader + 1);\r |
493 | FileSize = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;\r | |
1e57a462 | 494 | FileSize -= sizeof (EFI_FFS_FILE_HEADER);\r |
495 | \r | |
496 | return FfsProcessSection (\r | |
e7108d0e | 497 | SectionType,\r |
c673216f | 498 | SectionCheckHook,\r |
e7108d0e MK |
499 | Section,\r |
500 | FileSize,\r | |
501 | SectionData\r | |
502 | );\r | |
1e57a462 | 503 | }\r |
504 | \r | |
1e57a462 | 505 | /**\r |
506 | This service enables discovery of additional firmware files.\r | |
507 | \r | |
508 | @param SearchType A filter to find files only of this type.\r | |
509 | @param FwVolHeader Pointer to the firmware volume header of the volume to search.\r | |
510 | This parameter must point to a valid FFS volume.\r | |
511 | @param FileHeader Pointer to the current file from which to begin searching.\r | |
512 | \r | |
513 | @retval EFI_SUCCESS The file was found.\r | |
514 | @retval EFI_NOT_FOUND The file was not found.\r | |
515 | @retval EFI_NOT_FOUND The header checksum was not zero.\r | |
516 | \r | |
517 | **/\r | |
518 | EFI_STATUS\r | |
519 | EFIAPI\r | |
520 | FfsFindNextFile (\r | |
e7108d0e MK |
521 | IN UINT8 SearchType,\r |
522 | IN EFI_PEI_FV_HANDLE VolumeHandle,\r | |
523 | IN OUT EFI_PEI_FILE_HANDLE *FileHandle\r | |
1e57a462 | 524 | )\r |
525 | {\r | |
526 | return FindFileEx (VolumeHandle, NULL, SearchType, FileHandle);\r | |
527 | }\r | |
528 | \r | |
1e57a462 | 529 | /**\r |
530 | This service enables discovery of additional firmware volumes.\r | |
531 | \r | |
532 | @param Instance This instance of the firmware volume to find. The value 0 is the\r | |
533 | Boot Firmware Volume (BFV).\r | |
534 | @param FwVolHeader Pointer to the firmware volume header of the volume to return.\r | |
535 | \r | |
536 | @retval EFI_SUCCESS The volume was found.\r | |
537 | @retval EFI_NOT_FOUND The volume was not found.\r | |
538 | \r | |
539 | **/\r | |
540 | EFI_STATUS\r | |
541 | EFIAPI\r | |
542 | FfsFindNextVolume (\r | |
e7108d0e MK |
543 | IN UINTN Instance,\r |
544 | IN OUT EFI_PEI_FV_HANDLE *VolumeHandle\r | |
1e57a462 | 545 | )\r |
546 | {\r | |
e7108d0e | 547 | EFI_PEI_HOB_POINTERS Hob;\r |
1e57a462 | 548 | \r |
549 | Hob.Raw = GetHobList ();\r | |
550 | if (Hob.Raw == NULL) {\r | |
551 | return EFI_NOT_FOUND;\r | |
552 | }\r | |
3402aac7 | 553 | \r |
1e57a462 | 554 | do {\r |
555 | Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw);\r | |
556 | if (Hob.Raw != NULL) {\r | |
557 | if (Instance-- == 0) {\r | |
558 | *VolumeHandle = (EFI_PEI_FV_HANDLE)(UINTN)(Hob.FirmwareVolume->BaseAddress);\r | |
559 | return EFI_SUCCESS;\r | |
560 | }\r | |
561 | \r | |
562 | Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, GET_NEXT_HOB (Hob));\r | |
563 | }\r | |
564 | } while (Hob.Raw != NULL);\r | |
3402aac7 | 565 | \r |
1e57a462 | 566 | return EFI_NOT_FOUND;\r |
1e57a462 | 567 | }\r |
568 | \r | |
1e57a462 | 569 | /**\r |
570 | Find a file in the volume by name\r | |
3402aac7 | 571 | \r |
1e57a462 | 572 | @param FileName A pointer to the name of the file to\r |
573 | find within the firmware volume.\r | |
574 | \r | |
575 | @param VolumeHandle The firmware volume to search FileHandle\r | |
576 | Upon exit, points to the found file's\r | |
577 | handle or NULL if it could not be found.\r | |
578 | \r | |
579 | @retval EFI_SUCCESS File was found.\r | |
580 | \r | |
581 | @retval EFI_NOT_FOUND File was not found.\r | |
582 | \r | |
583 | @retval EFI_INVALID_PARAMETER VolumeHandle or FileHandle or\r | |
584 | FileName was NULL.\r | |
585 | \r | |
586 | **/\r | |
587 | EFI_STATUS\r | |
3402aac7 | 588 | EFIAPI\r |
1e57a462 | 589 | FfsFindFileByName (\r |
e7108d0e MK |
590 | IN CONST EFI_GUID *FileName,\r |
591 | IN EFI_PEI_FV_HANDLE VolumeHandle,\r | |
592 | OUT EFI_PEI_FILE_HANDLE *FileHandle\r | |
1e57a462 | 593 | )\r |
594 | {\r | |
595 | EFI_STATUS Status;\r | |
e7108d0e | 596 | \r |
1e57a462 | 597 | if ((VolumeHandle == NULL) || (FileName == NULL) || (FileHandle == NULL)) {\r |
598 | return EFI_INVALID_PARAMETER;\r | |
599 | }\r | |
e7108d0e | 600 | \r |
1e57a462 | 601 | Status = FindFileEx (VolumeHandle, FileName, 0, FileHandle);\r |
602 | if (Status == EFI_NOT_FOUND) {\r | |
603 | *FileHandle = NULL;\r | |
604 | }\r | |
e7108d0e | 605 | \r |
1e57a462 | 606 | return Status;\r |
607 | }\r | |
608 | \r | |
1e57a462 | 609 | /**\r |
610 | Get information about the file by name.\r | |
611 | \r | |
612 | @param FileHandle Handle of the file.\r | |
613 | \r | |
614 | @param FileInfo Upon exit, points to the file's\r | |
615 | information.\r | |
616 | \r | |
617 | @retval EFI_SUCCESS File information returned.\r | |
3402aac7 | 618 | \r |
1e57a462 | 619 | @retval EFI_INVALID_PARAMETER If FileHandle does not\r |
620 | represent a valid file.\r | |
3402aac7 | 621 | \r |
1e57a462 | 622 | @retval EFI_INVALID_PARAMETER If FileInfo is NULL.\r |
3402aac7 | 623 | \r |
1e57a462 | 624 | **/\r |
625 | EFI_STATUS\r | |
3402aac7 | 626 | EFIAPI\r |
1e57a462 | 627 | FfsGetFileInfo (\r |
628 | IN EFI_PEI_FILE_HANDLE FileHandle,\r | |
629 | OUT EFI_FV_FILE_INFO *FileInfo\r | |
630 | )\r | |
631 | {\r | |
e7108d0e MK |
632 | UINT8 FileState;\r |
633 | UINT8 ErasePolarity;\r | |
634 | EFI_FFS_FILE_HEADER *FileHeader;\r | |
635 | EFI_PEI_FV_HANDLE VolumeHandle;\r | |
1e57a462 | 636 | \r |
637 | if ((FileHandle == NULL) || (FileInfo == NULL)) {\r | |
638 | return EFI_INVALID_PARAMETER;\r | |
639 | }\r | |
640 | \r | |
641 | VolumeHandle = 0;\r | |
642 | //\r | |
643 | // Retrieve the FirmwareVolume which the file resides in.\r | |
644 | //\r | |
e7108d0e | 645 | if (!FileHandleToVolume (FileHandle, &VolumeHandle)) {\r |
1e57a462 | 646 | return EFI_INVALID_PARAMETER;\r |
647 | }\r | |
648 | \r | |
e7108d0e | 649 | if (((EFI_FIRMWARE_VOLUME_HEADER *)VolumeHandle)->Attributes & EFI_FVB2_ERASE_POLARITY) {\r |
1e57a462 | 650 | ErasePolarity = 1;\r |
651 | } else {\r | |
652 | ErasePolarity = 0;\r | |
653 | }\r | |
654 | \r | |
655 | //\r | |
3402aac7 | 656 | // Get FileState which is the highest bit of the State\r |
1e57a462 | 657 | //\r |
e7108d0e | 658 | FileState = GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER *)FileHandle);\r |
1e57a462 | 659 | \r |
660 | switch (FileState) {\r | |
661 | case EFI_FILE_DATA_VALID:\r | |
662 | case EFI_FILE_MARKED_FOR_UPDATE:\r | |
3402aac7 | 663 | break;\r |
1e57a462 | 664 | default:\r |
665 | return EFI_INVALID_PARAMETER;\r | |
e7108d0e | 666 | }\r |
1e57a462 | 667 | \r |
668 | FileHeader = (EFI_FFS_FILE_HEADER *)FileHandle;\r | |
e7108d0e MK |
669 | CopyMem (&FileInfo->FileName, &FileHeader->Name, sizeof (EFI_GUID));\r |
670 | FileInfo->FileType = FileHeader->Type;\r | |
1e57a462 | 671 | FileInfo->FileAttributes = FileHeader->Attributes;\r |
e7108d0e MK |
672 | FileInfo->BufferSize = ((*(UINT32 *)FileHeader->Size) & 0x00FFFFFF) - sizeof (EFI_FFS_FILE_HEADER);\r |
673 | FileInfo->Buffer = (FileHeader + 1);\r | |
1e57a462 | 674 | return EFI_SUCCESS;\r |
675 | }\r | |
676 | \r | |
1e57a462 | 677 | /**\r |
678 | Get Information about the volume by name\r | |
679 | \r | |
680 | @param VolumeHandle Handle of the volume.\r | |
681 | \r | |
682 | @param VolumeInfo Upon exit, points to the volume's\r | |
683 | information.\r | |
684 | \r | |
685 | @retval EFI_SUCCESS File information returned.\r | |
3402aac7 | 686 | \r |
1e57a462 | 687 | @retval EFI_INVALID_PARAMETER If FileHandle does not\r |
688 | represent a valid file.\r | |
3402aac7 | 689 | \r |
1e57a462 | 690 | @retval EFI_INVALID_PARAMETER If FileInfo is NULL.\r |
691 | \r | |
692 | **/\r | |
693 | EFI_STATUS\r | |
3402aac7 | 694 | EFIAPI\r |
1e57a462 | 695 | FfsGetVolumeInfo (\r |
696 | IN EFI_PEI_FV_HANDLE VolumeHandle,\r | |
697 | OUT EFI_FV_INFO *VolumeInfo\r | |
698 | )\r | |
699 | {\r | |
e7108d0e MK |
700 | EFI_FIRMWARE_VOLUME_HEADER FwVolHeader;\r |
701 | EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo;\r | |
1e57a462 | 702 | \r |
703 | if (VolumeInfo == NULL) {\r | |
704 | return EFI_INVALID_PARAMETER;\r | |
705 | }\r | |
3402aac7 | 706 | \r |
1e57a462 | 707 | //\r |
3402aac7 RC |
708 | // VolumeHandle may not align at 8 byte,\r |
709 | // but FvLength is UINT64 type, which requires FvHeader align at least 8 byte.\r | |
1e57a462 | 710 | // So, Copy FvHeader into the local FvHeader structure.\r |
711 | //\r | |
712 | CopyMem (&FwVolHeader, VolumeHandle, sizeof (EFI_FIRMWARE_VOLUME_HEADER));\r | |
713 | //\r | |
714 | // Check Fv Image Signature\r | |
715 | //\r | |
716 | if (FwVolHeader.Signature != EFI_FVH_SIGNATURE) {\r | |
717 | return EFI_INVALID_PARAMETER;\r | |
718 | }\r | |
e7108d0e | 719 | \r |
1e57a462 | 720 | VolumeInfo->FvAttributes = FwVolHeader.Attributes;\r |
e7108d0e MK |
721 | VolumeInfo->FvStart = (VOID *)VolumeHandle;\r |
722 | VolumeInfo->FvSize = FwVolHeader.FvLength;\r | |
723 | CopyMem (&VolumeInfo->FvFormat, &FwVolHeader.FileSystemGuid, sizeof (EFI_GUID));\r | |
1e57a462 | 724 | \r |
725 | if (FwVolHeader.ExtHeaderOffset != 0) {\r | |
e7108d0e MK |
726 | FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)(((UINT8 *)VolumeHandle) + FwVolHeader.ExtHeaderOffset);\r |
727 | CopyMem (&VolumeInfo->FvName, &FwVolExHeaderInfo->FvName, sizeof (EFI_GUID));\r | |
1e57a462 | 728 | }\r |
e7108d0e | 729 | \r |
1e57a462 | 730 | return EFI_SUCCESS;\r |
731 | }\r | |
732 | \r | |
1e57a462 | 733 | /**\r |
734 | Search through every FV until you find a file of type FileType\r | |
735 | \r | |
91c38d4e | 736 | @param FileType File handle of a Fv type file.\r |
c6a72cd7 | 737 | @param Volumehandle On success Volume Handle of the match\r |
91c38d4e | 738 | @param FileHandle On success File Handle of the match\r |
3402aac7 | 739 | \r |
91c38d4e RC |
740 | @retval EFI_NOT_FOUND FV image can't be found.\r |
741 | @retval EFI_SUCCESS Successfully found FileType\r | |
1e57a462 | 742 | \r |
743 | **/\r | |
744 | EFI_STATUS\r | |
745 | EFIAPI\r | |
746 | FfsAnyFvFindFirstFile (\r | |
e7108d0e MK |
747 | IN EFI_FV_FILETYPE FileType,\r |
748 | OUT EFI_PEI_FV_HANDLE *VolumeHandle,\r | |
749 | OUT EFI_PEI_FILE_HANDLE *FileHandle\r | |
1e57a462 | 750 | )\r |
751 | {\r | |
e7108d0e MK |
752 | EFI_STATUS Status;\r |
753 | UINTN Instance;\r | |
1e57a462 | 754 | \r |
755 | //\r | |
756 | // Search every FV for the DXE Core\r | |
757 | //\r | |
758 | Instance = 0;\r | |
759 | *FileHandle = NULL;\r | |
760 | \r | |
e7108d0e | 761 | while (1) {\r |
1e57a462 | 762 | Status = FfsFindNextVolume (Instance++, VolumeHandle);\r |
e7108d0e | 763 | if (EFI_ERROR (Status)) {\r |
1e57a462 | 764 | break;\r |
765 | }\r | |
766 | \r | |
767 | Status = FfsFindNextFile (FileType, *VolumeHandle, FileHandle);\r | |
e7108d0e | 768 | if (!EFI_ERROR (Status)) {\r |
1e57a462 | 769 | break;\r |
770 | }\r | |
771 | }\r | |
3402aac7 | 772 | \r |
1e57a462 | 773 | return Status;\r |
774 | }\r | |
775 | \r | |
1e57a462 | 776 | /**\r |
777 | Get Fv image from the FV type file, then add FV & FV2 Hob.\r | |
778 | \r | |
91c38d4e | 779 | @param FileHandle File handle of a Fv type file.\r |
1e57a462 | 780 | \r |
781 | \r | |
91c38d4e RC |
782 | @retval EFI_NOT_FOUND FV image can't be found.\r |
783 | @retval EFI_SUCCESS Successfully to process it.\r | |
1e57a462 | 784 | \r |
785 | **/\r | |
786 | EFI_STATUS\r | |
787 | EFIAPI\r | |
788 | FfsProcessFvFile (\r | |
e7108d0e | 789 | IN EFI_PEI_FILE_HANDLE FvFileHandle\r |
1e57a462 | 790 | )\r |
791 | {\r | |
792 | EFI_STATUS Status;\r | |
793 | EFI_PEI_FV_HANDLE FvImageHandle;\r | |
794 | EFI_FV_INFO FvImageInfo;\r | |
795 | UINT32 FvAlignment;\r | |
796 | VOID *FvBuffer;\r | |
797 | EFI_PEI_HOB_POINTERS HobFv2;\r | |
798 | \r | |
e7108d0e | 799 | FvBuffer = NULL;\r |
1e57a462 | 800 | \r |
801 | //\r | |
802 | // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already\r | |
803 | // been extracted.\r | |
804 | //\r | |
805 | HobFv2.Raw = GetHobList ();\r | |
806 | while ((HobFv2.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobFv2.Raw)) != NULL) {\r | |
807 | if (CompareGuid (&(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name), &HobFv2.FirmwareVolume2->FileName)) {\r | |
808 | //\r | |
809 | // this FILE has been dispatched, it will not be dispatched again.\r | |
810 | //\r | |
811 | return EFI_SUCCESS;\r | |
812 | }\r | |
e7108d0e | 813 | \r |
1e57a462 | 814 | HobFv2.Raw = GET_NEXT_HOB (HobFv2);\r |
815 | }\r | |
816 | \r | |
817 | //\r | |
818 | // Find FvImage in FvFile\r | |
819 | //\r | |
c673216f | 820 | Status = FfsFindSectionData (EFI_SECTION_FIRMWARE_VOLUME_IMAGE, NULL, FvFileHandle, (VOID **)&FvImageHandle);\r |
1e57a462 | 821 | if (EFI_ERROR (Status)) {\r |
822 | return Status;\r | |
823 | }\r | |
3402aac7 | 824 | \r |
1e57a462 | 825 | //\r |
826 | // Collect FvImage Info.\r | |
827 | //\r | |
828 | ZeroMem (&FvImageInfo, sizeof (FvImageInfo));\r | |
829 | Status = FfsGetVolumeInfo (FvImageHandle, &FvImageInfo);\r | |
830 | ASSERT_EFI_ERROR (Status);\r | |
3402aac7 | 831 | \r |
1e57a462 | 832 | //\r |
833 | // FvAlignment must be more than 8 bytes required by FvHeader structure.\r | |
834 | //\r | |
835 | FvAlignment = 1 << ((FvImageInfo.FvAttributes & EFI_FVB2_ALIGNMENT) >> 16);\r | |
836 | if (FvAlignment < 8) {\r | |
837 | FvAlignment = 8;\r | |
838 | }\r | |
3402aac7 | 839 | \r |
1e57a462 | 840 | //\r |
841 | // Check FvImage\r | |
842 | //\r | |
e7108d0e MK |
843 | if ((UINTN)FvImageInfo.FvStart % FvAlignment != 0) {\r |
844 | FvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINT32)FvImageInfo.FvSize), FvAlignment);\r | |
1e57a462 | 845 | if (FvBuffer == NULL) {\r |
846 | return EFI_OUT_OF_RESOURCES;\r | |
847 | }\r | |
e7108d0e MK |
848 | \r |
849 | CopyMem (FvBuffer, FvImageInfo.FvStart, (UINTN)FvImageInfo.FvSize);\r | |
1e57a462 | 850 | //\r |
851 | // Update FvImageInfo after reload FvImage to new aligned memory\r | |
852 | //\r | |
e7108d0e | 853 | FfsGetVolumeInfo ((EFI_PEI_FV_HANDLE)FvBuffer, &FvImageInfo);\r |
1e57a462 | 854 | }\r |
855 | \r | |
1e57a462 | 856 | //\r |
c6a72cd7 | 857 | // Inform HOB consumer phase, i.e. DXE core, the existence of this FV\r |
1e57a462 | 858 | //\r |
e7108d0e | 859 | BuildFvHob ((EFI_PHYSICAL_ADDRESS)(UINTN)FvImageInfo.FvStart, FvImageInfo.FvSize);\r |
3402aac7 | 860 | \r |
1e57a462 | 861 | //\r |
862 | // Makes the encapsulated volume show up in DXE phase to skip processing of\r | |
863 | // encapsulated file again.\r | |
864 | //\r | |
865 | BuildFv2Hob (\r | |
e7108d0e | 866 | (EFI_PHYSICAL_ADDRESS)(UINTN)FvImageInfo.FvStart,\r |
1e57a462 | 867 | FvImageInfo.FvSize,\r |
868 | &FvImageInfo.FvName,\r | |
869 | &(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name)\r | |
870 | );\r | |
871 | \r | |
872 | return EFI_SUCCESS;\r | |
873 | }\r |