]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Pei/FwVol/FwVol.c
Update comments on setting >= 8 bytes Fv Alignment.
[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 // Post a call-back for the FvInfoPPI services to expose
286 // additional Fvs to PeiCore.
287 //
288 Status = PeiServicesNotifyPpi (&mNotifyOnFvInfoList);
289 ASSERT_EFI_ERROR (Status);
290
291 }
292
293 /**
294 Process Firmware Volum Information once FvInfoPPI install.
295 The FV Info will be registered into PeiCore private data structure.
296 And search the inside FV image, if found, the new FV INFO PPI will be installed.
297
298 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
299 @param NotifyDescriptor Address of the notification descriptor data structure.
300 @param Ppi Address of the PPI that was installed.
301
302 @retval EFI_SUCCESS The FV Info is registered into PeiCore private data structure.
303 @return if not EFI_SUCESS, fail to verify FV.
304
305 **/
306 EFI_STATUS
307 EFIAPI
308 FirmwareVolmeInfoPpiNotifyCallback (
309 IN EFI_PEI_SERVICES **PeiServices,
310 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
311 IN VOID *Ppi
312 )
313 {
314 UINT8 FvCount;
315 EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *Fv;
316 PEI_CORE_INSTANCE *PrivateData;
317 EFI_PEI_FILE_HANDLE FileHandle;
318 VOID *DepexData;
319 UINT32 AuthenticationStatus;
320 EFI_STATUS Status;
321
322 FileHandle = NULL;
323 DepexData = NULL;
324 Status = EFI_SUCCESS;
325 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
326
327 if (PrivateData->FvCount >= FixedPcdGet32 (PcdPeiCoreMaxFvSupported)) {
328 DEBUG ((EFI_D_ERROR, "The number of Fv Images (%d) exceed the max supported FVs (%d) in Pei", PrivateData->FvCount + 1, FixedPcdGet32 (PcdPeiCoreMaxFvSupported)));
329 DEBUG ((EFI_D_ERROR, "PcdPeiCoreMaxFvSupported value need be reconfigurated in DSC"));
330 ASSERT (FALSE);
331 }
332
333 Fv = (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *)Ppi;
334
335 //
336 // Only add FileSystem2 Fv to Fv list
337 //
338 if (CompareGuid (&Fv->FvFormat, &gEfiFirmwareFileSystem2Guid)) {
339 for (FvCount = 0; FvCount < PrivateData->FvCount; FvCount ++) {
340 if ((UINTN)PrivateData->Fv[FvCount].FvHeader == (UINTN)Fv->FvInfo) {
341 return EFI_SUCCESS;
342 }
343 }
344
345 Status = VerifyFv ((EFI_FIRMWARE_VOLUME_HEADER*)Fv->FvInfo);
346 if (EFI_ERROR(Status)) {
347 DEBUG ((EFI_D_ERROR, "Fail to verify FV which address is 0x%11p", (VOID *) Fv->FvInfo));
348 return Status;
349 }
350
351 PrivateData->Fv[PrivateData->FvCount++].FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Fv->FvInfo;
352
353 PrivateData->AllFv[PrivateData->AllFvCount++] = (EFI_PEI_FV_HANDLE)Fv->FvInfo;
354
355 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));
356 //
357 // Preprocess all FV type files in this new FileSystem2 Fv image
358 //
359 do {
360 Status = PeiFindFileEx (
361 (EFI_PEI_FV_HANDLE)Fv->FvInfo,
362 NULL,
363 EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,
364 &FileHandle,
365 NULL
366 );
367 if (!EFI_ERROR (Status)) {
368 Status = PeiFfsFindSectionData (
369 (CONST EFI_PEI_SERVICES **) PeiServices,
370 EFI_SECTION_PEI_DEPEX,
371 FileHandle,
372 (VOID **)&DepexData
373 );
374 if (!EFI_ERROR (Status)) {
375 if (!PeimDispatchReadiness (PeiServices, DepexData)) {
376 //
377 // Dependency is not satisfied.
378 //
379 continue;
380 }
381 }
382 //
383 // Process FvFile to install FvInfo ppi and build FvHob
384 //
385 ProcessFvFile ((CONST EFI_PEI_SERVICES **) PeiServices, (EFI_PEI_FV_HANDLE)Fv->FvInfo, FileHandle, &AuthenticationStatus);
386 }
387 } while (FileHandle != NULL);
388 }
389
390 return EFI_SUCCESS;
391 }
392
393 /**
394 Go through the file to search SectionType section.
395 Search within encapsulation sections (compression and GUIDed) recursively,
396 until the match section is found.
397
398 @param PeiServices - An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
399 @param SectionType - Filter to find only section of this type.
400 @param Section - From where to search.
401 @param SectionSize - The file size to search.
402 @param OutputBuffer - A pointer to the discovered section, if successful.
403 NULL if section not found
404
405 @return EFI_NOT_FOUND The match section is not found.
406 @return EFI_SUCCESS The match section is found.
407
408 **/
409 EFI_STATUS
410 PeiFfsProcessSection (
411 IN CONST EFI_PEI_SERVICES **PeiServices,
412 IN EFI_SECTION_TYPE SectionType,
413 IN EFI_COMMON_SECTION_HEADER *Section,
414 IN UINTN SectionSize,
415 OUT VOID **OutputBuffer
416 )
417 {
418 EFI_STATUS Status;
419 UINT32 SectionLength;
420 UINT32 ParsedLength;
421 EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *GuidSectionPpi;
422 EFI_PEI_DECOMPRESS_PPI *DecompressPpi;
423 VOID *PpiOutput;
424 UINTN PpiOutputSize;
425 UINTN Index;
426 UINT32 Authentication;
427 PEI_CORE_INSTANCE *PrivateData;
428
429 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
430 *OutputBuffer = NULL;
431 ParsedLength = 0;
432 Index = 0;
433 Status = EFI_NOT_FOUND;
434 PpiOutput = NULL;
435 PpiOutputSize = 0;
436 while (ParsedLength < SectionSize) {
437 if (Section->Type == SectionType) {
438 *OutputBuffer = (VOID *)(Section + 1);
439 return EFI_SUCCESS;
440 } else if ((Section->Type == EFI_SECTION_GUID_DEFINED) || (Section->Type == EFI_SECTION_COMPRESSION)) {
441 //
442 // Check the encapsulated section is extracted into the cache data.
443 //
444 for (Index = 0; Index < PrivateData->CacheSection.AllSectionCount; Index ++) {
445 if (Section == PrivateData->CacheSection.Section[Index]) {
446 PpiOutput = PrivateData->CacheSection.SectionData[Index];
447 PpiOutputSize = PrivateData->CacheSection.SectionSize[Index];
448 //
449 // Search section directly from the cache data.
450 //
451 return PeiFfsProcessSection (
452 PeiServices,
453 SectionType,
454 PpiOutput,
455 PpiOutputSize,
456 OutputBuffer
457 );
458 }
459 }
460
461 Status = EFI_NOT_FOUND;
462 if (Section->Type == EFI_SECTION_GUID_DEFINED) {
463 Status = PeiServicesLocatePpi (
464 &((EFI_GUID_DEFINED_SECTION *)Section)->SectionDefinitionGuid,
465 0,
466 NULL,
467 (VOID **) &GuidSectionPpi
468 );
469 if (!EFI_ERROR (Status)) {
470 Status = GuidSectionPpi->ExtractSection (
471 GuidSectionPpi,
472 Section,
473 &PpiOutput,
474 &PpiOutputSize,
475 &Authentication
476 );
477 }
478 } else if (Section->Type == EFI_SECTION_COMPRESSION) {
479 Status = PeiServicesLocatePpi (&gEfiPeiDecompressPpiGuid, 0, NULL, (VOID **) &DecompressPpi);
480 if (!EFI_ERROR (Status)) {
481 Status = DecompressPpi->Decompress (
482 DecompressPpi,
483 (CONST EFI_COMPRESSION_SECTION*) Section,
484 &PpiOutput,
485 &PpiOutputSize
486 );
487 }
488 }
489
490 if (!EFI_ERROR (Status)) {
491 //
492 // Update cache section data.
493 //
494 if (PrivateData->CacheSection.AllSectionCount < CACHE_SETION_MAX_NUMBER) {
495 PrivateData->CacheSection.AllSectionCount ++;
496 }
497 PrivateData->CacheSection.Section [PrivateData->CacheSection.SectionIndex] = Section;
498 PrivateData->CacheSection.SectionData [PrivateData->CacheSection.SectionIndex] = PpiOutput;
499 PrivateData->CacheSection.SectionSize [PrivateData->CacheSection.SectionIndex] = PpiOutputSize;
500 PrivateData->CacheSection.SectionIndex = (PrivateData->CacheSection.SectionIndex + 1)%CACHE_SETION_MAX_NUMBER;
501
502 return PeiFfsProcessSection (
503 PeiServices,
504 SectionType,
505 PpiOutput,
506 PpiOutputSize,
507 OutputBuffer
508 );
509 }
510 }
511
512 //
513 // Size is 24 bits wide so mask upper 8 bits.
514 // SectionLength is adjusted it is 4 byte aligned.
515 // Go to the next section
516 //
517 SectionLength = *(UINT32 *)Section->Size & 0x00FFFFFF;
518 SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
519 ASSERT (SectionLength != 0);
520 ParsedLength += SectionLength;
521 Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength);
522 }
523
524 return EFI_NOT_FOUND;
525 }
526
527
528 /**
529 Given the input file pointer, search for the first matching section in the
530 FFS volume.
531
532 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
533 @param SectionType Filter to find only sections of this type.
534 @param FileHandle Pointer to the current file to search.
535 @param SectionData A pointer to the discovered section, if successful.
536 NULL if section not found
537
538 @retval EFI_NOT_FOUND No files matching the search criteria were found
539 @retval EFI_SUCCESS Success to find section data in given file
540
541 **/
542 EFI_STATUS
543 EFIAPI
544 PeiFfsFindSectionData (
545 IN CONST EFI_PEI_SERVICES **PeiServices,
546 IN EFI_SECTION_TYPE SectionType,
547 IN EFI_PEI_FILE_HANDLE FileHandle,
548 IN OUT VOID **SectionData
549 )
550 {
551 EFI_FFS_FILE_HEADER *FfsFileHeader;
552 UINT32 FileSize;
553 EFI_COMMON_SECTION_HEADER *Section;
554
555 FfsFileHeader = (EFI_FFS_FILE_HEADER *)(FileHandle);
556
557 //
558 // Size is 24 bits wide so mask upper 8 bits.
559 // Does not include FfsFileHeader header size
560 // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned.
561 //
562 Section = (EFI_COMMON_SECTION_HEADER *)(FfsFileHeader + 1);
563 FileSize = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;
564 FileSize -= sizeof (EFI_FFS_FILE_HEADER);
565
566 return PeiFfsProcessSection (
567 PeiServices,
568 SectionType,
569 Section,
570 FileSize,
571 SectionData
572 );
573 }
574
575 /**
576 Given the input file pointer, search for the next matching file in the
577 FFS volume as defined by SearchType. The search starts from FileHeader inside
578 the Firmware Volume defined by FwVolHeader.
579
580
581 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
582 @param SearchType Filter to find only files of this type.
583 Type EFI_FV_FILETYPE_ALL causes no filtering to be done.
584 @param VolumeHandle Pointer to the FV header of the volume to search.
585 @param FileHandle Pointer to the current file from which to begin searching.
586 This pointer will be updated upon return to reflect the file found.
587 @retval EFI_NOT_FOUND No files matching the search criteria were found
588 @retval EFI_SUCCESS Success to find next file in given volume
589
590 **/
591 EFI_STATUS
592 EFIAPI
593 PeiFfsFindNextFile (
594 IN CONST EFI_PEI_SERVICES **PeiServices,
595 IN UINT8 SearchType,
596 IN EFI_PEI_FV_HANDLE VolumeHandle,
597 IN OUT EFI_PEI_FILE_HANDLE *FileHandle
598 )
599 {
600 return PeiFindFileEx (VolumeHandle, NULL, SearchType, FileHandle, NULL);
601 }
602
603
604 /**
605 Search the firmware volumes by index
606
607 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
608 @param Instance Instance of FV to find
609 @param VolumeHandle Pointer to found Volume.
610
611 @retval EFI_INVALID_PARAMETER FwVolHeader is NULL
612 @retval EFI_SUCCESS Firmware volume instance successfully found.
613
614 **/
615 EFI_STATUS
616 EFIAPI
617 PeiFvFindNextVolume (
618 IN CONST EFI_PEI_SERVICES **PeiServices,
619 IN UINTN Instance,
620 IN OUT EFI_PEI_FV_HANDLE *VolumeHandle
621 )
622 {
623 PEI_CORE_INSTANCE *Private;
624 UINTN Index;
625 BOOLEAN Match;
626 EFI_HOB_FIRMWARE_VOLUME *FvHob;
627
628 Private = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
629 if (VolumeHandle == NULL) {
630 return EFI_INVALID_PARAMETER;
631 }
632
633 //
634 // Handle Framework FvHob and Install FvInfo Ppi for it.
635 //
636 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
637 //
638 // Loop to search the wanted FirmwareVolume which supports FFS
639 //
640 FvHob = (EFI_HOB_FIRMWARE_VOLUME *)GetFirstHob (EFI_HOB_TYPE_FV);
641 while (FvHob != NULL) {
642 for (Index = 0, Match = FALSE; Index < Private->AllFvCount; Index++) {
643 if ((EFI_PEI_FV_HANDLE)(UINTN)FvHob->BaseAddress == Private->AllFv[Index]) {
644 Match = TRUE;
645 break;
646 }
647 }
648 //
649 // If Not Found, Install FvInfo Ppi for it.
650 //
651 if (!Match) {
652 PeiServicesInstallFvInfoPpi (
653 &(((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvHob->BaseAddress)->FileSystemGuid),
654 (VOID *)(UINTN)FvHob->BaseAddress,
655 (UINT32)FvHob->Length,
656 NULL,
657 NULL
658 );
659 }
660 FvHob = (EFI_HOB_FIRMWARE_VOLUME *)GetNextHob (EFI_HOB_TYPE_FV, (VOID *)((UINTN)FvHob + FvHob->Header.HobLength));
661 }
662 }
663
664 if (Instance >= Private->AllFvCount) {
665 VolumeHandle = NULL;
666 return EFI_NOT_FOUND;
667 }
668
669 *VolumeHandle = Private->AllFv[Instance];
670 return EFI_SUCCESS;
671 }
672
673
674 /**
675 Find a file within a volume by its name.
676
677 @param FileName A pointer to the name of the file to find within the firmware volume.
678 @param VolumeHandle The firmware volume to search
679 @param FileHandle Upon exit, points to the found file's handle
680 or NULL if it could not be found.
681
682 @retval EFI_SUCCESS File was found.
683 @retval EFI_NOT_FOUND File was not found.
684 @retval EFI_INVALID_PARAMETER VolumeHandle or FileHandle or FileName was NULL.
685
686 **/
687 EFI_STATUS
688 EFIAPI
689 PeiFfsFindFileByName (
690 IN CONST EFI_GUID *FileName,
691 IN EFI_PEI_FV_HANDLE VolumeHandle,
692 OUT EFI_PEI_FILE_HANDLE *FileHandle
693 )
694 {
695 EFI_STATUS Status;
696 if ((VolumeHandle == NULL) || (FileName == NULL) || (FileHandle == NULL)) {
697 return EFI_INVALID_PARAMETER;
698 }
699 Status = PeiFindFileEx (VolumeHandle, FileName, 0, FileHandle, NULL);
700 if (Status == EFI_NOT_FOUND) {
701 *FileHandle = NULL;
702 }
703 return Status;
704 }
705
706 /**
707
708 Returns information about a specific file.
709
710
711 @param FileHandle - The handle to file.
712 @param FileInfo - Pointer to the file information.
713
714 @retval EFI_INVALID_PARAMETER Invalid FileHandle or FileInfo.
715 @retval EFI_SUCCESS Success to collect file info.
716
717 **/
718 EFI_STATUS
719 EFIAPI
720 PeiFfsGetFileInfo (
721 IN EFI_PEI_FILE_HANDLE FileHandle,
722 OUT EFI_FV_FILE_INFO *FileInfo
723 )
724 {
725 UINT8 FileState;
726 UINT8 ErasePolarity;
727 EFI_FFS_FILE_HEADER *FileHeader;
728 EFI_PEI_FV_HANDLE VolumeHandle;
729
730 if ((FileHandle == NULL) || (FileInfo == NULL)) {
731 return EFI_INVALID_PARAMETER;
732 }
733
734 VolumeHandle = 0;
735 //
736 // Retrieve the FirmwareVolume which the file resides in.
737 //
738 if (!PeiFileHandleToVolume(FileHandle, &VolumeHandle)) {
739 return EFI_INVALID_PARAMETER;
740 }
741
742 if (((EFI_FIRMWARE_VOLUME_HEADER*)VolumeHandle)->Attributes & EFI_FVB2_ERASE_POLARITY) {
743 ErasePolarity = 1;
744 } else {
745 ErasePolarity = 0;
746 }
747
748 //
749 // Get FileState which is the highest bit of the State
750 //
751 FileState = GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER*)FileHandle);
752
753 switch (FileState) {
754 case EFI_FILE_DATA_VALID:
755 case EFI_FILE_MARKED_FOR_UPDATE:
756 break;
757 default:
758 return EFI_INVALID_PARAMETER;
759 }
760
761 FileHeader = (EFI_FFS_FILE_HEADER *)FileHandle;
762 CopyMem (&FileInfo->FileName, &FileHeader->Name, sizeof(EFI_GUID));
763 FileInfo->FileType = FileHeader->Type;
764 FileInfo->FileAttributes = FileHeader->Attributes;
765 FileInfo->BufferSize = ((*(UINT32 *)FileHeader->Size) & 0x00FFFFFF) - sizeof (EFI_FFS_FILE_HEADER);
766 FileInfo->Buffer = (FileHeader + 1);
767 return EFI_SUCCESS;
768 }
769
770
771 /**
772
773 Collect information of given Fv Volume.
774
775 @param VolumeHandle - The handle to Fv Volume.
776 @param VolumeInfo - The pointer to volume information.
777
778 @retval EFI_INVALID_PARAMETER VolumeInfo is NULL
779 @retval EFI_SUCCESS Success to collect fv info.
780 **/
781 EFI_STATUS
782 EFIAPI
783 PeiFfsGetVolumeInfo (
784 IN EFI_PEI_FV_HANDLE VolumeHandle,
785 OUT EFI_FV_INFO *VolumeInfo
786 )
787 {
788 EFI_FIRMWARE_VOLUME_HEADER FwVolHeader;
789 EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo;
790
791 if (VolumeInfo == NULL) {
792 return EFI_INVALID_PARAMETER;
793 }
794
795 //
796 // VolumeHandle may not align at 8 byte,
797 // but FvLength is UINT64 type, which requires FvHeader align at least 8 byte.
798 // So, Copy FvHeader into the local FvHeader structure.
799 //
800 CopyMem (&FwVolHeader, VolumeHandle, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
801 //
802 // Check Fv Image Signature
803 //
804 if (FwVolHeader.Signature != EFI_FVH_SIGNATURE) {
805 return EFI_INVALID_PARAMETER;
806 }
807 ZeroMem (VolumeInfo, sizeof (EFI_FV_INFO));
808 VolumeInfo->FvAttributes = FwVolHeader.Attributes;
809 VolumeInfo->FvStart = (VOID *) VolumeHandle;
810 VolumeInfo->FvSize = FwVolHeader.FvLength;
811 CopyMem (&VolumeInfo->FvFormat, &FwVolHeader.FileSystemGuid, sizeof(EFI_GUID));
812
813 if (FwVolHeader.ExtHeaderOffset != 0) {
814 FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER*)(((UINT8 *)VolumeHandle) + FwVolHeader.ExtHeaderOffset);
815 CopyMem (&VolumeInfo->FvName, &FwVolExHeaderInfo->FvName, sizeof(EFI_GUID));
816 }
817 return EFI_SUCCESS;
818 }
819
820 /**
821 Get Fv image from the FV type file, then install FV INFO ppi, Build FV hob.
822
823 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
824 @param ParentFvHandle Fv handle to parent Fv image that contain this Fv image.
825 @param ParentFvFileHandle File handle of a Fv type file that contain this Fv image.
826 @param AuthenticationState Pointer to attestation authentication state of image.
827
828
829 @retval EFI_NOT_FOUND FV image can't be found.
830 @retval EFI_SUCCESS Successfully to process it.
831 @retval EFI_OUT_OF_RESOURCES Can not allocate page when aligning FV image
832 @retval Others Can not find EFI_SECTION_FIRMWARE_VOLUME_IMAGE section
833
834 **/
835 EFI_STATUS
836 ProcessFvFile (
837 IN CONST EFI_PEI_SERVICES **PeiServices,
838 IN EFI_PEI_FV_HANDLE ParentFvHandle,
839 IN EFI_PEI_FILE_HANDLE ParentFvFileHandle,
840 OUT UINT32 *AuthenticationState
841 )
842 {
843 EFI_STATUS Status;
844 EFI_PEI_FV_HANDLE FvImageHandle;
845 EFI_FV_INFO FvImageInfo;
846 EFI_FV_INFO ParentFvImageInfo;
847 UINT32 FvAlignment;
848 VOID *FvBuffer;
849 EFI_PEI_HOB_POINTERS HobPtr;
850
851 FvBuffer = NULL;
852 *AuthenticationState = 0;
853
854 //
855 // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already
856 // been extracted.
857 //
858 HobPtr.Raw = GetHobList ();
859 while ((HobPtr.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobPtr.Raw)) != NULL) {
860 if (CompareGuid (&(((EFI_FFS_FILE_HEADER *)ParentFvFileHandle)->Name), &HobPtr.FirmwareVolume2->FileName)) {
861 //
862 // this FILE has been dispatched, it will not be dispatched again.
863 //
864 return EFI_SUCCESS;
865 }
866 HobPtr.Raw = GET_NEXT_HOB (HobPtr);
867 }
868
869 //
870 // Find FvImage in FvFile
871 //
872 Status = PeiFfsFindSectionData (
873 PeiServices,
874 EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
875 ParentFvFileHandle,
876 (VOID **)&FvImageHandle
877 );
878
879 if (EFI_ERROR (Status)) {
880 return Status;
881 }
882
883 //
884 // Collect Parent FvImage Info.
885 //
886 Status = PeiFfsGetVolumeInfo (ParentFvHandle, &ParentFvImageInfo);
887 ASSERT_EFI_ERROR (Status);
888
889 //
890 // Collect FvImage Info.
891 //
892 Status = PeiFfsGetVolumeInfo (FvImageHandle, &FvImageInfo);
893 ASSERT_EFI_ERROR (Status);
894
895 //
896 // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
897 //
898 FvAlignment = 1 << ((FvImageInfo.FvAttributes & EFI_FVB2_ALIGNMENT) >> 16);
899 if (FvAlignment < 8) {
900 FvAlignment = 8;
901 }
902
903 //
904 // Check FvImage
905 //
906 if ((UINTN) FvImageInfo.FvStart % FvAlignment != 0) {
907 FvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINT32) FvImageInfo.FvSize), FvAlignment);
908 if (FvBuffer == NULL) {
909 return EFI_OUT_OF_RESOURCES;
910 }
911 CopyMem (FvBuffer, FvImageInfo.FvStart, (UINTN) FvImageInfo.FvSize);
912 //
913 // Update FvImageInfo after reload FvImage to new aligned memory
914 //
915 Status = PeiFfsGetVolumeInfo ((EFI_PEI_FV_HANDLE) FvBuffer, &FvImageInfo);
916 ASSERT_EFI_ERROR (Status);
917 }
918
919 //
920 // Install FvPpi and Build FvHob
921 //
922 PeiServicesInstallFvInfoPpi (
923 NULL,
924 FvImageInfo.FvStart,
925 (UINT32) FvImageInfo.FvSize,
926 &ParentFvImageInfo.FvName,
927 &(((EFI_FFS_FILE_HEADER*)ParentFvFileHandle)->Name)
928 );
929
930 //
931 // Inform the extracted FvImage to Fv HOB consumer phase, i.e. DXE phase
932 //
933 BuildFvHob (
934 (EFI_PHYSICAL_ADDRESS) (UINTN) FvImageInfo.FvStart,
935 FvImageInfo.FvSize
936 );
937
938 //
939 // Makes the encapsulated volume show up in DXE phase to skip processing of
940 // encapsulated file again.
941 //
942 BuildFv2Hob (
943 (EFI_PHYSICAL_ADDRESS) (UINTN) FvImageInfo.FvStart,
944 FvImageInfo.FvSize,
945 &ParentFvImageInfo.FvName,
946 &(((EFI_FFS_FILE_HEADER *)ParentFvFileHandle)->Name)
947 );
948
949 return EFI_SUCCESS;
950 }
951
952