]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/CpuMpPei/CpuMpPei.c
UefiCpuPkg/CpuMpPei: Do not load new GDT table
[mirror_edk2.git] / UefiCpuPkg / CpuMpPei / CpuMpPei.c
1 /** @file
2 CPU PEI Module installs CPU Multiple Processor PPI.
3
4 Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "CpuMpPei.h"
16
17 //
18 // Global Descriptor Table (GDT)
19 //
20 GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT mGdtEntries[] = {
21 /* selector { Global Segment Descriptor } */
22 /* 0x00 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //null descriptor
23 /* 0x08 */ {{0xffff, 0, 0, 0x2, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear data segment descriptor
24 /* 0x10 */ {{0xffff, 0, 0, 0xf, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear code segment descriptor
25 /* 0x18 */ {{0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor
26 /* 0x20 */ {{0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system code segment descriptor
27 /* 0x28 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor
28 /* 0x30 */ {{0xffff, 0, 0, 0x2, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor
29 /* 0x38 */ {{0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 1, 0, 1, 0}}, //system code segment descriptor
30 /* 0x40 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor
31 };
32
33 //
34 // IA32 Gdt register
35 //
36 GLOBAL_REMOVE_IF_UNREFERENCED IA32_DESCRIPTOR mGdt = {
37 sizeof (mGdtEntries) - 1,
38 (UINTN) mGdtEntries
39 };
40
41 GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList = {
42 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
43 &gEfiEndOfPeiSignalPpiGuid,
44 CpuMpEndOfPeiCallback
45 };
46
47 /**
48 Sort the APIC ID of all processors.
49
50 This function sorts the APIC ID of all processors so that processor number is
51 assigned in the ascending order of APIC ID which eases MP debugging.
52
53 @param PeiCpuMpData Pointer to PEI CPU MP Data
54 **/
55 VOID
56 SortApicId (
57 IN PEI_CPU_MP_DATA *PeiCpuMpData
58 )
59 {
60 UINTN Index1;
61 UINTN Index2;
62 UINTN Index3;
63 UINT32 ApicId;
64 PEI_CPU_DATA CpuData;
65 UINT32 ApCount;
66
67 ApCount = PeiCpuMpData->CpuCount - 1;
68
69 if (ApCount != 0) {
70 for (Index1 = 0; Index1 < ApCount; Index1++) {
71 Index3 = Index1;
72 //
73 // Sort key is the hardware default APIC ID
74 //
75 ApicId = PeiCpuMpData->CpuData[Index1].ApicId;
76 for (Index2 = Index1 + 1; Index2 <= ApCount; Index2++) {
77 if (ApicId > PeiCpuMpData->CpuData[Index2].ApicId) {
78 Index3 = Index2;
79 ApicId = PeiCpuMpData->CpuData[Index2].ApicId;
80 }
81 }
82 if (Index3 != Index1) {
83 CopyMem (&CpuData, &PeiCpuMpData->CpuData[Index3], sizeof (PEI_CPU_DATA));
84 CopyMem (
85 &PeiCpuMpData->CpuData[Index3],
86 &PeiCpuMpData->CpuData[Index1],
87 sizeof (PEI_CPU_DATA)
88 );
89 CopyMem (&PeiCpuMpData->CpuData[Index1], &CpuData, sizeof (PEI_CPU_DATA));
90 }
91 }
92
93 //
94 // Get the processor number for the BSP
95 //
96 ApicId = GetInitialApicId ();
97 for (Index1 = 0; Index1 < PeiCpuMpData->CpuCount; Index1++) {
98 if (PeiCpuMpData->CpuData[Index1].ApicId == ApicId) {
99 PeiCpuMpData->BspNumber = (UINT32) Index1;
100 break;
101 }
102 }
103 }
104 }
105
106 /**
107 Enable x2APIC mode on APs.
108
109 @param Buffer Pointer to private data buffer.
110 **/
111 VOID
112 EFIAPI
113 ApFuncEnableX2Apic (
114 IN OUT VOID *Buffer
115 )
116 {
117 SetApicMode (LOCAL_APIC_MODE_X2APIC);
118 }
119
120 /**
121 Get AP loop mode.
122
123 @param MonitorFilterSize Returns the largest monitor-line size in bytes.
124
125 @return The AP loop mode.
126 **/
127 UINT8
128 GetApLoopMode (
129 OUT UINT16 *MonitorFilterSize
130 )
131 {
132 UINT8 ApLoopMode;
133 UINT32 RegEbx;
134 UINT32 RegEcx;
135 UINT32 RegEdx;
136
137 ASSERT (MonitorFilterSize != NULL);
138
139 ApLoopMode = PcdGet8 (PcdCpuApLoopMode);
140 ASSERT (ApLoopMode >= ApInHltLoop && ApLoopMode <= ApInRunLoop);
141 if (ApLoopMode == ApInMwaitLoop) {
142 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &RegEcx, NULL);
143 if ((RegEcx & BIT3) == 0) {
144 //
145 // If processor does not support MONITOR/MWAIT feature
146 // by CPUID.[EAX=01H]:ECX.BIT3, force AP in Hlt-loop mode
147 //
148 ApLoopMode = ApInHltLoop;
149 }
150 }
151
152 if (ApLoopMode == ApInHltLoop) {
153 *MonitorFilterSize = 0;
154 } else if (ApLoopMode == ApInRunLoop) {
155 *MonitorFilterSize = sizeof (UINT32);
156 } else if (ApLoopMode == ApInMwaitLoop) {
157 //
158 // CPUID.[EAX=05H]:EBX.BIT0-15: Largest monitor-line size in bytes
159 // CPUID.[EAX=05H].EDX: C-states supported using MWAIT
160 //
161 AsmCpuid (CPUID_MONITOR_MWAIT, NULL, &RegEbx, NULL, &RegEdx);
162 *MonitorFilterSize = RegEbx & 0xFFFF;
163 }
164
165 return ApLoopMode;
166 }
167
168 /**
169 Get CPU MP Data pointer from the Guided HOB.
170
171 @return Pointer to Pointer to PEI CPU MP Data
172 **/
173 PEI_CPU_MP_DATA *
174 GetMpHobData (
175 VOID
176 )
177 {
178 EFI_HOB_GUID_TYPE *GuidHob;
179 VOID *DataInHob;
180 PEI_CPU_MP_DATA *CpuMpData;
181
182 CpuMpData = NULL;
183 GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);
184 if (GuidHob != NULL) {
185 DataInHob = GET_GUID_HOB_DATA (GuidHob);
186 CpuMpData = (PEI_CPU_MP_DATA *)(*(UINTN *)DataInHob);
187 }
188 ASSERT (CpuMpData != NULL);
189 return CpuMpData;
190 }
191
192 /**
193 Save the volatile registers required to be restored following INIT IPI.
194
195 @param VolatileRegisters Returns buffer saved the volatile resisters
196 **/
197 VOID
198 SaveVolatileRegisters (
199 OUT CPU_VOLATILE_REGISTERS *VolatileRegisters
200 )
201 {
202 UINT32 RegEdx;
203
204 VolatileRegisters->Cr0 = AsmReadCr0 ();
205 VolatileRegisters->Cr3 = AsmReadCr3 ();
206 VolatileRegisters->Cr4 = AsmReadCr4 ();
207
208 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &RegEdx);
209 if ((RegEdx & BIT2) != 0) {
210 //
211 // If processor supports Debugging Extensions feature
212 // by CPUID.[EAX=01H]:EDX.BIT2
213 //
214 VolatileRegisters->Dr0 = AsmReadDr0 ();
215 VolatileRegisters->Dr1 = AsmReadDr1 ();
216 VolatileRegisters->Dr2 = AsmReadDr2 ();
217 VolatileRegisters->Dr3 = AsmReadDr3 ();
218 VolatileRegisters->Dr6 = AsmReadDr6 ();
219 VolatileRegisters->Dr7 = AsmReadDr7 ();
220 }
221 }
222
223 /**
224 Restore the volatile registers following INIT IPI.
225
226 @param VolatileRegisters Pointer to volatile resisters
227 @param IsRestoreDr TRUE: Restore DRx if supported
228 FALSE: Do not restore DRx
229 **/
230 VOID
231 RestoreVolatileRegisters (
232 IN CPU_VOLATILE_REGISTERS *VolatileRegisters,
233 IN BOOLEAN IsRestoreDr
234 )
235 {
236 UINT32 RegEdx;
237
238 AsmWriteCr0 (VolatileRegisters->Cr0);
239 AsmWriteCr3 (VolatileRegisters->Cr3);
240 AsmWriteCr4 (VolatileRegisters->Cr4);
241
242 if (IsRestoreDr) {
243 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &RegEdx);
244 if ((RegEdx & BIT2) != 0) {
245 //
246 // If processor supports Debugging Extensions feature
247 // by CPUID.[EAX=01H]:EDX.BIT2
248 //
249 AsmWriteDr0 (VolatileRegisters->Dr0);
250 AsmWriteDr1 (VolatileRegisters->Dr1);
251 AsmWriteDr2 (VolatileRegisters->Dr2);
252 AsmWriteDr3 (VolatileRegisters->Dr3);
253 AsmWriteDr6 (VolatileRegisters->Dr6);
254 AsmWriteDr7 (VolatileRegisters->Dr7);
255 }
256 }
257 }
258
259 /**
260 This function will be called from AP reset code if BSP uses WakeUpAP.
261
262 @param ExchangeInfo Pointer to the MP exchange info buffer
263 @param NumApsExecuting Number of current executing AP
264 **/
265 VOID
266 EFIAPI
267 ApCFunction (
268 IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,
269 IN UINTN NumApsExecuting
270 )
271 {
272 PEI_CPU_MP_DATA *PeiCpuMpData;
273 UINTN ProcessorNumber;
274 EFI_AP_PROCEDURE Procedure;
275 UINTN BistData;
276 volatile UINT32 *ApStartupSignalBuffer;
277
278 PeiCpuMpData = ExchangeInfo->PeiCpuMpData;
279 while (TRUE) {
280 if (PeiCpuMpData->InitFlag) {
281 ProcessorNumber = NumApsExecuting;
282 //
283 // Sync BSP's Control registers to APs
284 //
285 RestoreVolatileRegisters (&PeiCpuMpData->CpuData[0].VolatileRegisters, FALSE);
286 //
287 // This is first time AP wakeup, get BIST information from AP stack
288 //
289 BistData = *(UINTN *) (PeiCpuMpData->Buffer + ProcessorNumber * PeiCpuMpData->CpuApStackSize - sizeof (UINTN));
290 PeiCpuMpData->CpuData[ProcessorNumber].Health.Uint32 = (UINT32) BistData;
291 PeiCpuMpData->CpuData[ProcessorNumber].ApicId = GetInitialApicId ();
292 if (PeiCpuMpData->CpuData[ProcessorNumber].ApicId >= 0xFF) {
293 //
294 // Set x2APIC mode if there are any logical processor reporting
295 // an APIC ID of 255 or greater.
296 //
297 AcquireSpinLock(&PeiCpuMpData->MpLock);
298 PeiCpuMpData->X2ApicEnable = TRUE;
299 ReleaseSpinLock(&PeiCpuMpData->MpLock);
300 }
301 //
302 // Sync BSP's Mtrr table to all wakeup APs and load microcode on APs.
303 //
304 MtrrSetAllMtrrs (&PeiCpuMpData->MtrrTable);
305 MicrocodeDetect (PeiCpuMpData);
306 PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle;
307 } else {
308 //
309 // Execute AP function if AP is not disabled
310 //
311 GetProcessorNumber (PeiCpuMpData, &ProcessorNumber);
312 if (PeiCpuMpData->ApLoopMode == ApInHltLoop) {
313 //
314 // Restore AP's volatile registers saved
315 //
316 RestoreVolatileRegisters (&PeiCpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE);
317 }
318
319 if ((PeiCpuMpData->CpuData[ProcessorNumber].State != CpuStateDisabled) &&
320 (PeiCpuMpData->ApFunction != 0)) {
321 PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateBusy;
322 Procedure = (EFI_AP_PROCEDURE)(UINTN)PeiCpuMpData->ApFunction;
323 //
324 // Invoke AP function here
325 //
326 Procedure ((VOID *)(UINTN)PeiCpuMpData->ApFunctionArgument);
327 //
328 // Re-get the processor number due to BSP/AP maybe exchange in AP function
329 //
330 GetProcessorNumber (PeiCpuMpData, &ProcessorNumber);
331 PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle;
332 }
333 }
334
335 //
336 // AP finished executing C code
337 //
338 InterlockedIncrement ((UINT32 *)&PeiCpuMpData->FinishedCount);
339
340 //
341 // Place AP is specified loop mode
342 //
343 if (PeiCpuMpData->ApLoopMode == ApInHltLoop) {
344 //
345 // Save AP volatile registers
346 //
347 SaveVolatileRegisters (&PeiCpuMpData->CpuData[ProcessorNumber].VolatileRegisters);
348 //
349 // Place AP in Hlt-loop
350 //
351 while (TRUE) {
352 DisableInterrupts ();
353 CpuSleep ();
354 CpuPause ();
355 }
356 }
357 ApStartupSignalBuffer = PeiCpuMpData->CpuData[ProcessorNumber].StartupApSignal;
358 while (TRUE) {
359 DisableInterrupts ();
360 if (PeiCpuMpData->ApLoopMode == ApInMwaitLoop) {
361 //
362 // Place AP in Mwait-loop
363 //
364 AsmMonitor ((UINTN)ApStartupSignalBuffer, 0, 0);
365 if (*ApStartupSignalBuffer != WAKEUP_AP_SIGNAL) {
366 //
367 // If AP start-up signal is not set, place AP into
368 // the maximum C-state
369 //
370 AsmMwait (PeiCpuMpData->ApTargetCState << 4, 0);
371 }
372 } else if (PeiCpuMpData->ApLoopMode == ApInRunLoop) {
373 //
374 // Place AP in Run-loop
375 //
376 CpuPause ();
377 } else {
378 ASSERT (FALSE);
379 }
380
381 //
382 // If AP start-up signal is written, AP is waken up
383 // otherwise place AP in loop again
384 //
385 if (*ApStartupSignalBuffer == WAKEUP_AP_SIGNAL) {
386 //
387 // Clear AP start-up signal when AP waken up
388 //
389 InterlockedCompareExchange32 (
390 (UINT32 *)ApStartupSignalBuffer,
391 WAKEUP_AP_SIGNAL,
392 0
393 );
394 break;
395 }
396 }
397 }
398 }
399
400 /**
401 Write AP start-up signal to wakeup AP.
402
403 @param ApStartupSignalBuffer Pointer to AP wakeup signal
404 **/
405 VOID
406 WriteStartupSignal (
407 IN volatile UINT32 *ApStartupSignalBuffer
408 )
409 {
410 *ApStartupSignalBuffer = WAKEUP_AP_SIGNAL;
411 //
412 // If AP is waken up, StartupApSignal should be cleared.
413 // Otherwise, write StartupApSignal again till AP waken up.
414 //
415 while (InterlockedCompareExchange32 (
416 (UINT32 *)ApStartupSignalBuffer,
417 WAKEUP_AP_SIGNAL,
418 WAKEUP_AP_SIGNAL
419 ) != 0) {
420 CpuPause ();
421 }
422 }
423
424 /**
425 This function will be called by BSP to wakeup AP.
426
427 @param PeiCpuMpData Pointer to PEI CPU MP Data
428 @param Broadcast TRUE: Send broadcast IPI to all APs
429 FALSE: Send IPI to AP by ApicId
430 @param ProcessorNumber The handle number of specified processor
431 @param Procedure The function to be invoked by AP
432 @param ProcedureArgument The argument to be passed into AP function
433 **/
434 VOID
435 WakeUpAP (
436 IN PEI_CPU_MP_DATA *PeiCpuMpData,
437 IN BOOLEAN Broadcast,
438 IN UINTN ProcessorNumber,
439 IN EFI_AP_PROCEDURE Procedure, OPTIONAL
440 IN VOID *ProcedureArgument OPTIONAL
441 )
442 {
443 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
444 UINTN Index;
445
446 PeiCpuMpData->ApFunction = (UINTN) Procedure;
447 PeiCpuMpData->ApFunctionArgument = (UINTN) ProcedureArgument;
448 PeiCpuMpData->FinishedCount = 0;
449
450 ExchangeInfo = PeiCpuMpData->MpCpuExchangeInfo;
451 ExchangeInfo->Lock = 0;
452 ExchangeInfo->StackStart = PeiCpuMpData->Buffer;
453 ExchangeInfo->StackSize = PeiCpuMpData->CpuApStackSize;
454 ExchangeInfo->BufferStart = PeiCpuMpData->WakeupBuffer;
455 ExchangeInfo->PmodeOffset = PeiCpuMpData->AddressMap.PModeEntryOffset;
456 ExchangeInfo->LmodeOffset = PeiCpuMpData->AddressMap.LModeEntryOffset;
457 ExchangeInfo->Cr3 = AsmReadCr3 ();
458 ExchangeInfo->CodeSegment = AsmReadCs ();
459 ExchangeInfo->DataSegment = AsmReadDs ();
460 ExchangeInfo->CFunction = (UINTN) ApCFunction;
461 ExchangeInfo->NumApsExecuting = 0;
462 ExchangeInfo->PeiCpuMpData = PeiCpuMpData;
463
464 //
465 // Get the BSP's data of GDT and IDT
466 //
467 AsmReadGdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->GdtrProfile);
468 AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);
469
470 if (PeiCpuMpData->ApLoopMode == ApInMwaitLoop) {
471 //
472 // Get AP target C-state each time when waking up AP,
473 // for it maybe updated by platform again
474 //
475 PeiCpuMpData->ApTargetCState = PcdGet8 (PcdCpuApTargetCstate);
476 }
477
478 //
479 // Wakeup APs per AP loop state
480 //
481 if (PeiCpuMpData->ApLoopMode == ApInHltLoop || PeiCpuMpData->InitFlag) {
482 if (Broadcast) {
483 SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);
484 } else {
485 SendInitSipiSipi (
486 PeiCpuMpData->CpuData[ProcessorNumber].ApicId,
487 (UINT32) ExchangeInfo->BufferStart
488 );
489 }
490 } else if ((PeiCpuMpData->ApLoopMode == ApInMwaitLoop) ||
491 (PeiCpuMpData->ApLoopMode == ApInRunLoop)) {
492 if (Broadcast) {
493 for (Index = 0; Index < PeiCpuMpData->CpuCount; Index++) {
494 if (Index != PeiCpuMpData->BspNumber) {
495 WriteStartupSignal (PeiCpuMpData->CpuData[Index].StartupApSignal);
496 }
497 }
498 } else {
499 WriteStartupSignal (PeiCpuMpData->CpuData[ProcessorNumber].StartupApSignal);
500 }
501 } else {
502 ASSERT (FALSE);
503 }
504 return ;
505 }
506
507 /**
508 Get available system memory below 1MB by specified size.
509
510 @param WakeupBufferSize Wakeup buffer size required
511
512 @retval other Return wakeup buffer address below 1MB.
513 @retval -1 Cannot find free memory below 1MB.
514 **/
515 UINTN
516 GetWakeupBuffer (
517 IN UINTN WakeupBufferSize
518 )
519 {
520 EFI_PEI_HOB_POINTERS Hob;
521 UINTN WakeupBufferStart;
522 UINTN WakeupBufferEnd;
523
524 //
525 // Get the HOB list for processing
526 //
527 Hob.Raw = GetHobList ();
528
529 //
530 // Collect memory ranges
531 //
532 while (!END_OF_HOB_LIST (Hob)) {
533 if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
534 if ((Hob.ResourceDescriptor->PhysicalStart < BASE_1MB) &&
535 (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&
536 ((Hob.ResourceDescriptor->ResourceAttribute &
537 (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |
538 EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |
539 EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED
540 )) == 0)
541 ) {
542 //
543 // Need memory under 1MB to be collected here
544 //
545 WakeupBufferEnd = (UINTN) (Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength);
546 if (WakeupBufferEnd > BASE_1MB) {
547 //
548 // Wakeup buffer should be under 1MB
549 //
550 WakeupBufferEnd = BASE_1MB;
551 }
552 //
553 // Wakeup buffer should be aligned on 4KB
554 //
555 WakeupBufferStart = (WakeupBufferEnd - WakeupBufferSize) & ~(SIZE_4KB - 1);
556 if (WakeupBufferStart < Hob.ResourceDescriptor->PhysicalStart) {
557 continue;
558 }
559 //
560 // Create a memory allocation HOB.
561 //
562 BuildMemoryAllocationHob (
563 WakeupBufferStart,
564 WakeupBufferSize,
565 EfiBootServicesData
566 );
567 return WakeupBufferStart;
568 }
569 }
570 //
571 // Find the next HOB
572 //
573 Hob.Raw = GET_NEXT_HOB (Hob);
574 }
575
576 return (UINTN) -1;
577 }
578
579 /**
580 Get available system memory below 1MB by specified size.
581
582 @param PeiCpuMpData Pointer to PEI CPU MP Data
583 **/
584 VOID
585 BackupAndPrepareWakeupBuffer(
586 IN PEI_CPU_MP_DATA *PeiCpuMpData
587 )
588 {
589 CopyMem (
590 (VOID *) PeiCpuMpData->BackupBuffer,
591 (VOID *) PeiCpuMpData->WakeupBuffer,
592 PeiCpuMpData->BackupBufferSize
593 );
594 CopyMem (
595 (VOID *) PeiCpuMpData->WakeupBuffer,
596 (VOID *) PeiCpuMpData->AddressMap.RendezvousFunnelAddress,
597 PeiCpuMpData->AddressMap.RendezvousFunnelSize
598 );
599 }
600
601 /**
602 Restore wakeup buffer data.
603
604 @param PeiCpuMpData Pointer to PEI CPU MP Data
605 **/
606 VOID
607 RestoreWakeupBuffer(
608 IN PEI_CPU_MP_DATA *PeiCpuMpData
609 )
610 {
611 CopyMem ((VOID *) PeiCpuMpData->WakeupBuffer, (VOID *) PeiCpuMpData->BackupBuffer, PeiCpuMpData->BackupBufferSize);
612 }
613
614 /**
615 This function will get CPU count in the system.
616
617 @param PeiCpuMpData Pointer to PEI CPU MP Data
618
619 @return AP processor count
620 **/
621 UINT32
622 CountProcessorNumber (
623 IN PEI_CPU_MP_DATA *PeiCpuMpData
624 )
625 {
626 //
627 // Load Microcode on BSP
628 //
629 MicrocodeDetect (PeiCpuMpData);
630 //
631 // Store BSP's MTRR setting
632 //
633 MtrrGetAllMtrrs (&PeiCpuMpData->MtrrTable);
634
635 //
636 // Only perform AP detection if PcdCpuMaxLogicalProcessorNumber is greater than 1
637 //
638 if (PcdGet32 (PcdCpuMaxLogicalProcessorNumber) > 1) {
639 //
640 // Send 1st broadcast IPI to APs to wakeup APs
641 //
642 PeiCpuMpData->InitFlag = TRUE;
643 PeiCpuMpData->X2ApicEnable = FALSE;
644 WakeUpAP (PeiCpuMpData, TRUE, 0, NULL, NULL);
645 //
646 // Wait for AP task to complete and then exit.
647 //
648 MicroSecondDelay (PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds));
649 PeiCpuMpData->InitFlag = FALSE;
650 PeiCpuMpData->CpuCount += (UINT32)PeiCpuMpData->MpCpuExchangeInfo->NumApsExecuting;
651 ASSERT (PeiCpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));
652 //
653 // Wait for all APs finished the initialization
654 //
655 while (PeiCpuMpData->FinishedCount < (PeiCpuMpData->CpuCount - 1)) {
656 CpuPause ();
657 }
658
659 if (PeiCpuMpData->X2ApicEnable) {
660 DEBUG ((EFI_D_INFO, "Force x2APIC mode!\n"));
661 //
662 // Wakeup all APs to enable x2APIC mode
663 //
664 WakeUpAP (PeiCpuMpData, TRUE, 0, ApFuncEnableX2Apic, NULL);
665 //
666 // Wait for all known APs finished
667 //
668 while (PeiCpuMpData->FinishedCount < (PeiCpuMpData->CpuCount - 1)) {
669 CpuPause ();
670 }
671 //
672 // Enable x2APIC on BSP
673 //
674 SetApicMode (LOCAL_APIC_MODE_X2APIC);
675 }
676 DEBUG ((EFI_D_INFO, "APIC MODE is %d\n", GetApicMode ()));
677 //
678 // Sort BSP/Aps by CPU APIC ID in ascending order
679 //
680 SortApicId (PeiCpuMpData);
681 }
682
683 DEBUG ((EFI_D_INFO, "CpuMpPei: Find %d processors in system.\n", PeiCpuMpData->CpuCount));
684 return PeiCpuMpData->CpuCount;
685 }
686
687 /**
688 Prepare for AP wakeup buffer and copy AP reset code into it.
689
690 Get wakeup buffer below 1MB. Allocate memory for CPU MP Data and APs Stack.
691
692 @return Pointer to PEI CPU MP Data
693 **/
694 PEI_CPU_MP_DATA *
695 PrepareAPStartupVector (
696 VOID
697 )
698 {
699 EFI_STATUS Status;
700 UINT32 MaxCpuCount;
701 PEI_CPU_MP_DATA *PeiCpuMpData;
702 EFI_PHYSICAL_ADDRESS Buffer;
703 UINTN BufferSize;
704 UINTN WakeupBuffer;
705 UINTN WakeupBufferSize;
706 MP_ASSEMBLY_ADDRESS_MAP AddressMap;
707 UINT8 ApLoopMode;
708 UINT16 MonitorFilterSize;
709 UINT8 *MonitorBuffer;
710 UINTN Index;
711
712 AsmGetAddressMap (&AddressMap);
713 WakeupBufferSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);
714 WakeupBuffer = GetWakeupBuffer ((WakeupBufferSize + SIZE_4KB - 1) & ~(SIZE_4KB - 1));
715 ASSERT (WakeupBuffer != (UINTN) -1);
716 DEBUG ((EFI_D_INFO, "CpuMpPei: WakeupBuffer = 0x%x\n", WakeupBuffer));
717
718 //
719 // Allocate Pages for APs stack, CPU MP Data, backup buffer for wakeup buffer,
720 // and monitor buffer if required.
721 //
722 MaxCpuCount = PcdGet32(PcdCpuMaxLogicalProcessorNumber);
723 BufferSize = PcdGet32 (PcdCpuApStackSize) * MaxCpuCount + sizeof (PEI_CPU_MP_DATA)
724 + WakeupBufferSize + sizeof (PEI_CPU_DATA) * MaxCpuCount;
725 ApLoopMode = GetApLoopMode (&MonitorFilterSize);
726 BufferSize += MonitorFilterSize * MaxCpuCount;
727 Status = PeiServicesAllocatePages (
728 EfiBootServicesData,
729 EFI_SIZE_TO_PAGES (BufferSize),
730 &Buffer
731 );
732 ASSERT_EFI_ERROR (Status);
733
734 PeiCpuMpData = (PEI_CPU_MP_DATA *) (UINTN) (Buffer + PcdGet32 (PcdCpuApStackSize) * MaxCpuCount);
735 PeiCpuMpData->Buffer = (UINTN) Buffer;
736 PeiCpuMpData->CpuApStackSize = PcdGet32 (PcdCpuApStackSize);
737 PeiCpuMpData->WakeupBuffer = WakeupBuffer;
738 PeiCpuMpData->BackupBuffer = (UINTN)PeiCpuMpData + sizeof (PEI_CPU_MP_DATA);
739 PeiCpuMpData->BackupBufferSize = WakeupBufferSize;
740 PeiCpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeupBuffer + AddressMap.RendezvousFunnelSize);
741
742 PeiCpuMpData->CpuCount = 1;
743 PeiCpuMpData->BspNumber = 0;
744 PeiCpuMpData->CpuData = (PEI_CPU_DATA *) (PeiCpuMpData->BackupBuffer +
745 PeiCpuMpData->BackupBufferSize);
746 PeiCpuMpData->CpuData[0].ApicId = GetInitialApicId ();
747 PeiCpuMpData->CpuData[0].Health.Uint32 = 0;
748 PeiCpuMpData->EndOfPeiFlag = FALSE;
749 InitializeSpinLock(&PeiCpuMpData->MpLock);
750 SaveVolatileRegisters (&PeiCpuMpData->CpuData[0].VolatileRegisters);
751 CopyMem (&PeiCpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));
752 //
753 // Initialize AP loop mode
754 //
755 PeiCpuMpData->ApLoopMode = ApLoopMode;
756 DEBUG ((EFI_D_INFO, "AP Loop Mode is %d\n", PeiCpuMpData->ApLoopMode));
757 MonitorBuffer = (UINT8 *)(PeiCpuMpData->CpuData + MaxCpuCount);
758 if (PeiCpuMpData->ApLoopMode != ApInHltLoop) {
759 //
760 // Set up APs wakeup signal buffer
761 //
762 for (Index = 0; Index < MaxCpuCount; Index++) {
763 PeiCpuMpData->CpuData[Index].StartupApSignal =
764 (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);
765 }
766 }
767 //
768 // Backup original data and copy AP reset code in it
769 //
770 BackupAndPrepareWakeupBuffer(PeiCpuMpData);
771
772 return PeiCpuMpData;
773 }
774
775 /**
776 Notify function on End Of Pei PPI.
777
778 On S3 boot, this function will restore wakeup buffer data.
779 On normal boot, this function will flag wakeup buffer to be un-used type.
780
781 @param PeiServices The pointer to the PEI Services Table.
782 @param NotifyDescriptor Address of the notification descriptor data structure.
783 @param Ppi Address of the PPI that was installed.
784
785 @retval EFI_SUCCESS When everything is OK.
786
787 **/
788 EFI_STATUS
789 EFIAPI
790 CpuMpEndOfPeiCallback (
791 IN EFI_PEI_SERVICES **PeiServices,
792 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
793 IN VOID *Ppi
794 )
795 {
796 EFI_STATUS Status;
797 EFI_BOOT_MODE BootMode;
798 PEI_CPU_MP_DATA *PeiCpuMpData;
799 EFI_PEI_HOB_POINTERS Hob;
800 EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
801
802 DEBUG ((EFI_D_INFO, "CpuMpPei: CpuMpEndOfPeiCallback () invoked\n"));
803
804 Status = PeiServicesGetBootMode (&BootMode);
805 ASSERT_EFI_ERROR (Status);
806
807 PeiCpuMpData = GetMpHobData ();
808 ASSERT (PeiCpuMpData != NULL);
809
810 if (BootMode != BOOT_ON_S3_RESUME) {
811 //
812 // Get the HOB list for processing
813 //
814 Hob.Raw = GetHobList ();
815 //
816 // Collect memory ranges
817 //
818 while (!END_OF_HOB_LIST (Hob)) {
819 if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
820 MemoryHob = Hob.MemoryAllocation;
821 if(MemoryHob->AllocDescriptor.MemoryBaseAddress == PeiCpuMpData->WakeupBuffer) {
822 //
823 // Flag this HOB type to un-used
824 //
825 GET_HOB_TYPE (Hob) = EFI_HOB_TYPE_UNUSED;
826 break;
827 }
828 }
829 Hob.Raw = GET_NEXT_HOB (Hob);
830 }
831 } else {
832 RestoreWakeupBuffer (PeiCpuMpData);
833 PeiCpuMpData->EndOfPeiFlag = TRUE;
834 }
835 return EFI_SUCCESS;
836 }
837
838 /**
839 The Entry point of the MP CPU PEIM.
840
841 This function will wakeup APs and collect CPU AP count and install the
842 Mp Service Ppi.
843
844 @param FileHandle Handle of the file being invoked.
845 @param PeiServices Describes the list of possible PEI Services.
846
847 @retval EFI_SUCCESS MpServicePpi is installed successfully.
848
849 **/
850 EFI_STATUS
851 EFIAPI
852 CpuMpPeimInit (
853 IN EFI_PEI_FILE_HANDLE FileHandle,
854 IN CONST EFI_PEI_SERVICES **PeiServices
855 )
856 {
857 EFI_STATUS Status;
858 PEI_CPU_MP_DATA *PeiCpuMpData;
859 EFI_VECTOR_HANDOFF_INFO *VectorInfo;
860 EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi;
861
862 //
863 // Get Vector Hand-off Info PPI
864 //
865 VectorInfo = NULL;
866 Status = PeiServicesLocatePpi (
867 &gEfiVectorHandoffInfoPpiGuid,
868 0,
869 NULL,
870 (VOID **)&VectorHandoffInfoPpi
871 );
872 if (Status == EFI_SUCCESS) {
873 VectorInfo = VectorHandoffInfoPpi->Info;
874 }
875 Status = InitializeCpuExceptionHandlers (VectorInfo);
876 ASSERT_EFI_ERROR (Status);
877 //
878 // Get wakeup buffer and copy AP reset code in it
879 //
880 PeiCpuMpData = PrepareAPStartupVector ();
881 //
882 // Count processor number and collect processor information
883 //
884 CountProcessorNumber (PeiCpuMpData);
885 //
886 // Build location of PEI CPU MP DATA buffer in HOB
887 //
888 BuildGuidDataHob (
889 &gEfiCallerIdGuid,
890 (VOID *)&PeiCpuMpData,
891 sizeof(UINT64)
892 );
893 //
894 // Update and publish CPU BIST information
895 //
896 CollectBistDataFromPpi (PeiServices, PeiCpuMpData);
897 //
898 // register an event for EndOfPei
899 //
900 Status = PeiServicesNotifyPpi (&mNotifyList);
901 ASSERT_EFI_ERROR (Status);
902 //
903 // Install CPU MP PPI
904 //
905 Status = PeiServicesInstallPpi(&mPeiCpuMpPpiDesc);
906 ASSERT_EFI_ERROR (Status);
907
908 return Status;
909 }