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