]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/Library/PrePiLib/FwVol.c
ARM Packages: Fixed line endings
[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
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 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
217 // Get FileState which is the highest bit of the State \r
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
227 \r
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
244 } else if (((SearchType == FfsFileHeader->Type) || (SearchType == EFI_FV_FILETYPE_ALL)) && \r
245 (FfsFileHeader->Type != EFI_FV_FILETYPE_FFS_PAD)) { \r
246 *FileHeader = FfsFileHeader;\r
247 return EFI_SUCCESS;\r
248 }\r
249\r
250 FileOffset += FileOccupiedSize; \r
251 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize);\r
252 break;\r
253 \r
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
264 } \r
265 }\r
266\r
267 \r
268 *FileHeader = NULL;\r
269 return EFI_NOT_FOUND; \r
270}\r
271\r
272\r
273/**\r
274 Go through the file to search SectionType section,\r
275 when meeting an encapsuled section. \r
276 \r
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
281 \r
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
296 UINTN DstBufferSize;\r
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
313 \r
314 if (Section->Type == EFI_SECTION_COMPRESSION) {\r
315 CompressionSection = (EFI_COMPRESSION_SECTION *) Section;\r
316 SectionLength = *(UINT32 *)Section->Size & 0x00FFFFFF;\r
317 \r
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
325 (UINT32 *) &DstBufferSize,\r
326 &ScratchBufferSize\r
327 );\r
328 } else if (Section->Type == EFI_SECTION_GUID_DEFINED) {\r
329 Status = ExtractGuidedSectionGetInfo (\r
330 Section,\r
331 (UINT32 *) &DstBufferSize,\r
332 &ScratchBufferSize,\r
333 &SectionAttribute\r
334 );\r
335 }\r
336 \r
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
352 // Allocate destination buffer, extra one page for adjustment \r
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
380 \r
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
389 SectionType, \r
390 DstBuffer, \r
391 DstBufferSize, \r
392 OutputBuffer \r
393 );\r
394 } \r
395 }\r
396\r
397 //\r
398 // Size is 24 bits wide so mask upper 8 bits. \r
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
408 \r
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
441 // Size is 24 bits wide so mask upper 8 bits. \r
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
450 SectionType, \r
451 Section, \r
452 FileSize, \r
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
506 \r
507\r
508 Hob.Raw = GetHobList ();\r
509 if (Hob.Raw == NULL) {\r
510 return EFI_NOT_FOUND;\r
511 }\r
512 \r
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
524 \r
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
532 \r
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
549EFIAPI \r
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
579 \r
580 @retval EFI_INVALID_PARAMETER If FileHandle does not\r
581 represent a valid file.\r
582 \r
583 @retval EFI_INVALID_PARAMETER If FileInfo is NULL.\r
584 \r
585**/\r
586EFI_STATUS\r
587EFIAPI \r
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
617 // Get FileState which is the highest bit of the State \r
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
624 break; \r
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
648 \r
649 @retval EFI_INVALID_PARAMETER If FileHandle does not\r
650 represent a valid file.\r
651 \r
652 @retval EFI_INVALID_PARAMETER If FileInfo is NULL.\r
653\r
654**/\r
655EFI_STATUS\r
656EFIAPI \r
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
668 \r
669 //\r
670 // VolumeHandle may not align at 8 byte, \r
671 // but FvLength is UINT64 type, which requires FvHeader align at least 8 byte. \r
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
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
701 \r
702 @retval EFI_NOT_FOUND FV image can't be found.\r
703 @retval EFI_SUCCESS Successfully found FileType\r
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
737 \r
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
746 @param FileHandle File handle of a Fv type file.\r
747\r
748\r
749 @retval EFI_NOT_FOUND FV image can't be found.\r
750 @retval EFI_SUCCESS Successfully to process it.\r
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
791 \r
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
798 \r
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
806 \r
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
827 \r
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