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