]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Pei/FwVol/FwVol.c
MdeModulePkg: Add support for weakly aligned FVs.
[mirror_edk2.git] / MdeModulePkg / Core / Pei / FwVol / FwVol.c
1 /** @file
2 Pei Core Firmware File System service routines.
3
4 Copyright (c) 2006 - 2013, 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_FILE_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 Verify the Guided Section GUID by checking if there is the Guided Section GUID HOB recorded the GUID itself.
611
612 @param GuidedSectionGuid The Guided Section GUID.
613 @param GuidedSectionExtraction A pointer to the pointer to the supported Guided Section Extraction Ppi
614 for the Guided Section.
615
616 @return TRUE The GuidedSectionGuid could be identified, and the pointer to
617 the Guided Section Extraction Ppi will be returned to *GuidedSectionExtraction.
618 @return FALSE The GuidedSectionGuid could not be identified, or
619 the Guided Section Extraction Ppi has not been installed yet.
620
621 **/
622 BOOLEAN
623 VerifyGuidedSectionGuid (
624 IN EFI_GUID *GuidedSectionGuid,
625 OUT EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI **GuidedSectionExtraction
626 )
627 {
628 EFI_PEI_HOB_POINTERS Hob;
629 EFI_GUID *GuidRecorded;
630 VOID *Interface;
631 EFI_STATUS Status;
632
633 //
634 // Check if there is the Guided Section GUID HOB recorded the GUID itself.
635 //
636 Hob.Raw = GetFirstGuidHob (GuidedSectionGuid);
637 if (Hob.Raw != NULL) {
638 GuidRecorded = (EFI_GUID *) GET_GUID_HOB_DATA (Hob);
639 if (CompareGuid (GuidRecorded, GuidedSectionGuid)) {
640 //
641 // Found the recorded GuidedSectionGuid.
642 //
643 Status = PeiServicesLocatePpi (GuidedSectionGuid, 0, NULL, (VOID **) &Interface);
644 if (!EFI_ERROR (Status) && Interface != NULL) {
645 //
646 // Found the supported Guided Section Extraction Ppi for the Guided Section.
647 //
648 *GuidedSectionExtraction = (EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *) Interface;
649 return TRUE;
650 }
651 return FALSE;
652 }
653 }
654
655 return FALSE;
656 }
657
658 /**
659 Go through the file to search SectionType section.
660 Search within encapsulation sections (compression and GUIDed) recursively,
661 until the match section is found.
662
663 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
664 @param SectionType Filter to find only section of this type.
665 @param Section From where to search.
666 @param SectionSize The file size to search.
667 @param OutputBuffer A pointer to the discovered section, if successful.
668 NULL if section not found
669 @param IsFfs3Fv Indicates the FV format.
670
671 @return EFI_NOT_FOUND The match section is not found.
672 @return EFI_SUCCESS The match section is found.
673
674 **/
675 EFI_STATUS
676 ProcessSection (
677 IN CONST EFI_PEI_SERVICES **PeiServices,
678 IN EFI_SECTION_TYPE SectionType,
679 IN EFI_COMMON_SECTION_HEADER *Section,
680 IN UINTN SectionSize,
681 OUT VOID **OutputBuffer,
682 IN BOOLEAN IsFfs3Fv
683 )
684 {
685 EFI_STATUS Status;
686 UINT32 SectionLength;
687 UINT32 ParsedLength;
688 EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *GuidSectionPpi;
689 EFI_PEI_DECOMPRESS_PPI *DecompressPpi;
690 VOID *PpiOutput;
691 UINTN PpiOutputSize;
692 UINTN Index;
693 UINT32 Authentication;
694 PEI_CORE_INSTANCE *PrivateData;
695 EFI_GUID *SectionDefinitionGuid;
696
697 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
698 *OutputBuffer = NULL;
699 ParsedLength = 0;
700 Index = 0;
701 Status = EFI_NOT_FOUND;
702 PpiOutput = NULL;
703 PpiOutputSize = 0;
704 while (ParsedLength < SectionSize) {
705
706 if (IS_SECTION2 (Section)) {
707 ASSERT (SECTION2_SIZE (Section) > 0x00FFFFFF);
708 if (!IsFfs3Fv) {
709 DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted section in a non-FFS3 formatted FV.\n"));
710 SectionLength = SECTION2_SIZE (Section);
711 //
712 // SectionLength is adjusted it is 4 byte aligned.
713 // Go to the next section
714 //
715 SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
716 ASSERT (SectionLength != 0);
717 ParsedLength += SectionLength;
718 Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + SectionLength);
719 continue;
720 }
721 }
722
723 if (Section->Type == SectionType) {
724 if (IS_SECTION2 (Section)) {
725 *OutputBuffer = (VOID *)((UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER2));
726 } else {
727 *OutputBuffer = (VOID *)((UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER));
728 }
729 return EFI_SUCCESS;
730 } else if ((Section->Type == EFI_SECTION_GUID_DEFINED) || (Section->Type == EFI_SECTION_COMPRESSION)) {
731 //
732 // Check the encapsulated section is extracted into the cache data.
733 //
734 for (Index = 0; Index < PrivateData->CacheSection.AllSectionCount; Index ++) {
735 if (Section == PrivateData->CacheSection.Section[Index]) {
736 PpiOutput = PrivateData->CacheSection.SectionData[Index];
737 PpiOutputSize = PrivateData->CacheSection.SectionSize[Index];
738 //
739 // Search section directly from the cache data.
740 //
741 return ProcessSection (
742 PeiServices,
743 SectionType,
744 PpiOutput,
745 PpiOutputSize,
746 OutputBuffer,
747 IsFfs3Fv
748 );
749 }
750 }
751
752 Status = EFI_NOT_FOUND;
753 if (Section->Type == EFI_SECTION_GUID_DEFINED) {
754 if (IS_SECTION2 (Section)) {
755 SectionDefinitionGuid = &((EFI_GUID_DEFINED_SECTION2 *)Section)->SectionDefinitionGuid;
756 } else {
757 SectionDefinitionGuid = &((EFI_GUID_DEFINED_SECTION *)Section)->SectionDefinitionGuid;
758 }
759 if (VerifyGuidedSectionGuid (SectionDefinitionGuid, &GuidSectionPpi)) {
760 Status = GuidSectionPpi->ExtractSection (
761 GuidSectionPpi,
762 Section,
763 &PpiOutput,
764 &PpiOutputSize,
765 &Authentication
766 );
767 }
768 } else if (Section->Type == EFI_SECTION_COMPRESSION) {
769 Status = PeiServicesLocatePpi (&gEfiPeiDecompressPpiGuid, 0, NULL, (VOID **) &DecompressPpi);
770 if (!EFI_ERROR (Status)) {
771 Status = DecompressPpi->Decompress (
772 DecompressPpi,
773 (CONST EFI_COMPRESSION_SECTION*) Section,
774 &PpiOutput,
775 &PpiOutputSize
776 );
777 }
778 }
779
780 if (!EFI_ERROR (Status)) {
781 //
782 // Update cache section data.
783 //
784 if (PrivateData->CacheSection.AllSectionCount < CACHE_SETION_MAX_NUMBER) {
785 PrivateData->CacheSection.AllSectionCount ++;
786 }
787 PrivateData->CacheSection.Section [PrivateData->CacheSection.SectionIndex] = Section;
788 PrivateData->CacheSection.SectionData [PrivateData->CacheSection.SectionIndex] = PpiOutput;
789 PrivateData->CacheSection.SectionSize [PrivateData->CacheSection.SectionIndex] = PpiOutputSize;
790 PrivateData->CacheSection.SectionIndex = (PrivateData->CacheSection.SectionIndex + 1)%CACHE_SETION_MAX_NUMBER;
791
792 return ProcessSection (
793 PeiServices,
794 SectionType,
795 PpiOutput,
796 PpiOutputSize,
797 OutputBuffer,
798 IsFfs3Fv
799 );
800 }
801 }
802
803 if (IS_SECTION2 (Section)) {
804 SectionLength = SECTION2_SIZE (Section);
805 } else {
806 SectionLength = SECTION_SIZE (Section);
807 }
808 //
809 // SectionLength is adjusted it is 4 byte aligned.
810 // Go to the next section
811 //
812 SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
813 ASSERT (SectionLength != 0);
814 ParsedLength += SectionLength;
815 Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength);
816 }
817
818 return EFI_NOT_FOUND;
819 }
820
821
822 /**
823 Searches for the next matching section within the specified file.
824
825 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
826 @param SectionType Filter to find only sections of this type.
827 @param FileHandle Pointer to the current file to search.
828 @param SectionData A pointer to the discovered section, if successful.
829 NULL if section not found
830
831 @retval EFI_NOT_FOUND The section was not found.
832 @retval EFI_SUCCESS The section was found.
833
834 **/
835 EFI_STATUS
836 EFIAPI
837 PeiFfsFindSectionData (
838 IN CONST EFI_PEI_SERVICES **PeiServices,
839 IN EFI_SECTION_TYPE SectionType,
840 IN EFI_PEI_FILE_HANDLE FileHandle,
841 OUT VOID **SectionData
842 )
843 {
844 PEI_CORE_FV_HANDLE *CoreFvHandle;
845
846 CoreFvHandle = FileHandleToVolume (FileHandle);
847 if ((CoreFvHandle == NULL) || (CoreFvHandle->FvPpi == NULL)) {
848 return EFI_NOT_FOUND;
849 }
850
851 return CoreFvHandle->FvPpi->FindSectionByType (CoreFvHandle->FvPpi, SectionType, FileHandle, SectionData);
852 }
853
854 /**
855 Searches for the next matching file in the firmware volume.
856
857 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
858 @param SearchType Filter to find only files of this type.
859 Type EFI_FV_FILETYPE_ALL causes no filtering to be done.
860 @param FvHandle Handle of firmware volume in which to search.
861 @param FileHandle On entry, points to the current handle from which to begin searching or NULL to start
862 at the beginning of the firmware volume. On exit, points the file handle of the next file
863 in the volume or NULL if there are no more files.
864
865 @retval EFI_NOT_FOUND The file was not found.
866 @retval EFI_NOT_FOUND The header checksum was not zero.
867 @retval EFI_SUCCESS The file was found.
868
869 **/
870 EFI_STATUS
871 EFIAPI
872 PeiFfsFindNextFile (
873 IN CONST EFI_PEI_SERVICES **PeiServices,
874 IN UINT8 SearchType,
875 IN EFI_PEI_FV_HANDLE FvHandle,
876 IN OUT EFI_PEI_FILE_HANDLE *FileHandle
877 )
878 {
879 PEI_CORE_FV_HANDLE *CoreFvHandle;
880
881 CoreFvHandle = FvHandleToCoreHandle (FvHandle);
882
883 //
884 // To make backward compatiblity, if can not find corresponding the handle of FV
885 // then treat FV as build-in FFS2/FFS3 format and memory mapped FV that FV handle is pointed
886 // to the address of first byte of FV.
887 //
888 if ((CoreFvHandle == NULL) && FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
889 return FindFileEx (FvHandle, NULL, SearchType, FileHandle, NULL);
890 }
891
892 if ((CoreFvHandle == NULL) || CoreFvHandle->FvPpi == NULL) {
893 return EFI_NOT_FOUND;
894 }
895
896 return CoreFvHandle->FvPpi->FindFileByType (CoreFvHandle->FvPpi, SearchType, FvHandle, FileHandle);
897 }
898
899
900 /**
901 Search the firmware volumes by index
902
903 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
904 @param Instance This instance of the firmware volume to find. The value 0 is the Boot Firmware
905 Volume (BFV).
906 @param VolumeHandle On exit, points to the next volume handle or NULL if it does not exist.
907
908 @retval EFI_INVALID_PARAMETER VolumeHandle is NULL
909 @retval EFI_NOT_FOUND The volume was not found.
910 @retval EFI_SUCCESS The volume was found.
911
912 **/
913 EFI_STATUS
914 EFIAPI
915 PeiFfsFindNextVolume (
916 IN CONST EFI_PEI_SERVICES **PeiServices,
917 IN UINTN Instance,
918 IN OUT EFI_PEI_FV_HANDLE *VolumeHandle
919 )
920 {
921 PEI_CORE_INSTANCE *Private;
922 PEI_CORE_FV_HANDLE *CoreFvHandle;
923
924 if (VolumeHandle == NULL) {
925 return EFI_INVALID_PARAMETER;
926 }
927
928 Private = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
929
930 CoreFvHandle = FindNextCoreFvHandle (Private, Instance);
931 if (CoreFvHandle == NULL) {
932 *VolumeHandle = NULL;
933 return EFI_NOT_FOUND;
934 }
935
936 *VolumeHandle = CoreFvHandle->FvHandle;
937
938 return EFI_SUCCESS;
939 }
940
941
942 /**
943 Find a file within a volume by its name.
944
945 @param FileName A pointer to the name of the file to find within the firmware volume.
946 @param VolumeHandle The firmware volume to search
947 @param FileHandle Upon exit, points to the found file's handle
948 or NULL if it could not be found.
949
950 @retval EFI_SUCCESS File was found.
951 @retval EFI_NOT_FOUND File was not found.
952 @retval EFI_INVALID_PARAMETER VolumeHandle or FileHandle or FileName was NULL.
953
954 **/
955 EFI_STATUS
956 EFIAPI
957 PeiFfsFindFileByName (
958 IN CONST EFI_GUID *FileName,
959 IN EFI_PEI_FV_HANDLE VolumeHandle,
960 OUT EFI_PEI_FILE_HANDLE *FileHandle
961 )
962 {
963 PEI_CORE_FV_HANDLE *CoreFvHandle;
964
965 if ((VolumeHandle == NULL) || (FileName == NULL) || (FileHandle == NULL)) {
966 return EFI_INVALID_PARAMETER;
967 }
968
969 CoreFvHandle = FvHandleToCoreHandle (VolumeHandle);
970 if ((CoreFvHandle == NULL) || (CoreFvHandle->FvPpi == NULL)) {
971 return EFI_NOT_FOUND;
972 }
973
974 return CoreFvHandle->FvPpi->FindFileByName (CoreFvHandle->FvPpi, FileName, &VolumeHandle, FileHandle);
975 }
976
977 /**
978 Returns information about a specific file.
979
980 @param FileHandle Handle of the file.
981 @param FileInfo Upon exit, points to the file's information.
982
983 @retval EFI_INVALID_PARAMETER If FileInfo is NULL.
984 @retval EFI_INVALID_PARAMETER If FileHandle does not represent a valid file.
985 @retval EFI_SUCCESS File information returned.
986
987 **/
988 EFI_STATUS
989 EFIAPI
990 PeiFfsGetFileInfo (
991 IN EFI_PEI_FILE_HANDLE FileHandle,
992 OUT EFI_FV_FILE_INFO *FileInfo
993 )
994 {
995 PEI_CORE_FV_HANDLE *CoreFvHandle;
996
997 if ((FileHandle == NULL) || (FileInfo == NULL)) {
998 return EFI_INVALID_PARAMETER;
999 }
1000
1001 //
1002 // Retrieve the FirmwareVolume which the file resides in.
1003 //
1004 CoreFvHandle = FileHandleToVolume (FileHandle);
1005 if ((CoreFvHandle == NULL) || (CoreFvHandle->FvPpi == NULL)) {
1006 return EFI_INVALID_PARAMETER;
1007 }
1008
1009 return CoreFvHandle->FvPpi->GetFileInfo (CoreFvHandle->FvPpi, FileHandle, FileInfo);
1010 }
1011
1012
1013 /**
1014 Returns information about the specified volume.
1015
1016 This function returns information about a specific firmware
1017 volume, including its name, type, attributes, starting address
1018 and size.
1019
1020 @param VolumeHandle Handle of the volume.
1021 @param VolumeInfo Upon exit, points to the volume's information.
1022
1023 @retval EFI_SUCCESS Volume information returned.
1024 @retval EFI_INVALID_PARAMETER If VolumeHandle does not represent a valid volume.
1025 @retval EFI_INVALID_PARAMETER If VolumeHandle is NULL.
1026 @retval EFI_SUCCESS Information successfully returned.
1027 @retval EFI_INVALID_PARAMETER The volume designated by the VolumeHandle is not available.
1028
1029 **/
1030 EFI_STATUS
1031 EFIAPI
1032 PeiFfsGetVolumeInfo (
1033 IN EFI_PEI_FV_HANDLE VolumeHandle,
1034 OUT EFI_FV_INFO *VolumeInfo
1035 )
1036 {
1037 PEI_CORE_FV_HANDLE *CoreHandle;
1038
1039 if ((VolumeInfo == NULL) || (VolumeHandle == NULL)) {
1040 return EFI_INVALID_PARAMETER;
1041 }
1042
1043 CoreHandle = FvHandleToCoreHandle (VolumeHandle);
1044
1045 if ((CoreHandle == NULL) || (CoreHandle->FvPpi == NULL)) {
1046 return EFI_INVALID_PARAMETER;
1047 }
1048
1049 return CoreHandle->FvPpi->GetVolumeInfo (CoreHandle->FvPpi, VolumeHandle, VolumeInfo);
1050 }
1051
1052 /**
1053 Get Fv image from the FV type file, then install FV INFO ppi, Build FV hob.
1054
1055 @param ParentFvCoreHandle Pointer of EFI_CORE_FV_HANDLE to parent Fv image that contain this Fv image.
1056 @param ParentFvFileHandle File handle of a Fv type file that contain this Fv image.
1057
1058 @retval EFI_NOT_FOUND FV image can't be found.
1059 @retval EFI_SUCCESS Successfully to process it.
1060 @retval EFI_OUT_OF_RESOURCES Can not allocate page when aligning FV image
1061 @retval Others Can not find EFI_SECTION_FIRMWARE_VOLUME_IMAGE section
1062
1063 **/
1064 EFI_STATUS
1065 ProcessFvFile (
1066 IN PEI_CORE_FV_HANDLE *ParentFvCoreHandle,
1067 IN EFI_PEI_FILE_HANDLE ParentFvFileHandle
1068 )
1069 {
1070 EFI_STATUS Status;
1071 EFI_FV_INFO ParentFvImageInfo;
1072 UINT32 FvAlignment;
1073 VOID *NewFvBuffer;
1074 EFI_PEI_HOB_POINTERS HobPtr;
1075 EFI_PEI_FIRMWARE_VOLUME_PPI *ParentFvPpi;
1076 EFI_PEI_FV_HANDLE ParentFvHandle;
1077 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
1078 EFI_FV_FILE_INFO FileInfo;
1079 UINT64 FvLength;
1080
1081 //
1082 // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already
1083 // been extracted.
1084 //
1085 HobPtr.Raw = GetHobList ();
1086 while ((HobPtr.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobPtr.Raw)) != NULL) {
1087 if (CompareGuid (&(((EFI_FFS_FILE_HEADER *)ParentFvFileHandle)->Name), &HobPtr.FirmwareVolume2->FileName)) {
1088 //
1089 // this FILE has been dispatched, it will not be dispatched again.
1090 //
1091 DEBUG ((EFI_D_INFO, "FV file %p has been dispatched!\r\n", ParentFvFileHandle));
1092 return EFI_SUCCESS;
1093 }
1094 HobPtr.Raw = GET_NEXT_HOB (HobPtr);
1095 }
1096
1097 ParentFvHandle = ParentFvCoreHandle->FvHandle;
1098 ParentFvPpi = ParentFvCoreHandle->FvPpi;
1099
1100 //
1101 // Find FvImage in FvFile
1102 //
1103 Status = ParentFvPpi->FindSectionByType (
1104 ParentFvPpi,
1105 EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
1106 ParentFvFileHandle,
1107 (VOID **)&FvHeader
1108 );
1109
1110 if (EFI_ERROR (Status)) {
1111 return Status;
1112 }
1113
1114 //
1115 // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume
1116 // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from
1117 // its initial linked location and maintain its alignment.
1118 //
1119 if ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) {
1120 //
1121 // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
1122 //
1123 FvAlignment = 1 << ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_ALIGNMENT) >> 16);
1124 if (FvAlignment < 8) {
1125 FvAlignment = 8;
1126 }
1127
1128 //
1129 // Check FvImage
1130 //
1131 if ((UINTN) FvHeader % FvAlignment != 0) {
1132 FvLength = ReadUnaligned64 (&FvHeader->FvLength);
1133 NewFvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINT32) FvLength), FvAlignment);
1134 if (NewFvBuffer == NULL) {
1135 return EFI_OUT_OF_RESOURCES;
1136 }
1137 CopyMem (NewFvBuffer, FvHeader, (UINTN) FvLength);
1138 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*) NewFvBuffer;
1139 }
1140 }
1141
1142 Status = ParentFvPpi->GetVolumeInfo (ParentFvPpi, ParentFvHandle, &ParentFvImageInfo);
1143 ASSERT_EFI_ERROR (Status);
1144
1145 Status = ParentFvPpi->GetFileInfo (ParentFvPpi, ParentFvFileHandle, &FileInfo);
1146 ASSERT_EFI_ERROR (Status);
1147
1148 //
1149 // Install FvPpi and Build FvHob
1150 //
1151 PeiServicesInstallFvInfoPpi (
1152 &FvHeader->FileSystemGuid,
1153 (VOID**) FvHeader,
1154 (UINT32) FvHeader->FvLength,
1155 &ParentFvImageInfo.FvName,
1156 &FileInfo.FileName
1157 );
1158
1159 //
1160 // Inform the extracted FvImage to Fv HOB consumer phase, i.e. DXE phase
1161 //
1162 BuildFvHob (
1163 (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader,
1164 FvHeader->FvLength
1165 );
1166
1167 //
1168 // Makes the encapsulated volume show up in DXE phase to skip processing of
1169 // encapsulated file again.
1170 //
1171 BuildFv2Hob (
1172 (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader,
1173 FvHeader->FvLength,
1174 &ParentFvImageInfo.FvName,
1175 &FileInfo.FileName
1176 );
1177
1178 return EFI_SUCCESS;
1179 }
1180
1181 /**
1182 Process a firmware volume and create a volume handle.
1183
1184 Create a volume handle from the information in the buffer. For
1185 memory-mapped firmware volumes, Buffer and BufferSize refer to
1186 the start of the firmware volume and the firmware volume size.
1187 For non memory-mapped firmware volumes, this points to a
1188 buffer which contains the necessary information for creating
1189 the firmware volume handle. Normally, these values are derived
1190 from the EFI_FIRMWARE_VOLUME_INFO_PPI.
1191
1192
1193 @param This Points to this instance of the
1194 EFI_PEI_FIRMWARE_VOLUME_PPI.
1195 @param Buffer Points to the start of the buffer.
1196 @param BufferSize Size of the buffer.
1197 @param FvHandle Points to the returned firmware volume
1198 handle. The firmware volume handle must
1199 be unique within the system.
1200
1201 @retval EFI_SUCCESS Firmware volume handle created.
1202 @retval EFI_VOLUME_CORRUPTED Volume was corrupt.
1203
1204 **/
1205 EFI_STATUS
1206 EFIAPI
1207 PeiFfsFvPpiProcessVolume (
1208 IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
1209 IN VOID *Buffer,
1210 IN UINTN BufferSize,
1211 OUT EFI_PEI_FV_HANDLE *FvHandle
1212 )
1213 {
1214 EFI_STATUS Status;
1215
1216 ASSERT (FvHandle != NULL);
1217
1218 if (Buffer == NULL) {
1219 return EFI_VOLUME_CORRUPTED;
1220 }
1221
1222 //
1223 // The build-in EFI_PEI_FIRMWARE_VOLUME_PPI for FFS2/FFS3 support memory-mapped
1224 // FV image and the handle is pointed to Fv image's buffer.
1225 //
1226 *FvHandle = (EFI_PEI_FV_HANDLE) Buffer;
1227
1228 //
1229 // Do verify for given FV buffer.
1230 //
1231 Status = VerifyFv ((EFI_FIRMWARE_VOLUME_HEADER*) Buffer);
1232 if (EFI_ERROR(Status)) {
1233 DEBUG ((EFI_D_ERROR, "Fail to verify FV which address is 0x%11p", Buffer));
1234 return EFI_VOLUME_CORRUPTED;
1235 }
1236
1237 return EFI_SUCCESS;
1238 }
1239
1240 /**
1241 Finds the next file of the specified type.
1242
1243 This service enables PEI modules to discover additional firmware files.
1244 The FileHandle must be unique within the system.
1245
1246 @param This Points to this instance of the
1247 EFI_PEI_FIRMWARE_VOLUME_PPI.
1248 @param SearchType A filter to find only files of this type. Type
1249 EFI_FV_FILETYPE_ALL causes no filtering to be
1250 done.
1251 @param FvHandle Handle of firmware volume in which to
1252 search.
1253 @param FileHandle Points to the current handle from which to
1254 begin searching or NULL to start at the
1255 beginning of the firmware volume. Updated
1256 upon return to reflect the file found.
1257
1258 @retval EFI_SUCCESS The file was found.
1259 @retval EFI_NOT_FOUND The file was not found. FileHandle contains NULL.
1260
1261 **/
1262 EFI_STATUS
1263 EFIAPI
1264 PeiFfsFvPpiFindFileByType (
1265 IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
1266 IN EFI_FV_FILETYPE SearchType,
1267 IN EFI_PEI_FV_HANDLE FvHandle,
1268 IN OUT EFI_PEI_FILE_HANDLE *FileHandle
1269 )
1270 {
1271 return FindFileEx (FvHandle, NULL, SearchType, FileHandle, NULL);
1272 }
1273
1274 /**
1275 Find a file within a volume by its name.
1276
1277 This service searches for files with a specific name, within
1278 either the specified firmware volume or all firmware volumes.
1279
1280 @param This Points to this instance of the
1281 EFI_PEI_FIRMWARE_VOLUME_PPI.
1282 @param FileName A pointer to the name of the file to find
1283 within the firmware volume.
1284 @param FvHandle Upon entry, the pointer to the firmware
1285 volume to search or NULL if all firmware
1286 volumes should be searched. Upon exit, the
1287 actual firmware volume in which the file was
1288 found.
1289 @param FileHandle Upon exit, points to the found file's
1290 handle or NULL if it could not be found.
1291
1292 @retval EFI_SUCCESS File was found.
1293 @retval EFI_NOT_FOUND File was not found.
1294 @retval EFI_INVALID_PARAMETER FvHandle or FileHandle or
1295 FileName was NULL.
1296
1297
1298 **/
1299 EFI_STATUS
1300 EFIAPI
1301 PeiFfsFvPpiFindFileByName (
1302 IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
1303 IN CONST EFI_GUID *FileName,
1304 IN EFI_PEI_FV_HANDLE *FvHandle,
1305 OUT EFI_PEI_FILE_HANDLE *FileHandle
1306 )
1307 {
1308 EFI_STATUS Status;
1309 PEI_CORE_INSTANCE *PrivateData;
1310 UINTN Index;
1311
1312 if ((FvHandle == NULL) || (FileName == NULL) || (FileHandle == NULL)) {
1313 return EFI_INVALID_PARAMETER;
1314 }
1315
1316 if (*FvHandle != NULL) {
1317 Status = FindFileEx (*FvHandle, FileName, 0, FileHandle, NULL);
1318 if (Status == EFI_NOT_FOUND) {
1319 *FileHandle = NULL;
1320 }
1321 } else {
1322 //
1323 // If *FvHandle = NULL, so search all FV for given filename
1324 //
1325 Status = EFI_NOT_FOUND;
1326
1327 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer());
1328 for (Index = 0; Index < PrivateData->FvCount; Index ++) {
1329 //
1330 // Only search the FV which is associated with a EFI_PEI_FIRMWARE_VOLUME_PPI instance.
1331 //
1332 if (PrivateData->Fv[Index].FvPpi != NULL) {
1333 Status = FindFileEx (PrivateData->Fv[Index].FvHandle, FileName, 0, FileHandle, NULL);
1334 if (!EFI_ERROR (Status)) {
1335 *FvHandle = PrivateData->Fv[Index].FvHandle;
1336 break;
1337 }
1338 }
1339 }
1340 }
1341
1342 return Status;
1343 }
1344
1345 /**
1346 Returns information about a specific file.
1347
1348 This function returns information about a specific
1349 file, including its file name, type, attributes, starting
1350 address and size.
1351
1352 @param This Points to this instance of the
1353 EFI_PEI_FIRMWARE_VOLUME_PPI.
1354 @param FileHandle Handle of the file.
1355 @param FileInfo Upon exit, points to the file's
1356 information.
1357
1358 @retval EFI_SUCCESS File information returned.
1359 @retval EFI_INVALID_PARAMETER If FileHandle does not
1360 represent a valid file.
1361 @retval EFI_INVALID_PARAMETER If FileInfo is NULL.
1362
1363 **/
1364 EFI_STATUS
1365 EFIAPI
1366 PeiFfsFvPpiGetFileInfo (
1367 IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
1368 IN EFI_PEI_FILE_HANDLE FileHandle,
1369 OUT EFI_FV_FILE_INFO *FileInfo
1370 )
1371 {
1372 UINT8 FileState;
1373 UINT8 ErasePolarity;
1374 EFI_FFS_FILE_HEADER *FileHeader;
1375 PEI_CORE_FV_HANDLE *CoreFvHandle;
1376 PEI_FW_VOL_INSTANCE *FwVolInstance;
1377
1378 if ((FileHandle == NULL) || (FileInfo == NULL)) {
1379 return EFI_INVALID_PARAMETER;
1380 }
1381
1382 //
1383 // Retrieve the FirmwareVolume which the file resides in.
1384 //
1385 CoreFvHandle = FileHandleToVolume (FileHandle);
1386 if (CoreFvHandle == NULL) {
1387 return EFI_INVALID_PARAMETER;
1388 }
1389
1390 FwVolInstance = PEI_FW_VOL_INSTANCE_FROM_FV_THIS (This);
1391
1392 if ((CoreFvHandle->FvHeader->Attributes & EFI_FVB2_ERASE_POLARITY) != 0) {
1393 ErasePolarity = 1;
1394 } else {
1395 ErasePolarity = 0;
1396 }
1397
1398 //
1399 // Get FileState which is the highest bit of the State
1400 //
1401 FileState = GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER*)FileHandle);
1402
1403 switch (FileState) {
1404 case EFI_FILE_DATA_VALID:
1405 case EFI_FILE_MARKED_FOR_UPDATE:
1406 break;
1407 default:
1408 return EFI_INVALID_PARAMETER;
1409 }
1410
1411 FileHeader = (EFI_FFS_FILE_HEADER *)FileHandle;
1412 CopyMem (&FileInfo->FileName, &FileHeader->Name, sizeof(EFI_GUID));
1413 FileInfo->FileType = FileHeader->Type;
1414 FileInfo->FileAttributes = FfsAttributes2FvFileAttributes (FileHeader->Attributes);
1415 if ((CoreFvHandle->FvHeader->Attributes & EFI_FVB2_MEMORY_MAPPED) == EFI_FVB2_MEMORY_MAPPED) {
1416 FileInfo->FileAttributes |= EFI_FV_FILE_ATTRIB_MEMORY_MAPPED;
1417 }
1418 if (IS_FFS_FILE2 (FileHeader)) {
1419 ASSERT (FFS_FILE2_SIZE (FileHeader) > 0x00FFFFFF);
1420 if (!FwVolInstance->IsFfs3Fv) {
1421 DEBUG ((EFI_D_ERROR, "It is a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FileHeader->Name));
1422 return EFI_INVALID_PARAMETER;
1423 }
1424 FileInfo->BufferSize = FFS_FILE2_SIZE (FileHeader) - sizeof (EFI_FFS_FILE_HEADER2);
1425 FileInfo->Buffer = (UINT8 *) FileHeader + sizeof (EFI_FFS_FILE_HEADER2);
1426 } else {
1427 FileInfo->BufferSize = FFS_FILE_SIZE (FileHeader) - sizeof (EFI_FFS_FILE_HEADER);
1428 FileInfo->Buffer = (UINT8 *) FileHeader + sizeof (EFI_FFS_FILE_HEADER);
1429 }
1430 return EFI_SUCCESS;
1431 }
1432
1433 /**
1434 This function returns information about the firmware volume.
1435
1436 @param This Points to this instance of the
1437 EFI_PEI_FIRMWARE_VOLUME_PPI.
1438 @param FvHandle Handle to the firmware handle.
1439 @param VolumeInfo Points to the returned firmware volume
1440 information.
1441
1442 @retval EFI_SUCCESS Information returned successfully.
1443 @retval EFI_INVALID_PARAMETER FvHandle does not indicate a valid
1444 firmware volume or VolumeInfo is NULL.
1445
1446 **/
1447 EFI_STATUS
1448 EFIAPI
1449 PeiFfsFvPpiGetVolumeInfo (
1450 IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
1451 IN EFI_PEI_FV_HANDLE FvHandle,
1452 OUT EFI_FV_INFO *VolumeInfo
1453 )
1454 {
1455 EFI_FIRMWARE_VOLUME_HEADER FwVolHeader;
1456 EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo;
1457
1458 if ((VolumeInfo == NULL) || (FvHandle == NULL)) {
1459 return EFI_INVALID_PARAMETER;
1460 }
1461
1462 //
1463 // VolumeHandle may not align at 8 byte,
1464 // but FvLength is UINT64 type, which requires FvHeader align at least 8 byte.
1465 // So, Copy FvHeader into the local FvHeader structure.
1466 //
1467 CopyMem (&FwVolHeader, FvHandle, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
1468
1469 //
1470 // Check Fv Image Signature
1471 //
1472 if (FwVolHeader.Signature != EFI_FVH_SIGNATURE) {
1473 return EFI_INVALID_PARAMETER;
1474 }
1475
1476 ZeroMem (VolumeInfo, sizeof (EFI_FV_INFO));
1477 VolumeInfo->FvAttributes = FwVolHeader.Attributes;
1478 VolumeInfo->FvStart = (VOID *) FvHandle;
1479 VolumeInfo->FvSize = FwVolHeader.FvLength;
1480 CopyMem (&VolumeInfo->FvFormat, &FwVolHeader.FileSystemGuid, sizeof(EFI_GUID));
1481
1482 if (FwVolHeader.ExtHeaderOffset != 0) {
1483 FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER*)(((UINT8 *)FvHandle) + FwVolHeader.ExtHeaderOffset);
1484 CopyMem (&VolumeInfo->FvName, &FwVolExHeaderInfo->FvName, sizeof(EFI_GUID));
1485 }
1486
1487 return EFI_SUCCESS;
1488 }
1489
1490 /**
1491 Find the next matching section in the firmware file.
1492
1493 This service enables PEI modules to discover sections
1494 of a given type within a valid file.
1495
1496 @param This Points to this instance of the
1497 EFI_PEI_FIRMWARE_VOLUME_PPI.
1498 @param SearchType A filter to find only sections of this
1499 type.
1500 @param FileHandle Handle of firmware file in which to
1501 search.
1502 @param SectionData Updated upon return to point to the
1503 section found.
1504
1505 @retval EFI_SUCCESS Section was found.
1506 @retval EFI_NOT_FOUND Section of the specified type was not
1507 found. SectionData contains NULL.
1508 **/
1509 EFI_STATUS
1510 EFIAPI
1511 PeiFfsFvPpiFindSectionByType (
1512 IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This,
1513 IN EFI_SECTION_TYPE SearchType,
1514 IN EFI_PEI_FILE_HANDLE FileHandle,
1515 OUT VOID **SectionData
1516 )
1517 {
1518 EFI_FFS_FILE_HEADER *FfsFileHeader;
1519 UINT32 FileSize;
1520 EFI_COMMON_SECTION_HEADER *Section;
1521 PEI_FW_VOL_INSTANCE *FwVolInstance;
1522
1523 FwVolInstance = PEI_FW_VOL_INSTANCE_FROM_FV_THIS (This);
1524
1525 FfsFileHeader = (EFI_FFS_FILE_HEADER *)(FileHandle);
1526
1527 if (IS_FFS_FILE2 (FfsFileHeader)) {
1528 ASSERT (FFS_FILE2_SIZE (FfsFileHeader) > 0x00FFFFFF);
1529 if (!FwVolInstance->IsFfs3Fv) {
1530 DEBUG ((EFI_D_ERROR, "It is a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsFileHeader->Name));
1531 return EFI_NOT_FOUND;
1532 }
1533 Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER2));
1534 FileSize = FFS_FILE2_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER2);
1535 } else {
1536 Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER));
1537 FileSize = FFS_FILE_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER);
1538 }
1539
1540 return ProcessSection (
1541 GetPeiServicesTablePointer (),
1542 SearchType,
1543 Section,
1544 FileSize,
1545 SectionData,
1546 FwVolInstance->IsFfs3Fv
1547 );
1548 }
1549
1550 /**
1551 Convert the handle of FV to pointer of corresponding PEI_CORE_FV_HANDLE.
1552
1553 @param FvHandle The handle of a FV.
1554
1555 @retval NULL if can not find.
1556 @return Pointer of corresponding PEI_CORE_FV_HANDLE.
1557 **/
1558 PEI_CORE_FV_HANDLE *
1559 FvHandleToCoreHandle (
1560 IN EFI_PEI_FV_HANDLE FvHandle
1561 )
1562 {
1563 UINTN Index;
1564 PEI_CORE_INSTANCE *PrivateData;
1565
1566 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer());
1567 for (Index = 0; Index < PrivateData->FvCount; Index ++) {
1568 if (FvHandle == PrivateData->Fv[Index].FvHandle) {
1569 return &PrivateData->Fv[Index];
1570 }
1571 }
1572
1573 return NULL;
1574 }
1575
1576 /**
1577 Get instance of PEI_CORE_FV_HANDLE for next volume according to given index.
1578
1579 This routine also will install FvInfo ppi for FV hob in PI ways.
1580
1581 @param Private Pointer of PEI_CORE_INSTANCE
1582 @param Instance The index of FV want to be searched.
1583
1584 @return Instance of PEI_CORE_FV_HANDLE.
1585 **/
1586 PEI_CORE_FV_HANDLE *
1587 FindNextCoreFvHandle (
1588 IN PEI_CORE_INSTANCE *Private,
1589 IN UINTN Instance
1590 )
1591 {
1592 UINTN Index;
1593 BOOLEAN Match;
1594 EFI_HOB_FIRMWARE_VOLUME *FvHob;
1595
1596 //
1597 // Handle Framework FvHob and Install FvInfo Ppi for it.
1598 //
1599 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
1600 //
1601 // Loop to search the wanted FirmwareVolume which supports FFS
1602 //
1603 FvHob = (EFI_HOB_FIRMWARE_VOLUME *)GetFirstHob (EFI_HOB_TYPE_FV);
1604 while (FvHob != NULL) {
1605 //
1606 // Search whether FvHob has been installed into PeiCore's FV database.
1607 // If found, no need install new FvInfoPpi for it.
1608 //
1609 for (Index = 0, Match = FALSE; Index < Private->FvCount; Index++) {
1610 if ((EFI_PEI_FV_HANDLE)(UINTN)FvHob->BaseAddress == Private->Fv[Index].FvHeader) {
1611 Match = TRUE;
1612 break;
1613 }
1614 }
1615
1616 //
1617 // Search whether FvHob has been cached into PeiCore's Unknown FV database.
1618 // If found, no need install new FvInfoPpi for it.
1619 //
1620 if (!Match) {
1621 for (Index = 0; Index < Private->UnknownFvInfoCount; Index ++) {
1622 if ((UINTN)FvHob->BaseAddress == (UINTN)Private->UnknownFvInfo[Index].FvInfo) {
1623 Match = TRUE;
1624 break;
1625 }
1626 }
1627 }
1628
1629 //
1630 // If the Fv in FvHob has not been installed into PeiCore's FV database and has
1631 // not been cached into PeiCore's Unknown FV database, install a new FvInfoPpi
1632 // for it then PeiCore will dispatch it in callback of FvInfoPpi.
1633 //
1634 if (!Match) {
1635 PeiServicesInstallFvInfoPpi (
1636 &(((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvHob->BaseAddress)->FileSystemGuid),
1637 (VOID *)(UINTN)FvHob->BaseAddress,
1638 (UINT32)FvHob->Length,
1639 NULL,
1640 NULL
1641 );
1642 }
1643
1644 FvHob = (EFI_HOB_FIRMWARE_VOLUME *)GetNextHob (EFI_HOB_TYPE_FV, (VOID *)((UINTN)FvHob + FvHob->Header.HobLength));
1645 }
1646 }
1647
1648 ASSERT (Private->FvCount <= FixedPcdGet32 (PcdPeiCoreMaxFvSupported));
1649 if (Instance >= Private->FvCount) {
1650 return NULL;
1651 }
1652
1653 return &Private->Fv[Instance];
1654 }
1655
1656 /**
1657 After PeiCore image is shadowed into permanent memory, all build-in FvPpi should
1658 be re-installed with the instance in permanent memory and all cached FvPpi pointers in
1659 PrivateData->Fv[] array should be fixed up to be pointed to the one in permenant
1660 memory.
1661
1662 @param PrivateData Pointer to PEI_CORE_INSTANCE.
1663 **/
1664 VOID
1665 PeiReinitializeFv (
1666 IN PEI_CORE_INSTANCE *PrivateData
1667 )
1668 {
1669 VOID *OldFfsFvPpi;
1670 EFI_PEI_PPI_DESCRIPTOR *OldDescriptor;
1671 UINTN Index;
1672 EFI_STATUS Status;
1673
1674 //
1675 // Locate old build-in Ffs2 EFI_PEI_FIRMWARE_VOLUME_PPI which
1676 // in flash.
1677 //
1678 Status = PeiServicesLocatePpi (
1679 &gEfiFirmwareFileSystem2Guid,
1680 0,
1681 &OldDescriptor,
1682 &OldFfsFvPpi
1683 );
1684 ASSERT_EFI_ERROR (Status);
1685
1686 //
1687 // Re-install the EFI_PEI_FIRMWARE_VOLUME_PPI for build-in Ffs2
1688 // which is shadowed from flash to permanent memory within PeiCore image.
1689 //
1690 Status = PeiServicesReInstallPpi (OldDescriptor, &mPeiFfs2FvPpiList);
1691 ASSERT_EFI_ERROR (Status);
1692
1693 //
1694 // Fixup all FvPpi pointers for the implementation in flash to permanent memory.
1695 //
1696 for (Index = 0; Index < FixedPcdGet32 (PcdPeiCoreMaxFvSupported); Index ++) {
1697 if (PrivateData->Fv[Index].FvPpi == OldFfsFvPpi) {
1698 PrivateData->Fv[Index].FvPpi = &mPeiFfs2FwVol.Fv;
1699 }
1700 }
1701
1702 //
1703 // Locate old build-in Ffs3 EFI_PEI_FIRMWARE_VOLUME_PPI which
1704 // in flash.
1705 //
1706 Status = PeiServicesLocatePpi (
1707 &gEfiFirmwareFileSystem3Guid,
1708 0,
1709 &OldDescriptor,
1710 &OldFfsFvPpi
1711 );
1712 ASSERT_EFI_ERROR (Status);
1713
1714 //
1715 // Re-install the EFI_PEI_FIRMWARE_VOLUME_PPI for build-in Ffs3
1716 // which is shadowed from flash to permanent memory within PeiCore image.
1717 //
1718 Status = PeiServicesReInstallPpi (OldDescriptor, &mPeiFfs3FvPpiList);
1719 ASSERT_EFI_ERROR (Status);
1720
1721 //
1722 // Fixup all FvPpi pointers for the implementation in flash to permanent memory.
1723 //
1724 for (Index = 0; Index < FixedPcdGet32 (PcdPeiCoreMaxFvSupported); Index ++) {
1725 if (PrivateData->Fv[Index].FvPpi == OldFfsFvPpi) {
1726 PrivateData->Fv[Index].FvPpi = &mPeiFfs3FwVol.Fv;
1727 }
1728 }
1729 }
1730
1731 /**
1732 Report the information for a new discoveried FV in unknown third-party format.
1733
1734 If the EFI_PEI_FIRMWARE_VOLUME_PPI has not been installed for third-party FV format, but
1735 the FV in this format has been discoveried, then this FV's information will be cached into
1736 PEI_CORE_INSTANCE's UnknownFvInfo array.
1737 Also a notification would be installed for unknown third-party FV format guid, if EFI_PEI_FIRMWARE_VOLUME_PPI
1738 is installed later by platform's PEIM, the original unknown third-party FV will be processed by
1739 using new installed EFI_PEI_FIRMWARE_VOLUME_PPI.
1740
1741 @param PrivateData Point to instance of PEI_CORE_INSTANCE
1742 @param Format Point to the unknown third-party format guid.
1743 @param FvInfo Point to FvInfo buffer.
1744 @param FvInfoSize The size of FvInfo buffer.
1745
1746 @retval EFI_OUT_OF_RESOURCES The FV info array in PEI_CORE_INSTANCE has no more spaces.
1747 @retval EFI_SUCCESS Success to add the information for unknown FV.
1748 **/
1749 EFI_STATUS
1750 AddUnknownFormatFvInfo (
1751 IN PEI_CORE_INSTANCE *PrivateData,
1752 IN EFI_GUID *Format,
1753 IN VOID *FvInfo,
1754 IN UINT32 FvInfoSize
1755 )
1756 {
1757 PEI_CORE_UNKNOW_FORMAT_FV_INFO *NewUnknownFv;
1758
1759 if (PrivateData->UnknownFvInfoCount + 1 >= FixedPcdGet32 (PcdPeiCoreMaxFvSupported)) {
1760 return EFI_OUT_OF_RESOURCES;
1761 }
1762
1763 NewUnknownFv = &PrivateData->UnknownFvInfo[PrivateData->UnknownFvInfoCount];
1764 PrivateData->UnknownFvInfoCount ++;
1765
1766 CopyGuid (&NewUnknownFv->FvFormat, Format);
1767 NewUnknownFv->FvInfo = FvInfo;
1768 NewUnknownFv->FvInfoSize = FvInfoSize;
1769 NewUnknownFv->NotifyDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
1770 NewUnknownFv->NotifyDescriptor.Guid = &NewUnknownFv->FvFormat;
1771 NewUnknownFv->NotifyDescriptor.Notify = ThirdPartyFvPpiNotifyCallback;
1772
1773 PeiServicesNotifyPpi (&NewUnknownFv->NotifyDescriptor);
1774 return EFI_SUCCESS;
1775 }
1776
1777 /**
1778 Find the FV information according to third-party FV format guid.
1779
1780 This routine also will remove the FV information found by given FV format guid from
1781 PrivateData->UnknownFvInfo[].
1782
1783 @param PrivateData Point to instance of PEI_CORE_INSTANCE
1784 @param Format Point to given FV format guid
1785 @param FvInfo On return, the pointer of FV information buffer
1786 @param FvInfoSize On return, the size of FV information buffer.
1787
1788 @retval EFI_NOT_FOUND The FV is not found for new installed EFI_PEI_FIRMWARE_VOLUME_PPI
1789 @retval EFI_SUCCESS Success to find a FV which could be processed by new installed EFI_PEI_FIRMWARE_VOLUME_PPI.
1790 **/
1791 EFI_STATUS
1792 FindUnknownFormatFvInfo (
1793 IN PEI_CORE_INSTANCE *PrivateData,
1794 IN EFI_GUID *Format,
1795 OUT VOID **FvInfo,
1796 OUT UINT32 *FvInfoSize
1797 )
1798 {
1799 UINTN Index;
1800 UINTN Index2;
1801
1802 Index = 0;
1803 for (; Index < PrivateData->UnknownFvInfoCount; Index ++) {
1804 if (CompareGuid (Format, &PrivateData->UnknownFvInfo[Index].FvFormat)) {
1805 break;
1806 }
1807 }
1808
1809 if (Index == PrivateData->UnknownFvInfoCount) {
1810 return EFI_NOT_FOUND;
1811 }
1812
1813 *FvInfo = PrivateData->UnknownFvInfo[Index].FvInfo;
1814 *FvInfoSize = PrivateData->UnknownFvInfo[Index].FvInfoSize;
1815
1816 //
1817 // Remove an entry from UnknownFvInfo array.
1818 //
1819 Index2 = Index + 1;
1820 for (;Index2 < PrivateData->UnknownFvInfoCount; Index2 ++, Index ++) {
1821 CopyMem (&PrivateData->UnknownFvInfo[Index], &PrivateData->UnknownFvInfo[Index2], sizeof (PEI_CORE_UNKNOW_FORMAT_FV_INFO));
1822 }
1823 PrivateData->UnknownFvInfoCount --;
1824 return EFI_SUCCESS;
1825 }
1826
1827 /**
1828 Notification callback function for EFI_PEI_FIRMWARE_VOLUME_PPI.
1829
1830 When a EFI_PEI_FIRMWARE_VOLUME_PPI is installed to support new FV format, this
1831 routine is called to process all discoveried FVs in this format.
1832
1833 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
1834 @param NotifyDescriptor Address of the notification descriptor data structure.
1835 @param Ppi Address of the PPI that was installed.
1836
1837 @retval EFI_SUCCESS The notification callback is processed correctly.
1838 **/
1839 EFI_STATUS
1840 EFIAPI
1841 ThirdPartyFvPpiNotifyCallback (
1842 IN EFI_PEI_SERVICES **PeiServices,
1843 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
1844 IN VOID *Ppi
1845 )
1846 {
1847 PEI_CORE_INSTANCE *PrivateData;
1848 EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
1849 VOID *FvInfo;
1850 UINT32 FvInfoSize;
1851 EFI_STATUS Status;
1852 EFI_PEI_FV_HANDLE FvHandle;
1853 BOOLEAN IsProcessed;
1854 UINTN FvIndex;
1855 EFI_PEI_FILE_HANDLE FileHandle;
1856 VOID *DepexData;
1857
1858 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
1859 FvPpi = (EFI_PEI_FIRMWARE_VOLUME_PPI*) Ppi;
1860
1861 do {
1862 Status = FindUnknownFormatFvInfo (PrivateData, NotifyDescriptor->Guid, &FvInfo, &FvInfoSize);
1863 if (EFI_ERROR (Status)) {
1864 return EFI_SUCCESS;
1865 }
1866
1867 //
1868 // Process new found FV and get FV handle.
1869 //
1870 Status = FvPpi->ProcessVolume (FvPpi, FvInfo, FvInfoSize, &FvHandle);
1871 if (EFI_ERROR (Status)) {
1872 DEBUG ((EFI_D_ERROR, "Fail to process the FV 0x%p, FV may be corrupted!\n", FvInfo));
1873 continue;
1874 }
1875
1876 //
1877 // Check whether the FV has already been processed.
1878 //
1879 IsProcessed = FALSE;
1880 for (FvIndex = 0; FvIndex < PrivateData->FvCount; FvIndex ++) {
1881 if (PrivateData->Fv[FvIndex].FvHandle == FvHandle) {
1882 DEBUG ((EFI_D_INFO, "The Fv %p has already been processed!\n", FvInfo));
1883 IsProcessed = TRUE;
1884 break;
1885 }
1886 }
1887
1888 if (IsProcessed) {
1889 continue;
1890 }
1891
1892 if (PrivateData->FvCount >= FixedPcdGet32 (PcdPeiCoreMaxFvSupported)) {
1893 DEBUG ((EFI_D_ERROR, "The number of Fv Images (%d) exceed the max supported FVs (%d) in Pei", PrivateData->FvCount + 1, FixedPcdGet32 (PcdPeiCoreMaxFvSupported)));
1894 DEBUG ((EFI_D_ERROR, "PcdPeiCoreMaxFvSupported value need be reconfigurated in DSC"));
1895 ASSERT (FALSE);
1896 }
1897
1898 //
1899 // Update internal PEI_CORE_FV array.
1900 //
1901 PrivateData->Fv[PrivateData->FvCount].FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*) FvInfo;
1902 PrivateData->Fv[PrivateData->FvCount].FvPpi = FvPpi;
1903 PrivateData->Fv[PrivateData->FvCount].FvHandle = FvHandle;
1904 DEBUG ((
1905 EFI_D_INFO,
1906 "The %dth FV start address is 0x%11p, size is 0x%08x, handle is 0x%p\n",
1907 (UINT32) PrivateData->FvCount,
1908 (VOID *) FvInfo,
1909 FvInfoSize,
1910 FvHandle
1911 ));
1912 PrivateData->FvCount ++;
1913
1914 //
1915 // Scan and process the new discoveried FV for EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
1916 //
1917 FileHandle = NULL;
1918 do {
1919 Status = FvPpi->FindFileByType (
1920 FvPpi,
1921 EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,
1922 FvHandle,
1923 &FileHandle
1924 );
1925 if (!EFI_ERROR (Status)) {
1926 Status = FvPpi->FindSectionByType (
1927 FvPpi,
1928 EFI_SECTION_PEI_DEPEX,
1929 FileHandle,
1930 (VOID**)&DepexData
1931 );
1932 if (!EFI_ERROR (Status)) {
1933 if (!PeimDispatchReadiness (PeiServices, DepexData)) {
1934 //
1935 // Dependency is not satisfied.
1936 //
1937 continue;
1938 }
1939 }
1940
1941 DEBUG ((EFI_D_INFO, "Found firmware volume Image File %p in FV[%d] %p\n", FileHandle, PrivateData->FvCount - 1, FvHandle));
1942 ProcessFvFile (&PrivateData->Fv[PrivateData->FvCount - 1], FileHandle);
1943 }
1944 } while (FileHandle != NULL);
1945 } while (TRUE);
1946 }