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