]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Pei/FwVol/FwVol.c
Update PeiCore to handle FvImage with PI FV extension header
[mirror_edk2.git] / MdeModulePkg / Core / Pei / FwVol / FwVol.c
1 /** @file
2 Pei Core Firmware File System service routines.
3
4 Copyright (c) 2006 - 2008, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "PeiMain.h"
16
17 EFI_PEI_NOTIFY_DESCRIPTOR mNotifyOnFvInfoList = {
18 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
19 &gEfiPeiFirmwareVolumeInfoPpiGuid,
20 FirmwareVolmeInfoPpiNotifyCallback
21 };
22
23
24 #define GET_OCCUPIED_SIZE(ActualSize, Alignment) \
25 ((ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)))
26
27 /**
28 Returns the file state set by the highest zero bit in the State field
29
30 @param ErasePolarity Erase Polarity as defined by EFI_FVB2_ERASE_POLARITY
31 in the Attributes field.
32 @param FfsHeader Pointer to FFS File Header.
33
34 @retval EFI_FFS_FILE_STATE File state is set by the highest none zero bit
35 in the header State field.
36 **/
37 EFI_FFS_FILE_STATE
38 GetFileState(
39 IN UINT8 ErasePolarity,
40 IN EFI_FFS_FILE_HEADER *FfsHeader
41 )
42 {
43 EFI_FFS_FILE_STATE FileState;
44 EFI_FFS_FILE_STATE HighestBit;
45
46 FileState = FfsHeader->State;
47
48 if (ErasePolarity != 0) {
49 FileState = (EFI_FFS_FILE_STATE)~FileState;
50 }
51
52 //
53 // Get file state set by its highest none zero bit.
54 //
55 HighestBit = 0x80;
56 while (HighestBit != 0 && (HighestBit & FileState) == 0) {
57 HighestBit >>= 1;
58 }
59
60 return HighestBit;
61 }
62
63 /**
64 Calculates the checksum of the header of a file.
65
66 @param FileHeader Pointer to FFS File Header.
67
68 @return Checksum of the header.
69 Zero means the header is good.
70 Non-zero means the header is bad.
71 **/
72 UINT8
73 CalculateHeaderChecksum (
74 IN EFI_FFS_FILE_HEADER *FileHeader
75 )
76 {
77 EFI_FFS_FILE_HEADER TestFileHeader;
78
79 CopyMem (&TestFileHeader, FileHeader, sizeof (EFI_FFS_FILE_HEADER));
80 //
81 // Ingore State and File field in FFS header.
82 //
83 TestFileHeader.State = 0;
84 TestFileHeader.IntegrityCheck.Checksum.File = 0;
85
86 return CalculateSum8 ((CONST UINT8 *) &TestFileHeader, sizeof (EFI_FFS_FILE_HEADER));
87 }
88
89 /**
90 Find FV handler according some FileHandle in that FV.
91
92 @param FileHandle Handle of file image
93 @param VolumeHandle Handle of the found FV, if not found, NULL will be set.
94
95 @retval TRUE The corresponding FV handler is found.
96 @retval FALSE The corresponding FV handler is not found.
97
98 **/
99 BOOLEAN
100 EFIAPI
101 PeiFileHandleToVolume (
102 IN EFI_PEI_FILE_HANDLE FileHandle,
103 OUT EFI_PEI_FV_HANDLE *VolumeHandle
104 )
105 {
106 UINTN Index;
107 PEI_CORE_INSTANCE *PrivateData;
108 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
109
110 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
111 for (Index = 0; Index < PrivateData->FvCount; Index++) {
112 FwVolHeader = PrivateData->Fv[Index].FvHeader;
113 if (((UINT64) (UINTN) FileHandle > (UINT64) (UINTN) FwVolHeader ) && \
114 ((UINT64) (UINTN) FileHandle <= ((UINT64) (UINTN) FwVolHeader + FwVolHeader->FvLength - 1))) {
115 *VolumeHandle = (EFI_PEI_FV_HANDLE)FwVolHeader;
116 return TRUE;
117 }
118 }
119 *VolumeHandle = NULL;
120 return FALSE;
121 }
122
123 /**
124 Given the input file pointer, search for the first matching file in the
125 FFS volume as defined by SearchType. The search starts from FileHeader inside
126 the Firmware Volume defined by FwVolHeader.
127 If SearchType is EFI_FV_FILETYPE_ALL, the first FFS file will return without check its file type.
128 If SearchType is PEI_CORE_INTERNAL_FFS_FILE_DISPATCH_TYPE,
129 the first PEIM, or COMBINED PEIM or FV file type FFS file will return.
130
131 @param FvHandle Pointer to the FV header of the volume to search
132 @param FileName File name
133 @param SearchType Filter to find only files of this type.
134 Type EFI_FV_FILETYPE_ALL causes no filtering to be done.
135 @param FileHandle This parameter must point to a valid FFS volume.
136 @param AprioriFile Pointer to AprioriFile image in this FV if has
137
138 @return EFI_NOT_FOUND No files matching the search criteria were found
139 @retval EFI_SUCCESS Success to search given file
140
141 **/
142 EFI_STATUS
143 PeiFindFileEx (
144 IN CONST EFI_PEI_FV_HANDLE FvHandle,
145 IN CONST EFI_GUID *FileName, OPTIONAL
146 IN EFI_FV_FILETYPE SearchType,
147 IN OUT EFI_PEI_FILE_HANDLE *FileHandle,
148 IN OUT EFI_PEI_FV_HANDLE *AprioriFile OPTIONAL
149 )
150 {
151 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
152 EFI_FFS_FILE_HEADER **FileHeader;
153 EFI_FFS_FILE_HEADER *FfsFileHeader;
154 UINT32 FileLength;
155 UINT32 FileOccupiedSize;
156 UINT32 FileOffset;
157 UINT64 FvLength;
158 UINT8 ErasePolarity;
159 UINT8 FileState;
160
161 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FvHandle;
162 FileHeader = (EFI_FFS_FILE_HEADER **)FileHandle;
163
164 FvLength = FwVolHeader->FvLength;
165 if ((FwVolHeader->Attributes & EFI_FVB2_ERASE_POLARITY) != 0) {
166 ErasePolarity = 1;
167 } else {
168 ErasePolarity = 0;
169 }
170
171 //
172 // If FileHeader is not specified (NULL) or FileName is not NULL,
173 // start with the first file in the firmware volume. Otherwise,
174 // start from the FileHeader.
175 //
176 if ((*FileHeader == NULL) || (FileName != NULL)) {
177 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FwVolHeader + FwVolHeader->HeaderLength);
178 } else {
179 //
180 // Length is 24 bits wide so mask upper 8 bits
181 // FileLength is adjusted to FileOccupiedSize as it is 8 byte aligned.
182 //
183 FileLength = *(UINT32 *)(*FileHeader)->Size & 0x00FFFFFF;
184 FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);
185 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)*FileHeader + FileOccupiedSize);
186 }
187
188 FileOffset = (UINT32) ((UINT8 *)FfsFileHeader - (UINT8 *)FwVolHeader);
189 ASSERT (FileOffset <= 0xFFFFFFFF);
190
191 while (FileOffset < (FvLength - sizeof (EFI_FFS_FILE_HEADER))) {
192 //
193 // Get FileState which is the highest bit of the State
194 //
195 FileState = GetFileState (ErasePolarity, FfsFileHeader);
196 switch (FileState) {
197
198 case EFI_FILE_HEADER_INVALID:
199 FileOffset += sizeof(EFI_FFS_FILE_HEADER);
200 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + sizeof(EFI_FFS_FILE_HEADER));
201 break;
202
203 case EFI_FILE_DATA_VALID:
204 case EFI_FILE_MARKED_FOR_UPDATE:
205 if (CalculateHeaderChecksum (FfsFileHeader) != 0) {
206 ASSERT (FALSE);
207 *FileHeader = NULL;
208 return EFI_NOT_FOUND;
209 }
210
211 FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;
212 FileOccupiedSize = GET_OCCUPIED_SIZE(FileLength, 8);
213
214 if (FileName != NULL) {
215 if (CompareGuid (&FfsFileHeader->Name, (EFI_GUID*)FileName)) {
216 *FileHeader = FfsFileHeader;
217 return EFI_SUCCESS;
218 }
219 } else if (SearchType == PEI_CORE_INTERNAL_FFS_FILE_DISPATCH_TYPE) {
220 if ((FfsFileHeader->Type == EFI_FV_FILETYPE_PEIM) ||
221 (FfsFileHeader->Type == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER) ||
222 (FfsFileHeader->Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE)) {
223
224 *FileHeader = FfsFileHeader;
225 return EFI_SUCCESS;
226 } else if (AprioriFile != NULL) {
227 if (FfsFileHeader->Type == EFI_FV_FILETYPE_FREEFORM) {
228 if (CompareGuid (&FfsFileHeader->Name, &gPeiAprioriFileNameGuid)) {
229 *AprioriFile = FfsFileHeader;
230 }
231 }
232 }
233 } else if (((SearchType == FfsFileHeader->Type) || (SearchType == EFI_FV_FILETYPE_ALL)) &&
234 (FfsFileHeader->Type != EFI_FV_FILETYPE_FFS_PAD)) {
235 *FileHeader = FfsFileHeader;
236 return EFI_SUCCESS;
237 }
238
239 FileOffset += FileOccupiedSize;
240 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize);
241 break;
242
243 case EFI_FILE_DELETED:
244 FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;
245 FileOccupiedSize = GET_OCCUPIED_SIZE(FileLength, 8);
246 FileOffset += FileOccupiedSize;
247 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize);
248 break;
249
250 default:
251 *FileHeader = NULL;
252 return EFI_NOT_FOUND;
253 }
254 }
255
256 *FileHeader = NULL;
257 return EFI_NOT_FOUND;
258 }
259
260 /**
261 Initialize PeiCore Fv List.
262
263 @param PrivateData - Pointer to PEI_CORE_INSTANCE.
264 @param SecCoreData - Pointer to EFI_SEC_PEI_HAND_OFF.
265 **/
266 VOID
267 PeiInitializeFv (
268 IN PEI_CORE_INSTANCE *PrivateData,
269 IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData
270 )
271 {
272 EFI_STATUS Status;
273 //
274 // The BFV must be the first entry. The Core FV support is stateless
275 // The AllFV list has a single entry per FV in PEI.
276 // The Fv list only includes FV that PEIMs will be dispatched from and
277 // its File System Format is PI 1.0 definition.
278 //
279 PrivateData->FvCount = 1;
280 PrivateData->Fv[0].FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase;
281
282 PrivateData->AllFvCount = 1;
283 PrivateData->AllFv[0] = (EFI_PEI_FV_HANDLE)PrivateData->Fv[0].FvHeader;
284
285
286 //
287 // Post a call-back for the FvInfoPPI services to expose
288 // additional Fvs to PeiCore.
289 //
290 Status = PeiServicesNotifyPpi (&mNotifyOnFvInfoList);
291 ASSERT_EFI_ERROR (Status);
292
293 }
294
295 /**
296 Process Firmware Volum Information once FvInfoPPI install.
297 The FV Info will be registered into PeiCore private data structure.
298 And search the inside FV image, if found, the new FV INFO PPI will be installed.
299
300 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
301 @param NotifyDescriptor Address of the notification descriptor data structure.
302 @param Ppi Address of the PPI that was installed.
303
304 @retval EFI_SUCCESS The FV Info is registered into PeiCore private data structure.
305 @return if not EFI_SUCESS, fail to verify FV.
306
307 **/
308 EFI_STATUS
309 EFIAPI
310 FirmwareVolmeInfoPpiNotifyCallback (
311 IN EFI_PEI_SERVICES **PeiServices,
312 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
313 IN VOID *Ppi
314 )
315 {
316 UINT8 FvCount;
317 EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *Fv;
318 PEI_CORE_INSTANCE *PrivateData;
319 EFI_PEI_FILE_HANDLE FileHandle;
320 VOID *DepexData;
321 UINT32 AuthenticationStatus;
322 EFI_STATUS Status;
323
324 FileHandle = NULL;
325 DepexData = NULL;
326 Status = EFI_SUCCESS;
327 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
328
329 if (PrivateData->FvCount >= FixedPcdGet32 (PcdPeiCoreMaxFvSupported)) {
330 DEBUG ((EFI_D_ERROR, "The number of Fv Images (%d) exceed the max supported FVs (%d) in Pei", PrivateData->FvCount + 1, FixedPcdGet32 (PcdPeiCoreMaxFvSupported)));
331 DEBUG ((EFI_D_ERROR, "PcdPeiCoreMaxFvSupported value need be reconfigurated in DSC"));
332 ASSERT (FALSE);
333 }
334
335 Fv = (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *)Ppi;
336
337 //
338 // Only add FileSystem2 Fv to Fv list
339 //
340 if (CompareGuid (&Fv->FvFormat, &gEfiFirmwareFileSystem2Guid)) {
341 for (FvCount = 0; FvCount < PrivateData->FvCount; FvCount ++) {
342 if ((UINTN)PrivateData->Fv[FvCount].FvHeader == (UINTN)Fv->FvInfo) {
343 return EFI_SUCCESS;
344 }
345 }
346
347 Status = VerifyFv ((EFI_FIRMWARE_VOLUME_HEADER*)Fv->FvInfo);
348 if (EFI_ERROR(Status)) {
349 DEBUG ((EFI_D_ERROR, "Fail to verify FV which address is 0x%11p", (VOID *) Fv->FvInfo));
350 return Status;
351 }
352
353 PrivateData->Fv[PrivateData->FvCount++].FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Fv->FvInfo;
354
355 PrivateData->AllFv[PrivateData->AllFvCount++] = (EFI_PEI_FV_HANDLE)Fv->FvInfo;
356
357 DEBUG ((EFI_D_INFO, "The %dth FvImage start address is 0x%11p and size is 0x%08x\n", (UINT32)PrivateData->AllFvCount, (VOID *) Fv->FvInfo, Fv->FvInfoSize));
358 //
359 // Preprocess all FV type files in this new FileSystem2 Fv image
360 //
361 do {
362 Status = PeiFindFileEx (
363 (EFI_PEI_FV_HANDLE)Fv->FvInfo,
364 NULL,
365 EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,
366 &FileHandle,
367 NULL
368 );
369 if (!EFI_ERROR (Status)) {
370 Status = PeiFfsFindSectionData (
371 (CONST EFI_PEI_SERVICES **) PeiServices,
372 EFI_SECTION_PEI_DEPEX,
373 FileHandle,
374 (VOID **)&DepexData
375 );
376 if (!EFI_ERROR (Status)) {
377 if (!PeimDispatchReadiness (PeiServices, DepexData)) {
378 //
379 // Dependency is not satisfied.
380 //
381 continue;
382 }
383 }
384 //
385 // Process FvFile to install FvInfo ppi and build FvHob
386 //
387 ProcessFvFile ((CONST EFI_PEI_SERVICES **) PeiServices, (EFI_PEI_FV_HANDLE)Fv->FvInfo, FileHandle, &AuthenticationStatus);
388 }
389 } while (FileHandle != NULL);
390 }
391
392 return EFI_SUCCESS;
393 }
394
395 /**
396 Go through the file to search SectionType section.
397 Search within encapsulation sections (compression and GUIDed) recursively,
398 until the match section is found.
399
400 @param PeiServices - An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
401 @param SectionType - Filter to find only section of this type.
402 @param Section - From where to search.
403 @param SectionSize - The file size to search.
404 @param OutputBuffer - A pointer to the discovered section, if successful.
405 NULL if section not found
406
407 @return EFI_NOT_FOUND The match section is not found.
408 @return EFI_SUCCESS The match section is found.
409
410 **/
411 EFI_STATUS
412 PeiFfsProcessSection (
413 IN CONST EFI_PEI_SERVICES **PeiServices,
414 IN EFI_SECTION_TYPE SectionType,
415 IN EFI_COMMON_SECTION_HEADER *Section,
416 IN UINTN SectionSize,
417 OUT VOID **OutputBuffer
418 )
419 {
420 EFI_STATUS Status;
421 UINT32 SectionLength;
422 UINT32 ParsedLength;
423 EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *GuidSectionPpi;
424 EFI_PEI_DECOMPRESS_PPI *DecompressPpi;
425 VOID *PpiOutput;
426 UINTN PpiOutputSize;
427 UINTN Index;
428 UINT32 Authentication;
429 PEI_CORE_INSTANCE *PrivateData;
430
431 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
432 *OutputBuffer = NULL;
433 ParsedLength = 0;
434 Index = 0;
435 Status = EFI_NOT_FOUND;
436 PpiOutput = NULL;
437 PpiOutputSize = 0;
438 while (ParsedLength < SectionSize) {
439 if (Section->Type == SectionType) {
440 *OutputBuffer = (VOID *)(Section + 1);
441 return EFI_SUCCESS;
442 } else if ((Section->Type == EFI_SECTION_GUID_DEFINED) || (Section->Type == EFI_SECTION_COMPRESSION)) {
443 //
444 // Check the encapsulated section is extracted into the cache data.
445 //
446 for (Index = 0; Index < PrivateData->CacheSection.AllSectionCount; Index ++) {
447 if (Section == PrivateData->CacheSection.Section[Index]) {
448 PpiOutput = PrivateData->CacheSection.SectionData[Index];
449 PpiOutputSize = PrivateData->CacheSection.SectionSize[Index];
450 //
451 // Search section directly from the cache data.
452 //
453 return PeiFfsProcessSection (
454 PeiServices,
455 SectionType,
456 PpiOutput,
457 PpiOutputSize,
458 OutputBuffer
459 );
460 }
461 }
462
463 Status = EFI_NOT_FOUND;
464 if (Section->Type == EFI_SECTION_GUID_DEFINED) {
465 Status = PeiServicesLocatePpi (
466 &((EFI_GUID_DEFINED_SECTION *)Section)->SectionDefinitionGuid,
467 0,
468 NULL,
469 (VOID **) &GuidSectionPpi
470 );
471 if (!EFI_ERROR (Status)) {
472 Status = GuidSectionPpi->ExtractSection (
473 GuidSectionPpi,
474 Section,
475 &PpiOutput,
476 &PpiOutputSize,
477 &Authentication
478 );
479 }
480 } else if (Section->Type == EFI_SECTION_COMPRESSION) {
481 Status = PeiServicesLocatePpi (&gEfiPeiDecompressPpiGuid, 0, NULL, (VOID **) &DecompressPpi);
482 if (!EFI_ERROR (Status)) {
483 Status = DecompressPpi->Decompress (
484 DecompressPpi,
485 (CONST EFI_COMPRESSION_SECTION*) Section,
486 &PpiOutput,
487 &PpiOutputSize
488 );
489 }
490 }
491
492 if (!EFI_ERROR (Status)) {
493 //
494 // Update cache section data.
495 //
496 if (PrivateData->CacheSection.AllSectionCount < CACHE_SETION_MAX_NUMBER) {
497 PrivateData->CacheSection.AllSectionCount ++;
498 }
499 PrivateData->CacheSection.Section [PrivateData->CacheSection.SectionIndex] = Section;
500 PrivateData->CacheSection.SectionData [PrivateData->CacheSection.SectionIndex] = PpiOutput;
501 PrivateData->CacheSection.SectionSize [PrivateData->CacheSection.SectionIndex] = PpiOutputSize;
502 PrivateData->CacheSection.SectionIndex = (PrivateData->CacheSection.SectionIndex + 1)%CACHE_SETION_MAX_NUMBER;
503
504 return PeiFfsProcessSection (
505 PeiServices,
506 SectionType,
507 PpiOutput,
508 PpiOutputSize,
509 OutputBuffer
510 );
511 }
512 }
513
514 //
515 // Size is 24 bits wide so mask upper 8 bits.
516 // SectionLength is adjusted it is 4 byte aligned.
517 // Go to the next section
518 //
519 SectionLength = *(UINT32 *)Section->Size & 0x00FFFFFF;
520 SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
521 ASSERT (SectionLength != 0);
522 ParsedLength += SectionLength;
523 Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength);
524 }
525
526 return EFI_NOT_FOUND;
527 }
528
529
530 /**
531 Given the input file pointer, search for the first matching section in the
532 FFS volume.
533
534 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
535 @param SectionType Filter to find only sections of this type.
536 @param FileHandle Pointer to the current file to search.
537 @param SectionData A pointer to the discovered section, if successful.
538 NULL if section not found
539
540 @retval EFI_NOT_FOUND No files matching the search criteria were found
541 @retval EFI_SUCCESS Success to find section data in given file
542
543 **/
544 EFI_STATUS
545 EFIAPI
546 PeiFfsFindSectionData (
547 IN CONST EFI_PEI_SERVICES **PeiServices,
548 IN EFI_SECTION_TYPE SectionType,
549 IN EFI_PEI_FILE_HANDLE FileHandle,
550 IN OUT VOID **SectionData
551 )
552 {
553 EFI_FFS_FILE_HEADER *FfsFileHeader;
554 UINT32 FileSize;
555 EFI_COMMON_SECTION_HEADER *Section;
556
557 FfsFileHeader = (EFI_FFS_FILE_HEADER *)(FileHandle);
558
559 //
560 // Size is 24 bits wide so mask upper 8 bits.
561 // Does not include FfsFileHeader header size
562 // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned.
563 //
564 Section = (EFI_COMMON_SECTION_HEADER *)(FfsFileHeader + 1);
565 FileSize = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;
566 FileSize -= sizeof (EFI_FFS_FILE_HEADER);
567
568 return PeiFfsProcessSection (
569 PeiServices,
570 SectionType,
571 Section,
572 FileSize,
573 SectionData
574 );
575 }
576
577 /**
578 Given the input file pointer, search for the next matching file in the
579 FFS volume as defined by SearchType. The search starts from FileHeader inside
580 the Firmware Volume defined by FwVolHeader.
581
582
583 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
584 @param SearchType Filter to find only files of this type.
585 Type EFI_FV_FILETYPE_ALL causes no filtering to be done.
586 @param VolumeHandle Pointer to the FV header of the volume to search.
587 @param FileHandle Pointer to the current file from which to begin searching.
588 This pointer will be updated upon return to reflect the file found.
589 @retval EFI_NOT_FOUND No files matching the search criteria were found
590 @retval EFI_SUCCESS Success to find next file in given volume
591
592 **/
593 EFI_STATUS
594 EFIAPI
595 PeiFfsFindNextFile (
596 IN CONST EFI_PEI_SERVICES **PeiServices,
597 IN UINT8 SearchType,
598 IN EFI_PEI_FV_HANDLE VolumeHandle,
599 IN OUT EFI_PEI_FILE_HANDLE *FileHandle
600 )
601 {
602 return PeiFindFileEx (VolumeHandle, NULL, SearchType, FileHandle, NULL);
603 }
604
605
606 /**
607 Search the firmware volumes by index
608
609 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
610 @param Instance Instance of FV to find
611 @param VolumeHandle Pointer to found Volume.
612
613 @retval EFI_INVALID_PARAMETER FwVolHeader is NULL
614 @retval EFI_SUCCESS Firmware volume instance successfully found.
615
616 **/
617 EFI_STATUS
618 EFIAPI
619 PeiFvFindNextVolume (
620 IN CONST EFI_PEI_SERVICES **PeiServices,
621 IN UINTN Instance,
622 IN OUT EFI_PEI_FV_HANDLE *VolumeHandle
623 )
624 {
625 PEI_CORE_INSTANCE *Private;
626 UINTN Index;
627 BOOLEAN Match;
628 EFI_HOB_FIRMWARE_VOLUME *FvHob;
629
630 Private = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
631 if (VolumeHandle == NULL) {
632 return EFI_INVALID_PARAMETER;
633 }
634
635 //
636 // Handle Framework FvHob and Install FvInfo Ppi for it.
637 //
638 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
639 //
640 // Loop to search the wanted FirmwareVolume which supports FFS
641 //
642 FvHob = (EFI_HOB_FIRMWARE_VOLUME *)GetFirstHob (EFI_HOB_TYPE_FV);
643 while (FvHob != NULL) {
644 for (Index = 0, Match = FALSE; Index < Private->AllFvCount; Index++) {
645 if ((EFI_PEI_FV_HANDLE)(UINTN)FvHob->BaseAddress == Private->AllFv[Index]) {
646 Match = TRUE;
647 break;
648 }
649 }
650 //
651 // If Not Found, Install FvInfo Ppi for it.
652 //
653 if (!Match) {
654 PeiServicesInstallFvInfoPpi (
655 NULL,
656 (VOID *)(UINTN)FvHob->BaseAddress,
657 (UINT32)FvHob->Length,
658 NULL,
659 NULL
660 );
661 }
662 FvHob = (EFI_HOB_FIRMWARE_VOLUME *)GetNextHob (EFI_HOB_TYPE_FV, (VOID *)((UINTN)FvHob + FvHob->Header.HobLength));
663 }
664 }
665
666 if (Instance >= Private->AllFvCount) {
667 VolumeHandle = NULL;
668 return EFI_NOT_FOUND;
669 }
670
671 *VolumeHandle = Private->AllFv[Instance];
672 return EFI_SUCCESS;
673 }
674
675
676 /**
677 Find a file within a volume by its name.
678
679 @param FileName A pointer to the name of the file to find within the firmware volume.
680 @param VolumeHandle The firmware volume to search
681 @param FileHandle Upon exit, points to the found file's handle
682 or NULL if it could not be found.
683
684 @retval EFI_SUCCESS File was found.
685 @retval EFI_NOT_FOUND File was not found.
686 @retval EFI_INVALID_PARAMETER VolumeHandle or FileHandle or FileName was NULL.
687
688 **/
689 EFI_STATUS
690 EFIAPI
691 PeiFfsFindFileByName (
692 IN CONST EFI_GUID *FileName,
693 IN EFI_PEI_FV_HANDLE VolumeHandle,
694 OUT EFI_PEI_FILE_HANDLE *FileHandle
695 )
696 {
697 EFI_STATUS Status;
698 if ((VolumeHandle == NULL) || (FileName == NULL) || (FileHandle == NULL)) {
699 return EFI_INVALID_PARAMETER;
700 }
701 Status = PeiFindFileEx (VolumeHandle, FileName, 0, FileHandle, NULL);
702 if (Status == EFI_NOT_FOUND) {
703 *FileHandle = NULL;
704 }
705 return Status;
706 }
707
708 /**
709
710 Returns information about a specific file.
711
712
713 @param FileHandle - The handle to file.
714 @param FileInfo - Pointer to the file information.
715
716 @retval EFI_INVALID_PARAMETER Invalid FileHandle or FileInfo.
717 @retval EFI_SUCCESS Success to collect file info.
718
719 **/
720 EFI_STATUS
721 EFIAPI
722 PeiFfsGetFileInfo (
723 IN EFI_PEI_FILE_HANDLE FileHandle,
724 OUT EFI_FV_FILE_INFO *FileInfo
725 )
726 {
727 UINT8 FileState;
728 UINT8 ErasePolarity;
729 EFI_FFS_FILE_HEADER *FileHeader;
730 EFI_PEI_FV_HANDLE VolumeHandle;
731
732 if ((FileHandle == NULL) || (FileInfo == NULL)) {
733 return EFI_INVALID_PARAMETER;
734 }
735
736 VolumeHandle = 0;
737 //
738 // Retrieve the FirmwareVolume which the file resides in.
739 //
740 if (!PeiFileHandleToVolume(FileHandle, &VolumeHandle)) {
741 return EFI_INVALID_PARAMETER;
742 }
743
744 if (((EFI_FIRMWARE_VOLUME_HEADER*)VolumeHandle)->Attributes & EFI_FVB2_ERASE_POLARITY) {
745 ErasePolarity = 1;
746 } else {
747 ErasePolarity = 0;
748 }
749
750 //
751 // Get FileState which is the highest bit of the State
752 //
753 FileState = GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER*)FileHandle);
754
755 switch (FileState) {
756 case EFI_FILE_DATA_VALID:
757 case EFI_FILE_MARKED_FOR_UPDATE:
758 break;
759 default:
760 return EFI_INVALID_PARAMETER;
761 }
762
763 FileHeader = (EFI_FFS_FILE_HEADER *)FileHandle;
764 CopyMem (&FileInfo->FileName, &FileHeader->Name, sizeof(EFI_GUID));
765 FileInfo->FileType = FileHeader->Type;
766 FileInfo->FileAttributes = FileHeader->Attributes;
767 FileInfo->BufferSize = ((*(UINT32 *)FileHeader->Size) & 0x00FFFFFF) - sizeof (EFI_FFS_FILE_HEADER);
768 FileInfo->Buffer = (FileHeader + 1);
769 return EFI_SUCCESS;
770 }
771
772
773 /**
774
775 Collect information of given Fv Volume.
776
777 @param VolumeHandle - The handle to Fv Volume.
778 @param VolumeInfo - The pointer to volume information.
779
780 @retval EFI_INVALID_PARAMETER VolumeInfo is NULL
781 @retval EFI_SUCCESS Success to collect fv info.
782 **/
783 EFI_STATUS
784 EFIAPI
785 PeiFfsGetVolumeInfo (
786 IN EFI_PEI_FV_HANDLE VolumeHandle,
787 OUT EFI_FV_INFO *VolumeInfo
788 )
789 {
790 EFI_FIRMWARE_VOLUME_HEADER FwVolHeader;
791 EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo;
792
793 if (VolumeInfo == NULL) {
794 return EFI_INVALID_PARAMETER;
795 }
796
797 //
798 // VolumeHandle may not align at 8 byte,
799 // but FvLength is UINT64 type, which requires FvHeader align at least 8 byte.
800 // So, Copy FvHeader into the local FvHeader structure.
801 //
802 CopyMem (&FwVolHeader, VolumeHandle, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
803 //
804 // Check Fv Image Signature
805 //
806 if (FwVolHeader.Signature != EFI_FVH_SIGNATURE) {
807 return EFI_INVALID_PARAMETER;
808 }
809 ZeroMem (VolumeInfo, sizeof (EFI_FV_INFO));
810 VolumeInfo->FvAttributes = FwVolHeader.Attributes;
811 VolumeInfo->FvStart = (VOID *) VolumeHandle;
812 VolumeInfo->FvSize = FwVolHeader.FvLength;
813 CopyMem (&VolumeInfo->FvFormat, &FwVolHeader.FileSystemGuid, sizeof(EFI_GUID));
814
815 if (FwVolHeader.ExtHeaderOffset != 0) {
816 FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER*)(((UINT8 *)VolumeHandle) + FwVolHeader.ExtHeaderOffset);
817 CopyMem (&VolumeInfo->FvName, &FwVolExHeaderInfo->FvName, sizeof(EFI_GUID));
818 }
819 return EFI_SUCCESS;
820 }
821
822 /**
823 Get Fv image from the FV type file, then install FV INFO ppi, Build FV hob.
824
825 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
826 @param ParentFvHandle Fv handle to parent Fv image that contain this Fv image.
827 @param ParentFvFileHandle File handle of a Fv type file that contain this Fv image.
828 @param AuthenticationState Pointer to attestation authentication state of image.
829
830
831 @retval EFI_NOT_FOUND FV image can't be found.
832 @retval EFI_SUCCESS Successfully to process it.
833 @retval EFI_OUT_OF_RESOURCES Can not allocate page when aligning FV image
834 @retval Others Can not find EFI_SECTION_FIRMWARE_VOLUME_IMAGE section
835
836 **/
837 EFI_STATUS
838 ProcessFvFile (
839 IN CONST EFI_PEI_SERVICES **PeiServices,
840 IN EFI_PEI_FV_HANDLE ParentFvHandle,
841 IN EFI_PEI_FILE_HANDLE ParentFvFileHandle,
842 OUT UINT32 *AuthenticationState
843 )
844 {
845 EFI_STATUS Status;
846 EFI_PEI_FV_HANDLE FvImageHandle;
847 EFI_FV_INFO FvImageInfo;
848 EFI_FV_INFO ParentFvImageInfo;
849 UINT32 FvAlignment;
850 VOID *FvBuffer;
851 EFI_PEI_HOB_POINTERS HobPtr;
852
853 FvBuffer = NULL;
854 *AuthenticationState = 0;
855
856 //
857 // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already
858 // been extracted.
859 //
860 HobPtr.Raw = GetHobList ();
861 while ((HobPtr.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobPtr.Raw)) != NULL) {
862 if (CompareGuid (&(((EFI_FFS_FILE_HEADER *)ParentFvFileHandle)->Name), &HobPtr.FirmwareVolume2->FileName)) {
863 //
864 // this FILE has been dispatched, it will not be dispatched again.
865 //
866 return EFI_SUCCESS;
867 }
868 HobPtr.Raw = GET_NEXT_HOB (HobPtr);
869 }
870
871 //
872 // Find FvImage in FvFile
873 //
874 Status = PeiFfsFindSectionData (
875 PeiServices,
876 EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
877 ParentFvFileHandle,
878 (VOID **)&FvImageHandle
879 );
880
881 if (EFI_ERROR (Status)) {
882 return Status;
883 }
884
885 //
886 // Collect Parent FvImage Info.
887 //
888 Status = PeiFfsGetVolumeInfo (ParentFvHandle, &ParentFvImageInfo);
889 ASSERT_EFI_ERROR (Status);
890
891 //
892 // Collect FvImage Info.
893 //
894 Status = PeiFfsGetVolumeInfo (FvImageHandle, &FvImageInfo);
895 ASSERT_EFI_ERROR (Status);
896
897 //
898 // FvAlignment must be more than 8 bytes required by FvHeader structure.
899 //
900 FvAlignment = 1 << ((FvImageInfo.FvAttributes & EFI_FVB2_ALIGNMENT) >> 16);
901 if (FvAlignment < 8) {
902 FvAlignment = 8;
903 }
904
905 //
906 // Check FvImage
907 //
908 if ((UINTN) FvImageInfo.FvStart % FvAlignment != 0) {
909 FvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINT32) FvImageInfo.FvSize), FvAlignment);
910 if (FvBuffer == NULL) {
911 return EFI_OUT_OF_RESOURCES;
912 }
913 CopyMem (FvBuffer, FvImageInfo.FvStart, (UINTN) FvImageInfo.FvSize);
914 //
915 // Update FvImageInfo after reload FvImage to new aligned memory
916 //
917 Status = PeiFfsGetVolumeInfo ((EFI_PEI_FV_HANDLE) FvBuffer, &FvImageInfo);
918 ASSERT_EFI_ERROR (Status);
919 }
920
921 //
922 // Install FvPpi and Build FvHob
923 //
924 PeiServicesInstallFvInfoPpi (
925 NULL,
926 FvImageInfo.FvStart,
927 (UINT32) FvImageInfo.FvSize,
928 &ParentFvImageInfo.FvName,
929 &(((EFI_FFS_FILE_HEADER*)ParentFvFileHandle)->Name)
930 );
931
932 //
933 // Inform the extracted FvImage to Fv HOB consumer phase, i.e. DXE phase
934 //
935 BuildFvHob (
936 (EFI_PHYSICAL_ADDRESS) (UINTN) FvImageInfo.FvStart,
937 FvImageInfo.FvSize
938 );
939
940 //
941 // Makes the encapsulated volume show up in DXE phase to skip processing of
942 // encapsulated file again.
943 //
944 BuildFv2Hob (
945 (EFI_PHYSICAL_ADDRESS) (UINTN) FvImageInfo.FvStart,
946 FvImageInfo.FvSize,
947 &ParentFvImageInfo.FvName,
948 &(((EFI_FFS_FILE_HEADER *)ParentFvFileHandle)->Name)
949 );
950
951 return EFI_SUCCESS;
952 }
953
954