]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Pei/FwVol/FwVol.c
Searching for files starts on an 8 byte aligned boundary after the end of the Extende...
[mirror_edk2.git] / MdeModulePkg / Core / Pei / FwVol / FwVol.c
1 /** @file
2 Pei Core Firmware File System service routines.
3
4 Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
5 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 "FwVol.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 PEI_FW_VOL_INSTANCE mPeiFfs2FwVol = {
24 PEI_FW_VOL_SIGNATURE,
25 FALSE,
26 {
27 PeiFfsFvPpiProcessVolume,
28 PeiFfsFvPpiFindFileByType,
29 PeiFfsFvPpiFindFileByName,
30 PeiFfsFvPpiGetFileInfo,
31 PeiFfsFvPpiGetVolumeInfo,
32 PeiFfsFvPpiFindSectionByType
33 }
34 };
35
36 PEI_FW_VOL_INSTANCE mPeiFfs3FwVol = {
37 PEI_FW_VOL_SIGNATURE,
38 TRUE,
39 {
40 PeiFfsFvPpiProcessVolume,
41 PeiFfsFvPpiFindFileByType,
42 PeiFfsFvPpiFindFileByName,
43 PeiFfsFvPpiGetFileInfo,
44 PeiFfsFvPpiGetVolumeInfo,
45 PeiFfsFvPpiFindSectionByType
46 }
47 };
48
49 EFI_PEI_PPI_DESCRIPTOR mPeiFfs2FvPpiList = {
50 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
51 &gEfiFirmwareFileSystem2Guid,
52 &mPeiFfs2FwVol.Fv
53 };
54
55 EFI_PEI_PPI_DESCRIPTOR mPeiFfs3FvPpiList = {
56 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
57 &gEfiFirmwareFileSystem3Guid,
58 &mPeiFfs3FwVol.Fv
59 };
60
61 /**
62 Required Alignment Alignment Value in FFS Alignment Value in
63 (bytes) Attributes Field Firmware Volume Interfaces
64 1 0 0
65 16 1 4
66 128 2 7
67 512 3 9
68 1 KB 4 10
69 4 KB 5 12
70 32 KB 6 15
71 64 KB 7 16
72 **/
73 UINT8 mFvAttributes[] = {0, 4, 7, 9, 10, 12, 15, 16};
74
75 /**
76 Convert the FFS File Attributes to FV File Attributes
77
78 @param FfsAttributes The attributes of UINT8 type.
79
80 @return The attributes of EFI_FV_FILE_ATTRIBUTES
81
82 **/
83 EFI_FV_FILE_ATTRIBUTES
84 FfsAttributes2FvFileAttributes (
85 IN EFI_FFS_FILE_ATTRIBUTES FfsAttributes
86 )
87 {
88 UINT8 DataAlignment;
89 EFI_FV_FILE_ATTRIBUTES FileAttribute;
90
91 DataAlignment = (UINT8) ((FfsAttributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3);
92 ASSERT (DataAlignment < 8);
93
94 FileAttribute = (EFI_FV_FILE_ATTRIBUTES) mFvAttributes[DataAlignment];
95
96 if ((FfsAttributes & FFS_ATTRIB_FIXED) == FFS_ATTRIB_FIXED) {
97 FileAttribute |= EFI_FV_FILE_ATTRIB_FIXED;
98 }
99
100 return FileAttribute;
101 }
102
103 /**
104 Returns the file state set by the highest zero bit in the State field
105
106 @param ErasePolarity Erase Polarity as defined by EFI_FVB2_ERASE_POLARITY
107 in the Attributes field.
108 @param FfsHeader Pointer to FFS File Header.
109
110 @retval EFI_FFS_FILE_STATE File state is set by the highest none zero bit
111 in the header State field.
112 **/
113 EFI_FFS_FILE_STATE
114 GetFileState(
115 IN UINT8 ErasePolarity,
116 IN EFI_FFS_FILE_HEADER *FfsHeader
117 )
118 {
119 EFI_FFS_FILE_STATE FileState;
120 EFI_FFS_FILE_STATE HighestBit;
121
122 FileState = FfsHeader->State;
123
124 if (ErasePolarity != 0) {
125 FileState = (EFI_FFS_FILE_STATE)~FileState;
126 }
127
128 //
129 // Get file state set by its highest none zero bit.
130 //
131 HighestBit = 0x80;
132 while (HighestBit != 0 && (HighestBit & FileState) == 0) {
133 HighestBit >>= 1;
134 }
135
136 return HighestBit;
137 }
138
139 /**
140 Calculates the checksum of the header of a file.
141
142 @param FileHeader Pointer to FFS File Header.
143
144 @return Checksum of the header.
145 Zero means the header is good.
146 Non-zero means the header is bad.
147 **/
148 UINT8
149 CalculateHeaderChecksum (
150 IN EFI_FFS_FILE_HEADER *FileHeader
151 )
152 {
153 EFI_FFS_FILE_HEADER2 TestFileHeader;
154
155 if (IS_FFS_FILE2 (FileHeader)) {
156 CopyMem (&TestFileHeader, FileHeader, sizeof (EFI_FFS_FILE_HEADER2));
157 //
158 // Ingore State and File field in FFS header.
159 //
160 TestFileHeader.State = 0;
161 TestFileHeader.IntegrityCheck.Checksum.File = 0;
162
163 return CalculateSum8 ((CONST UINT8 *) &TestFileHeader, sizeof (EFI_FFS_FILE_HEADER2));
164 } else {
165 CopyMem (&TestFileHeader, FileHeader, sizeof (EFI_FFS_FILE_HEADER));
166 //
167 // Ingore State and File field in FFS header.
168 //
169 TestFileHeader.State = 0;
170 TestFileHeader.IntegrityCheck.Checksum.File = 0;
171
172 return CalculateSum8 ((CONST UINT8 *) &TestFileHeader, sizeof (EFI_FFS_FILE_HEADER));
173 }
174 }
175
176 /**
177 Find FV handler according to FileHandle in that FV.
178
179 @param FileHandle Handle of file image
180
181 @return Pointer to instance of PEI_CORE_FV_HANDLE.
182 **/
183 PEI_CORE_FV_HANDLE*
184 FileHandleToVolume (
185 IN EFI_PEI_FILE_HANDLE FileHandle
186 )
187 {
188 UINTN Index;
189 PEI_CORE_INSTANCE *PrivateData;
190 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
191
192 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
193
194 for (Index = 0; Index < PrivateData->FvCount; Index++) {
195 FwVolHeader = PrivateData->Fv[Index].FvHeader;
196 if (((UINT64) (UINTN) FileHandle > (UINT64) (UINTN) FwVolHeader ) && \
197 ((UINT64) (UINTN) FileHandle <= ((UINT64) (UINTN) FwVolHeader + FwVolHeader->FvLength - 1))) {
198 return &PrivateData->Fv[Index];
199 }
200 }
201 return NULL;
202 }
203
204 /**
205 Given the input file pointer, search for the first matching file in the
206 FFS volume as defined by SearchType. The search starts from FileHeader inside
207 the Firmware Volume defined by FwVolHeader.
208 If SearchType is EFI_FV_FILETYPE_ALL, the first FFS file will return without check its file type.
209 If SearchType is PEI_CORE_INTERNAL_FFS_FILE_DISPATCH_TYPE,
210 the first PEIM, or COMBINED PEIM or FV file type FFS file will return.
211
212 @param FvHandle Pointer to the FV header of the volume to search
213 @param FileName File name
214 @param SearchType Filter to find only files of this type.
215 Type EFI_FV_FILETYPE_ALL causes no filtering to be done.
216 @param FileHandle This parameter must point to a valid FFS volume.
217 @param AprioriFile Pointer to AprioriFile image in this FV if has
218
219 @return EFI_NOT_FOUND No files matching the search criteria were found
220 @retval EFI_SUCCESS Success to search given file
221
222 **/
223 EFI_STATUS
224 FindFileEx (
225 IN CONST EFI_PEI_FV_HANDLE FvHandle,
226 IN CONST EFI_GUID *FileName, OPTIONAL
227 IN EFI_FV_FILETYPE SearchType,
228 IN OUT EFI_PEI_FILE_HANDLE *FileHandle,
229 IN OUT EFI_PEI_FV_HANDLE *AprioriFile OPTIONAL
230 )
231 {
232 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
233 EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExtHeader;
234 EFI_FFS_FILE_HEADER **FileHeader;
235 EFI_FFS_FILE_HEADER *FfsFileHeader;
236 UINT32 FileLength;
237 UINT32 FileOccupiedSize;
238 UINT32 FileOffset;
239 UINT64 FvLength;
240 UINT8 ErasePolarity;
241 UINT8 FileState;
242 UINT8 DataCheckSum;
243 BOOLEAN IsFfs3Fv;
244
245 //
246 // Convert the handle of FV to FV header for memory-mapped firmware volume
247 //
248 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FvHandle;
249 FileHeader = (EFI_FFS_FILE_HEADER **)FileHandle;
250
251 IsFfs3Fv = CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid);
252
253 FvLength = FwVolHeader->FvLength;
254 if ((FwVolHeader->Attributes & EFI_FVB2_ERASE_POLARITY) != 0) {
255 ErasePolarity = 1;
256 } else {
257 ErasePolarity = 0;
258 }
259
260 //
261 // If FileHeader is not specified (NULL) or FileName is not NULL,
262 // start with the first file in the firmware volume. Otherwise,
263 // start from the FileHeader.
264 //
265 if ((*FileHeader == NULL) || (FileName != NULL)) {
266 if (FwVolHeader->ExtHeaderOffset != 0) {
267 //
268 // Searching for files starts on an 8 byte aligned boundary after the end of the Extended Header if it exists.
269 //
270 FwVolExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) ((UINT8 *) FwVolHeader + FwVolHeader->ExtHeaderOffset);
271 FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FwVolExtHeader + FwVolExtHeader->ExtHeaderSize);
272 FfsFileHeader = (EFI_FFS_FILE_HEADER *) ALIGN_POINTER (FfsFileHeader, 8);
273 } else {
274 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *) FwVolHeader + FwVolHeader->HeaderLength);
275 }
276 } else {
277 if (IS_FFS_FILE2 (*FileHeader)) {
278 if (!IsFfs3Fv) {
279 DEBUG ((EFI_D_ERROR, "It is a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &(*FileHeader)->Name));
280 }
281 FileLength = FFS_FILE2_SIZE (*FileHeader);
282 ASSERT (FileLength > 0x00FFFFFF);
283 } else {
284 FileLength = FFS_FILE_SIZE (*FileHeader);
285 }
286 //
287 // FileLength is adjusted to FileOccupiedSize as it is 8 byte aligned.
288 //
289 FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);
290 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)*FileHeader + FileOccupiedSize);
291 }
292
293 FileOffset = (UINT32) ((UINT8 *)FfsFileHeader - (UINT8 *)FwVolHeader);
294 ASSERT (FileOffset <= 0xFFFFFFFF);
295
296 while (FileOffset < (FvLength - sizeof (EFI_FFS_FILE_HEADER))) {
297 //
298 // Get FileState which is the highest bit of the State
299 //
300 FileState = GetFileState (ErasePolarity, FfsFileHeader);
301 switch (FileState) {
302
303 case EFI_FILE_HEADER_CONSTRUCTION:
304 case EFI_FILE_HEADER_INVALID:
305 if (IS_FFS_FILE2 (FfsFileHeader)) {
306 if (!IsFfs3Fv) {
307 DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsFileHeader->Name));
308 }
309 FileOffset += sizeof (EFI_FFS_FILE_HEADER2);
310 FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER2));
311 } else {
312 FileOffset += sizeof (EFI_FFS_FILE_HEADER);
313 FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER));
314 }
315 break;
316
317 case EFI_FILE_DATA_VALID:
318 case EFI_FILE_MARKED_FOR_UPDATE:
319 if (CalculateHeaderChecksum (FfsFileHeader) != 0) {
320 ASSERT (FALSE);
321 *FileHeader = NULL;
322 return EFI_NOT_FOUND;
323 }
324
325 if (IS_FFS_FILE2 (FfsFileHeader)) {
326 FileLength = FFS_FILE2_SIZE (FfsFileHeader);
327 ASSERT (FileLength > 0x00FFFFFF);
328 FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);
329 if (!IsFfs3Fv) {
330 DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsFileHeader->Name));
331 FileOffset += FileOccupiedSize;
332 FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsFileHeader + FileOccupiedSize);
333 break;
334 }
335 } else {
336 FileLength = FFS_FILE_SIZE (FfsFileHeader);
337 FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);
338 }
339
340 DataCheckSum = FFS_FIXED_CHECKSUM;
341 if ((FfsFileHeader->Attributes & FFS_ATTRIB_CHECKSUM) == FFS_ATTRIB_CHECKSUM) {
342 if (IS_FFS_FILE2 (FfsFileHeader)) {
343 DataCheckSum = CalculateCheckSum8 ((CONST UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER2), FileLength - sizeof(EFI_FFS_FILE_HEADER2));
344 } else {
345 DataCheckSum = CalculateCheckSum8 ((CONST UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER), FileLength - sizeof(EFI_FFS_FILE_HEADER));
346 }
347 }
348 if (FfsFileHeader->IntegrityCheck.Checksum.File != DataCheckSum) {
349 ASSERT (FALSE);
350 *FileHeader = NULL;
351 return EFI_NOT_FOUND;
352 }
353
354 if (FileName != NULL) {
355 if (CompareGuid (&FfsFileHeader->Name, (EFI_GUID*)FileName)) {
356 *FileHeader = FfsFileHeader;
357 return EFI_SUCCESS;
358 }
359 } else if (SearchType == PEI_CORE_INTERNAL_FFS_FILE_DISPATCH_TYPE) {
360 if ((FfsFileHeader->Type == EFI_FV_FILETYPE_PEIM) ||
361 (FfsFileHeader->Type == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER) ||
362 (FfsFileHeader->Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE)) {
363
364 *FileHeader = FfsFileHeader;
365 return EFI_SUCCESS;
366 } else if (AprioriFile != NULL) {
367 if (FfsFileHeader->Type == EFI_FV_FILETYPE_FREEFORM) {
368 if (CompareGuid (&FfsFileHeader->Name, &gPeiAprioriFileNameGuid)) {
369 *AprioriFile = FfsFileHeader;
370 }
371 }
372 }
373 } else if (((SearchType == FfsFileHeader->Type) || (SearchType == EFI_FV_FILETYPE_ALL)) &&
374 (FfsFileHeader->Type != EFI_FV_FILETYPE_FFS_PAD)) {
375 *FileHeader = FfsFileHeader;
376 return EFI_SUCCESS;
377 }
378
379 FileOffset += FileOccupiedSize;
380 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize);
381 break;
382
383 case EFI_FILE_DELETED:
384 if (IS_FFS_FILE2 (FfsFileHeader)) {
385 if (!IsFfs3Fv) {
386 DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsFileHeader->Name));
387 }
388 FileLength = FFS_FILE2_SIZE (FfsFileHeader);
389 ASSERT (FileLength > 0x00FFFFFF);
390 } else {
391 FileLength = FFS_FILE_SIZE (FfsFileHeader);
392 }
393 FileOccupiedSize = GET_OCCUPIED_SIZE(FileLength, 8);
394 FileOffset += FileOccupiedSize;
395 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize);
396 break;
397
398 default:
399 *FileHeader = NULL;
400 return EFI_NOT_FOUND;
401 }
402 }
403
404 *FileHeader = NULL;
405 return EFI_NOT_FOUND;
406 }
407
408 /**
409 Initialize PeiCore Fv List.
410
411 @param PrivateData - Pointer to PEI_CORE_INSTANCE.
412 @param SecCoreData - Pointer to EFI_SEC_PEI_HAND_OFF.
413 **/
414 VOID
415 PeiInitializeFv (
416 IN PEI_CORE_INSTANCE *PrivateData,
417 IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData
418 )
419 {
420 EFI_STATUS Status;
421 EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
422 EFI_PEI_FV_HANDLE FvHandle;
423 EFI_FIRMWARE_VOLUME_HEADER *BfvHeader;
424
425 //
426 // Install FV_PPI for FFS2 file system.
427 //
428 PeiServicesInstallPpi (&mPeiFfs2FvPpiList);
429
430 //
431 // Install FV_PPI for FFS3 file system.
432 //
433 PeiServicesInstallPpi (&mPeiFfs3FvPpiList);
434
435 BfvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase;
436
437 //
438 // The FV_PPI in BFV's format should be installed.
439 //
440 Status = PeiServicesLocatePpi (
441 &BfvHeader->FileSystemGuid,
442 0,
443 NULL,
444 (VOID**)&FvPpi
445 );
446 ASSERT_EFI_ERROR (Status);
447
448 //
449 // Get handle of BFV
450 //
451 FvPpi->ProcessVolume (
452 FvPpi,
453 SecCoreData->BootFirmwareVolumeBase,
454 (UINTN)BfvHeader->FvLength,
455 &FvHandle
456 );
457
458 //
459 // Update internal PEI_CORE_FV array.
460 //
461 PrivateData->Fv[PrivateData->FvCount].FvHeader = BfvHeader;
462 PrivateData->Fv[PrivateData->FvCount].FvPpi = FvPpi;
463 PrivateData->Fv[PrivateData->FvCount].FvHandle = FvHandle;
464 DEBUG ((
465 EFI_D_INFO,
466 "The %dth FV start address is 0x%11p, size is 0x%08x, handle is 0x%p\n",
467 (UINT32) PrivateData->FvCount,
468 (VOID *) BfvHeader,
469 BfvHeader->FvLength,
470 FvHandle
471 ));
472 PrivateData->FvCount ++;
473
474 //
475 // Post a call-back for the FvInfoPPI services to expose
476 // additional Fvs to PeiCore.
477 //
478 Status = PeiServicesNotifyPpi (&mNotifyOnFvInfoList);
479 ASSERT_EFI_ERROR (Status);
480
481 }
482
483 /**
484 Process Firmware Volum Information once FvInfoPPI install.
485 The FV Info will be registered into PeiCore private data structure.
486 And search the inside FV image, if found, the new FV INFO PPI will be installed.
487
488 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
489 @param NotifyDescriptor Address of the notification descriptor data structure.
490 @param Ppi Address of the PPI that was installed.
491
492 @retval EFI_SUCCESS The FV Info is registered into PeiCore private data structure.
493 @return if not EFI_SUCESS, fail to verify FV.
494
495 **/
496 EFI_STATUS
497 EFIAPI
498 FirmwareVolmeInfoPpiNotifyCallback (
499 IN EFI_PEI_SERVICES **PeiServices,
500 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
501 IN VOID *Ppi
502 )
503 {
504 EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *FvInfoPpi;
505 EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
506 PEI_CORE_INSTANCE *PrivateData;
507 EFI_STATUS Status;
508 EFI_PEI_FV_HANDLE FvHandle;
509 UINTN FvIndex;
510 EFI_PEI_FILE_HANDLE FileHandle;
511 VOID *DepexData;
512
513 Status = EFI_SUCCESS;
514 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
515
516 if (PrivateData->FvCount >= FixedPcdGet32 (PcdPeiCoreMaxFvSupported)) {
517 DEBUG ((EFI_D_ERROR, "The number of Fv Images (%d) exceed the max supported FVs (%d) in Pei", PrivateData->FvCount + 1, FixedPcdGet32 (PcdPeiCoreMaxFvSupported)));
518 DEBUG ((EFI_D_ERROR, "PcdPeiCoreMaxFvSupported value need be reconfigurated in DSC"));
519 ASSERT (FALSE);
520 }
521
522 FvInfoPpi = (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *)Ppi;
523
524 //
525 // Locate the corresponding FV_PPI according to founded FV's format guid
526 //
527 Status = PeiServicesLocatePpi (
528 &FvInfoPpi->FvFormat,
529 0,
530 NULL,
531 (VOID**)&FvPpi
532 );
533 if (!EFI_ERROR (Status)) {
534 //
535 // Process new found FV and get FV handle.
536 //
537 Status = FvPpi->ProcessVolume (FvPpi, FvInfoPpi->FvInfo, FvInfoPpi->FvInfoSize, &FvHandle);
538 if (EFI_ERROR (Status)) {
539 DEBUG ((EFI_D_ERROR, "Fail to process new found FV, FV may be corrupted!\n"));
540 return Status;
541 }
542
543 //
544 // Check whether the FV has already been processed.
545 //
546 for (FvIndex = 0; FvIndex < PrivateData->FvCount; FvIndex ++) {
547 if (PrivateData->Fv[FvIndex].FvHandle == FvHandle) {
548 DEBUG ((EFI_D_INFO, "The Fv %p has already been processed!\n", FvInfoPpi->FvInfo));
549 return EFI_SUCCESS;
550 }
551 }
552
553 //
554 // Update internal PEI_CORE_FV array.
555 //
556 PrivateData->Fv[PrivateData->FvCount].FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*) FvInfoPpi->FvInfo;
557 PrivateData->Fv[PrivateData->FvCount].FvPpi = FvPpi;
558 PrivateData->Fv[PrivateData->FvCount].FvHandle = FvHandle;
559 DEBUG ((
560 EFI_D_INFO,
561 "The %dth FV start address is 0x%11p, size is 0x%08x, handle is 0x%p\n",
562 (UINT32) PrivateData->FvCount,
563 (VOID *) FvInfoPpi->FvInfo,
564 FvInfoPpi->FvInfoSize,
565 FvHandle
566 ));
567 PrivateData->FvCount ++;
568
569 //
570 // Scan and process the new discoveried FV for EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
571 //
572 FileHandle = NULL;
573 do {
574 Status = FvPpi->FindFileByType (
575 FvPpi,
576 EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,
577 FvHandle,
578 &FileHandle
579 );
580 if (!EFI_ERROR (Status)) {
581 Status = FvPpi->FindSectionByType (
582 FvPpi,
583 EFI_SECTION_PEI_DEPEX,
584 FileHandle,
585 (VOID**)&DepexData
586 );
587 if (!EFI_ERROR (Status)) {
588 if (!PeimDispatchReadiness (PeiServices, DepexData)) {
589 //
590 // Dependency is not satisfied.
591 //
592 continue;
593 }
594 }
595
596 DEBUG ((EFI_D_INFO, "Found firmware volume Image File %p in FV[%d] %p\n", FileHandle, PrivateData->FvCount - 1, FvHandle));
597 ProcessFvFile (&PrivateData->Fv[PrivateData->FvCount - 1], FileHandle);
598 }
599 } while (FileHandle != NULL);
600 } else {
601 DEBUG ((EFI_D_ERROR, "Fail to process FV %p because no corresponding EFI_FIRMWARE_VOLUME_PPI is found!\n", FvInfoPpi->FvInfo));
602
603 AddUnknownFormatFvInfo (PrivateData, &FvInfoPpi->FvFormat, FvInfoPpi->FvInfo, FvInfoPpi->FvInfoSize);
604 }
605
606 return EFI_SUCCESS;
607 }
608
609 /**
610 Go through the file to search SectionType section.
611 Search within encapsulation sections (compression and GUIDed) recursively,
612 until the match section is found.
613
614 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
615 @param SectionType Filter to find only section of this type.
616 @param Section From where to search.
617 @param SectionSize The file size to search.
618 @param OutputBuffer A pointer to the discovered section, if successful.
619 NULL if section not found
620 @param IsFfs3Fv Indicates the FV format.
621
622 @return EFI_NOT_FOUND The match section is not found.
623 @return EFI_SUCCESS The match section is found.
624
625 **/
626 EFI_STATUS
627 ProcessSection (
628 IN CONST EFI_PEI_SERVICES **PeiServices,
629 IN EFI_SECTION_TYPE SectionType,
630 IN EFI_COMMON_SECTION_HEADER *Section,
631 IN UINTN SectionSize,
632 OUT VOID **OutputBuffer,
633 IN BOOLEAN IsFfs3Fv
634 )
635 {
636 EFI_STATUS Status;
637 UINT32 SectionLength;
638 UINT32 ParsedLength;
639 EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *GuidSectionPpi;
640 EFI_PEI_DECOMPRESS_PPI *DecompressPpi;
641 VOID *PpiOutput;
642 UINTN PpiOutputSize;
643 UINTN Index;
644 UINT32 Authentication;
645 PEI_CORE_INSTANCE *PrivateData;
646
647 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
648 *OutputBuffer = NULL;
649 ParsedLength = 0;
650 Index = 0;
651 Status = EFI_NOT_FOUND;
652 PpiOutput = NULL;
653 PpiOutputSize = 0;
654 while (ParsedLength < SectionSize) {
655
656 if (IS_SECTION2 (Section)) {
657 ASSERT (SECTION2_SIZE (Section) > 0x00FFFFFF);
658 if (!IsFfs3Fv) {
659 DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted section in a non-FFS3 formatted FV.\n"));
660 SectionLength = SECTION2_SIZE (Section);
661 //
662 // SectionLength is adjusted it is 4 byte aligned.
663 // Go to the next section
664 //
665 SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
666 ASSERT (SectionLength != 0);
667 ParsedLength += SectionLength;
668 Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + SectionLength);
669 continue;
670 }
671 }
672
673 if (Section->Type == SectionType) {
674 if (IS_SECTION2 (Section)) {
675 *OutputBuffer = (VOID *)((UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER2));
676 } else {
677 *OutputBuffer = (VOID *)((UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER));
678 }
679 return EFI_SUCCESS;
680 } else if ((Section->Type == EFI_SECTION_GUID_DEFINED) || (Section->Type == EFI_SECTION_COMPRESSION)) {
681 //
682 // Check the encapsulated section is extracted into the cache data.
683 //
684 for (Index = 0; Index < PrivateData->CacheSection.AllSectionCount; Index ++) {
685 if (Section == PrivateData->CacheSection.Section[Index]) {
686 PpiOutput = PrivateData->CacheSection.SectionData[Index];
687 PpiOutputSize = PrivateData->CacheSection.SectionSize[Index];
688 //
689 // Search section directly from the cache data.
690 //
691 return ProcessSection (
692 PeiServices,
693 SectionType,
694 PpiOutput,
695 PpiOutputSize,
696 OutputBuffer,
697 IsFfs3Fv
698 );
699 }
700 }
701
702 Status = EFI_NOT_FOUND;
703 if (Section->Type == EFI_SECTION_GUID_DEFINED) {
704 if (IS_SECTION2 (Section)) {
705 Status = PeiServicesLocatePpi (
706 &((EFI_GUID_DEFINED_SECTION2 *)Section)->SectionDefinitionGuid,
707 0,
708 NULL,
709 (VOID **) &GuidSectionPpi
710 );
711 } else {
712 Status = PeiServicesLocatePpi (
713 &((EFI_GUID_DEFINED_SECTION *)Section)->SectionDefinitionGuid,
714 0,
715 NULL,
716 (VOID **) &GuidSectionPpi
717 );
718 }
719 if (!EFI_ERROR (Status)) {
720 Status = GuidSectionPpi->ExtractSection (
721 GuidSectionPpi,
722 Section,
723 &PpiOutput,
724 &PpiOutputSize,
725 &Authentication
726 );
727 }
728 } else if (Section->Type == EFI_SECTION_COMPRESSION) {
729 Status = PeiServicesLocatePpi (&gEfiPeiDecompressPpiGuid, 0, NULL, (VOID **) &DecompressPpi);
730 if (!EFI_ERROR (Status)) {
731 Status = DecompressPpi->Decompress (
732 DecompressPpi,
733 (CONST EFI_COMPRESSION_SECTION*) Section,
734 &PpiOutput,
735 &PpiOutputSize
736 );
737 }
738 }
739
740 if (!EFI_ERROR (Status)) {
741 //
742 // Update cache section data.
743 //
744 if (PrivateData->CacheSection.AllSectionCount < CACHE_SETION_MAX_NUMBER) {
745 PrivateData->CacheSection.AllSectionCount ++;
746 }
747 PrivateData->CacheSection.Section [PrivateData->CacheSection.SectionIndex] = Section;
748 PrivateData->CacheSection.SectionData [PrivateData->CacheSection.SectionIndex] = PpiOutput;
749 PrivateData->CacheSection.SectionSize [PrivateData->CacheSection.SectionIndex] = PpiOutputSize;
750 PrivateData->CacheSection.SectionIndex = (PrivateData->CacheSection.SectionIndex + 1)%CACHE_SETION_MAX_NUMBER;
751
752 return ProcessSection (
753 PeiServices,
754 SectionType,
755 PpiOutput,
756 PpiOutputSize,
757 OutputBuffer,
758 IsFfs3Fv
759 );
760 }
761 }
762
763 if (IS_SECTION2 (Section)) {
764 SectionLength = SECTION2_SIZE (Section);
765 } else {
766 SectionLength = SECTION_SIZE (Section);
767 }
768 //
769 // SectionLength is adjusted it is 4 byte aligned.
770 // Go to the next section
771 //
772 SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
773 ASSERT (SectionLength != 0);
774 ParsedLength += SectionLength;
775 Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength);
776 }
777
778 return EFI_NOT_FOUND;
779 }
780
781
782 /**
783 Searches for the next matching section within the specified file.
784
785 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
786 @param SectionType Filter to find only sections of this type.
787 @param FileHandle Pointer to the current file to search.
788 @param SectionData A pointer to the discovered section, if successful.
789 NULL if section not found
790
791 @retval EFI_NOT_FOUND The section was not found.
792 @retval EFI_SUCCESS The section was found.
793
794 **/
795 EFI_STATUS
796 EFIAPI
797 PeiFfsFindSectionData (
798 IN CONST EFI_PEI_SERVICES **PeiServices,
799 IN EFI_SECTION_TYPE SectionType,
800 IN EFI_PEI_FILE_HANDLE FileHandle,
801 OUT VOID **SectionData
802 )
803 {
804 PEI_CORE_FV_HANDLE *CoreFvHandle;
805
806 CoreFvHandle = FileHandleToVolume (FileHandle);
807 if ((CoreFvHandle == NULL) || (CoreFvHandle->FvPpi == NULL)) {
808 return EFI_NOT_FOUND;
809 }
810
811 return CoreFvHandle->FvPpi->FindSectionByType (CoreFvHandle->FvPpi, SectionType, FileHandle, SectionData);
812 }
813
814 /**
815 Searches for the next matching file in the firmware volume.
816
817 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
818 @param SearchType Filter to find only files of this type.
819 Type EFI_FV_FILETYPE_ALL causes no filtering to be done.
820 @param FvHandle Handle of firmware volume in which to search.
821 @param FileHandle On entry, points to the current handle from which to begin searching or NULL to start
822 at the beginning of the firmware volume. On exit, points the file handle of the next file
823 in the volume or NULL if there are no more files.
824
825 @retval EFI_NOT_FOUND The file was not found.
826 @retval EFI_NOT_FOUND The header checksum was not zero.
827 @retval EFI_SUCCESS The file was found.
828
829 **/
830 EFI_STATUS
831 EFIAPI
832 PeiFfsFindNextFile (
833 IN CONST EFI_PEI_SERVICES **PeiServices,
834 IN UINT8 SearchType,
835 IN EFI_PEI_FV_HANDLE FvHandle,
836 IN OUT EFI_PEI_FILE_HANDLE *FileHandle
837 )
838 {
839 PEI_CORE_FV_HANDLE *CoreFvHandle;
840
841 CoreFvHandle = FvHandleToCoreHandle (FvHandle);
842
843 //
844 // To make backward compatiblity, if can not find corresponding the handle of FV
845 // then treat FV as build-in FFS2/FFS3 format and memory mapped FV that FV handle is pointed
846 // to the address of first byte of FV.
847 //
848 if ((CoreFvHandle == NULL) && FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
849 return FindFileEx (FvHandle, NULL, SearchType, FileHandle, NULL);
850 }
851
852 if ((CoreFvHandle == NULL) || CoreFvHandle->FvPpi == NULL) {
853 return EFI_NOT_FOUND;
854 }
855
856 return CoreFvHandle->FvPpi->FindFileByType (CoreFvHandle->FvPpi, SearchType, FvHandle, FileHandle);
857 }
858
859
860 /**
861 Search the firmware volumes by index
862
863 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
864 @param Instance This instance of the firmware volume to find. The value 0 is the Boot Firmware
865 Volume (BFV).
866 @param VolumeHandle On exit, points to the next volume handle or NULL if it does not exist.
867
868 @retval EFI_INVALID_PARAMETER VolumeHandle is NULL
869 @retval EFI_NOT_FOUND The volume was not found.
870 @retval EFI_SUCCESS The volume was found.
871
872 **/
873 EFI_STATUS
874 EFIAPI
875 PeiFfsFindNextVolume (
876 IN CONST EFI_PEI_SERVICES **PeiServices,
877 IN UINTN Instance,
878 IN OUT EFI_PEI_FV_HANDLE *VolumeHandle
879 )
880 {
881 PEI_CORE_INSTANCE *Private;
882 PEI_CORE_FV_HANDLE *CoreFvHandle;
883
884 if (VolumeHandle == NULL) {
885 return EFI_INVALID_PARAMETER;
886 }
887
888 Private = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
889
890 CoreFvHandle = FindNextCoreFvHandle (Private, Instance);
891 if (CoreFvHandle == NULL) {
892 *VolumeHandle = NULL;
893 return EFI_NOT_FOUND;
894 }
895
896 *VolumeHandle = CoreFvHandle->FvHandle;
897
898 return EFI_SUCCESS;
899 }
900
901
902 /**
903 Find a file within a volume by its name.
904
905 @param FileName A pointer to the name of the file to find within the firmware volume.
906 @param VolumeHandle The firmware volume to search
907 @param FileHandle Upon exit, points to the found file's handle
908 or NULL if it could not be found.
909
910 @retval EFI_SUCCESS File was found.
911 @retval EFI_NOT_FOUND File was not found.
912 @retval EFI_INVALID_PARAMETER VolumeHandle or FileHandle or FileName was NULL.
913
914 **/
915 EFI_STATUS
916 EFIAPI
917 PeiFfsFindFileByName (
918 IN CONST EFI_GUID *FileName,
919 IN EFI_PEI_FV_HANDLE VolumeHandle,
920 OUT EFI_PEI_FILE_HANDLE *FileHandle
921 )
922 {
923 PEI_CORE_FV_HANDLE *CoreFvHandle;
924
925 if ((VolumeHandle == NULL) || (FileName == NULL) || (FileHandle == NULL)) {
926 return EFI_INVALID_PARAMETER;
927 }
928
929 CoreFvHandle = FvHandleToCoreHandle (VolumeHandle);
930 if ((CoreFvHandle == NULL) || (CoreFvHandle->FvPpi == NULL)) {
931 return EFI_NOT_FOUND;
932 }
933
934 return CoreFvHandle->FvPpi->FindFileByName (CoreFvHandle->FvPpi, FileName, &VolumeHandle, FileHandle);
935 }
936
937 /**
938 Returns information about a specific file.
939
940 @param FileHandle Handle of the file.
941 @param FileInfo Upon exit, points to the file's information.
942
943 @retval EFI_INVALID_PARAMETER If FileInfo is NULL.
944 @retval EFI_INVALID_PARAMETER If FileHandle does not represent a valid file.
945 @retval EFI_SUCCESS File information returned.
946
947 **/
948 EFI_STATUS
949 EFIAPI
950 PeiFfsGetFileInfo (
951 IN EFI_PEI_FILE_HANDLE FileHandle,
952 OUT EFI_FV_FILE_INFO *FileInfo
953 )
954 {
955 PEI_CORE_FV_HANDLE *CoreFvHandle;
956
957 if ((FileHandle == NULL) || (FileInfo == NULL)) {
958 return EFI_INVALID_PARAMETER;
959 }
960
961 //
962 // Retrieve the FirmwareVolume which the file resides in.
963 //
964 CoreFvHandle = FileHandleToVolume (FileHandle);
965 if ((CoreFvHandle == NULL) || (CoreFvHandle->FvPpi == NULL)) {
966 return EFI_INVALID_PARAMETER;
967 }
968
969 return CoreFvHandle->FvPpi->GetFileInfo (CoreFvHandle->FvPpi, FileHandle, FileInfo);
970 }
971
972
973 /**
974 Returns information about the specified volume.
975
976 This function returns information about a specific firmware
977 volume, including its name, type, attributes, starting address
978 and size.
979
980 @param VolumeHandle Handle of the volume.
981 @param VolumeInfo Upon exit, points to the volume's information.
982
983 @retval EFI_SUCCESS Volume information returned.
984 @retval EFI_INVALID_PARAMETER If VolumeHandle does not represent a valid volume.
985 @retval EFI_INVALID_PARAMETER If VolumeHandle is NULL.
986 @retval EFI_SUCCESS Information successfully returned.
987 @retval EFI_INVALID_PARAMETER The volume designated by the VolumeHandle is not available.
988
989 **/
990 EFI_STATUS
991 EFIAPI
992 PeiFfsGetVolumeInfo (
993 IN EFI_PEI_FV_HANDLE VolumeHandle,
994 OUT EFI_FV_INFO *VolumeInfo
995 )
996 {
997 PEI_CORE_FV_HANDLE *CoreHandle;
998
999 if ((VolumeInfo == NULL) || (VolumeHandle == NULL)) {
1000 return EFI_INVALID_PARAMETER;
1001 }
1002
1003 CoreHandle = FvHandleToCoreHandle (VolumeHandle);
1004
1005 if ((CoreHandle == NULL) || (CoreHandle->FvPpi == NULL)) {
1006 return EFI_INVALID_PARAMETER;
1007 }
1008
1009 return CoreHandle->FvPpi->GetVolumeInfo (CoreHandle->FvPpi, VolumeHandle, VolumeInfo);
1010 }
1011
1012 /**
1013 Get Fv image from the FV type file, then install FV INFO ppi, Build FV hob.
1014
1015 @param ParentFvCoreHandle Pointer of EFI_CORE_FV_HANDLE to parent Fv image that contain this Fv image.
1016 @param ParentFvFileHandle File handle of a Fv type file that contain this Fv image.
1017
1018 @retval EFI_NOT_FOUND FV image can't be found.
1019 @retval EFI_SUCCESS Successfully to process it.
1020 @retval EFI_OUT_OF_RESOURCES Can not allocate page when aligning FV image
1021 @retval Others Can not find EFI_SECTION_FIRMWARE_VOLUME_IMAGE section
1022
1023 **/
1024 EFI_STATUS
1025 ProcessFvFile (
1026 IN PEI_CORE_FV_HANDLE *ParentFvCoreHandle,
1027 IN EFI_PEI_FILE_HANDLE ParentFvFileHandle
1028 )
1029 {
1030 EFI_STATUS Status;
1031 EFI_FV_INFO ParentFvImageInfo;
1032 UINT32 FvAlignment;
1033 VOID *NewFvBuffer;
1034 EFI_PEI_HOB_POINTERS HobPtr;
1035 EFI_PEI_FIRMWARE_VOLUME_PPI *ParentFvPpi;
1036 EFI_PEI_FV_HANDLE ParentFvHandle;
1037 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
1038 EFI_FV_FILE_INFO FileInfo;
1039 UINT64 FvLength;
1040
1041 //
1042 // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already
1043 // been extracted.
1044 //
1045 HobPtr.Raw = GetHobList ();
1046 while ((HobPtr.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobPtr.Raw)) != NULL) {
1047 if (CompareGuid (&(((EFI_FFS_FILE_HEADER *)ParentFvFileHandle)->Name), &HobPtr.FirmwareVolume2->FileName)) {
1048 //
1049 // this FILE has been dispatched, it will not be dispatched again.
1050 //
1051 DEBUG ((EFI_D_INFO, "FV file %p has been dispatched!\r\n", ParentFvFileHandle));
1052 return EFI_SUCCESS;
1053 }
1054 HobPtr.Raw = GET_NEXT_HOB (HobPtr);
1055 }
1056
1057 ParentFvHandle = ParentFvCoreHandle->FvHandle;
1058 ParentFvPpi = ParentFvCoreHandle->FvPpi;
1059
1060 //
1061 // Find FvImage in FvFile
1062 //
1063 Status = ParentFvPpi->FindSectionByType (
1064 ParentFvPpi,
1065 EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
1066 ParentFvFileHandle,
1067 (VOID **)&FvHeader
1068 );
1069
1070 if (EFI_ERROR (Status)) {
1071 return Status;
1072 }
1073
1074 //
1075 // FvAlignment must be more than 8 bytes required by FvHeader structure.
1076 //
1077 FvAlignment = 1 << ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_ALIGNMENT) >> 16);
1078 if (FvAlignment < 8) {
1079 FvAlignment = 8;
1080 }
1081
1082 //
1083 // Check FvImage
1084 //
1085 if ((UINTN) FvHeader % FvAlignment != 0) {
1086 FvLength = ReadUnaligned64 (&FvHeader->FvLength);
1087 NewFvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINT32) FvLength), FvAlignment);
1088 if (NewFvBuffer == NULL) {
1089 return EFI_OUT_OF_RESOURCES;
1090 }
1091 CopyMem (NewFvBuffer, FvHeader, (UINTN) FvLength);
1092 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*) NewFvBuffer;
1093 }
1094
1095 Status = ParentFvPpi->GetVolumeInfo (ParentFvPpi, ParentFvHandle, &ParentFvImageInfo);
1096 ASSERT_EFI_ERROR (Status);
1097
1098 Status = ParentFvPpi->GetFileInfo (ParentFvPpi, ParentFvFileHandle, &FileInfo);
1099 ASSERT_EFI_ERROR (Status);
1100
1101 //
1102 // Install FvPpi and Build FvHob
1103 //
1104 PeiServicesInstallFvInfoPpi (
1105 &FvHeader->FileSystemGuid,
1106 (VOID**) FvHeader,
1107 (UINT32) FvHeader->FvLength,
1108 &ParentFvImageInfo.FvName,
1109 &FileInfo.FileName
1110 );
1111
1112 //
1113 // Inform the extracted FvImage to Fv HOB consumer phase, i.e. DXE phase
1114 //
1115 BuildFvHob (
1116 (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader,
1117 FvHeader->FvLength
1118 );
1119
1120 //
1121 // Makes the encapsulated volume show up in DXE phase to skip processing of
1122 // encapsulated file again.
1123 //
1124 BuildFv2Hob (
1125 (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader,
1126 FvHeader->FvLength,
1127 &ParentFvImageInfo.FvName,
1128 &FileInfo.FileName
1129 );
1130
1131 return EFI_SUCCESS;
1132 }
1133
1134 /**
1135 Process a firmware volume and create a volume handle.
1136
1137 Create a volume handle from the information in the buffer. For
1138 memory-mapped firmware volumes, Buffer and BufferSize refer to
1139 the start of the firmware volume and the firmware volume size.
1140 For non memory-mapped firmware volumes, this points to a
1141 buffer which contains the necessary information for creating
1142 the firmware volume handle. Normally, these values are derived
1143 from the EFI_FIRMWARE_VOLUME_INFO_PPI.
1144
1145
1146 @param This Points to this instance of the
1147 EFI_PEI_FIRMWARE_VOLUME_PPI.
1148 @param Buffer Points to the start of the buffer.
1149 @param BufferSize Size of the buffer.
1150 @param FvHandle Points to the returned firmware volume
1151 handle. The firmware volume handle must
1152 be unique within the system.
1153
1154 @retval EFI_SUCCESS Firmware volume handle created.
1155 @retval EFI_VOLUME_CORRUPTED Volume was corrupt.
1156
1157 **/
1158 EFI_STATUS
1159 EFIAPI
1160 PeiFfsFvPpiProcessVolume (
1161 IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
1162 IN VOID *Buffer,
1163 IN UINTN BufferSize,
1164 OUT EFI_PEI_FV_HANDLE *FvHandle
1165 )
1166 {
1167 EFI_STATUS Status;
1168
1169 ASSERT (FvHandle != NULL);
1170
1171 if (Buffer == NULL) {
1172 return EFI_VOLUME_CORRUPTED;
1173 }
1174
1175 //
1176 // The build-in EFI_PEI_FIRMWARE_VOLUME_PPI for FFS2/FFS3 support memory-mapped
1177 // FV image and the handle is pointed to Fv image's buffer.
1178 //
1179 *FvHandle = (EFI_PEI_FV_HANDLE) Buffer;
1180
1181 //
1182 // Do verify for given FV buffer.
1183 //
1184 Status = VerifyFv ((EFI_FIRMWARE_VOLUME_HEADER*) Buffer);
1185 if (EFI_ERROR(Status)) {
1186 DEBUG ((EFI_D_ERROR, "Fail to verify FV which address is 0x%11p", Buffer));
1187 return EFI_VOLUME_CORRUPTED;
1188 }
1189
1190 return EFI_SUCCESS;
1191 }
1192
1193 /**
1194 Finds the next file of the specified type.
1195
1196 This service enables PEI modules to discover additional firmware files.
1197 The FileHandle must be unique within the system.
1198
1199 @param This Points to this instance of the
1200 EFI_PEI_FIRMWARE_VOLUME_PPI.
1201 @param SearchType A filter to find only files of this type. Type
1202 EFI_FV_FILETYPE_ALL causes no filtering to be
1203 done.
1204 @param FvHandle Handle of firmware volume in which to
1205 search.
1206 @param FileHandle Points to the current handle from which to
1207 begin searching or NULL to start at the
1208 beginning of the firmware volume. Updated
1209 upon return to reflect the file found.
1210
1211 @retval EFI_SUCCESS The file was found.
1212 @retval EFI_NOT_FOUND The file was not found. FileHandle contains NULL.
1213
1214 **/
1215 EFI_STATUS
1216 EFIAPI
1217 PeiFfsFvPpiFindFileByType (
1218 IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
1219 IN EFI_FV_FILETYPE SearchType,
1220 IN EFI_PEI_FV_HANDLE FvHandle,
1221 IN OUT EFI_PEI_FILE_HANDLE *FileHandle
1222 )
1223 {
1224 return FindFileEx (FvHandle, NULL, SearchType, FileHandle, NULL);
1225 }
1226
1227 /**
1228 Find a file within a volume by its name.
1229
1230 This service searches for files with a specific name, within
1231 either the specified firmware volume or all firmware volumes.
1232
1233 @param This Points to this instance of the
1234 EFI_PEI_FIRMWARE_VOLUME_PPI.
1235 @param FileName A pointer to the name of the file to find
1236 within the firmware volume.
1237 @param FvHandle Upon entry, the pointer to the firmware
1238 volume to search or NULL if all firmware
1239 volumes should be searched. Upon exit, the
1240 actual firmware volume in which the file was
1241 found.
1242 @param FileHandle Upon exit, points to the found file's
1243 handle or NULL if it could not be found.
1244
1245 @retval EFI_SUCCESS File was found.
1246 @retval EFI_NOT_FOUND File was not found.
1247 @retval EFI_INVALID_PARAMETER FvHandle or FileHandle or
1248 FileName was NULL.
1249
1250
1251 **/
1252 EFI_STATUS
1253 EFIAPI
1254 PeiFfsFvPpiFindFileByName (
1255 IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
1256 IN CONST EFI_GUID *FileName,
1257 IN EFI_PEI_FV_HANDLE *FvHandle,
1258 OUT EFI_PEI_FILE_HANDLE *FileHandle
1259 )
1260 {
1261 EFI_STATUS Status;
1262 PEI_CORE_INSTANCE *PrivateData;
1263 UINTN Index;
1264
1265 if ((FvHandle == NULL) || (FileName == NULL) || (FileHandle == NULL)) {
1266 return EFI_INVALID_PARAMETER;
1267 }
1268
1269 if (*FvHandle != NULL) {
1270 Status = FindFileEx (*FvHandle, FileName, 0, FileHandle, NULL);
1271 if (Status == EFI_NOT_FOUND) {
1272 *FileHandle = NULL;
1273 }
1274 } else {
1275 //
1276 // If *FvHandle = NULL, so search all FV for given filename
1277 //
1278 Status = EFI_NOT_FOUND;
1279
1280 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer());
1281 for (Index = 0; Index < PrivateData->FvCount; Index ++) {
1282 //
1283 // Only search the FV which is associated with a EFI_PEI_FIRMWARE_VOLUME_PPI instance.
1284 //
1285 if (PrivateData->Fv[Index].FvPpi != NULL) {
1286 Status = FindFileEx (PrivateData->Fv[Index].FvHandle, FileName, 0, FileHandle, NULL);
1287 if (!EFI_ERROR (Status)) {
1288 *FvHandle = PrivateData->Fv[Index].FvHandle;
1289 break;
1290 }
1291 }
1292 }
1293 }
1294
1295 return Status;
1296 }
1297
1298 /**
1299 Returns information about a specific file.
1300
1301 This function returns information about a specific
1302 file, including its file name, type, attributes, starting
1303 address and size.
1304
1305 @param This Points to this instance of the
1306 EFI_PEI_FIRMWARE_VOLUME_PPI.
1307 @param FileHandle Handle of the file.
1308 @param FileInfo Upon exit, points to the file's
1309 information.
1310
1311 @retval EFI_SUCCESS File information returned.
1312 @retval EFI_INVALID_PARAMETER If FileHandle does not
1313 represent a valid file.
1314 @retval EFI_INVALID_PARAMETER If FileInfo is NULL.
1315
1316 **/
1317 EFI_STATUS
1318 EFIAPI
1319 PeiFfsFvPpiGetFileInfo (
1320 IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
1321 IN EFI_PEI_FILE_HANDLE FileHandle,
1322 OUT EFI_FV_FILE_INFO *FileInfo
1323 )
1324 {
1325 UINT8 FileState;
1326 UINT8 ErasePolarity;
1327 EFI_FFS_FILE_HEADER *FileHeader;
1328 PEI_CORE_FV_HANDLE *CoreFvHandle;
1329 PEI_FW_VOL_INSTANCE *FwVolInstance;
1330
1331 if ((FileHandle == NULL) || (FileInfo == NULL)) {
1332 return EFI_INVALID_PARAMETER;
1333 }
1334
1335 //
1336 // Retrieve the FirmwareVolume which the file resides in.
1337 //
1338 CoreFvHandle = FileHandleToVolume (FileHandle);
1339 if (CoreFvHandle == NULL) {
1340 return EFI_INVALID_PARAMETER;
1341 }
1342
1343 FwVolInstance = PEI_FW_VOL_INSTANCE_FROM_FV_THIS (This);
1344
1345 if ((CoreFvHandle->FvHeader->Attributes & EFI_FVB2_ERASE_POLARITY) != 0) {
1346 ErasePolarity = 1;
1347 } else {
1348 ErasePolarity = 0;
1349 }
1350
1351 //
1352 // Get FileState which is the highest bit of the State
1353 //
1354 FileState = GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER*)FileHandle);
1355
1356 switch (FileState) {
1357 case EFI_FILE_DATA_VALID:
1358 case EFI_FILE_MARKED_FOR_UPDATE:
1359 break;
1360 default:
1361 return EFI_INVALID_PARAMETER;
1362 }
1363
1364 FileHeader = (EFI_FFS_FILE_HEADER *)FileHandle;
1365 CopyMem (&FileInfo->FileName, &FileHeader->Name, sizeof(EFI_GUID));
1366 FileInfo->FileType = FileHeader->Type;
1367 FileInfo->FileAttributes = FfsAttributes2FvFileAttributes (FileHeader->Attributes);
1368 if ((CoreFvHandle->FvHeader->Attributes & EFI_FVB2_MEMORY_MAPPED) == EFI_FVB2_MEMORY_MAPPED) {
1369 FileInfo->FileAttributes |= EFI_FV_FILE_ATTRIB_MEMORY_MAPPED;
1370 }
1371 if (IS_FFS_FILE2 (FileHeader)) {
1372 ASSERT (FFS_FILE2_SIZE (FileHeader) > 0x00FFFFFF);
1373 if (!FwVolInstance->IsFfs3Fv) {
1374 DEBUG ((EFI_D_ERROR, "It is a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FileHeader->Name));
1375 return EFI_INVALID_PARAMETER;
1376 }
1377 FileInfo->BufferSize = FFS_FILE2_SIZE (FileHeader) - sizeof (EFI_FFS_FILE_HEADER2);
1378 FileInfo->Buffer = (UINT8 *) FileHeader + sizeof (EFI_FFS_FILE_HEADER2);
1379 } else {
1380 FileInfo->BufferSize = FFS_FILE_SIZE (FileHeader) - sizeof (EFI_FFS_FILE_HEADER);
1381 FileInfo->Buffer = (UINT8 *) FileHeader + sizeof (EFI_FFS_FILE_HEADER);
1382 }
1383 return EFI_SUCCESS;
1384 }
1385
1386 /**
1387 This function returns information about the firmware volume.
1388
1389 @param This Points to this instance of the
1390 EFI_PEI_FIRMWARE_VOLUME_PPI.
1391 @param FvHandle Handle to the firmware handle.
1392 @param VolumeInfo Points to the returned firmware volume
1393 information.
1394
1395 @retval EFI_SUCCESS Information returned successfully.
1396 @retval EFI_INVALID_PARAMETER FvHandle does not indicate a valid
1397 firmware volume or VolumeInfo is NULL.
1398
1399 **/
1400 EFI_STATUS
1401 EFIAPI
1402 PeiFfsFvPpiGetVolumeInfo (
1403 IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
1404 IN EFI_PEI_FV_HANDLE FvHandle,
1405 OUT EFI_FV_INFO *VolumeInfo
1406 )
1407 {
1408 EFI_FIRMWARE_VOLUME_HEADER FwVolHeader;
1409 EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo;
1410
1411 if ((VolumeInfo == NULL) || (FvHandle == NULL)) {
1412 return EFI_INVALID_PARAMETER;
1413 }
1414
1415 //
1416 // VolumeHandle may not align at 8 byte,
1417 // but FvLength is UINT64 type, which requires FvHeader align at least 8 byte.
1418 // So, Copy FvHeader into the local FvHeader structure.
1419 //
1420 CopyMem (&FwVolHeader, FvHandle, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
1421
1422 //
1423 // Check Fv Image Signature
1424 //
1425 if (FwVolHeader.Signature != EFI_FVH_SIGNATURE) {
1426 return EFI_INVALID_PARAMETER;
1427 }
1428
1429 ZeroMem (VolumeInfo, sizeof (EFI_FV_INFO));
1430 VolumeInfo->FvAttributes = FwVolHeader.Attributes;
1431 VolumeInfo->FvStart = (VOID *) FvHandle;
1432 VolumeInfo->FvSize = FwVolHeader.FvLength;
1433 CopyMem (&VolumeInfo->FvFormat, &FwVolHeader.FileSystemGuid, sizeof(EFI_GUID));
1434
1435 if (FwVolHeader.ExtHeaderOffset != 0) {
1436 FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER*)(((UINT8 *)FvHandle) + FwVolHeader.ExtHeaderOffset);
1437 CopyMem (&VolumeInfo->FvName, &FwVolExHeaderInfo->FvName, sizeof(EFI_GUID));
1438 }
1439
1440 return EFI_SUCCESS;
1441 }
1442
1443 /**
1444 Find the next matching section in the firmware file.
1445
1446 This service enables PEI modules to discover sections
1447 of a given type within a valid file.
1448
1449 @param This Points to this instance of the
1450 EFI_PEI_FIRMWARE_VOLUME_PPI.
1451 @param SearchType A filter to find only sections of this
1452 type.
1453 @param FileHandle Handle of firmware file in which to
1454 search.
1455 @param SectionData Updated upon return to point to the
1456 section found.
1457
1458 @retval EFI_SUCCESS Section was found.
1459 @retval EFI_NOT_FOUND Section of the specified type was not
1460 found. SectionData contains NULL.
1461 **/
1462 EFI_STATUS
1463 EFIAPI
1464 PeiFfsFvPpiFindSectionByType (
1465 IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
1466 IN EFI_SECTION_TYPE SearchType,
1467 IN EFI_PEI_FILE_HANDLE FileHandle,
1468 OUT VOID **SectionData
1469 )
1470 {
1471 EFI_FFS_FILE_HEADER *FfsFileHeader;
1472 UINT32 FileSize;
1473 EFI_COMMON_SECTION_HEADER *Section;
1474 PEI_FW_VOL_INSTANCE *FwVolInstance;
1475
1476 FwVolInstance = PEI_FW_VOL_INSTANCE_FROM_FV_THIS (This);
1477
1478 FfsFileHeader = (EFI_FFS_FILE_HEADER *)(FileHandle);
1479
1480 if (IS_FFS_FILE2 (FfsFileHeader)) {
1481 ASSERT (FFS_FILE2_SIZE (FfsFileHeader) > 0x00FFFFFF);
1482 if (!FwVolInstance->IsFfs3Fv) {
1483 DEBUG ((EFI_D_ERROR, "It is a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsFileHeader->Name));
1484 return EFI_NOT_FOUND;
1485 }
1486 Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER2));
1487 FileSize = FFS_FILE2_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER2);
1488 } else {
1489 Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER));
1490 FileSize = FFS_FILE_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER);
1491 }
1492
1493 return ProcessSection (
1494 GetPeiServicesTablePointer (),
1495 SearchType,
1496 Section,
1497 FileSize,
1498 SectionData,
1499 FwVolInstance->IsFfs3Fv
1500 );
1501 }
1502
1503 /**
1504 Convert the handle of FV to pointer of corresponding PEI_CORE_FV_HANDLE.
1505
1506 @param FvHandle The handle of a FV.
1507
1508 @retval NULL if can not find.
1509 @return Pointer of corresponding PEI_CORE_FV_HANDLE.
1510 **/
1511 PEI_CORE_FV_HANDLE *
1512 FvHandleToCoreHandle (
1513 IN EFI_PEI_FV_HANDLE FvHandle
1514 )
1515 {
1516 UINTN Index;
1517 PEI_CORE_INSTANCE *PrivateData;
1518
1519 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer());
1520 for (Index = 0; Index < PrivateData->FvCount; Index ++) {
1521 if (FvHandle == PrivateData->Fv[Index].FvHandle) {
1522 return &PrivateData->Fv[Index];
1523 }
1524 }
1525
1526 return NULL;
1527 }
1528
1529 /**
1530 Get instance of PEI_CORE_FV_HANDLE for next volume according to given index.
1531
1532 This routine also will install FvInfo ppi for FV hob in PI ways.
1533
1534 @param Private Pointer of PEI_CORE_INSTANCE
1535 @param Instance The index of FV want to be searched.
1536
1537 @return Instance of PEI_CORE_FV_HANDLE.
1538 **/
1539 PEI_CORE_FV_HANDLE *
1540 FindNextCoreFvHandle (
1541 IN PEI_CORE_INSTANCE *Private,
1542 IN UINTN Instance
1543 )
1544 {
1545 UINTN Index;
1546 BOOLEAN Match;
1547 EFI_HOB_FIRMWARE_VOLUME *FvHob;
1548
1549 //
1550 // Handle Framework FvHob and Install FvInfo Ppi for it.
1551 //
1552 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
1553 //
1554 // Loop to search the wanted FirmwareVolume which supports FFS
1555 //
1556 FvHob = (EFI_HOB_FIRMWARE_VOLUME *)GetFirstHob (EFI_HOB_TYPE_FV);
1557 while (FvHob != NULL) {
1558 //
1559 // Search whether FvHob has been installed into PeiCore's FV database.
1560 // If found, no need install new FvInfoPpi for it.
1561 //
1562 for (Index = 0, Match = FALSE; Index < Private->FvCount; Index++) {
1563 if ((EFI_PEI_FV_HANDLE)(UINTN)FvHob->BaseAddress == Private->Fv[Index].FvHeader) {
1564 Match = TRUE;
1565 break;
1566 }
1567 }
1568
1569 //
1570 // Search whether FvHob has been cached into PeiCore's Unknown FV database.
1571 // If found, no need install new FvInfoPpi for it.
1572 //
1573 if (!Match) {
1574 for (Index = 0; Index < Private->UnknownFvInfoCount; Index ++) {
1575 if ((UINTN)FvHob->BaseAddress == (UINTN)Private->UnknownFvInfo[Index].FvInfo) {
1576 Match = TRUE;
1577 break;
1578 }
1579 }
1580 }
1581
1582 //
1583 // If the Fv in FvHob has not been installed into PeiCore's FV database and has
1584 // not been cached into PeiCore's Unknown FV database, install a new FvInfoPpi
1585 // for it then PeiCore will dispatch it in callback of FvInfoPpi.
1586 //
1587 if (!Match) {
1588 PeiServicesInstallFvInfoPpi (
1589 &(((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvHob->BaseAddress)->FileSystemGuid),
1590 (VOID *)(UINTN)FvHob->BaseAddress,
1591 (UINT32)FvHob->Length,
1592 NULL,
1593 NULL
1594 );
1595 }
1596
1597 FvHob = (EFI_HOB_FIRMWARE_VOLUME *)GetNextHob (EFI_HOB_TYPE_FV, (VOID *)((UINTN)FvHob + FvHob->Header.HobLength));
1598 }
1599 }
1600
1601 ASSERT (Private->FvCount <= FixedPcdGet32 (PcdPeiCoreMaxFvSupported));
1602 if (Instance >= Private->FvCount) {
1603 return NULL;
1604 }
1605
1606 return &Private->Fv[Instance];
1607 }
1608
1609 /**
1610 After PeiCore image is shadowed into permanent memory, all build-in FvPpi should
1611 be re-installed with the instance in permanent memory and all cached FvPpi pointers in
1612 PrivateData->Fv[] array should be fixed up to be pointed to the one in permenant
1613 memory.
1614
1615 @param PrivateData Pointer to PEI_CORE_INSTANCE.
1616 **/
1617 VOID
1618 PeiReinitializeFv (
1619 IN PEI_CORE_INSTANCE *PrivateData
1620 )
1621 {
1622 VOID *OldFfsFvPpi;
1623 EFI_PEI_PPI_DESCRIPTOR *OldDescriptor;
1624 UINTN Index;
1625 EFI_STATUS Status;
1626
1627 //
1628 // Locate old build-in Ffs2 EFI_PEI_FIRMWARE_VOLUME_PPI which
1629 // in flash.
1630 //
1631 Status = PeiServicesLocatePpi (
1632 &gEfiFirmwareFileSystem2Guid,
1633 0,
1634 &OldDescriptor,
1635 &OldFfsFvPpi
1636 );
1637 ASSERT_EFI_ERROR (Status);
1638
1639 //
1640 // Re-install the EFI_PEI_FIRMWARE_VOLUME_PPI for build-in Ffs2
1641 // which is shadowed from flash to permanent memory within PeiCore image.
1642 //
1643 Status = PeiServicesReInstallPpi (OldDescriptor, &mPeiFfs2FvPpiList);
1644 ASSERT_EFI_ERROR (Status);
1645
1646 //
1647 // Fixup all FvPpi pointers for the implementation in flash to permanent memory.
1648 //
1649 for (Index = 0; Index < FixedPcdGet32 (PcdPeiCoreMaxFvSupported); Index ++) {
1650 if (PrivateData->Fv[Index].FvPpi == OldFfsFvPpi) {
1651 PrivateData->Fv[Index].FvPpi = &mPeiFfs2FwVol.Fv;
1652 }
1653 }
1654
1655 //
1656 // Locate old build-in Ffs3 EFI_PEI_FIRMWARE_VOLUME_PPI which
1657 // in flash.
1658 //
1659 Status = PeiServicesLocatePpi (
1660 &gEfiFirmwareFileSystem3Guid,
1661 0,
1662 &OldDescriptor,
1663 &OldFfsFvPpi
1664 );
1665 ASSERT_EFI_ERROR (Status);
1666
1667 //
1668 // Re-install the EFI_PEI_FIRMWARE_VOLUME_PPI for build-in Ffs3
1669 // which is shadowed from flash to permanent memory within PeiCore image.
1670 //
1671 Status = PeiServicesReInstallPpi (OldDescriptor, &mPeiFfs3FvPpiList);
1672 ASSERT_EFI_ERROR (Status);
1673
1674 //
1675 // Fixup all FvPpi pointers for the implementation in flash to permanent memory.
1676 //
1677 for (Index = 0; Index < FixedPcdGet32 (PcdPeiCoreMaxFvSupported); Index ++) {
1678 if (PrivateData->Fv[Index].FvPpi == OldFfsFvPpi) {
1679 PrivateData->Fv[Index].FvPpi = &mPeiFfs3FwVol.Fv;
1680 }
1681 }
1682 }
1683
1684 /**
1685 Report the information for a new discoveried FV in unknown third-party format.
1686
1687 If the EFI_PEI_FIRMWARE_VOLUME_PPI has not been installed for third-party FV format, but
1688 the FV in this format has been discoveried, then this FV's information will be cached into
1689 PEI_CORE_INSTANCE's UnknownFvInfo array.
1690 Also a notification would be installed for unknown third-party FV format guid, if EFI_PEI_FIRMWARE_VOLUME_PPI
1691 is installed later by platform's PEIM, the original unknown third-party FV will be processed by
1692 using new installed EFI_PEI_FIRMWARE_VOLUME_PPI.
1693
1694 @param PrivateData Point to instance of PEI_CORE_INSTANCE
1695 @param Format Point to the unknown third-party format guid.
1696 @param FvInfo Point to FvInfo buffer.
1697 @param FvInfoSize The size of FvInfo buffer.
1698
1699 @retval EFI_OUT_OF_RESOURCES The FV info array in PEI_CORE_INSTANCE has no more spaces.
1700 @retval EFI_SUCCESS Success to add the information for unknown FV.
1701 **/
1702 EFI_STATUS
1703 AddUnknownFormatFvInfo (
1704 IN PEI_CORE_INSTANCE *PrivateData,
1705 IN EFI_GUID *Format,
1706 IN VOID *FvInfo,
1707 IN UINT32 FvInfoSize
1708 )
1709 {
1710 PEI_CORE_UNKNOW_FORMAT_FV_INFO *NewUnknownFv;
1711
1712 if (PrivateData->UnknownFvInfoCount + 1 >= FixedPcdGet32 (PcdPeiCoreMaxFvSupported)) {
1713 return EFI_OUT_OF_RESOURCES;
1714 }
1715
1716 NewUnknownFv = &PrivateData->UnknownFvInfo[PrivateData->UnknownFvInfoCount];
1717 PrivateData->UnknownFvInfoCount ++;
1718
1719 CopyGuid (&NewUnknownFv->FvFormat, Format);
1720 NewUnknownFv->FvInfo = FvInfo;
1721 NewUnknownFv->FvInfoSize = FvInfoSize;
1722 NewUnknownFv->NotifyDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
1723 NewUnknownFv->NotifyDescriptor.Guid = &NewUnknownFv->FvFormat;
1724 NewUnknownFv->NotifyDescriptor.Notify = ThirdPartyFvPpiNotifyCallback;
1725
1726 PeiServicesNotifyPpi (&NewUnknownFv->NotifyDescriptor);
1727 return EFI_SUCCESS;
1728 }
1729
1730 /**
1731 Find the FV information according to third-party FV format guid.
1732
1733 This routine also will remove the FV information found by given FV format guid from
1734 PrivateData->UnknownFvInfo[].
1735
1736 @param PrivateData Point to instance of PEI_CORE_INSTANCE
1737 @param Format Point to given FV format guid
1738 @param FvInfo On return, the pointer of FV information buffer
1739 @param FvInfoSize On return, the size of FV information buffer.
1740
1741 @retval EFI_NOT_FOUND The FV is not found for new installed EFI_PEI_FIRMWARE_VOLUME_PPI
1742 @retval EFI_SUCCESS Success to find a FV which could be processed by new installed EFI_PEI_FIRMWARE_VOLUME_PPI.
1743 **/
1744 EFI_STATUS
1745 FindUnknownFormatFvInfo (
1746 IN PEI_CORE_INSTANCE *PrivateData,
1747 IN EFI_GUID *Format,
1748 OUT VOID **FvInfo,
1749 OUT UINT32 *FvInfoSize
1750 )
1751 {
1752 UINTN Index;
1753 UINTN Index2;
1754
1755 Index = 0;
1756 for (; Index < PrivateData->UnknownFvInfoCount; Index ++) {
1757 if (CompareGuid (Format, &PrivateData->UnknownFvInfo[Index].FvFormat)) {
1758 break;
1759 }
1760 }
1761
1762 if (Index == PrivateData->UnknownFvInfoCount) {
1763 return EFI_NOT_FOUND;
1764 }
1765
1766 *FvInfo = PrivateData->UnknownFvInfo[Index].FvInfo;
1767 *FvInfoSize = PrivateData->UnknownFvInfo[Index].FvInfoSize;
1768
1769 //
1770 // Remove an entry from UnknownFvInfo array.
1771 //
1772 Index2 = Index + 1;
1773 for (;Index2 < PrivateData->UnknownFvInfoCount; Index2 ++, Index ++) {
1774 CopyMem (&PrivateData->UnknownFvInfo[Index], &PrivateData->UnknownFvInfo[Index2], sizeof (PEI_CORE_UNKNOW_FORMAT_FV_INFO));
1775 }
1776 PrivateData->UnknownFvInfoCount --;
1777 return EFI_SUCCESS;
1778 }
1779
1780 /**
1781 Notification callback function for EFI_PEI_FIRMWARE_VOLUME_PPI.
1782
1783 When a EFI_PEI_FIRMWARE_VOLUME_PPI is installed to support new FV format, this
1784 routine is called to process all discoveried FVs in this format.
1785
1786 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
1787 @param NotifyDescriptor Address of the notification descriptor data structure.
1788 @param Ppi Address of the PPI that was installed.
1789
1790 @retval EFI_SUCCESS The notification callback is processed correctly.
1791 **/
1792 EFI_STATUS
1793 EFIAPI
1794 ThirdPartyFvPpiNotifyCallback (
1795 IN EFI_PEI_SERVICES **PeiServices,
1796 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
1797 IN VOID *Ppi
1798 )
1799 {
1800 PEI_CORE_INSTANCE *PrivateData;
1801 EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
1802 VOID *FvInfo;
1803 UINT32 FvInfoSize;
1804 EFI_STATUS Status;
1805 EFI_PEI_FV_HANDLE FvHandle;
1806 BOOLEAN IsProcessed;
1807 UINTN FvIndex;
1808 EFI_PEI_FILE_HANDLE FileHandle;
1809 VOID *DepexData;
1810
1811 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
1812 FvPpi = (EFI_PEI_FIRMWARE_VOLUME_PPI*) Ppi;
1813
1814 do {
1815 Status = FindUnknownFormatFvInfo (PrivateData, NotifyDescriptor->Guid, &FvInfo, &FvInfoSize);
1816 if (EFI_ERROR (Status)) {
1817 return EFI_SUCCESS;
1818 }
1819
1820 //
1821 // Process new found FV and get FV handle.
1822 //
1823 Status = FvPpi->ProcessVolume (FvPpi, FvInfo, FvInfoSize, &FvHandle);
1824 if (EFI_ERROR (Status)) {
1825 DEBUG ((EFI_D_ERROR, "Fail to process the FV 0x%p, FV may be corrupted!\n", FvInfo));
1826 continue;
1827 }
1828
1829 //
1830 // Check whether the FV has already been processed.
1831 //
1832 IsProcessed = FALSE;
1833 for (FvIndex = 0; FvIndex < PrivateData->FvCount; FvIndex ++) {
1834 if (PrivateData->Fv[FvIndex].FvHandle == FvHandle) {
1835 DEBUG ((EFI_D_INFO, "The Fv %p has already been processed!\n", FvInfo));
1836 IsProcessed = TRUE;
1837 break;
1838 }
1839 }
1840
1841 if (IsProcessed) {
1842 continue;
1843 }
1844
1845 if (PrivateData->FvCount >= FixedPcdGet32 (PcdPeiCoreMaxFvSupported)) {
1846 DEBUG ((EFI_D_ERROR, "The number of Fv Images (%d) exceed the max supported FVs (%d) in Pei", PrivateData->FvCount + 1, FixedPcdGet32 (PcdPeiCoreMaxFvSupported)));
1847 DEBUG ((EFI_D_ERROR, "PcdPeiCoreMaxFvSupported value need be reconfigurated in DSC"));
1848 ASSERT (FALSE);
1849 }
1850
1851 //
1852 // Update internal PEI_CORE_FV array.
1853 //
1854 PrivateData->Fv[PrivateData->FvCount].FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*) FvInfo;
1855 PrivateData->Fv[PrivateData->FvCount].FvPpi = FvPpi;
1856 PrivateData->Fv[PrivateData->FvCount].FvHandle = FvHandle;
1857 DEBUG ((
1858 EFI_D_INFO,
1859 "The %dth FV start address is 0x%11p, size is 0x%08x, handle is 0x%p\n",
1860 (UINT32) PrivateData->FvCount,
1861 (VOID *) FvInfo,
1862 FvInfoSize,
1863 FvHandle
1864 ));
1865 PrivateData->FvCount ++;
1866
1867 //
1868 // Scan and process the new discoveried FV for EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
1869 //
1870 FileHandle = NULL;
1871 do {
1872 Status = FvPpi->FindFileByType (
1873 FvPpi,
1874 EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,
1875 FvHandle,
1876 &FileHandle
1877 );
1878 if (!EFI_ERROR (Status)) {
1879 Status = FvPpi->FindSectionByType (
1880 FvPpi,
1881 EFI_SECTION_PEI_DEPEX,
1882 FileHandle,
1883 (VOID**)&DepexData
1884 );
1885 if (!EFI_ERROR (Status)) {
1886 if (!PeimDispatchReadiness (PeiServices, DepexData)) {
1887 //
1888 // Dependency is not satisfied.
1889 //
1890 continue;
1891 }
1892 }
1893
1894 DEBUG ((EFI_D_INFO, "Found firmware volume Image File %p in FV[%d] %p\n", FileHandle, PrivateData->FvCount - 1, FvHandle));
1895 ProcessFvFile (&PrivateData->Fv[PrivateData->FvCount - 1], FileHandle);
1896 }
1897 } while (FileHandle != NULL);
1898 } while (TRUE);
1899 }