]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
38299c5d98c653042af5cb27a42739e394e8886c
[mirror_edk2.git] / MdeModulePkg / Core / Pei / Dispatcher / Dispatcher.c
1 /** @file
2 EFI PEI Core dispatch services
3
4 Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "PeiMain.h"
17
18 ///
19 /// temporary memory is filled with this initial value during SEC phase
20 ///
21 #define INIT_CAR_VALUE 0x5AA55AA5
22
23 /**
24
25 Discover all Peims and optional Apriori file in one FV. There is at most one
26 Apriori file in one FV.
27
28
29 @param Private Pointer to the private data passed in from caller
30 @param CoreFileHandle The instance of PEI_CORE_FV_HANDLE.
31
32 **/
33 VOID
34 DiscoverPeimsAndOrderWithApriori (
35 IN PEI_CORE_INSTANCE *Private,
36 IN PEI_CORE_FV_HANDLE *CoreFileHandle
37 )
38 {
39 EFI_STATUS Status;
40 EFI_PEI_FILE_HANDLE FileHandle;
41 EFI_PEI_FILE_HANDLE AprioriFileHandle;
42 EFI_GUID *Apriori;
43 UINTN Index;
44 UINTN Index2;
45 UINTN PeimIndex;
46 UINTN PeimCount;
47 EFI_GUID *Guid;
48 EFI_PEI_FILE_HANDLE *TempFileHandles;
49 EFI_GUID *FileGuid;
50 EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
51 EFI_FV_FILE_INFO FileInfo;
52
53 FvPpi = CoreFileHandle->FvPpi;
54
55 //
56 // Walk the FV and find all the PEIMs and the Apriori file.
57 //
58 AprioriFileHandle = NULL;
59 Private->CurrentFvFileHandles[0] = NULL;
60 Guid = NULL;
61 FileHandle = NULL;
62 TempFileHandles = Private->FileHandles;
63 FileGuid = Private->FileGuid;
64
65 //
66 // If the current Fv has been scanned, directly get its cachable record.
67 //
68 if (Private->Fv[Private->CurrentPeimFvCount].ScanFv) {
69 CopyMem (Private->CurrentFvFileHandles, Private->Fv[Private->CurrentPeimFvCount].FvFileHandles, sizeof (EFI_PEI_FILE_HANDLE) * PcdGet32 (PcdPeiCoreMaxPeimPerFv));
70 return;
71 }
72
73 //
74 // Go ahead to scan this Fv, and cache FileHandles within it.
75 //
76 Status = EFI_NOT_FOUND;
77 for (PeimCount = 0; PeimCount <= PcdGet32 (PcdPeiCoreMaxPeimPerFv); PeimCount++) {
78 Status = FvPpi->FindFileByType (FvPpi, PEI_CORE_INTERNAL_FFS_FILE_DISPATCH_TYPE, CoreFileHandle->FvHandle, &FileHandle);
79 if (Status != EFI_SUCCESS || PeimCount == PcdGet32 (PcdPeiCoreMaxPeimPerFv)) {
80 break;
81 }
82
83 Private->CurrentFvFileHandles[PeimCount] = FileHandle;
84 }
85
86 //
87 // Check whether the count of files exceeds the max support files in a FV image
88 // If more files are required in a FV image, PcdPeiCoreMaxPeimPerFv can be set to a larger value in DSC file.
89 //
90 ASSERT ((Status != EFI_SUCCESS) || (PeimCount < PcdGet32 (PcdPeiCoreMaxPeimPerFv)));
91
92 //
93 // Get Apriori File handle
94 //
95 Private->AprioriCount = 0;
96 Status = FvPpi->FindFileByName (FvPpi, &gPeiAprioriFileNameGuid, &CoreFileHandle->FvHandle, &AprioriFileHandle);
97 if (!EFI_ERROR(Status) && AprioriFileHandle != NULL) {
98 //
99 // Read the Apriori file
100 //
101 Status = FvPpi->FindSectionByType (FvPpi, EFI_SECTION_RAW, AprioriFileHandle, (VOID **) &Apriori);
102 if (!EFI_ERROR (Status)) {
103 //
104 // Calculate the number of PEIMs in the A Priori list
105 //
106 Status = FvPpi->GetFileInfo (FvPpi, AprioriFileHandle, &FileInfo);
107 ASSERT_EFI_ERROR (Status);
108 Private->AprioriCount = FileInfo.BufferSize;
109 if (IS_SECTION2 (FileInfo.Buffer)) {
110 Private->AprioriCount -= sizeof (EFI_COMMON_SECTION_HEADER2);
111 } else {
112 Private->AprioriCount -= sizeof (EFI_COMMON_SECTION_HEADER);
113 }
114 Private->AprioriCount /= sizeof (EFI_GUID);
115
116 for (Index = 0; Index < PeimCount; Index++) {
117 //
118 // Make an array of file name guids that matches the FileHandle array so we can convert
119 // quickly from file name to file handle
120 //
121 Status = FvPpi->GetFileInfo (FvPpi, Private->CurrentFvFileHandles[Index], &FileInfo);
122 CopyMem (&FileGuid[Index], &FileInfo.FileName, sizeof(EFI_GUID));
123 }
124
125 //
126 // Walk through FileGuid array to find out who is invalid PEIM guid in Apriori file.
127 // Add available PEIMs in Apriori file into TempFileHandles array at first.
128 //
129 Index2 = 0;
130 for (Index = 0; Index2 < Private->AprioriCount; Index++) {
131 while (Index2 < Private->AprioriCount) {
132 Guid = ScanGuid (FileGuid, PeimCount * sizeof (EFI_GUID), &Apriori[Index2++]);
133 if (Guid != NULL) {
134 break;
135 }
136 }
137 if (Guid == NULL) {
138 break;
139 }
140 PeimIndex = ((UINTN)Guid - (UINTN)&FileGuid[0])/sizeof (EFI_GUID);
141 TempFileHandles[Index] = Private->CurrentFvFileHandles[PeimIndex];
142
143 //
144 // Since we have copied the file handle we can remove it from this list.
145 //
146 Private->CurrentFvFileHandles[PeimIndex] = NULL;
147 }
148
149 //
150 // Update valid Aprioricount
151 //
152 Private->AprioriCount = Index;
153
154 //
155 // Add in any PEIMs not in the Apriori file
156 //
157 for (;Index < PeimCount; Index++) {
158 for (Index2 = 0; Index2 < PeimCount; Index2++) {
159 if (Private->CurrentFvFileHandles[Index2] != NULL) {
160 TempFileHandles[Index] = Private->CurrentFvFileHandles[Index2];
161 Private->CurrentFvFileHandles[Index2] = NULL;
162 break;
163 }
164 }
165 }
166 //
167 //Index the end of array contains re-range Pei moudle.
168 //
169 TempFileHandles[Index] = NULL;
170
171 //
172 // Private->CurrentFvFileHandles is currently in PEIM in the FV order.
173 // We need to update it to start with files in the A Priori list and
174 // then the remaining files in PEIM order.
175 //
176 CopyMem (Private->CurrentFvFileHandles, TempFileHandles, sizeof (EFI_PEI_FILE_HANDLE) * PcdGet32 (PcdPeiCoreMaxPeimPerFv));
177 }
178 }
179 //
180 // Cache the current Fv File Handle. So that we don't have to scan the Fv again.
181 // Instead, we can retrieve the file handles within this Fv from cachable data.
182 //
183 Private->Fv[Private->CurrentPeimFvCount].ScanFv = TRUE;
184 CopyMem (Private->Fv[Private->CurrentPeimFvCount].FvFileHandles, Private->CurrentFvFileHandles, sizeof (EFI_PEI_FILE_HANDLE) * PcdGet32 (PcdPeiCoreMaxPeimPerFv));
185
186 }
187
188 //
189 // This is the minimum memory required by DxeCore initialization. When LMFA feature enabled,
190 // This part of memory still need reserved on the very top of memory so that the DXE Core could
191 // use these memory for data initialization. This macro should be sync with the same marco
192 // defined in DXE Core.
193 //
194 #define MINIMUM_INITIAL_MEMORY_SIZE 0x10000
195 /**
196 This function is to test if the memory range described in resource HOB is available or not.
197
198 This function should only be invoked when Loading Module at Fixed Address(LMFA) feature is enabled. Some platform may allocate the
199 memory before PeiLoadFixAddressHook in invoked. so this function is to test if the memory range described by the input resource HOB is
200 available or not.
201
202 @param PrivateData Pointer to the private data passed in from caller
203 @param ResourceHob Pointer to a resource HOB which described the memory range described by the input resource HOB
204 **/
205 BOOLEAN
206 PeiLoadFixAddressIsMemoryRangeAvailable (
207 IN PEI_CORE_INSTANCE *PrivateData,
208 IN EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob
209 )
210 {
211 EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
212 BOOLEAN IsAvailable;
213 EFI_PEI_HOB_POINTERS Hob;
214
215 IsAvailable = TRUE;
216 if (PrivateData == NULL || ResourceHob == NULL) {
217 return FALSE;
218 }
219 //
220 // test if the memory range describe in the HOB is already allocated.
221 //
222 for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
223 //
224 // See if this is a memory allocation HOB
225 //
226 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
227 MemoryHob = Hob.MemoryAllocation;
228 if(MemoryHob->AllocDescriptor.MemoryBaseAddress == ResourceHob->PhysicalStart &&
229 MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength == ResourceHob->PhysicalStart + ResourceHob->ResourceLength) {
230 IsAvailable = FALSE;
231 break;
232 }
233 }
234 }
235
236 return IsAvailable;
237
238 }
239 /**
240 Hook function for Loading Module at Fixed Address feature
241
242 This function should only be invoked when Loading Module at Fixed Address(LMFA) feature is enabled. When feature is
243 configured as Load Modules at Fix Absolute Address, this function is to validate the top address assigned by user. When
244 feature is configured as Load Modules at Fixed Offset, the functino is to find the top address which is TOLM-TSEG in general.
245 And also the function will re-install PEI memory.
246
247 @param PrivateData Pointer to the private data passed in from caller
248
249 **/
250 VOID
251 PeiLoadFixAddressHook(
252 IN PEI_CORE_INSTANCE *PrivateData
253 )
254 {
255 EFI_PHYSICAL_ADDRESS TopLoadingAddress;
256 UINT64 PeiMemorySize;
257 UINT64 TotalReservedMemorySize;
258 UINT64 MemoryRangeEnd;
259 EFI_PHYSICAL_ADDRESS HighAddress;
260 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
261 EFI_HOB_RESOURCE_DESCRIPTOR *NextResourceHob;
262 EFI_HOB_RESOURCE_DESCRIPTOR *CurrentResourceHob;
263 EFI_PEI_HOB_POINTERS CurrentHob;
264 EFI_PEI_HOB_POINTERS Hob;
265 EFI_PEI_HOB_POINTERS NextHob;
266 EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
267 //
268 // Initialize Local Variables
269 //
270 CurrentResourceHob = NULL;
271 ResourceHob = NULL;
272 NextResourceHob = NULL;
273 HighAddress = 0;
274 TopLoadingAddress = 0;
275 MemoryRangeEnd = 0;
276 CurrentHob.Raw = PrivateData->HobList.Raw;
277 PeiMemorySize = PrivateData->PhysicalMemoryLength;
278 //
279 // The top reserved memory include 3 parts: the topest range is for DXE core initialization with the size MINIMUM_INITIAL_MEMORY_SIZE
280 // then RuntimeCodePage range and Boot time code range.
281 //
282 TotalReservedMemorySize = MINIMUM_INITIAL_MEMORY_SIZE + EFI_PAGES_TO_SIZE(PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber));
283 TotalReservedMemorySize+= EFI_PAGES_TO_SIZE(PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber)) ;
284 //
285 // PEI memory range lies below the top reserved memory
286 //
287 TotalReservedMemorySize += PeiMemorySize;
288
289 DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressRuntimeCodePageNumber= 0x%x.\n", PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber)));
290 DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressBootTimeCodePageNumber= 0x%x.\n", PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber)));
291 DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressPeiCodePageNumber= 0x%x.\n", PcdGet32(PcdLoadFixAddressPeiCodePageNumber)));
292 DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: Total Reserved Memory Size = 0x%lx.\n", TotalReservedMemorySize));
293 //
294 // Loop through the system memory typed hob to merge the adjacent memory range
295 //
296 for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
297 //
298 // See if this is a resource descriptor HOB
299 //
300 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
301
302 ResourceHob = Hob.ResourceDescriptor;
303 //
304 // If range described in this hob is not system memory or heigher than MAX_ADDRESS, ignored.
305 //
306 if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY ||
307 ResourceHob->PhysicalStart + ResourceHob->ResourceLength > MAX_ADDRESS) {
308 continue;
309 }
310
311 for (NextHob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(NextHob); NextHob.Raw = GET_NEXT_HOB(NextHob)) {
312 if (NextHob.Raw == Hob.Raw){
313 continue;
314 }
315 //
316 // See if this is a resource descriptor HOB
317 //
318 if (GET_HOB_TYPE (NextHob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
319
320 NextResourceHob = NextHob.ResourceDescriptor;
321 //
322 // test if range described in this NextResourceHob is system memory and have the same attribute.
323 // Note: Here is a assumption that system memory should always be healthy even without test.
324 //
325 if (NextResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY &&
326 (((NextResourceHob->ResourceAttribute^ResourceHob->ResourceAttribute)&(~EFI_RESOURCE_ATTRIBUTE_TESTED)) == 0)){
327
328 //
329 // See if the memory range described in ResourceHob and NextResourceHob is adjacent
330 //
331 if ((ResourceHob->PhysicalStart <= NextResourceHob->PhysicalStart &&
332 ResourceHob->PhysicalStart + ResourceHob->ResourceLength >= NextResourceHob->PhysicalStart)||
333 (ResourceHob->PhysicalStart >= NextResourceHob->PhysicalStart&&
334 ResourceHob->PhysicalStart <= NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength)) {
335
336 MemoryRangeEnd = ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength)>(NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength)) ?
337 (ResourceHob->PhysicalStart + ResourceHob->ResourceLength):(NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength);
338
339 ResourceHob->PhysicalStart = (ResourceHob->PhysicalStart < NextResourceHob->PhysicalStart) ?
340 ResourceHob->PhysicalStart : NextResourceHob->PhysicalStart;
341
342
343 ResourceHob->ResourceLength = (MemoryRangeEnd - ResourceHob->PhysicalStart);
344
345 ResourceHob->ResourceAttribute = ResourceHob->ResourceAttribute & (~EFI_RESOURCE_ATTRIBUTE_TESTED);
346 //
347 // Delete the NextResourceHob by marking it as unused.
348 //
349 GET_HOB_TYPE (NextHob) = EFI_HOB_TYPE_UNUSED;
350
351 }
352 }
353 }
354 }
355 }
356 }
357 //
358 // Some platform is already allocated pages before the HOB re-org. Here to build dedicated resource HOB to describe
359 // the allocated memory range
360 //
361 for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
362 //
363 // See if this is a memory allocation HOB
364 //
365 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
366 MemoryHob = Hob.MemoryAllocation;
367 for (NextHob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(NextHob); NextHob.Raw = GET_NEXT_HOB(NextHob)) {
368 //
369 // See if this is a resource descriptor HOB
370 //
371 if (GET_HOB_TYPE (NextHob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
372 NextResourceHob = NextHob.ResourceDescriptor;
373 //
374 // If range described in this hob is not system memory or heigher than MAX_ADDRESS, ignored.
375 //
376 if (NextResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY || NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength > MAX_ADDRESS) {
377 continue;
378 }
379 //
380 // If the range describe in memory allocation HOB belongs to the memroy range described by the resource hob
381 //
382 if (MemoryHob->AllocDescriptor.MemoryBaseAddress >= NextResourceHob->PhysicalStart &&
383 MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength <= NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength) {
384 //
385 // Build seperate resource hob for this allocated range
386 //
387 if (MemoryHob->AllocDescriptor.MemoryBaseAddress > NextResourceHob->PhysicalStart) {
388 BuildResourceDescriptorHob (
389 EFI_RESOURCE_SYSTEM_MEMORY,
390 NextResourceHob->ResourceAttribute,
391 NextResourceHob->PhysicalStart,
392 (MemoryHob->AllocDescriptor.MemoryBaseAddress - NextResourceHob->PhysicalStart)
393 );
394 }
395 if (MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength < NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength) {
396 BuildResourceDescriptorHob (
397 EFI_RESOURCE_SYSTEM_MEMORY,
398 NextResourceHob->ResourceAttribute,
399 MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength,
400 (NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength -(MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength))
401 );
402 }
403 NextResourceHob->PhysicalStart = MemoryHob->AllocDescriptor.MemoryBaseAddress;
404 NextResourceHob->ResourceLength = MemoryHob->AllocDescriptor.MemoryLength;
405 break;
406 }
407 }
408 }
409 }
410 }
411
412 //
413 // Try to find and validate the TOP address.
414 //
415 if ((INT64)PcdGet64(PcdLoadModuleAtFixAddressEnable) > 0 ) {
416 //
417 // The LMFA feature is enabled as load module at fixed absolute address.
418 //
419 TopLoadingAddress = (EFI_PHYSICAL_ADDRESS)PcdGet64(PcdLoadModuleAtFixAddressEnable);
420 DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: Loading module at fixed absolute address.\n"));
421 //
422 // validate the Address. Loop the resource descriptor HOB to make sure the address is in valid memory range
423 //
424 if ((TopLoadingAddress & EFI_PAGE_MASK) != 0) {
425 DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:Top Address 0x%lx is invalid since top address should be page align. \n", TopLoadingAddress));
426 ASSERT (FALSE);
427 }
428 //
429 // Search for a memory region that is below MAX_ADDRESS and in which TopLoadingAddress lies
430 //
431 for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
432 //
433 // See if this is a resource descriptor HOB
434 //
435 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
436
437 ResourceHob = Hob.ResourceDescriptor;
438 //
439 // See if this resource descrior HOB describes tested system memory below MAX_ADDRESS
440 //
441 if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY &&
442 ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS) {
443 //
444 // See if Top address specified by user is valid.
445 //
446 if (ResourceHob->PhysicalStart + TotalReservedMemorySize < TopLoadingAddress &&
447 (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - MINIMUM_INITIAL_MEMORY_SIZE) >= TopLoadingAddress &&
448 PeiLoadFixAddressIsMemoryRangeAvailable(PrivateData, ResourceHob)) {
449 CurrentResourceHob = ResourceHob;
450 CurrentHob = Hob;
451 break;
452 }
453 }
454 }
455 }
456 if (CurrentResourceHob != NULL) {
457 DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO:Top Address 0x%lx is valid \n", TopLoadingAddress));
458 TopLoadingAddress += MINIMUM_INITIAL_MEMORY_SIZE;
459 } else {
460 DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:Top Address 0x%lx is invalid \n", TopLoadingAddress));
461 DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:The recommended Top Address for the platform is: \n"));
462 //
463 // Print the recomended Top address range.
464 //
465 for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
466 //
467 // See if this is a resource descriptor HOB
468 //
469 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
470
471 ResourceHob = Hob.ResourceDescriptor;
472 //
473 // See if this resource descrior HOB describes tested system memory below MAX_ADDRESS
474 //
475 if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY &&
476 ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS) {
477 //
478 // See if Top address specified by user is valid.
479 //
480 if (ResourceHob->ResourceLength > TotalReservedMemorySize && PeiLoadFixAddressIsMemoryRangeAvailable(PrivateData, ResourceHob)) {
481 DEBUG ((EFI_D_INFO, "(0x%lx, 0x%lx)\n",
482 (ResourceHob->PhysicalStart + TotalReservedMemorySize -MINIMUM_INITIAL_MEMORY_SIZE),
483 (ResourceHob->PhysicalStart + ResourceHob->ResourceLength -MINIMUM_INITIAL_MEMORY_SIZE)
484 ));
485 }
486 }
487 }
488 }
489 //
490 // Assert here
491 //
492 ASSERT (FALSE);
493 return;
494 }
495 } else {
496 //
497 // The LMFA feature is enabled as load module at fixed offset relative to TOLM
498 // Parse the Hob list to find the topest available memory. Generally it is (TOLM - TSEG)
499 //
500 //
501 // Search for a tested memory region that is below MAX_ADDRESS
502 //
503 for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
504 //
505 // See if this is a resource descriptor HOB
506 //
507 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
508
509 ResourceHob = Hob.ResourceDescriptor;
510 //
511 // See if this resource descrior HOB describes tested system memory below MAX_ADDRESS
512 //
513 if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY &&
514 ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS &&
515 ResourceHob->ResourceLength > TotalReservedMemorySize && PeiLoadFixAddressIsMemoryRangeAvailable(PrivateData, ResourceHob)) {
516 //
517 // See if this is the highest largest system memory region below MaxAddress
518 //
519 if (ResourceHob->PhysicalStart > HighAddress) {
520 CurrentResourceHob = ResourceHob;
521 CurrentHob = Hob;
522 HighAddress = CurrentResourceHob->PhysicalStart;
523 }
524 }
525 }
526 }
527 if (CurrentResourceHob == NULL) {
528 DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:The System Memory is too small\n"));
529 //
530 // Assert here
531 //
532 ASSERT (FALSE);
533 return;
534 } else {
535 TopLoadingAddress = CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength ;
536 }
537 }
538
539 if (CurrentResourceHob != NULL) {
540 //
541 // rebuild resource HOB for PEI memmory and reserved memory
542 //
543 BuildResourceDescriptorHob (
544 EFI_RESOURCE_SYSTEM_MEMORY,
545 (
546 EFI_RESOURCE_ATTRIBUTE_PRESENT |
547 EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
548 EFI_RESOURCE_ATTRIBUTE_TESTED |
549 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
550 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
551 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
552 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
553 ),
554 (TopLoadingAddress - TotalReservedMemorySize),
555 TotalReservedMemorySize
556 );
557 //
558 // rebuild resource for the remain memory if necessary
559 //
560 if (CurrentResourceHob->PhysicalStart < TopLoadingAddress - TotalReservedMemorySize) {
561 BuildResourceDescriptorHob (
562 EFI_RESOURCE_SYSTEM_MEMORY,
563 (
564 EFI_RESOURCE_ATTRIBUTE_PRESENT |
565 EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
566 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
567 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
568 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
569 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
570 ),
571 CurrentResourceHob->PhysicalStart,
572 (TopLoadingAddress - TotalReservedMemorySize - CurrentResourceHob->PhysicalStart)
573 );
574 }
575 if (CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength > TopLoadingAddress ) {
576 BuildResourceDescriptorHob (
577 EFI_RESOURCE_SYSTEM_MEMORY,
578 (
579 EFI_RESOURCE_ATTRIBUTE_PRESENT |
580 EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
581 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
582 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
583 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
584 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
585 ),
586 TopLoadingAddress,
587 (CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength - TopLoadingAddress)
588 );
589 }
590 //
591 // Delete CurrentHob by marking it as unused since the the memory range described by is rebuilt.
592 //
593 GET_HOB_TYPE (CurrentHob) = EFI_HOB_TYPE_UNUSED;
594 }
595
596 //
597 // Cache the top address for Loading Module at Fixed Address feature
598 //
599 PrivateData->LoadModuleAtFixAddressTopAddress = TopLoadingAddress - MINIMUM_INITIAL_MEMORY_SIZE;
600 DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: Top address = 0x%lx\n", PrivateData->LoadModuleAtFixAddressTopAddress));
601 //
602 // reinstall the PEI memory relative to TopLoadingAddress
603 //
604 PrivateData->PhysicalMemoryBegin = TopLoadingAddress - TotalReservedMemorySize;
605 PrivateData->FreePhysicalMemoryTop = PrivateData->PhysicalMemoryBegin + PeiMemorySize;
606 }
607
608 /**
609 This routine is invoked in switch stack as PeiCore Entry.
610
611 @param SecCoreData Points to a data structure containing information about the PEI core's operating
612 environment, such as the size and location of temporary RAM, the stack location and
613 the BFV location.
614 @param Private Pointer to old core data that is used to initialize the
615 core's data areas.
616 **/
617 VOID
618 EFIAPI
619 PeiCoreEntry (
620 IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
621 IN PEI_CORE_INSTANCE *Private
622 )
623 {
624 //
625 // Entry PEI Phase 2
626 //
627 PeiCore (SecCoreData, NULL, Private);
628 }
629
630 /**
631 Check SwitchStackSignal and switch stack if SwitchStackSignal is TRUE.
632
633 @param[in] SecCoreData Points to a data structure containing information about the PEI core's operating
634 environment, such as the size and location of temporary RAM, the stack location and
635 the BFV location.
636 @param[in] Private Pointer to the private data passed in from caller.
637
638 **/
639 VOID
640 PeiCheckAndSwitchStack (
641 IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
642 IN PEI_CORE_INSTANCE *Private
643 )
644 {
645 VOID *LoadFixPeiCodeBegin;
646 EFI_STATUS Status;
647 CONST EFI_PEI_SERVICES **PeiServices;
648 UINT64 NewStackSize;
649 EFI_PHYSICAL_ADDRESS TopOfOldStack;
650 EFI_PHYSICAL_ADDRESS TopOfNewStack;
651 UINTN StackOffset;
652 BOOLEAN StackOffsetPositive;
653 EFI_PHYSICAL_ADDRESS TemporaryRamBase;
654 UINTN TemporaryRamSize;
655 UINTN TemporaryStackSize;
656 VOID *TemporaryStackBase;
657 UINTN PeiTemporaryRamSize;
658 VOID *PeiTemporaryRamBase;
659 EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI *TemporaryRamSupportPpi;
660 EFI_PHYSICAL_ADDRESS BaseOfNewHeap;
661 EFI_PHYSICAL_ADDRESS HoleMemBase;
662 UINTN HoleMemSize;
663 UINTN HeapTemporaryRamSize;
664 EFI_PHYSICAL_ADDRESS TempBase1;
665 UINTN TempSize1;
666 EFI_PHYSICAL_ADDRESS TempBase2;
667 UINTN TempSize2;
668 UINTN Index;
669
670 PeiServices = (CONST EFI_PEI_SERVICES **) &Private->Ps;
671
672 if (Private->SwitchStackSignal) {
673 //
674 // Before switch stack from temporary memory to permanent memory, calculate the heap and stack
675 // usage in temporary memory for debugging.
676 //
677 DEBUG_CODE_BEGIN ();
678 UINT32 *StackPointer;
679 EFI_PEI_HOB_POINTERS Hob;
680
681 for (StackPointer = (UINT32*)SecCoreData->StackBase;
682 (StackPointer < (UINT32*)((UINTN)SecCoreData->StackBase + SecCoreData->StackSize)) \
683 && (*StackPointer == INIT_CAR_VALUE);
684 StackPointer ++);
685
686 DEBUG ((DEBUG_INFO, "Temp Stack : BaseAddress=0x%p Length=0x%X\n", SecCoreData->StackBase, (UINT32)SecCoreData->StackSize));
687 DEBUG ((DEBUG_INFO, "Temp Heap : BaseAddress=0x%p Length=0x%X\n", SecCoreData->PeiTemporaryRamBase, (UINT32)SecCoreData->PeiTemporaryRamSize));
688 DEBUG ((DEBUG_INFO, "Total temporary memory: %d bytes.\n", (UINT32)SecCoreData->TemporaryRamSize));
689 DEBUG ((DEBUG_INFO, " temporary memory stack ever used: %d bytes.\n",
690 (UINT32)(SecCoreData->StackSize - ((UINTN) StackPointer - (UINTN)SecCoreData->StackBase))
691 ));
692 DEBUG ((DEBUG_INFO, " temporary memory heap used for HobList: %d bytes.\n",
693 (UINT32)((UINTN)Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom - (UINTN)Private->HobList.Raw)
694 ));
695 DEBUG ((DEBUG_INFO, " temporary memory heap occupied by memory pages: %d bytes.\n",
696 (UINT32)(UINTN)(Private->HobList.HandoffInformationTable->EfiMemoryTop - Private->HobList.HandoffInformationTable->EfiFreeMemoryTop)
697 ));
698 for (Hob.Raw = Private->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
699 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
700 DEBUG ((DEBUG_INFO, "Memory Allocation 0x%08x 0x%0lx - 0x%0lx\n", \
701 Hob.MemoryAllocation->AllocDescriptor.MemoryType, \
702 Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress, \
703 Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress + Hob.MemoryAllocation->AllocDescriptor.MemoryLength - 1));
704 }
705 }
706 DEBUG_CODE_END ();
707
708 if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0 && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
709 //
710 // Loading Module at Fixed Address is enabled
711 //
712 PeiLoadFixAddressHook (Private);
713
714 //
715 // If Loading Module at Fixed Address is enabled, Allocating memory range for Pei code range.
716 //
717 LoadFixPeiCodeBegin = AllocatePages((UINTN)PcdGet32(PcdLoadFixAddressPeiCodePageNumber));
718 DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PeiCodeBegin = 0x%lX, PeiCodeTop= 0x%lX\n", (UINT64)(UINTN)LoadFixPeiCodeBegin, (UINT64)((UINTN)LoadFixPeiCodeBegin + PcdGet32(PcdLoadFixAddressPeiCodePageNumber) * EFI_PAGE_SIZE)));
719 }
720
721 //
722 // Reserve the size of new stack at bottom of physical memory
723 //
724 // The size of new stack in permanent memory must be the same size
725 // or larger than the size of old stack in temporary memory.
726 // But if new stack is smaller than the size of old stack, we also reserve
727 // the size of old stack at bottom of permanent memory.
728 //
729 NewStackSize = RShiftU64 (Private->PhysicalMemoryLength, 1);
730 NewStackSize = ALIGN_VALUE (NewStackSize, EFI_PAGE_SIZE);
731 NewStackSize = MIN (PcdGet32(PcdPeiCoreMaxPeiStackSize), NewStackSize);
732 DEBUG ((EFI_D_INFO, "Old Stack size %d, New stack size %d\n", (UINT32)SecCoreData->StackSize, (UINT32)NewStackSize));
733 ASSERT (NewStackSize >= SecCoreData->StackSize);
734
735 //
736 // Calculate stack offset and heap offset between temporary memory and new permement
737 // memory seperately.
738 //
739 TopOfOldStack = (UINTN)SecCoreData->StackBase + SecCoreData->StackSize;
740 TopOfNewStack = Private->PhysicalMemoryBegin + NewStackSize;
741 if (TopOfNewStack >= TopOfOldStack) {
742 StackOffsetPositive = TRUE;
743 StackOffset = (UINTN)(TopOfNewStack - TopOfOldStack);
744 } else {
745 StackOffsetPositive = FALSE;
746 StackOffset = (UINTN)(TopOfOldStack - TopOfNewStack);
747 }
748 Private->StackOffsetPositive = StackOffsetPositive;
749 Private->StackOffset = StackOffset;
750
751 //
752 // Build Stack HOB that describes the permanent memory stack
753 //
754 DEBUG ((EFI_D_INFO, "Stack Hob: BaseAddress=0x%lX Length=0x%lX\n", TopOfNewStack - NewStackSize, NewStackSize));
755 BuildStackHob (TopOfNewStack - NewStackSize, NewStackSize);
756
757 //
758 // Cache information from SecCoreData into locals before SecCoreData is converted to a permanent memory address
759 //
760 TemporaryRamBase = (EFI_PHYSICAL_ADDRESS)(UINTN)SecCoreData->TemporaryRamBase;
761 TemporaryRamSize = SecCoreData->TemporaryRamSize;
762 TemporaryStackSize = SecCoreData->StackSize;
763 TemporaryStackBase = SecCoreData->StackBase;
764 PeiTemporaryRamSize = SecCoreData->PeiTemporaryRamSize;
765 PeiTemporaryRamBase = SecCoreData->PeiTemporaryRamBase;
766
767 //
768 // TemporaryRamSupportPpi is produced by platform's SEC
769 //
770 Status = PeiServicesLocatePpi (
771 &gEfiTemporaryRamSupportPpiGuid,
772 0,
773 NULL,
774 (VOID**)&TemporaryRamSupportPpi
775 );
776 if (!EFI_ERROR (Status)) {
777 //
778 // Heap Offset
779 //
780 BaseOfNewHeap = TopOfNewStack;
781 if (BaseOfNewHeap >= (UINTN)SecCoreData->PeiTemporaryRamBase) {
782 Private->HeapOffsetPositive = TRUE;
783 Private->HeapOffset = (UINTN)(BaseOfNewHeap - (UINTN)SecCoreData->PeiTemporaryRamBase);
784 } else {
785 Private->HeapOffsetPositive = FALSE;
786 Private->HeapOffset = (UINTN)((UINTN)SecCoreData->PeiTemporaryRamBase - BaseOfNewHeap);
787 }
788
789 DEBUG ((EFI_D_INFO, "Heap Offset = 0x%lX Stack Offset = 0x%lX\n", (UINT64) Private->HeapOffset, (UINT64) Private->StackOffset));
790
791 //
792 // Calculate new HandOffTable and PrivateData address in permanent memory's stack
793 //
794 if (StackOffsetPositive) {
795 SecCoreData = (CONST EFI_SEC_PEI_HAND_OFF *)((UINTN)(VOID *)SecCoreData + StackOffset);
796 Private = (PEI_CORE_INSTANCE *)((UINTN)(VOID *)Private + StackOffset);
797 } else {
798 SecCoreData = (CONST EFI_SEC_PEI_HAND_OFF *)((UINTN)(VOID *)SecCoreData - StackOffset);
799 Private = (PEI_CORE_INSTANCE *)((UINTN)(VOID *)Private - StackOffset);
800 }
801
802 //
803 // Temporary Ram Support PPI is provided by platform, it will copy
804 // temporary memory to permanent memory and do stack switching.
805 // After invoking Temporary Ram Support PPI, the following code's
806 // stack is in permanent memory.
807 //
808 TemporaryRamSupportPpi->TemporaryRamMigration (
809 PeiServices,
810 TemporaryRamBase,
811 (EFI_PHYSICAL_ADDRESS)(UINTN)(TopOfNewStack - TemporaryStackSize),
812 TemporaryRamSize
813 );
814
815 //
816 // Migrate memory pages allocated in pre-memory phase.
817 // It could not be called before calling TemporaryRamSupportPpi->TemporaryRamMigration()
818 // as the migrated memory pages may be overridden by TemporaryRamSupportPpi->TemporaryRamMigration().
819 //
820 MigrateMemoryPages (Private, TRUE);
821
822 //
823 // Entry PEI Phase 2
824 //
825 PeiCore (SecCoreData, NULL, Private);
826 } else {
827 //
828 // Migrate memory pages allocated in pre-memory phase.
829 //
830 MigrateMemoryPages (Private, FALSE);
831
832 //
833 // Migrate the PEI Services Table pointer from temporary RAM to permanent RAM.
834 //
835 MigratePeiServicesTablePointer ();
836
837 //
838 // Heap Offset
839 //
840 BaseOfNewHeap = TopOfNewStack;
841 HoleMemBase = TopOfNewStack;
842 HoleMemSize = TemporaryRamSize - PeiTemporaryRamSize - TemporaryStackSize;
843 if (HoleMemSize != 0) {
844 //
845 // Make sure HOB List start address is 8 byte alignment.
846 //
847 BaseOfNewHeap = ALIGN_VALUE (BaseOfNewHeap + HoleMemSize, 8);
848 }
849 if (BaseOfNewHeap >= (UINTN)SecCoreData->PeiTemporaryRamBase) {
850 Private->HeapOffsetPositive = TRUE;
851 Private->HeapOffset = (UINTN)(BaseOfNewHeap - (UINTN)SecCoreData->PeiTemporaryRamBase);
852 } else {
853 Private->HeapOffsetPositive = FALSE;
854 Private->HeapOffset = (UINTN)((UINTN)SecCoreData->PeiTemporaryRamBase - BaseOfNewHeap);
855 }
856
857 DEBUG ((EFI_D_INFO, "Heap Offset = 0x%lX Stack Offset = 0x%lX\n", (UINT64) Private->HeapOffset, (UINT64) Private->StackOffset));
858
859 //
860 // Migrate Heap
861 //
862 HeapTemporaryRamSize = (UINTN) (Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom - Private->HobList.HandoffInformationTable->EfiMemoryBottom);
863 ASSERT (BaseOfNewHeap + HeapTemporaryRamSize <= Private->FreePhysicalMemoryTop);
864 CopyMem ((UINT8 *) (UINTN) BaseOfNewHeap, PeiTemporaryRamBase, HeapTemporaryRamSize);
865
866 //
867 // Migrate Stack
868 //
869 CopyMem ((UINT8 *) (UINTN) (TopOfNewStack - TemporaryStackSize), TemporaryStackBase, TemporaryStackSize);
870
871 //
872 // Copy Hole Range Data
873 //
874 if (HoleMemSize != 0) {
875 //
876 // Prepare Hole
877 //
878 if (PeiTemporaryRamBase < TemporaryStackBase) {
879 TempBase1 = (EFI_PHYSICAL_ADDRESS) (UINTN) PeiTemporaryRamBase;
880 TempSize1 = PeiTemporaryRamSize;
881 TempBase2 = (EFI_PHYSICAL_ADDRESS) (UINTN) TemporaryStackBase;
882 TempSize2 = TemporaryStackSize;
883 } else {
884 TempBase1 = (EFI_PHYSICAL_ADDRESS) (UINTN) TemporaryStackBase;
885 TempSize1 = TemporaryStackSize;
886 TempBase2 =(EFI_PHYSICAL_ADDRESS) (UINTN) PeiTemporaryRamBase;
887 TempSize2 = PeiTemporaryRamSize;
888 }
889 if (TemporaryRamBase < TempBase1) {
890 Private->HoleData[0].Base = TemporaryRamBase;
891 Private->HoleData[0].Size = (UINTN) (TempBase1 - TemporaryRamBase);
892 }
893 if (TempBase1 + TempSize1 < TempBase2) {
894 Private->HoleData[1].Base = TempBase1 + TempSize1;
895 Private->HoleData[1].Size = (UINTN) (TempBase2 - TempBase1 - TempSize1);
896 }
897 if (TempBase2 + TempSize2 < TemporaryRamBase + TemporaryRamSize) {
898 Private->HoleData[2].Base = TempBase2 + TempSize2;
899 Private->HoleData[2].Size = (UINTN) (TemporaryRamBase + TemporaryRamSize - TempBase2 - TempSize2);
900 }
901
902 //
903 // Copy Hole Range data.
904 //
905 for (Index = 0; Index < HOLE_MAX_NUMBER; Index ++) {
906 if (Private->HoleData[Index].Size > 0) {
907 if (HoleMemBase > Private->HoleData[Index].Base) {
908 Private->HoleData[Index].OffsetPositive = TRUE;
909 Private->HoleData[Index].Offset = (UINTN) (HoleMemBase - Private->HoleData[Index].Base);
910 } else {
911 Private->HoleData[Index].OffsetPositive = FALSE;
912 Private->HoleData[Index].Offset = (UINTN) (Private->HoleData[Index].Base - HoleMemBase);
913 }
914 CopyMem ((VOID *) (UINTN) HoleMemBase, (VOID *) (UINTN) Private->HoleData[Index].Base, Private->HoleData[Index].Size);
915 HoleMemBase = HoleMemBase + Private->HoleData[Index].Size;
916 }
917 }
918 }
919
920 //
921 // Switch new stack
922 //
923 SwitchStack (
924 (SWITCH_STACK_ENTRY_POINT)(UINTN)PeiCoreEntry,
925 (VOID *) SecCoreData,
926 (VOID *) Private,
927 (VOID *) (UINTN) TopOfNewStack
928 );
929 }
930
931 //
932 // Code should not come here
933 //
934 ASSERT (FALSE);
935 }
936 }
937
938 /**
939 Conduct PEIM dispatch.
940
941 @param SecCoreData Points to a data structure containing information about the PEI core's operating
942 environment, such as the size and location of temporary RAM, the stack location and
943 the BFV location.
944 @param Private Pointer to the private data passed in from caller
945
946 **/
947 VOID
948 PeiDispatcher (
949 IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
950 IN PEI_CORE_INSTANCE *Private
951 )
952 {
953 EFI_STATUS Status;
954 UINT32 Index1;
955 UINT32 Index2;
956 CONST EFI_PEI_SERVICES **PeiServices;
957 EFI_PEI_FILE_HANDLE PeimFileHandle;
958 UINTN FvCount;
959 UINTN PeimCount;
960 UINT32 AuthenticationState;
961 EFI_PHYSICAL_ADDRESS EntryPoint;
962 EFI_PEIM_ENTRY_POINT2 PeimEntryPoint;
963 UINTN SaveCurrentPeimCount;
964 UINTN SaveCurrentFvCount;
965 EFI_PEI_FILE_HANDLE SaveCurrentFileHandle;
966 EFI_FV_FILE_INFO FvFileInfo;
967 PEI_CORE_FV_HANDLE *CoreFvHandle;
968
969 PeiServices = (CONST EFI_PEI_SERVICES **) &Private->Ps;
970 PeimEntryPoint = NULL;
971 PeimFileHandle = NULL;
972 EntryPoint = 0;
973
974 if ((Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME || PcdGetBool (PcdShadowPeimOnS3Boot))) {
975 //
976 // Once real memory is available, shadow the RegisterForShadow modules. And meanwhile
977 // update the modules' status from PEIM_STATE_REGISITER_FOR_SHADOW to PEIM_STATE_DONE.
978 //
979 SaveCurrentPeimCount = Private->CurrentPeimCount;
980 SaveCurrentFvCount = Private->CurrentPeimFvCount;
981 SaveCurrentFileHandle = Private->CurrentFileHandle;
982
983 for (Index1 = 0; Index1 <= SaveCurrentFvCount; Index1++) {
984 for (Index2 = 0; (Index2 < PcdGet32 (PcdPeiCoreMaxPeimPerFv)) && (Private->Fv[Index1].FvFileHandles[Index2] != NULL); Index2++) {
985 if (Private->Fv[Index1].PeimState[Index2] == PEIM_STATE_REGISITER_FOR_SHADOW) {
986 PeimFileHandle = Private->Fv[Index1].FvFileHandles[Index2];
987 Private->CurrentFileHandle = PeimFileHandle;
988 Private->CurrentPeimFvCount = Index1;
989 Private->CurrentPeimCount = Index2;
990 Status = PeiLoadImage (
991 (CONST EFI_PEI_SERVICES **) &Private->Ps,
992 PeimFileHandle,
993 PEIM_STATE_REGISITER_FOR_SHADOW,
994 &EntryPoint,
995 &AuthenticationState
996 );
997 if (Status == EFI_SUCCESS) {
998 //
999 // PEIM_STATE_REGISITER_FOR_SHADOW move to PEIM_STATE_DONE
1000 //
1001 Private->Fv[Index1].PeimState[Index2]++;
1002 //
1003 // Call the PEIM entry point
1004 //
1005 PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
1006
1007 PERF_START (PeimFileHandle, "PEIM", NULL, 0);
1008 PeimEntryPoint(PeimFileHandle, (const EFI_PEI_SERVICES **) &Private->Ps);
1009 PERF_END (PeimFileHandle, "PEIM", NULL, 0);
1010 }
1011
1012 //
1013 // Process the Notify list and dispatch any notifies for
1014 // newly installed PPIs.
1015 //
1016 ProcessNotifyList (Private);
1017 }
1018 }
1019 }
1020 Private->CurrentFileHandle = SaveCurrentFileHandle;
1021 Private->CurrentPeimFvCount = SaveCurrentFvCount;
1022 Private->CurrentPeimCount = SaveCurrentPeimCount;
1023 }
1024
1025 //
1026 // This is the main dispatch loop. It will search known FVs for PEIMs and
1027 // attempt to dispatch them. If any PEIM gets dispatched through a single
1028 // pass of the dispatcher, it will start over from the Bfv again to see
1029 // if any new PEIMs dependencies got satisfied. With a well ordered
1030 // FV where PEIMs are found in the order their dependencies are also
1031 // satisfied, this dipatcher should run only once.
1032 //
1033 do {
1034 //
1035 // In case that reenter PeiCore happens, the last pass record is still available.
1036 //
1037 if (!Private->PeimDispatcherReenter) {
1038 Private->PeimNeedingDispatch = FALSE;
1039 Private->PeimDispatchOnThisPass = FALSE;
1040 } else {
1041 Private->PeimDispatcherReenter = FALSE;
1042 }
1043
1044 for (FvCount = Private->CurrentPeimFvCount; FvCount < Private->FvCount; FvCount++) {
1045 CoreFvHandle = FindNextCoreFvHandle (Private, FvCount);
1046 ASSERT (CoreFvHandle != NULL);
1047
1048 //
1049 // If the FV has corresponding EFI_PEI_FIRMWARE_VOLUME_PPI instance, then dispatch it.
1050 //
1051 if (CoreFvHandle->FvPpi == NULL) {
1052 continue;
1053 }
1054
1055 Private->CurrentPeimFvCount = FvCount;
1056
1057 if (Private->CurrentPeimCount == 0) {
1058 //
1059 // When going through each FV, at first, search Apriori file to
1060 // reorder all PEIMs to ensure the PEIMs in Apriori file to get
1061 // dispatch at first.
1062 //
1063 DiscoverPeimsAndOrderWithApriori (Private, CoreFvHandle);
1064 }
1065
1066 //
1067 // Start to dispatch all modules within the current Fv.
1068 //
1069 for (PeimCount = Private->CurrentPeimCount;
1070 (PeimCount < PcdGet32 (PcdPeiCoreMaxPeimPerFv)) && (Private->CurrentFvFileHandles[PeimCount] != NULL);
1071 PeimCount++) {
1072 Private->CurrentPeimCount = PeimCount;
1073 PeimFileHandle = Private->CurrentFileHandle = Private->CurrentFvFileHandles[PeimCount];
1074
1075 if (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_NOT_DISPATCHED) {
1076 if (!DepexSatisfied (Private, PeimFileHandle, PeimCount)) {
1077 Private->PeimNeedingDispatch = TRUE;
1078 } else {
1079 Status = CoreFvHandle->FvPpi->GetFileInfo (CoreFvHandle->FvPpi, PeimFileHandle, &FvFileInfo);
1080 ASSERT_EFI_ERROR (Status);
1081 if (FvFileInfo.FileType == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
1082 //
1083 // For Fv type file, Produce new FvInfo PPI and FV hob
1084 //
1085 Status = ProcessFvFile (Private, &Private->Fv[FvCount], PeimFileHandle);
1086 if (Status == EFI_SUCCESS) {
1087 //
1088 // PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED
1089 //
1090 Private->Fv[FvCount].PeimState[PeimCount]++;
1091 Private->PeimDispatchOnThisPass = TRUE;
1092 } else {
1093 //
1094 // The related GuidedSectionExtraction/Decompress PPI for the
1095 // encapsulated FV image section may be installed in the rest
1096 // of this do-while loop, so need to make another pass.
1097 //
1098 Private->PeimNeedingDispatch = TRUE;
1099 }
1100 } else {
1101 //
1102 // For PEIM driver, Load its entry point
1103 //
1104 Status = PeiLoadImage (
1105 PeiServices,
1106 PeimFileHandle,
1107 PEIM_STATE_NOT_DISPATCHED,
1108 &EntryPoint,
1109 &AuthenticationState
1110 );
1111 if (Status == EFI_SUCCESS) {
1112 //
1113 // The PEIM has its dependencies satisfied, and its entry point
1114 // has been found, so invoke it.
1115 //
1116 PERF_START (PeimFileHandle, "PEIM", NULL, 0);
1117
1118 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
1119 EFI_PROGRESS_CODE,
1120 (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_BEGIN),
1121 (VOID *)(&PeimFileHandle),
1122 sizeof (PeimFileHandle)
1123 );
1124
1125 Status = VerifyPeim (Private, CoreFvHandle->FvHandle, PeimFileHandle, AuthenticationState);
1126 if (Status != EFI_SECURITY_VIOLATION) {
1127 //
1128 // PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED
1129 //
1130 Private->Fv[FvCount].PeimState[PeimCount]++;
1131 //
1132 // Call the PEIM entry point for PEIM driver
1133 //
1134 PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
1135 PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **) PeiServices);
1136 Private->PeimDispatchOnThisPass = TRUE;
1137 } else {
1138 //
1139 // The related GuidedSectionExtraction PPI for the
1140 // signed PEIM image section may be installed in the rest
1141 // of this do-while loop, so need to make another pass.
1142 //
1143 Private->PeimNeedingDispatch = TRUE;
1144 }
1145
1146 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
1147 EFI_PROGRESS_CODE,
1148 (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_END),
1149 (VOID *)(&PeimFileHandle),
1150 sizeof (PeimFileHandle)
1151 );
1152 PERF_END (PeimFileHandle, "PEIM", NULL, 0);
1153
1154 }
1155 }
1156
1157 PeiCheckAndSwitchStack (SecCoreData, Private);
1158
1159 //
1160 // Process the Notify list and dispatch any notifies for
1161 // newly installed PPIs.
1162 //
1163 ProcessNotifyList (Private);
1164
1165 //
1166 // Recheck SwitchStackSignal after ProcessNotifyList()
1167 // in case PeiInstallPeiMemory() is done in a callback with
1168 // EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH.
1169 //
1170 PeiCheckAndSwitchStack (SecCoreData, Private);
1171
1172 if ((Private->PeiMemoryInstalled) && (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_REGISITER_FOR_SHADOW) && \
1173 (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME || PcdGetBool (PcdShadowPeimOnS3Boot))) {
1174 //
1175 // If memory is available we shadow images by default for performance reasons.
1176 // We call the entry point a 2nd time so the module knows it's shadowed.
1177 //
1178 //PERF_START (PeiServices, L"PEIM", PeimFileHandle, 0);
1179 if ((Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) && !PcdGetBool (PcdShadowPeimOnBoot)) {
1180 //
1181 // Load PEIM into Memory for Register for shadow PEIM.
1182 //
1183 Status = PeiLoadImage (
1184 PeiServices,
1185 PeimFileHandle,
1186 PEIM_STATE_REGISITER_FOR_SHADOW,
1187 &EntryPoint,
1188 &AuthenticationState
1189 );
1190 if (Status == EFI_SUCCESS) {
1191 PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
1192 }
1193 }
1194 ASSERT (PeimEntryPoint != NULL);
1195 PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **) PeiServices);
1196 //PERF_END (PeiServices, L"PEIM", PeimFileHandle, 0);
1197
1198 //
1199 // PEIM_STATE_REGISITER_FOR_SHADOW move to PEIM_STATE_DONE
1200 //
1201 Private->Fv[FvCount].PeimState[PeimCount]++;
1202
1203 //
1204 // Process the Notify list and dispatch any notifies for
1205 // newly installed PPIs.
1206 //
1207 ProcessNotifyList (Private);
1208 }
1209 }
1210 }
1211 }
1212
1213 //
1214 // We set to NULL here to optimize the 2nd entry to this routine after
1215 // memory is found. This reprevents rescanning of the FV. We set to
1216 // NULL here so we start at the begining of the next FV
1217 //
1218 Private->CurrentFileHandle = NULL;
1219 Private->CurrentPeimCount = 0;
1220 //
1221 // Before walking through the next FV,Private->CurrentFvFileHandles[]should set to NULL
1222 //
1223 SetMem (Private->CurrentFvFileHandles, sizeof (EFI_PEI_FILE_HANDLE) * PcdGet32 (PcdPeiCoreMaxPeimPerFv), 0);
1224 }
1225
1226 //
1227 // Before making another pass, we should set Private->CurrentPeimFvCount =0 to go
1228 // through all the FV.
1229 //
1230 Private->CurrentPeimFvCount = 0;
1231
1232 //
1233 // PeimNeedingDispatch being TRUE means we found a PEIM/FV that did not get
1234 // dispatched. So we need to make another pass
1235 //
1236 // PeimDispatchOnThisPass being TRUE means we dispatched a PEIM/FV on this
1237 // pass. If we did not dispatch a PEIM/FV there is no point in trying again
1238 // as it will fail the next time too (nothing has changed).
1239 //
1240 } while (Private->PeimNeedingDispatch && Private->PeimDispatchOnThisPass);
1241
1242 }
1243
1244 /**
1245 Initialize the Dispatcher's data members
1246
1247 @param PrivateData PeiCore's private data structure
1248 @param OldCoreData Old data from SecCore
1249 NULL if being run in non-permament memory mode.
1250 @param SecCoreData Points to a data structure containing information about the PEI core's operating
1251 environment, such as the size and location of temporary RAM, the stack location and
1252 the BFV location.
1253
1254 @return None.
1255
1256 **/
1257 VOID
1258 InitializeDispatcherData (
1259 IN PEI_CORE_INSTANCE *PrivateData,
1260 IN PEI_CORE_INSTANCE *OldCoreData,
1261 IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData
1262 )
1263 {
1264 if (OldCoreData == NULL) {
1265 PrivateData->PeimDispatcherReenter = FALSE;
1266 PeiInitializeFv (PrivateData, SecCoreData);
1267 } else {
1268 PeiReinitializeFv (PrivateData);
1269 }
1270
1271 return;
1272 }
1273
1274 /**
1275 This routine parses the Dependency Expression, if available, and
1276 decides if the module can be executed.
1277
1278
1279 @param Private PeiCore's private data structure
1280 @param FileHandle PEIM's file handle
1281 @param PeimCount Peim count in all dispatched PEIMs.
1282
1283 @retval TRUE Can be dispatched
1284 @retval FALSE Cannot be dispatched
1285
1286 **/
1287 BOOLEAN
1288 DepexSatisfied (
1289 IN PEI_CORE_INSTANCE *Private,
1290 IN EFI_PEI_FILE_HANDLE FileHandle,
1291 IN UINTN PeimCount
1292 )
1293 {
1294 EFI_STATUS Status;
1295 VOID *DepexData;
1296 EFI_FV_FILE_INFO FileInfo;
1297
1298 Status = PeiServicesFfsGetFileInfo (FileHandle, &FileInfo);
1299 if (EFI_ERROR (Status)) {
1300 DEBUG ((DEBUG_DISPATCH, "Evaluate PEI DEPEX for FFS(Unknown)\n"));
1301 } else {
1302 DEBUG ((DEBUG_DISPATCH, "Evaluate PEI DEPEX for FFS(%g)\n", &FileInfo.FileName));
1303 }
1304
1305 if (PeimCount < Private->AprioriCount) {
1306 //
1307 // If its in the A priori file then we set Depex to TRUE
1308 //
1309 DEBUG ((DEBUG_DISPATCH, " RESULT = TRUE (Apriori)\n"));
1310 return TRUE;
1311 }
1312
1313 //
1314 // Depex section not in the encapsulated section.
1315 //
1316 Status = PeiServicesFfsFindSectionData (
1317 EFI_SECTION_PEI_DEPEX,
1318 FileHandle,
1319 (VOID **)&DepexData
1320 );
1321
1322 if (EFI_ERROR (Status)) {
1323 //
1324 // If there is no DEPEX, assume the module can be executed
1325 //
1326 DEBUG ((DEBUG_DISPATCH, " RESULT = TRUE (No DEPEX)\n"));
1327 return TRUE;
1328 }
1329
1330 //
1331 // Evaluate a given DEPEX
1332 //
1333 return PeimDispatchReadiness (&Private->Ps, DepexData);
1334 }
1335
1336 /**
1337 This routine enable a PEIM to register itself to shadow when PEI Foundation
1338 discovery permanent memory.
1339
1340 @param FileHandle File handle of a PEIM.
1341
1342 @retval EFI_NOT_FOUND The file handle doesn't point to PEIM itself.
1343 @retval EFI_ALREADY_STARTED Indicate that the PEIM has been registered itself.
1344 @retval EFI_SUCCESS Successfully to register itself.
1345
1346 **/
1347 EFI_STATUS
1348 EFIAPI
1349 PeiRegisterForShadow (
1350 IN EFI_PEI_FILE_HANDLE FileHandle
1351 )
1352 {
1353 PEI_CORE_INSTANCE *Private;
1354 Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
1355
1356 if (Private->CurrentFileHandle != FileHandle) {
1357 //
1358 // The FileHandle must be for the current PEIM
1359 //
1360 return EFI_NOT_FOUND;
1361 }
1362
1363 if (Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] >= PEIM_STATE_REGISITER_FOR_SHADOW) {
1364 //
1365 // If the PEIM has already entered the PEIM_STATE_REGISTER_FOR_SHADOW or PEIM_STATE_DONE then it's already been started
1366 //
1367 return EFI_ALREADY_STARTED;
1368 }
1369
1370 Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] = PEIM_STATE_REGISITER_FOR_SHADOW;
1371
1372 return EFI_SUCCESS;
1373 }
1374
1375
1376