]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Core / Pei / Dispatcher / Dispatcher.c
1 /** @file
2 EFI PEI Core dispatch services
3
4 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "PeiMain.h"
11
12 /**
13
14 Discover all PEIMs and optional Apriori file in one FV. There is at most one
15 Apriori file in one FV.
16
17
18 @param Private Pointer to the private data passed in from caller
19 @param CoreFileHandle The instance of PEI_CORE_FV_HANDLE.
20
21 **/
22 VOID
23 DiscoverPeimsAndOrderWithApriori (
24 IN PEI_CORE_INSTANCE *Private,
25 IN PEI_CORE_FV_HANDLE *CoreFileHandle
26 )
27 {
28 EFI_STATUS Status;
29 EFI_PEI_FILE_HANDLE FileHandle;
30 EFI_PEI_FILE_HANDLE AprioriFileHandle;
31 EFI_GUID *Apriori;
32 UINTN Index;
33 UINTN Index2;
34 UINTN PeimIndex;
35 UINTN PeimCount;
36 EFI_GUID *Guid;
37 EFI_PEI_FILE_HANDLE *TempFileHandles;
38 EFI_GUID *TempFileGuid;
39 EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
40 EFI_FV_FILE_INFO FileInfo;
41
42 FvPpi = CoreFileHandle->FvPpi;
43
44 //
45 // Walk the FV and find all the PEIMs and the Apriori file.
46 //
47 AprioriFileHandle = NULL;
48 Private->CurrentFvFileHandles = NULL;
49 Guid = NULL;
50
51 //
52 // If the current FV has been scanned, directly get its cached records.
53 //
54 if (CoreFileHandle->ScanFv) {
55 Private->CurrentFvFileHandles = CoreFileHandle->FvFileHandles;
56 return;
57 }
58
59 TempFileHandles = Private->TempFileHandles;
60 TempFileGuid = Private->TempFileGuid;
61
62 //
63 // Go ahead to scan this FV, get PeimCount and cache FileHandles within it to TempFileHandles.
64 //
65 PeimCount = 0;
66 FileHandle = NULL;
67 do {
68 Status = FvPpi->FindFileByType (FvPpi, PEI_CORE_INTERNAL_FFS_FILE_DISPATCH_TYPE, CoreFileHandle->FvHandle, &FileHandle);
69 if (!EFI_ERROR (Status)) {
70 if (PeimCount >= Private->TempPeimCount) {
71 //
72 // Run out of room, grow the buffer.
73 //
74 TempFileHandles = AllocatePool (
75 sizeof (EFI_PEI_FILE_HANDLE) * (Private->TempPeimCount + TEMP_FILE_GROWTH_STEP)
76 );
77 ASSERT (TempFileHandles != NULL);
78 CopyMem (
79 TempFileHandles,
80 Private->TempFileHandles,
81 sizeof (EFI_PEI_FILE_HANDLE) * Private->TempPeimCount
82 );
83 Private->TempFileHandles = TempFileHandles;
84 TempFileGuid = AllocatePool (
85 sizeof (EFI_GUID) * (Private->TempPeimCount + TEMP_FILE_GROWTH_STEP)
86 );
87 ASSERT (TempFileGuid != NULL);
88 CopyMem (
89 TempFileGuid,
90 Private->TempFileGuid,
91 sizeof (EFI_GUID) * Private->TempPeimCount
92 );
93 Private->TempFileGuid = TempFileGuid;
94 Private->TempPeimCount = Private->TempPeimCount + TEMP_FILE_GROWTH_STEP;
95 }
96
97 TempFileHandles[PeimCount++] = FileHandle;
98 }
99 } while (!EFI_ERROR (Status));
100
101 DEBUG ((
102 DEBUG_INFO,
103 "%a(): Found 0x%x PEI FFS files in the %dth FV\n",
104 __FUNCTION__,
105 PeimCount,
106 Private->CurrentPeimFvCount
107 ));
108
109 if (PeimCount == 0) {
110 //
111 // No PEIM FFS file is found, set ScanFv flag and return.
112 //
113 CoreFileHandle->ScanFv = TRUE;
114 return;
115 }
116
117 //
118 // Record PeimCount, allocate buffer for PeimState and FvFileHandles.
119 //
120 CoreFileHandle->PeimCount = PeimCount;
121 CoreFileHandle->PeimState = AllocateZeroPool (sizeof (UINT8) * PeimCount);
122 ASSERT (CoreFileHandle->PeimState != NULL);
123 CoreFileHandle->FvFileHandles = AllocateZeroPool (sizeof (EFI_PEI_FILE_HANDLE) * PeimCount);
124 ASSERT (CoreFileHandle->FvFileHandles != NULL);
125
126 //
127 // Get Apriori File handle
128 //
129 Private->AprioriCount = 0;
130 Status = FvPpi->FindFileByName (FvPpi, &gPeiAprioriFileNameGuid, &CoreFileHandle->FvHandle, &AprioriFileHandle);
131 if (!EFI_ERROR (Status) && (AprioriFileHandle != NULL)) {
132 //
133 // Read the Apriori file
134 //
135 Status = FvPpi->FindSectionByType (FvPpi, EFI_SECTION_RAW, AprioriFileHandle, (VOID **)&Apriori);
136 if (!EFI_ERROR (Status)) {
137 //
138 // Calculate the number of PEIMs in the Apriori file
139 //
140 Status = FvPpi->GetFileInfo (FvPpi, AprioriFileHandle, &FileInfo);
141 ASSERT_EFI_ERROR (Status);
142 Private->AprioriCount = FileInfo.BufferSize;
143 if (IS_SECTION2 (FileInfo.Buffer)) {
144 Private->AprioriCount -= sizeof (EFI_COMMON_SECTION_HEADER2);
145 } else {
146 Private->AprioriCount -= sizeof (EFI_COMMON_SECTION_HEADER);
147 }
148
149 Private->AprioriCount /= sizeof (EFI_GUID);
150
151 for (Index = 0; Index < PeimCount; Index++) {
152 //
153 // Make an array of file name GUIDs that matches the FileHandle array so we can convert
154 // quickly from file name to file handle
155 //
156 Status = FvPpi->GetFileInfo (FvPpi, TempFileHandles[Index], &FileInfo);
157 ASSERT_EFI_ERROR (Status);
158 CopyMem (&TempFileGuid[Index], &FileInfo.FileName, sizeof (EFI_GUID));
159 }
160
161 //
162 // Walk through TempFileGuid array to find out who is invalid PEIM GUID in Apriori file.
163 // Add available PEIMs in Apriori file into FvFileHandles array.
164 //
165 Index = 0;
166 for (Index2 = 0; Index2 < Private->AprioriCount; Index2++) {
167 Guid = ScanGuid (TempFileGuid, PeimCount * sizeof (EFI_GUID), &Apriori[Index2]);
168 if (Guid != NULL) {
169 PeimIndex = ((UINTN)Guid - (UINTN)&TempFileGuid[0])/sizeof (EFI_GUID);
170 CoreFileHandle->FvFileHandles[Index++] = TempFileHandles[PeimIndex];
171
172 //
173 // Since we have copied the file handle we can remove it from this list.
174 //
175 TempFileHandles[PeimIndex] = NULL;
176 }
177 }
178
179 //
180 // Update valid AprioriCount
181 //
182 Private->AprioriCount = Index;
183
184 //
185 // Add in any PEIMs not in the Apriori file
186 //
187 for (Index2 = 0; Index2 < PeimCount; Index2++) {
188 if (TempFileHandles[Index2] != NULL) {
189 CoreFileHandle->FvFileHandles[Index++] = TempFileHandles[Index2];
190 TempFileHandles[Index2] = NULL;
191 }
192 }
193
194 ASSERT (Index == PeimCount);
195 }
196 } else {
197 CopyMem (CoreFileHandle->FvFileHandles, TempFileHandles, sizeof (EFI_PEI_FILE_HANDLE) * PeimCount);
198 }
199
200 //
201 // The current FV File Handles have been cached. So that we don't have to scan the FV again.
202 // Instead, we can retrieve the file handles within this FV from cached records.
203 //
204 CoreFileHandle->ScanFv = TRUE;
205 Private->CurrentFvFileHandles = CoreFileHandle->FvFileHandles;
206 }
207
208 //
209 // This is the minimum memory required by DxeCore initialization. When LMFA feature enabled,
210 // This part of memory still need reserved on the very top of memory so that the DXE Core could
211 // use these memory for data initialization. This macro should be sync with the same marco
212 // defined in DXE Core.
213 //
214 #define MINIMUM_INITIAL_MEMORY_SIZE 0x10000
215
216 /**
217 This function is to test if the memory range described in resource HOB is available or not.
218
219 This function should only be invoked when Loading Module at Fixed Address(LMFA) feature is enabled. Some platform may allocate the
220 memory before PeiLoadFixAddressHook in invoked. so this function is to test if the memory range described by the input resource HOB is
221 available or not.
222
223 @param PrivateData Pointer to the private data passed in from caller
224 @param ResourceHob Pointer to a resource HOB which described the memory range described by the input resource HOB
225 **/
226 BOOLEAN
227 PeiLoadFixAddressIsMemoryRangeAvailable (
228 IN PEI_CORE_INSTANCE *PrivateData,
229 IN EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob
230 )
231 {
232 EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
233 BOOLEAN IsAvailable;
234 EFI_PEI_HOB_POINTERS Hob;
235
236 IsAvailable = TRUE;
237 if ((PrivateData == NULL) || (ResourceHob == NULL)) {
238 return FALSE;
239 }
240
241 //
242 // test if the memory range describe in the HOB is already allocated.
243 //
244 for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
245 //
246 // See if this is a memory allocation HOB
247 //
248 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
249 MemoryHob = Hob.MemoryAllocation;
250 if ((MemoryHob->AllocDescriptor.MemoryBaseAddress == ResourceHob->PhysicalStart) &&
251 (MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength == ResourceHob->PhysicalStart + ResourceHob->ResourceLength))
252 {
253 IsAvailable = FALSE;
254 break;
255 }
256 }
257 }
258
259 return IsAvailable;
260 }
261
262 /**
263 Hook function for Loading Module at Fixed Address feature
264
265 This function should only be invoked when Loading Module at Fixed Address(LMFA) feature is enabled. When feature is
266 configured as Load Modules at Fix Absolute Address, this function is to validate the top address assigned by user. When
267 feature is configured as Load Modules at Fixed Offset, the function is to find the top address which is TOLM-TSEG in general.
268 And also the function will re-install PEI memory.
269
270 @param PrivateData Pointer to the private data passed in from caller
271
272 **/
273 VOID
274 PeiLoadFixAddressHook (
275 IN PEI_CORE_INSTANCE *PrivateData
276 )
277 {
278 EFI_PHYSICAL_ADDRESS TopLoadingAddress;
279 UINT64 PeiMemorySize;
280 UINT64 TotalReservedMemorySize;
281 UINT64 MemoryRangeEnd;
282 EFI_PHYSICAL_ADDRESS HighAddress;
283 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
284 EFI_HOB_RESOURCE_DESCRIPTOR *NextResourceHob;
285 EFI_HOB_RESOURCE_DESCRIPTOR *CurrentResourceHob;
286 EFI_PEI_HOB_POINTERS CurrentHob;
287 EFI_PEI_HOB_POINTERS Hob;
288 EFI_PEI_HOB_POINTERS NextHob;
289 EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
290
291 //
292 // Initialize Local Variables
293 //
294 CurrentResourceHob = NULL;
295 ResourceHob = NULL;
296 NextResourceHob = NULL;
297 HighAddress = 0;
298 TopLoadingAddress = 0;
299 MemoryRangeEnd = 0;
300 CurrentHob.Raw = PrivateData->HobList.Raw;
301 PeiMemorySize = PrivateData->PhysicalMemoryLength;
302 //
303 // The top reserved memory include 3 parts: the topest range is for DXE core initialization with the size MINIMUM_INITIAL_MEMORY_SIZE
304 // then RuntimeCodePage range and Boot time code range.
305 //
306 TotalReservedMemorySize = MINIMUM_INITIAL_MEMORY_SIZE + EFI_PAGES_TO_SIZE (PcdGet32 (PcdLoadFixAddressRuntimeCodePageNumber));
307 TotalReservedMemorySize += EFI_PAGES_TO_SIZE (PcdGet32 (PcdLoadFixAddressBootTimeCodePageNumber));
308 //
309 // PEI memory range lies below the top reserved memory
310 //
311 TotalReservedMemorySize += PeiMemorySize;
312
313 DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressRuntimeCodePageNumber= 0x%x.\n", PcdGet32 (PcdLoadFixAddressRuntimeCodePageNumber)));
314 DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressBootTimeCodePageNumber= 0x%x.\n", PcdGet32 (PcdLoadFixAddressBootTimeCodePageNumber)));
315 DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressPeiCodePageNumber= 0x%x.\n", PcdGet32 (PcdLoadFixAddressPeiCodePageNumber)));
316 DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: Total Reserved Memory Size = 0x%lx.\n", TotalReservedMemorySize));
317 //
318 // Loop through the system memory typed HOB to merge the adjacent memory range
319 //
320 for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
321 //
322 // See if this is a resource descriptor HOB
323 //
324 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
325 ResourceHob = Hob.ResourceDescriptor;
326 //
327 // If range described in this HOB is not system memory or higher than MAX_ADDRESS, ignored.
328 //
329 if ((ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) ||
330 (ResourceHob->PhysicalStart + ResourceHob->ResourceLength > MAX_ADDRESS))
331 {
332 continue;
333 }
334
335 for (NextHob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (NextHob); NextHob.Raw = GET_NEXT_HOB (NextHob)) {
336 if (NextHob.Raw == Hob.Raw) {
337 continue;
338 }
339
340 //
341 // See if this is a resource descriptor HOB
342 //
343 if (GET_HOB_TYPE (NextHob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
344 NextResourceHob = NextHob.ResourceDescriptor;
345 //
346 // test if range described in this NextResourceHob is system memory and have the same attribute.
347 // Note: Here is a assumption that system memory should always be healthy even without test.
348 //
349 if ((NextResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&
350 (((NextResourceHob->ResourceAttribute^ResourceHob->ResourceAttribute)&(~EFI_RESOURCE_ATTRIBUTE_TESTED)) == 0))
351 {
352 //
353 // See if the memory range described in ResourceHob and NextResourceHob is adjacent
354 //
355 if (((ResourceHob->PhysicalStart <= NextResourceHob->PhysicalStart) &&
356 (ResourceHob->PhysicalStart + ResourceHob->ResourceLength >= NextResourceHob->PhysicalStart)) ||
357 ((ResourceHob->PhysicalStart >= NextResourceHob->PhysicalStart) &&
358 (ResourceHob->PhysicalStart <= NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength)))
359 {
360 MemoryRangeEnd = ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength) > (NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength)) ?
361 (ResourceHob->PhysicalStart + ResourceHob->ResourceLength) : (NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength);
362
363 ResourceHob->PhysicalStart = (ResourceHob->PhysicalStart < NextResourceHob->PhysicalStart) ?
364 ResourceHob->PhysicalStart : NextResourceHob->PhysicalStart;
365
366 ResourceHob->ResourceLength = (MemoryRangeEnd - ResourceHob->PhysicalStart);
367
368 ResourceHob->ResourceAttribute = ResourceHob->ResourceAttribute & (~EFI_RESOURCE_ATTRIBUTE_TESTED);
369 //
370 // Delete the NextResourceHob by marking it as unused.
371 //
372 GET_HOB_TYPE (NextHob) = EFI_HOB_TYPE_UNUSED;
373 }
374 }
375 }
376 }
377 }
378 }
379
380 //
381 // Some platform is already allocated pages before the HOB re-org. Here to build dedicated resource HOB to describe
382 // the allocated memory range
383 //
384 for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
385 //
386 // See if this is a memory allocation HOB
387 //
388 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
389 MemoryHob = Hob.MemoryAllocation;
390 for (NextHob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (NextHob); NextHob.Raw = GET_NEXT_HOB (NextHob)) {
391 //
392 // See if this is a resource descriptor HOB
393 //
394 if (GET_HOB_TYPE (NextHob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
395 NextResourceHob = NextHob.ResourceDescriptor;
396 //
397 // If range described in this HOB is not system memory or higher than MAX_ADDRESS, ignored.
398 //
399 if ((NextResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) || (NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength > MAX_ADDRESS)) {
400 continue;
401 }
402
403 //
404 // If the range describe in memory allocation HOB belongs to the memory range described by the resource HOB
405 //
406 if ((MemoryHob->AllocDescriptor.MemoryBaseAddress >= NextResourceHob->PhysicalStart) &&
407 (MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength <= NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength))
408 {
409 //
410 // Build separate resource HOB for this allocated range
411 //
412 if (MemoryHob->AllocDescriptor.MemoryBaseAddress > NextResourceHob->PhysicalStart) {
413 BuildResourceDescriptorHob (
414 EFI_RESOURCE_SYSTEM_MEMORY,
415 NextResourceHob->ResourceAttribute,
416 NextResourceHob->PhysicalStart,
417 (MemoryHob->AllocDescriptor.MemoryBaseAddress - NextResourceHob->PhysicalStart)
418 );
419 }
420
421 if (MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength < NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength) {
422 BuildResourceDescriptorHob (
423 EFI_RESOURCE_SYSTEM_MEMORY,
424 NextResourceHob->ResourceAttribute,
425 MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength,
426 (NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength -(MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength))
427 );
428 }
429
430 NextResourceHob->PhysicalStart = MemoryHob->AllocDescriptor.MemoryBaseAddress;
431 NextResourceHob->ResourceLength = MemoryHob->AllocDescriptor.MemoryLength;
432 break;
433 }
434 }
435 }
436 }
437 }
438
439 //
440 // Try to find and validate the TOP address.
441 //
442 if ((INT64)PcdGet64 (PcdLoadModuleAtFixAddressEnable) > 0 ) {
443 //
444 // The LMFA feature is enabled as load module at fixed absolute address.
445 //
446 TopLoadingAddress = (EFI_PHYSICAL_ADDRESS)PcdGet64 (PcdLoadModuleAtFixAddressEnable);
447 DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: Loading module at fixed absolute address.\n"));
448 //
449 // validate the Address. Loop the resource descriptor HOB to make sure the address is in valid memory range
450 //
451 if ((TopLoadingAddress & EFI_PAGE_MASK) != 0) {
452 DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED ERROR:Top Address 0x%lx is invalid since top address should be page align. \n", TopLoadingAddress));
453 ASSERT (FALSE);
454 }
455
456 //
457 // Search for a memory region that is below MAX_ADDRESS and in which TopLoadingAddress lies
458 //
459 for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
460 //
461 // See if this is a resource descriptor HOB
462 //
463 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
464 ResourceHob = Hob.ResourceDescriptor;
465 //
466 // See if this resource descriptor HOB describes tested system memory below MAX_ADDRESS
467 //
468 if ((ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&
469 (ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS))
470 {
471 //
472 // See if Top address specified by user is valid.
473 //
474 if ((ResourceHob->PhysicalStart + TotalReservedMemorySize < TopLoadingAddress) &&
475 ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength - MINIMUM_INITIAL_MEMORY_SIZE) >= TopLoadingAddress) &&
476 PeiLoadFixAddressIsMemoryRangeAvailable (PrivateData, ResourceHob))
477 {
478 CurrentResourceHob = ResourceHob;
479 CurrentHob = Hob;
480 break;
481 }
482 }
483 }
484 }
485
486 if (CurrentResourceHob != NULL) {
487 DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO:Top Address 0x%lx is valid \n", TopLoadingAddress));
488 TopLoadingAddress += MINIMUM_INITIAL_MEMORY_SIZE;
489 } else {
490 DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED ERROR:Top Address 0x%lx is invalid \n", TopLoadingAddress));
491 DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED ERROR:The recommended Top Address for the platform is: \n"));
492 //
493 // Print the recommended Top address range.
494 //
495 for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
496 //
497 // See if this is a resource descriptor HOB
498 //
499 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
500 ResourceHob = Hob.ResourceDescriptor;
501 //
502 // See if this resource descriptor HOB describes tested system memory below MAX_ADDRESS
503 //
504 if ((ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&
505 (ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS))
506 {
507 //
508 // See if Top address specified by user is valid.
509 //
510 if ((ResourceHob->ResourceLength > TotalReservedMemorySize) && PeiLoadFixAddressIsMemoryRangeAvailable (PrivateData, ResourceHob)) {
511 DEBUG ((
512 DEBUG_INFO,
513 "(0x%lx, 0x%lx)\n",
514 (ResourceHob->PhysicalStart + TotalReservedMemorySize -MINIMUM_INITIAL_MEMORY_SIZE),
515 (ResourceHob->PhysicalStart + ResourceHob->ResourceLength -MINIMUM_INITIAL_MEMORY_SIZE)
516 ));
517 }
518 }
519 }
520 }
521
522 //
523 // Assert here
524 //
525 ASSERT (FALSE);
526 return;
527 }
528 } else {
529 //
530 // The LMFA feature is enabled as load module at fixed offset relative to TOLM
531 // Parse the Hob list to find the topest available memory. Generally it is (TOLM - TSEG)
532 //
533 //
534 // Search for a tested memory region that is below MAX_ADDRESS
535 //
536 for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
537 //
538 // See if this is a resource descriptor HOB
539 //
540 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
541 ResourceHob = Hob.ResourceDescriptor;
542 //
543 // See if this resource descriptor HOB describes tested system memory below MAX_ADDRESS
544 //
545 if ((ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&
546 (ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS) &&
547 (ResourceHob->ResourceLength > TotalReservedMemorySize) && PeiLoadFixAddressIsMemoryRangeAvailable (PrivateData, ResourceHob))
548 {
549 //
550 // See if this is the highest largest system memory region below MaxAddress
551 //
552 if (ResourceHob->PhysicalStart > HighAddress) {
553 CurrentResourceHob = ResourceHob;
554 CurrentHob = Hob;
555 HighAddress = CurrentResourceHob->PhysicalStart;
556 }
557 }
558 }
559 }
560
561 if (CurrentResourceHob == NULL) {
562 DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED ERROR:The System Memory is too small\n"));
563 //
564 // Assert here
565 //
566 ASSERT (FALSE);
567 return;
568 } else {
569 TopLoadingAddress = CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength;
570 }
571 }
572
573 if (CurrentResourceHob != NULL) {
574 //
575 // rebuild resource HOB for PEI memory and reserved memory
576 //
577 BuildResourceDescriptorHob (
578 EFI_RESOURCE_SYSTEM_MEMORY,
579 (
580 EFI_RESOURCE_ATTRIBUTE_PRESENT |
581 EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
582 EFI_RESOURCE_ATTRIBUTE_TESTED |
583 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
584 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
585 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
586 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
587 ),
588 (TopLoadingAddress - TotalReservedMemorySize),
589 TotalReservedMemorySize
590 );
591 //
592 // rebuild resource for the remain memory if necessary
593 //
594 if (CurrentResourceHob->PhysicalStart < TopLoadingAddress - TotalReservedMemorySize) {
595 BuildResourceDescriptorHob (
596 EFI_RESOURCE_SYSTEM_MEMORY,
597 (
598 EFI_RESOURCE_ATTRIBUTE_PRESENT |
599 EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
600 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
601 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
602 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
603 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
604 ),
605 CurrentResourceHob->PhysicalStart,
606 (TopLoadingAddress - TotalReservedMemorySize - CurrentResourceHob->PhysicalStart)
607 );
608 }
609
610 if (CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength > TopLoadingAddress ) {
611 BuildResourceDescriptorHob (
612 EFI_RESOURCE_SYSTEM_MEMORY,
613 (
614 EFI_RESOURCE_ATTRIBUTE_PRESENT |
615 EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
616 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
617 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
618 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
619 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
620 ),
621 TopLoadingAddress,
622 (CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength - TopLoadingAddress)
623 );
624 }
625
626 //
627 // Delete CurrentHob by marking it as unused since the memory range described by is rebuilt.
628 //
629 GET_HOB_TYPE (CurrentHob) = EFI_HOB_TYPE_UNUSED;
630 }
631
632 //
633 // Cache the top address for Loading Module at Fixed Address feature
634 //
635 PrivateData->LoadModuleAtFixAddressTopAddress = TopLoadingAddress - MINIMUM_INITIAL_MEMORY_SIZE;
636 DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: Top address = 0x%lx\n", PrivateData->LoadModuleAtFixAddressTopAddress));
637 //
638 // reinstall the PEI memory relative to TopLoadingAddress
639 //
640 PrivateData->PhysicalMemoryBegin = TopLoadingAddress - TotalReservedMemorySize;
641 PrivateData->FreePhysicalMemoryTop = PrivateData->PhysicalMemoryBegin + PeiMemorySize;
642 }
643
644 /**
645 This routine is invoked in switch stack as PeiCore Entry.
646
647 @param SecCoreData Points to a data structure containing information about the PEI core's operating
648 environment, such as the size and location of temporary RAM, the stack location and
649 the BFV location.
650 @param Private Pointer to old core data that is used to initialize the
651 core's data areas.
652 **/
653 VOID
654 EFIAPI
655 PeiCoreEntry (
656 IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
657 IN PEI_CORE_INSTANCE *Private
658 )
659 {
660 //
661 // Entry PEI Phase 2
662 //
663 PeiCore (SecCoreData, NULL, Private);
664 }
665
666 /**
667 Check SwitchStackSignal and switch stack if SwitchStackSignal is TRUE.
668
669 @param[in] SecCoreData Points to a data structure containing information about the PEI core's operating
670 environment, such as the size and location of temporary RAM, the stack location and
671 the BFV location.
672 @param[in] Private Pointer to the private data passed in from caller.
673
674 **/
675 VOID
676 PeiCheckAndSwitchStack (
677 IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
678 IN PEI_CORE_INSTANCE *Private
679 )
680 {
681 VOID *LoadFixPeiCodeBegin;
682 EFI_STATUS Status;
683 CONST EFI_PEI_SERVICES **PeiServices;
684 UINT64 NewStackSize;
685 EFI_PHYSICAL_ADDRESS TopOfOldStack;
686 EFI_PHYSICAL_ADDRESS TopOfNewStack;
687 UINTN StackOffset;
688 BOOLEAN StackOffsetPositive;
689 EFI_PHYSICAL_ADDRESS TemporaryRamBase;
690 UINTN TemporaryRamSize;
691 UINTN TemporaryStackSize;
692 VOID *TemporaryStackBase;
693 UINTN PeiTemporaryRamSize;
694 VOID *PeiTemporaryRamBase;
695 EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI *TemporaryRamSupportPpi;
696 EFI_PHYSICAL_ADDRESS BaseOfNewHeap;
697 EFI_PHYSICAL_ADDRESS HoleMemBase;
698 UINTN HoleMemSize;
699 UINTN HeapTemporaryRamSize;
700 EFI_PHYSICAL_ADDRESS TempBase1;
701 UINTN TempSize1;
702 EFI_PHYSICAL_ADDRESS TempBase2;
703 UINTN TempSize2;
704 UINTN Index;
705
706 PeiServices = (CONST EFI_PEI_SERVICES **)&Private->Ps;
707
708 if (Private->SwitchStackSignal) {
709 //
710 // Before switch stack from temporary memory to permanent memory, calculate the heap and stack
711 // usage in temporary memory for debugging.
712 //
713 DEBUG_CODE_BEGIN ();
714 UINT32 *StackPointer;
715 EFI_PEI_HOB_POINTERS Hob;
716
717 for ( StackPointer = (UINT32 *)SecCoreData->StackBase;
718 (StackPointer < (UINT32 *)((UINTN)SecCoreData->StackBase + SecCoreData->StackSize)) \
719 && (*StackPointer == PcdGet32 (PcdInitValueInTempStack));
720 StackPointer++)
721 {
722 }
723
724 DEBUG ((DEBUG_INFO, "Temp Stack : BaseAddress=0x%p Length=0x%X\n", SecCoreData->StackBase, (UINT32)SecCoreData->StackSize));
725 DEBUG ((DEBUG_INFO, "Temp Heap : BaseAddress=0x%p Length=0x%X\n", SecCoreData->PeiTemporaryRamBase, (UINT32)SecCoreData->PeiTemporaryRamSize));
726 DEBUG ((DEBUG_INFO, "Total temporary memory: %d bytes.\n", (UINT32)SecCoreData->TemporaryRamSize));
727 DEBUG ((
728 DEBUG_INFO,
729 " temporary memory stack ever used: %d bytes.\n",
730 (UINT32)(SecCoreData->StackSize - ((UINTN)StackPointer - (UINTN)SecCoreData->StackBase))
731 ));
732 DEBUG ((
733 DEBUG_INFO,
734 " temporary memory heap used for HobList: %d bytes.\n",
735 (UINT32)((UINTN)Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom - (UINTN)Private->HobList.Raw)
736 ));
737 DEBUG ((
738 DEBUG_INFO,
739 " temporary memory heap occupied by memory pages: %d bytes.\n",
740 (UINT32)(UINTN)(Private->HobList.HandoffInformationTable->EfiMemoryTop - Private->HobList.HandoffInformationTable->EfiFreeMemoryTop)
741 ));
742 for (Hob.Raw = Private->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
743 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
744 DEBUG ((
745 DEBUG_INFO,
746 "Memory Allocation 0x%08x 0x%0lx - 0x%0lx\n", \
747 Hob.MemoryAllocation->AllocDescriptor.MemoryType, \
748 Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress, \
749 Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress + Hob.MemoryAllocation->AllocDescriptor.MemoryLength - 1
750 ));
751 }
752 }
753
754 DEBUG_CODE_END ();
755
756 if ((PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
757 //
758 // Loading Module at Fixed Address is enabled
759 //
760 PeiLoadFixAddressHook (Private);
761
762 //
763 // If Loading Module at Fixed Address is enabled, Allocating memory range for Pei code range.
764 //
765 LoadFixPeiCodeBegin = AllocatePages ((UINTN)PcdGet32 (PcdLoadFixAddressPeiCodePageNumber));
766 DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: PeiCodeBegin = 0x%lX, PeiCodeTop= 0x%lX\n", (UINT64)(UINTN)LoadFixPeiCodeBegin, (UINT64)((UINTN)LoadFixPeiCodeBegin + PcdGet32 (PcdLoadFixAddressPeiCodePageNumber) * EFI_PAGE_SIZE)));
767 }
768
769 //
770 // Reserve the size of new stack at bottom of physical memory
771 //
772 // The size of new stack in permanent memory must be the same size
773 // or larger than the size of old stack in temporary memory.
774 // But if new stack is smaller than the size of old stack, we also reserve
775 // the size of old stack at bottom of permanent memory.
776 //
777 NewStackSize = RShiftU64 (Private->PhysicalMemoryLength, 1);
778 NewStackSize = ALIGN_VALUE (NewStackSize, EFI_PAGE_SIZE);
779 NewStackSize = MIN (PcdGet32 (PcdPeiCoreMaxPeiStackSize), NewStackSize);
780 DEBUG ((DEBUG_INFO, "Old Stack size %d, New stack size %d\n", (UINT32)SecCoreData->StackSize, (UINT32)NewStackSize));
781 ASSERT (NewStackSize >= SecCoreData->StackSize);
782
783 //
784 // Calculate stack offset and heap offset between temporary memory and new permanent
785 // memory separately.
786 //
787 TopOfOldStack = (UINTN)SecCoreData->StackBase + SecCoreData->StackSize;
788 TopOfNewStack = Private->PhysicalMemoryBegin + NewStackSize;
789 if (TopOfNewStack >= TopOfOldStack) {
790 StackOffsetPositive = TRUE;
791 StackOffset = (UINTN)(TopOfNewStack - TopOfOldStack);
792 } else {
793 StackOffsetPositive = FALSE;
794 StackOffset = (UINTN)(TopOfOldStack - TopOfNewStack);
795 }
796
797 Private->StackOffsetPositive = StackOffsetPositive;
798 Private->StackOffset = StackOffset;
799
800 //
801 // Build Stack HOB that describes the permanent memory stack
802 //
803 DEBUG ((DEBUG_INFO, "Stack Hob: BaseAddress=0x%lX Length=0x%lX\n", TopOfNewStack - NewStackSize, NewStackSize));
804 BuildStackHob (TopOfNewStack - NewStackSize, NewStackSize);
805
806 //
807 // Cache information from SecCoreData into locals before SecCoreData is converted to a permanent memory address
808 //
809 TemporaryRamBase = (EFI_PHYSICAL_ADDRESS)(UINTN)SecCoreData->TemporaryRamBase;
810 TemporaryRamSize = SecCoreData->TemporaryRamSize;
811 TemporaryStackSize = SecCoreData->StackSize;
812 TemporaryStackBase = SecCoreData->StackBase;
813 PeiTemporaryRamSize = SecCoreData->PeiTemporaryRamSize;
814 PeiTemporaryRamBase = SecCoreData->PeiTemporaryRamBase;
815
816 //
817 // TemporaryRamSupportPpi is produced by platform's SEC
818 //
819 Status = PeiServicesLocatePpi (
820 &gEfiTemporaryRamSupportPpiGuid,
821 0,
822 NULL,
823 (VOID **)&TemporaryRamSupportPpi
824 );
825 if (!EFI_ERROR (Status)) {
826 //
827 // Heap Offset
828 //
829 BaseOfNewHeap = TopOfNewStack;
830 if (BaseOfNewHeap >= (UINTN)SecCoreData->PeiTemporaryRamBase) {
831 Private->HeapOffsetPositive = TRUE;
832 Private->HeapOffset = (UINTN)(BaseOfNewHeap - (UINTN)SecCoreData->PeiTemporaryRamBase);
833 } else {
834 Private->HeapOffsetPositive = FALSE;
835 Private->HeapOffset = (UINTN)((UINTN)SecCoreData->PeiTemporaryRamBase - BaseOfNewHeap);
836 }
837
838 DEBUG ((DEBUG_INFO, "Heap Offset = 0x%lX Stack Offset = 0x%lX\n", (UINT64)Private->HeapOffset, (UINT64)Private->StackOffset));
839
840 //
841 // Calculate new HandOffTable and PrivateData address in permanent memory's stack
842 //
843 if (StackOffsetPositive) {
844 SecCoreData = (CONST EFI_SEC_PEI_HAND_OFF *)((UINTN)(VOID *)SecCoreData + StackOffset);
845 Private = (PEI_CORE_INSTANCE *)((UINTN)(VOID *)Private + StackOffset);
846 } else {
847 SecCoreData = (CONST EFI_SEC_PEI_HAND_OFF *)((UINTN)(VOID *)SecCoreData - StackOffset);
848 Private = (PEI_CORE_INSTANCE *)((UINTN)(VOID *)Private - StackOffset);
849 }
850
851 //
852 // Temporary Ram Support PPI is provided by platform, it will copy
853 // temporary memory to permanent memory and do stack switching.
854 // After invoking Temporary Ram Support PPI, the following code's
855 // stack is in permanent memory.
856 //
857 TemporaryRamSupportPpi->TemporaryRamMigration (
858 PeiServices,
859 TemporaryRamBase,
860 (EFI_PHYSICAL_ADDRESS)(UINTN)(TopOfNewStack - TemporaryStackSize),
861 TemporaryRamSize
862 );
863
864 //
865 // Migrate memory pages allocated in pre-memory phase.
866 // It could not be called before calling TemporaryRamSupportPpi->TemporaryRamMigration()
867 // as the migrated memory pages may be overridden by TemporaryRamSupportPpi->TemporaryRamMigration().
868 //
869 MigrateMemoryPages (Private, TRUE);
870
871 //
872 // Entry PEI Phase 2
873 //
874 PeiCore (SecCoreData, NULL, Private);
875 } else {
876 //
877 // Migrate memory pages allocated in pre-memory phase.
878 //
879 MigrateMemoryPages (Private, FALSE);
880
881 //
882 // Migrate the PEI Services Table pointer from temporary RAM to permanent RAM.
883 //
884 MigratePeiServicesTablePointer ();
885
886 //
887 // Heap Offset
888 //
889 BaseOfNewHeap = TopOfNewStack;
890 HoleMemBase = TopOfNewStack;
891 HoleMemSize = TemporaryRamSize - PeiTemporaryRamSize - TemporaryStackSize;
892 if (HoleMemSize != 0) {
893 //
894 // Make sure HOB List start address is 8 byte alignment.
895 //
896 BaseOfNewHeap = ALIGN_VALUE (BaseOfNewHeap + HoleMemSize, 8);
897 }
898
899 if (BaseOfNewHeap >= (UINTN)SecCoreData->PeiTemporaryRamBase) {
900 Private->HeapOffsetPositive = TRUE;
901 Private->HeapOffset = (UINTN)(BaseOfNewHeap - (UINTN)SecCoreData->PeiTemporaryRamBase);
902 } else {
903 Private->HeapOffsetPositive = FALSE;
904 Private->HeapOffset = (UINTN)((UINTN)SecCoreData->PeiTemporaryRamBase - BaseOfNewHeap);
905 }
906
907 DEBUG ((DEBUG_INFO, "Heap Offset = 0x%lX Stack Offset = 0x%lX\n", (UINT64)Private->HeapOffset, (UINT64)Private->StackOffset));
908
909 //
910 // Migrate Heap
911 //
912 HeapTemporaryRamSize = (UINTN)(Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom - Private->HobList.HandoffInformationTable->EfiMemoryBottom);
913 ASSERT (BaseOfNewHeap + HeapTemporaryRamSize <= Private->FreePhysicalMemoryTop);
914 CopyMem ((UINT8 *)(UINTN)BaseOfNewHeap, PeiTemporaryRamBase, HeapTemporaryRamSize);
915
916 //
917 // Migrate Stack
918 //
919 CopyMem ((UINT8 *)(UINTN)(TopOfNewStack - TemporaryStackSize), TemporaryStackBase, TemporaryStackSize);
920
921 //
922 // Copy Hole Range Data
923 //
924 if (HoleMemSize != 0) {
925 //
926 // Prepare Hole
927 //
928 if (PeiTemporaryRamBase < TemporaryStackBase) {
929 TempBase1 = (EFI_PHYSICAL_ADDRESS)(UINTN)PeiTemporaryRamBase;
930 TempSize1 = PeiTemporaryRamSize;
931 TempBase2 = (EFI_PHYSICAL_ADDRESS)(UINTN)TemporaryStackBase;
932 TempSize2 = TemporaryStackSize;
933 } else {
934 TempBase1 = (EFI_PHYSICAL_ADDRESS)(UINTN)TemporaryStackBase;
935 TempSize1 = TemporaryStackSize;
936 TempBase2 = (EFI_PHYSICAL_ADDRESS)(UINTN)PeiTemporaryRamBase;
937 TempSize2 = PeiTemporaryRamSize;
938 }
939
940 if (TemporaryRamBase < TempBase1) {
941 Private->HoleData[0].Base = TemporaryRamBase;
942 Private->HoleData[0].Size = (UINTN)(TempBase1 - TemporaryRamBase);
943 }
944
945 if (TempBase1 + TempSize1 < TempBase2) {
946 Private->HoleData[1].Base = TempBase1 + TempSize1;
947 Private->HoleData[1].Size = (UINTN)(TempBase2 - TempBase1 - TempSize1);
948 }
949
950 if (TempBase2 + TempSize2 < TemporaryRamBase + TemporaryRamSize) {
951 Private->HoleData[2].Base = TempBase2 + TempSize2;
952 Private->HoleData[2].Size = (UINTN)(TemporaryRamBase + TemporaryRamSize - TempBase2 - TempSize2);
953 }
954
955 //
956 // Copy Hole Range data.
957 //
958 for (Index = 0; Index < HOLE_MAX_NUMBER; Index++) {
959 if (Private->HoleData[Index].Size > 0) {
960 if (HoleMemBase > Private->HoleData[Index].Base) {
961 Private->HoleData[Index].OffsetPositive = TRUE;
962 Private->HoleData[Index].Offset = (UINTN)(HoleMemBase - Private->HoleData[Index].Base);
963 } else {
964 Private->HoleData[Index].OffsetPositive = FALSE;
965 Private->HoleData[Index].Offset = (UINTN)(Private->HoleData[Index].Base - HoleMemBase);
966 }
967
968 CopyMem ((VOID *)(UINTN)HoleMemBase, (VOID *)(UINTN)Private->HoleData[Index].Base, Private->HoleData[Index].Size);
969 HoleMemBase = HoleMemBase + Private->HoleData[Index].Size;
970 }
971 }
972 }
973
974 //
975 // Switch new stack
976 //
977 SwitchStack (
978 (SWITCH_STACK_ENTRY_POINT)(UINTN)PeiCoreEntry,
979 (VOID *)SecCoreData,
980 (VOID *)Private,
981 (VOID *)(UINTN)TopOfNewStack
982 );
983 }
984
985 //
986 // Code should not come here
987 //
988 ASSERT (FALSE);
989 }
990 }
991
992 /**
993 Migrate a PEIM from temporary RAM to permanent memory.
994
995 @param PeimFileHandle Pointer to the FFS file header of the image.
996 @param MigratedFileHandle Pointer to the FFS file header of the migrated image.
997
998 @retval EFI_SUCCESS Successfully migrated the PEIM to permanent memory.
999
1000 **/
1001 EFI_STATUS
1002 EFIAPI
1003 MigratePeim (
1004 IN EFI_PEI_FILE_HANDLE FileHandle,
1005 IN EFI_PEI_FILE_HANDLE MigratedFileHandle
1006 )
1007 {
1008 EFI_STATUS Status;
1009 EFI_FFS_FILE_HEADER *FileHeader;
1010 VOID *Pe32Data;
1011 VOID *ImageAddress;
1012 CHAR8 *AsciiString;
1013 UINTN Index;
1014
1015 Status = EFI_SUCCESS;
1016
1017 FileHeader = (EFI_FFS_FILE_HEADER *)FileHandle;
1018 ASSERT (!IS_FFS_FILE2 (FileHeader));
1019
1020 ImageAddress = NULL;
1021 PeiGetPe32Data (MigratedFileHandle, &ImageAddress);
1022 if (ImageAddress != NULL) {
1023 DEBUG_CODE_BEGIN ();
1024 AsciiString = PeCoffLoaderGetPdbPointer (ImageAddress);
1025 for (Index = 0; AsciiString[Index] != 0; Index++) {
1026 if ((AsciiString[Index] == '\\') || (AsciiString[Index] == '/')) {
1027 AsciiString = AsciiString + Index + 1;
1028 Index = 0;
1029 } else if (AsciiString[Index] == '.') {
1030 AsciiString[Index] = 0;
1031 }
1032 }
1033
1034 DEBUG ((DEBUG_VERBOSE, "%a", AsciiString));
1035 DEBUG_CODE_END ();
1036
1037 Pe32Data = (VOID *)((UINTN)ImageAddress - (UINTN)MigratedFileHandle + (UINTN)FileHandle);
1038 Status = LoadAndRelocatePeCoffImageInPlace (Pe32Data, ImageAddress);
1039 ASSERT_EFI_ERROR (Status);
1040 }
1041
1042 return Status;
1043 }
1044
1045 /**
1046 Migrate Status Code Callback function pointers inside an FV from temporary memory to permanent memory.
1047
1048 @param OrgFvHandle Address of FV handle in temporary memory.
1049 @param FvHandle Address of FV handle in permanent memory.
1050 @param FvSize Size of the FV.
1051
1052 **/
1053 VOID
1054 ConvertStatusCodeCallbacks (
1055 IN UINTN OrgFvHandle,
1056 IN UINTN FvHandle,
1057 IN UINTN FvSize
1058 )
1059 {
1060 EFI_PEI_HOB_POINTERS Hob;
1061 UINTN *NumberOfEntries;
1062 UINTN *CallbackEntry;
1063 UINTN Index;
1064
1065 Hob.Raw = GetFirstGuidHob (&gStatusCodeCallbackGuid);
1066 while (Hob.Raw != NULL) {
1067 NumberOfEntries = GET_GUID_HOB_DATA (Hob);
1068 CallbackEntry = NumberOfEntries + 1;
1069 for (Index = 0; Index < *NumberOfEntries; Index++) {
1070 if (((VOID *)CallbackEntry[Index]) != NULL) {
1071 if ((CallbackEntry[Index] >= OrgFvHandle) && (CallbackEntry[Index] < (OrgFvHandle + FvSize))) {
1072 DEBUG ((
1073 DEBUG_INFO,
1074 "Migrating CallbackEntry[%Lu] from 0x%0*Lx to ",
1075 (UINT64)Index,
1076 (sizeof CallbackEntry[Index]) * 2,
1077 (UINT64)CallbackEntry[Index]
1078 ));
1079 if (OrgFvHandle > FvHandle) {
1080 CallbackEntry[Index] = CallbackEntry[Index] - (OrgFvHandle - FvHandle);
1081 } else {
1082 CallbackEntry[Index] = CallbackEntry[Index] + (FvHandle - OrgFvHandle);
1083 }
1084
1085 DEBUG ((
1086 DEBUG_INFO,
1087 "0x%0*Lx\n",
1088 (sizeof CallbackEntry[Index]) * 2,
1089 (UINT64)CallbackEntry[Index]
1090 ));
1091 }
1092 }
1093 }
1094
1095 Hob.Raw = GET_NEXT_HOB (Hob);
1096 Hob.Raw = GetNextGuidHob (&gStatusCodeCallbackGuid, Hob.Raw);
1097 }
1098 }
1099
1100 /**
1101 Migrates PEIMs in the given firmware volume.
1102
1103 @param Private Pointer to the PeiCore's private data structure.
1104 @param FvIndex The firmware volume index to migrate.
1105 @param OrgFvHandle The handle to the firmware volume in temporary memory.
1106 @param FvHandle The handle to the firmware volume in permanent memory.
1107
1108 @retval EFI_SUCCESS The PEIMs in the FV were migrated successfully
1109 @retval EFI_INVALID_PARAMETER The Private pointer is NULL or FvCount is invalid.
1110
1111 **/
1112 EFI_STATUS
1113 EFIAPI
1114 MigratePeimsInFv (
1115 IN PEI_CORE_INSTANCE *Private,
1116 IN UINTN FvIndex,
1117 IN UINTN OrgFvHandle,
1118 IN UINTN FvHandle
1119 )
1120 {
1121 EFI_STATUS Status;
1122 volatile UINTN FileIndex;
1123 EFI_PEI_FILE_HANDLE MigratedFileHandle;
1124 EFI_PEI_FILE_HANDLE FileHandle;
1125
1126 if ((Private == NULL) || (FvIndex >= Private->FvCount)) {
1127 return EFI_INVALID_PARAMETER;
1128 }
1129
1130 if (Private->Fv[FvIndex].ScanFv) {
1131 for (FileIndex = 0; FileIndex < Private->Fv[FvIndex].PeimCount; FileIndex++) {
1132 if (Private->Fv[FvIndex].FvFileHandles[FileIndex] != NULL) {
1133 FileHandle = Private->Fv[FvIndex].FvFileHandles[FileIndex];
1134
1135 MigratedFileHandle = (EFI_PEI_FILE_HANDLE)((UINTN)FileHandle - OrgFvHandle + FvHandle);
1136
1137 DEBUG ((DEBUG_VERBOSE, " Migrating FileHandle %2d ", FileIndex));
1138 Status = MigratePeim (FileHandle, MigratedFileHandle);
1139 DEBUG ((DEBUG_VERBOSE, "\n"));
1140 ASSERT_EFI_ERROR (Status);
1141
1142 if (!EFI_ERROR (Status)) {
1143 Private->Fv[FvIndex].FvFileHandles[FileIndex] = MigratedFileHandle;
1144 if (FvIndex == Private->CurrentPeimFvCount) {
1145 Private->CurrentFvFileHandles[FileIndex] = MigratedFileHandle;
1146 }
1147 }
1148 }
1149 }
1150 }
1151
1152 return EFI_SUCCESS;
1153 }
1154
1155 /**
1156 Migrate FVs out of temporary RAM before the cache is flushed.
1157
1158 @param Private PeiCore's private data structure
1159 @param SecCoreData Points to a data structure containing information about the PEI core's operating
1160 environment, such as the size and location of temporary RAM, the stack location and
1161 the BFV location.
1162
1163 @retval EFI_SUCCESS Successfully migrated installed FVs from temporary RAM to permanent memory.
1164 @retval EFI_OUT_OF_RESOURCES Insufficient memory exists to allocate needed pages.
1165
1166 **/
1167 EFI_STATUS
1168 EFIAPI
1169 EvacuateTempRam (
1170 IN PEI_CORE_INSTANCE *Private,
1171 IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData
1172 )
1173 {
1174 EFI_STATUS Status;
1175 volatile UINTN FvIndex;
1176 volatile UINTN FvChildIndex;
1177 UINTN ChildFvOffset;
1178 EFI_PHYSICAL_ADDRESS FvHeaderAddress;
1179 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
1180 EFI_FIRMWARE_VOLUME_HEADER *ChildFvHeader;
1181 EFI_FIRMWARE_VOLUME_HEADER *MigratedFvHeader;
1182 EFI_FIRMWARE_VOLUME_HEADER *RawDataFvHeader;
1183 EFI_FIRMWARE_VOLUME_HEADER *MigratedChildFvHeader;
1184
1185 PEI_CORE_FV_HANDLE PeiCoreFvHandle;
1186 EFI_PEI_CORE_FV_LOCATION_PPI *PeiCoreFvLocationPpi;
1187 EDKII_MIGRATED_FV_INFO MigratedFvInfo;
1188
1189 ASSERT (Private->PeiMemoryInstalled);
1190
1191 DEBUG ((DEBUG_VERBOSE, "Beginning evacuation of content in temporary RAM.\n"));
1192
1193 //
1194 // Migrate PPI Pointers of PEI_CORE from temporary memory to newly loaded PEI_CORE in permanent memory.
1195 //
1196 Status = PeiLocatePpi ((CONST EFI_PEI_SERVICES **)&Private->Ps, &gEfiPeiCoreFvLocationPpiGuid, 0, NULL, (VOID **)&PeiCoreFvLocationPpi);
1197 if (!EFI_ERROR (Status) && (PeiCoreFvLocationPpi->PeiCoreFvLocation != NULL)) {
1198 PeiCoreFvHandle.FvHandle = (EFI_PEI_FV_HANDLE)PeiCoreFvLocationPpi->PeiCoreFvLocation;
1199 } else {
1200 PeiCoreFvHandle.FvHandle = (EFI_PEI_FV_HANDLE)SecCoreData->BootFirmwareVolumeBase;
1201 }
1202
1203 for (FvIndex = 0; FvIndex < Private->FvCount; FvIndex++) {
1204 if (Private->Fv[FvIndex].FvHandle == PeiCoreFvHandle.FvHandle) {
1205 CopyMem (&PeiCoreFvHandle, &Private->Fv[FvIndex], sizeof (PEI_CORE_FV_HANDLE));
1206 break;
1207 }
1208 }
1209
1210 Status = EFI_SUCCESS;
1211
1212 ConvertPeiCorePpiPointers (Private, &PeiCoreFvHandle);
1213
1214 for (FvIndex = 0; FvIndex < Private->FvCount; FvIndex++) {
1215 FvHeader = Private->Fv[FvIndex].FvHeader;
1216 ASSERT (FvHeader != NULL);
1217 ASSERT (FvIndex < Private->FvCount);
1218
1219 DEBUG ((DEBUG_VERBOSE, "FV[%02d] at 0x%x.\n", FvIndex, (UINTN)FvHeader));
1220 if (
1221 !(
1222 ((EFI_PHYSICAL_ADDRESS)(UINTN)FvHeader >= Private->PhysicalMemoryBegin) &&
1223 (((EFI_PHYSICAL_ADDRESS)(UINTN)FvHeader + (FvHeader->FvLength - 1)) < Private->FreePhysicalMemoryTop)
1224 )
1225 )
1226 {
1227 //
1228 // Allocate page to save the rebased PEIMs, the PEIMs will get dispatched later.
1229 //
1230 Status = PeiServicesAllocatePages (
1231 EfiBootServicesCode,
1232 EFI_SIZE_TO_PAGES ((UINTN)FvHeader->FvLength),
1233 &FvHeaderAddress
1234 );
1235 ASSERT_EFI_ERROR (Status);
1236 MigratedFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvHeaderAddress;
1237
1238 //
1239 // Allocate pool to save the raw PEIMs, which is used to keep consistent context across
1240 // multiple boot and PCR0 will keep the same no matter if the address of allocated page is changed.
1241 //
1242 Status = PeiServicesAllocatePages (
1243 EfiBootServicesCode,
1244 EFI_SIZE_TO_PAGES ((UINTN)FvHeader->FvLength),
1245 &FvHeaderAddress
1246 );
1247 ASSERT_EFI_ERROR (Status);
1248 RawDataFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvHeaderAddress;
1249
1250 DEBUG ((
1251 DEBUG_VERBOSE,
1252 " Migrating FV[%d] from 0x%08X to 0x%08X\n",
1253 FvIndex,
1254 (UINTN)FvHeader,
1255 (UINTN)MigratedFvHeader
1256 ));
1257
1258 //
1259 // Copy the context to the rebased pages and raw pages, and create hob to save the
1260 // information. The MigratedFvInfo HOB will never be produced when
1261 // PcdMigrateTemporaryRamFirmwareVolumes is FALSE, because the PCD control the
1262 // feature.
1263 //
1264 CopyMem (MigratedFvHeader, FvHeader, (UINTN)FvHeader->FvLength);
1265 CopyMem (RawDataFvHeader, MigratedFvHeader, (UINTN)FvHeader->FvLength);
1266 MigratedFvInfo.FvOrgBase = (UINT32)(UINTN)FvHeader;
1267 MigratedFvInfo.FvNewBase = (UINT32)(UINTN)MigratedFvHeader;
1268 MigratedFvInfo.FvDataBase = (UINT32)(UINTN)RawDataFvHeader;
1269 MigratedFvInfo.FvLength = (UINT32)(UINTN)FvHeader->FvLength;
1270 BuildGuidDataHob (&gEdkiiMigratedFvInfoGuid, &MigratedFvInfo, sizeof (MigratedFvInfo));
1271
1272 //
1273 // Migrate any children for this FV now
1274 //
1275 for (FvChildIndex = FvIndex; FvChildIndex < Private->FvCount; FvChildIndex++) {
1276 ChildFvHeader = Private->Fv[FvChildIndex].FvHeader;
1277 if (
1278 ((UINTN)ChildFvHeader > (UINTN)FvHeader) &&
1279 (((UINTN)ChildFvHeader + ChildFvHeader->FvLength) < ((UINTN)FvHeader) + FvHeader->FvLength)
1280 )
1281 {
1282 DEBUG ((DEBUG_VERBOSE, " Child FV[%02d] is being migrated.\n", FvChildIndex));
1283 ChildFvOffset = (UINTN)ChildFvHeader - (UINTN)FvHeader;
1284 DEBUG ((DEBUG_VERBOSE, " Child FV offset = 0x%x.\n", ChildFvOffset));
1285 MigratedChildFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)MigratedFvHeader + ChildFvOffset);
1286 Private->Fv[FvChildIndex].FvHeader = MigratedChildFvHeader;
1287 Private->Fv[FvChildIndex].FvHandle = (EFI_PEI_FV_HANDLE)MigratedChildFvHeader;
1288 DEBUG ((DEBUG_VERBOSE, " Child migrated FV header at 0x%x.\n", (UINTN)MigratedChildFvHeader));
1289
1290 Status = MigratePeimsInFv (Private, FvChildIndex, (UINTN)ChildFvHeader, (UINTN)MigratedChildFvHeader);
1291 ASSERT_EFI_ERROR (Status);
1292
1293 ConvertPpiPointersFv (
1294 Private,
1295 (UINTN)ChildFvHeader,
1296 (UINTN)MigratedChildFvHeader,
1297 (UINTN)ChildFvHeader->FvLength - 1
1298 );
1299
1300 ConvertStatusCodeCallbacks (
1301 (UINTN)ChildFvHeader,
1302 (UINTN)MigratedChildFvHeader,
1303 (UINTN)ChildFvHeader->FvLength - 1
1304 );
1305
1306 ConvertFvHob (Private, (UINTN)ChildFvHeader, (UINTN)MigratedChildFvHeader);
1307 }
1308 }
1309
1310 Private->Fv[FvIndex].FvHeader = MigratedFvHeader;
1311 Private->Fv[FvIndex].FvHandle = (EFI_PEI_FV_HANDLE)MigratedFvHeader;
1312
1313 Status = MigratePeimsInFv (Private, FvIndex, (UINTN)FvHeader, (UINTN)MigratedFvHeader);
1314 ASSERT_EFI_ERROR (Status);
1315
1316 ConvertPpiPointersFv (
1317 Private,
1318 (UINTN)FvHeader,
1319 (UINTN)MigratedFvHeader,
1320 (UINTN)FvHeader->FvLength - 1
1321 );
1322
1323 ConvertStatusCodeCallbacks (
1324 (UINTN)FvHeader,
1325 (UINTN)MigratedFvHeader,
1326 (UINTN)FvHeader->FvLength - 1
1327 );
1328
1329 ConvertFvHob (Private, (UINTN)FvHeader, (UINTN)MigratedFvHeader);
1330 }
1331 }
1332
1333 RemoveFvHobsInTemporaryMemory (Private);
1334
1335 return Status;
1336 }
1337
1338 /**
1339 Conduct PEIM dispatch.
1340
1341 @param SecCoreData Points to a data structure containing information about the PEI core's operating
1342 environment, such as the size and location of temporary RAM, the stack location and
1343 the BFV location.
1344 @param Private Pointer to the private data passed in from caller
1345
1346 **/
1347 VOID
1348 PeiDispatcher (
1349 IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
1350 IN PEI_CORE_INSTANCE *Private
1351 )
1352 {
1353 EFI_STATUS Status;
1354 UINT32 Index1;
1355 UINT32 Index2;
1356 CONST EFI_PEI_SERVICES **PeiServices;
1357 EFI_PEI_FILE_HANDLE PeimFileHandle;
1358 UINTN FvCount;
1359 UINTN PeimCount;
1360 UINT32 AuthenticationState;
1361 EFI_PHYSICAL_ADDRESS EntryPoint;
1362 EFI_PEIM_ENTRY_POINT2 PeimEntryPoint;
1363 UINTN SaveCurrentPeimCount;
1364 UINTN SaveCurrentFvCount;
1365 EFI_PEI_FILE_HANDLE SaveCurrentFileHandle;
1366 EFI_FV_FILE_INFO FvFileInfo;
1367 PEI_CORE_FV_HANDLE *CoreFvHandle;
1368
1369 PeiServices = (CONST EFI_PEI_SERVICES **)&Private->Ps;
1370 PeimEntryPoint = NULL;
1371 PeimFileHandle = NULL;
1372 EntryPoint = 0;
1373
1374 if ((Private->PeiMemoryInstalled) &&
1375 (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
1376 (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) ||
1377 PcdGetBool (PcdShadowPeimOnS3Boot))
1378 )
1379 {
1380 //
1381 // Once real memory is available, shadow the RegisterForShadow modules. And meanwhile
1382 // update the modules' status from PEIM_STATE_REGISTER_FOR_SHADOW to PEIM_STATE_DONE.
1383 //
1384 SaveCurrentPeimCount = Private->CurrentPeimCount;
1385 SaveCurrentFvCount = Private->CurrentPeimFvCount;
1386 SaveCurrentFileHandle = Private->CurrentFileHandle;
1387
1388 for (Index1 = 0; Index1 < Private->FvCount; Index1++) {
1389 for (Index2 = 0; Index2 < Private->Fv[Index1].PeimCount; Index2++) {
1390 if (Private->Fv[Index1].PeimState[Index2] == PEIM_STATE_REGISTER_FOR_SHADOW) {
1391 PeimFileHandle = Private->Fv[Index1].FvFileHandles[Index2];
1392 Private->CurrentFileHandle = PeimFileHandle;
1393 Private->CurrentPeimFvCount = Index1;
1394 Private->CurrentPeimCount = Index2;
1395 Status = PeiLoadImage (
1396 (CONST EFI_PEI_SERVICES **)&Private->Ps,
1397 PeimFileHandle,
1398 PEIM_STATE_REGISTER_FOR_SHADOW,
1399 &EntryPoint,
1400 &AuthenticationState
1401 );
1402 if (Status == EFI_SUCCESS) {
1403 //
1404 // PEIM_STATE_REGISTER_FOR_SHADOW move to PEIM_STATE_DONE
1405 //
1406 Private->Fv[Index1].PeimState[Index2]++;
1407 //
1408 // Call the PEIM entry point
1409 //
1410 PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
1411
1412 PERF_START_IMAGE_BEGIN (PeimFileHandle);
1413 PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **)&Private->Ps);
1414 PERF_START_IMAGE_END (PeimFileHandle);
1415 }
1416
1417 //
1418 // Process the Notify list and dispatch any notifies for
1419 // newly installed PPIs.
1420 //
1421 ProcessDispatchNotifyList (Private);
1422 }
1423 }
1424 }
1425
1426 Private->CurrentFileHandle = SaveCurrentFileHandle;
1427 Private->CurrentPeimFvCount = SaveCurrentFvCount;
1428 Private->CurrentPeimCount = SaveCurrentPeimCount;
1429 }
1430
1431 //
1432 // This is the main dispatch loop. It will search known FVs for PEIMs and
1433 // attempt to dispatch them. If any PEIM gets dispatched through a single
1434 // pass of the dispatcher, it will start over from the BFV again to see
1435 // if any new PEIMs dependencies got satisfied. With a well ordered
1436 // FV where PEIMs are found in the order their dependencies are also
1437 // satisfied, this dispatcher should run only once.
1438 //
1439 do {
1440 //
1441 // In case that reenter PeiCore happens, the last pass record is still available.
1442 //
1443 if (!Private->PeimDispatcherReenter) {
1444 Private->PeimNeedingDispatch = FALSE;
1445 Private->PeimDispatchOnThisPass = FALSE;
1446 } else {
1447 Private->PeimDispatcherReenter = FALSE;
1448 }
1449
1450 for (FvCount = Private->CurrentPeimFvCount; FvCount < Private->FvCount; FvCount++) {
1451 CoreFvHandle = FindNextCoreFvHandle (Private, FvCount);
1452 ASSERT (CoreFvHandle != NULL);
1453
1454 //
1455 // If the FV has corresponding EFI_PEI_FIRMWARE_VOLUME_PPI instance, then dispatch it.
1456 //
1457 if (CoreFvHandle->FvPpi == NULL) {
1458 continue;
1459 }
1460
1461 Private->CurrentPeimFvCount = FvCount;
1462
1463 if (Private->CurrentPeimCount == 0) {
1464 //
1465 // When going through each FV, at first, search Apriori file to
1466 // reorder all PEIMs to ensure the PEIMs in Apriori file to get
1467 // dispatch at first.
1468 //
1469 DiscoverPeimsAndOrderWithApriori (Private, CoreFvHandle);
1470 }
1471
1472 //
1473 // Start to dispatch all modules within the current FV.
1474 //
1475 for (PeimCount = Private->CurrentPeimCount;
1476 PeimCount < Private->Fv[FvCount].PeimCount;
1477 PeimCount++)
1478 {
1479 Private->CurrentPeimCount = PeimCount;
1480 PeimFileHandle = Private->CurrentFileHandle = Private->CurrentFvFileHandles[PeimCount];
1481
1482 if (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_NOT_DISPATCHED) {
1483 if (!DepexSatisfied (Private, PeimFileHandle, PeimCount)) {
1484 Private->PeimNeedingDispatch = TRUE;
1485 } else {
1486 Status = CoreFvHandle->FvPpi->GetFileInfo (CoreFvHandle->FvPpi, PeimFileHandle, &FvFileInfo);
1487 ASSERT_EFI_ERROR (Status);
1488 if (FvFileInfo.FileType == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
1489 //
1490 // For FV type file, Produce new FvInfo PPI and FV HOB
1491 //
1492 Status = ProcessFvFile (Private, &Private->Fv[FvCount], PeimFileHandle);
1493 if (Status == EFI_SUCCESS) {
1494 //
1495 // PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED
1496 //
1497 Private->Fv[FvCount].PeimState[PeimCount]++;
1498 Private->PeimDispatchOnThisPass = TRUE;
1499 } else {
1500 //
1501 // The related GuidedSectionExtraction/Decompress PPI for the
1502 // encapsulated FV image section may be installed in the rest
1503 // of this do-while loop, so need to make another pass.
1504 //
1505 Private->PeimNeedingDispatch = TRUE;
1506 }
1507 } else {
1508 //
1509 // For PEIM driver, Load its entry point
1510 //
1511 Status = PeiLoadImage (
1512 PeiServices,
1513 PeimFileHandle,
1514 PEIM_STATE_NOT_DISPATCHED,
1515 &EntryPoint,
1516 &AuthenticationState
1517 );
1518 if (Status == EFI_SUCCESS) {
1519 //
1520 // The PEIM has its dependencies satisfied, and its entry point
1521 // has been found, so invoke it.
1522 //
1523 PERF_START_IMAGE_BEGIN (PeimFileHandle);
1524
1525 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
1526 EFI_PROGRESS_CODE,
1527 (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_BEGIN),
1528 (VOID *)(&PeimFileHandle),
1529 sizeof (PeimFileHandle)
1530 );
1531
1532 Status = VerifyPeim (Private, CoreFvHandle->FvHandle, PeimFileHandle, AuthenticationState);
1533 if (Status != EFI_SECURITY_VIOLATION) {
1534 //
1535 // PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED
1536 //
1537 Private->Fv[FvCount].PeimState[PeimCount]++;
1538 //
1539 // Call the PEIM entry point for PEIM driver
1540 //
1541 PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
1542 PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **)PeiServices);
1543 Private->PeimDispatchOnThisPass = TRUE;
1544 } else {
1545 //
1546 // The related GuidedSectionExtraction PPI for the
1547 // signed PEIM image section may be installed in the rest
1548 // of this do-while loop, so need to make another pass.
1549 //
1550 Private->PeimNeedingDispatch = TRUE;
1551 }
1552
1553 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
1554 EFI_PROGRESS_CODE,
1555 (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_END),
1556 (VOID *)(&PeimFileHandle),
1557 sizeof (PeimFileHandle)
1558 );
1559 PERF_START_IMAGE_END (PeimFileHandle);
1560 }
1561 }
1562
1563 PeiCheckAndSwitchStack (SecCoreData, Private);
1564
1565 //
1566 // Process the Notify list and dispatch any notifies for
1567 // newly installed PPIs.
1568 //
1569 ProcessDispatchNotifyList (Private);
1570
1571 //
1572 // Recheck SwitchStackSignal after ProcessDispatchNotifyList()
1573 // in case PeiInstallPeiMemory() is done in a callback with
1574 // EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH.
1575 //
1576 PeiCheckAndSwitchStack (SecCoreData, Private);
1577
1578 if ((Private->PeiMemoryInstalled) && (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_REGISTER_FOR_SHADOW) && \
1579 (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
1580 (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) ||
1581 PcdGetBool (PcdShadowPeimOnS3Boot))
1582 )
1583 {
1584 //
1585 // If memory is available we shadow images by default for performance reasons.
1586 // We call the entry point a 2nd time so the module knows it's shadowed.
1587 //
1588 // PERF_START (PeiServices, L"PEIM", PeimFileHandle, 0);
1589 if ((Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) && !PcdGetBool (PcdShadowPeimOnBoot) &&
1590 !PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes))
1591 {
1592 //
1593 // Load PEIM into Memory for Register for shadow PEIM.
1594 //
1595 Status = PeiLoadImage (
1596 PeiServices,
1597 PeimFileHandle,
1598 PEIM_STATE_REGISTER_FOR_SHADOW,
1599 &EntryPoint,
1600 &AuthenticationState
1601 );
1602 if (Status == EFI_SUCCESS) {
1603 PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
1604 }
1605 }
1606
1607 ASSERT (PeimEntryPoint != NULL);
1608 PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **)PeiServices);
1609 // PERF_END (PeiServices, L"PEIM", PeimFileHandle, 0);
1610
1611 //
1612 // PEIM_STATE_REGISTER_FOR_SHADOW move to PEIM_STATE_DONE
1613 //
1614 Private->Fv[FvCount].PeimState[PeimCount]++;
1615
1616 //
1617 // Process the Notify list and dispatch any notifies for
1618 // newly installed PPIs.
1619 //
1620 ProcessDispatchNotifyList (Private);
1621 }
1622 }
1623 }
1624 }
1625
1626 //
1627 // Before walking through the next FV, we should set them to NULL/0 to
1628 // start at the beginning of the next FV.
1629 //
1630 Private->CurrentFileHandle = NULL;
1631 Private->CurrentPeimCount = 0;
1632 Private->CurrentFvFileHandles = NULL;
1633 }
1634
1635 //
1636 // Before making another pass, we should set it to 0 to
1637 // go through all the FVs.
1638 //
1639 Private->CurrentPeimFvCount = 0;
1640
1641 //
1642 // PeimNeedingDispatch being TRUE means we found a PEIM/FV that did not get
1643 // dispatched. So we need to make another pass
1644 //
1645 // PeimDispatchOnThisPass being TRUE means we dispatched a PEIM/FV on this
1646 // pass. If we did not dispatch a PEIM/FV there is no point in trying again
1647 // as it will fail the next time too (nothing has changed).
1648 //
1649 } while (Private->PeimNeedingDispatch && Private->PeimDispatchOnThisPass);
1650 }
1651
1652 /**
1653 Initialize the Dispatcher's data members
1654
1655 @param PrivateData PeiCore's private data structure
1656 @param OldCoreData Old data from SecCore
1657 NULL if being run in non-permanent memory mode.
1658 @param SecCoreData Points to a data structure containing information about the PEI core's operating
1659 environment, such as the size and location of temporary RAM, the stack location and
1660 the BFV location.
1661
1662 @return None.
1663
1664 **/
1665 VOID
1666 InitializeDispatcherData (
1667 IN PEI_CORE_INSTANCE *PrivateData,
1668 IN PEI_CORE_INSTANCE *OldCoreData,
1669 IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData
1670 )
1671 {
1672 if (OldCoreData == NULL) {
1673 PrivateData->PeimDispatcherReenter = FALSE;
1674 PeiInitializeFv (PrivateData, SecCoreData);
1675 } else {
1676 PeiReinitializeFv (PrivateData);
1677 }
1678
1679 return;
1680 }
1681
1682 /**
1683 This routine parses the Dependency Expression, if available, and
1684 decides if the module can be executed.
1685
1686
1687 @param Private PeiCore's private data structure
1688 @param FileHandle PEIM's file handle
1689 @param PeimCount Peim count in all dispatched PEIMs.
1690
1691 @retval TRUE Can be dispatched
1692 @retval FALSE Cannot be dispatched
1693
1694 **/
1695 BOOLEAN
1696 DepexSatisfied (
1697 IN PEI_CORE_INSTANCE *Private,
1698 IN EFI_PEI_FILE_HANDLE FileHandle,
1699 IN UINTN PeimCount
1700 )
1701 {
1702 EFI_STATUS Status;
1703 VOID *DepexData;
1704 EFI_FV_FILE_INFO FileInfo;
1705
1706 Status = PeiServicesFfsGetFileInfo (FileHandle, &FileInfo);
1707 if (EFI_ERROR (Status)) {
1708 DEBUG ((DEBUG_DISPATCH, "Evaluate PEI DEPEX for FFS(Unknown)\n"));
1709 } else {
1710 DEBUG ((DEBUG_DISPATCH, "Evaluate PEI DEPEX for FFS(%g)\n", &FileInfo.FileName));
1711 }
1712
1713 if (PeimCount < Private->AprioriCount) {
1714 //
1715 // If it's in the Apriori file then we set DEPEX to TRUE
1716 //
1717 DEBUG ((DEBUG_DISPATCH, " RESULT = TRUE (Apriori)\n"));
1718 return TRUE;
1719 }
1720
1721 //
1722 // Depex section not in the encapsulated section.
1723 //
1724 Status = PeiServicesFfsFindSectionData (
1725 EFI_SECTION_PEI_DEPEX,
1726 FileHandle,
1727 (VOID **)&DepexData
1728 );
1729
1730 if (EFI_ERROR (Status)) {
1731 //
1732 // If there is no DEPEX, assume the module can be executed
1733 //
1734 DEBUG ((DEBUG_DISPATCH, " RESULT = TRUE (No DEPEX)\n"));
1735 return TRUE;
1736 }
1737
1738 //
1739 // Evaluate a given DEPEX
1740 //
1741 return PeimDispatchReadiness (&Private->Ps, DepexData);
1742 }
1743
1744 /**
1745 This routine enables a PEIM to register itself for shadow when the PEI Foundation
1746 discovers permanent memory.
1747
1748 @param FileHandle File handle of a PEIM.
1749
1750 @retval EFI_NOT_FOUND The file handle doesn't point to PEIM itself.
1751 @retval EFI_ALREADY_STARTED Indicate that the PEIM has been registered itself.
1752 @retval EFI_SUCCESS Successfully to register itself.
1753
1754 **/
1755 EFI_STATUS
1756 EFIAPI
1757 PeiRegisterForShadow (
1758 IN EFI_PEI_FILE_HANDLE FileHandle
1759 )
1760 {
1761 PEI_CORE_INSTANCE *Private;
1762
1763 Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
1764
1765 if (Private->CurrentFileHandle != FileHandle) {
1766 //
1767 // The FileHandle must be for the current PEIM
1768 //
1769 return EFI_NOT_FOUND;
1770 }
1771
1772 if (Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] >= PEIM_STATE_REGISTER_FOR_SHADOW) {
1773 //
1774 // If the PEIM has already entered the PEIM_STATE_REGISTER_FOR_SHADOW or PEIM_STATE_DONE then it's already been started
1775 //
1776 return EFI_ALREADY_STARTED;
1777 }
1778
1779 Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] = PEIM_STATE_REGISTER_FOR_SHADOW;
1780
1781 return EFI_SUCCESS;
1782 }