]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MpInitLib/MpLib.c
UefiCpuPkg/MpInitLib: Enable x2APIC mode on BSP/APs
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / MpLib.c
1 /** @file
2 CPU MP Initialize Library common functions.
3
4 Copyright (c) 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 "MpLib.h"
16
17 EFI_GUID mCpuInitMpLibHobGuid = CPU_INIT_MP_LIB_HOB_GUID;
18
19 /**
20 The function will check if BSP Execute Disable is enabled.
21 DxeIpl may have enabled Execute Disable for BSP,
22 APs need to get the status and sync up the settings.
23
24 @retval TRUE BSP Execute Disable is enabled.
25 @retval FALSE BSP Execute Disable is not enabled.
26 **/
27 BOOLEAN
28 IsBspExecuteDisableEnabled (
29 VOID
30 )
31 {
32 UINT32 Eax;
33 CPUID_EXTENDED_CPU_SIG_EDX Edx;
34 MSR_IA32_EFER_REGISTER EferMsr;
35 BOOLEAN Enabled;
36
37 Enabled = FALSE;
38 AsmCpuid (CPUID_EXTENDED_FUNCTION, &Eax, NULL, NULL, NULL);
39 if (Eax >= CPUID_EXTENDED_CPU_SIG) {
40 AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &Edx.Uint32);
41 //
42 // CPUID 0x80000001
43 // Bit 20: Execute Disable Bit available.
44 //
45 if (Edx.Bits.NX != 0) {
46 EferMsr.Uint64 = AsmReadMsr64 (MSR_IA32_EFER);
47 //
48 // MSR 0xC0000080
49 // Bit 11: Execute Disable Bit enable.
50 //
51 if (EferMsr.Bits.NXE != 0) {
52 Enabled = TRUE;
53 }
54 }
55 }
56
57 return Enabled;
58 }
59
60 /**
61 Get the Application Processors state.
62
63 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
64
65 @return The AP status
66 **/
67 CPU_STATE
68 GetApState (
69 IN CPU_AP_DATA *CpuData
70 )
71 {
72 return CpuData->State;
73 }
74
75 /**
76 Set the Application Processors state.
77
78 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
79 @param[in] State The AP status
80 **/
81 VOID
82 SetApState (
83 IN CPU_AP_DATA *CpuData,
84 IN CPU_STATE State
85 )
86 {
87 AcquireSpinLock (&CpuData->ApLock);
88 CpuData->State = State;
89 ReleaseSpinLock (&CpuData->ApLock);
90 }
91
92 /**
93 Save the volatile registers required to be restored following INIT IPI.
94
95 @param[out] VolatileRegisters Returns buffer saved the volatile resisters
96 **/
97 VOID
98 SaveVolatileRegisters (
99 OUT CPU_VOLATILE_REGISTERS *VolatileRegisters
100 )
101 {
102 CPUID_VERSION_INFO_EDX VersionInfoEdx;
103
104 VolatileRegisters->Cr0 = AsmReadCr0 ();
105 VolatileRegisters->Cr3 = AsmReadCr3 ();
106 VolatileRegisters->Cr4 = AsmReadCr4 ();
107
108 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
109 if (VersionInfoEdx.Bits.DE != 0) {
110 //
111 // If processor supports Debugging Extensions feature
112 // by CPUID.[EAX=01H]:EDX.BIT2
113 //
114 VolatileRegisters->Dr0 = AsmReadDr0 ();
115 VolatileRegisters->Dr1 = AsmReadDr1 ();
116 VolatileRegisters->Dr2 = AsmReadDr2 ();
117 VolatileRegisters->Dr3 = AsmReadDr3 ();
118 VolatileRegisters->Dr6 = AsmReadDr6 ();
119 VolatileRegisters->Dr7 = AsmReadDr7 ();
120 }
121 }
122
123 /**
124 Restore the volatile registers following INIT IPI.
125
126 @param[in] VolatileRegisters Pointer to volatile resisters
127 @param[in] IsRestoreDr TRUE: Restore DRx if supported
128 FALSE: Do not restore DRx
129 **/
130 VOID
131 RestoreVolatileRegisters (
132 IN CPU_VOLATILE_REGISTERS *VolatileRegisters,
133 IN BOOLEAN IsRestoreDr
134 )
135 {
136 CPUID_VERSION_INFO_EDX VersionInfoEdx;
137
138 AsmWriteCr0 (VolatileRegisters->Cr0);
139 AsmWriteCr3 (VolatileRegisters->Cr3);
140 AsmWriteCr4 (VolatileRegisters->Cr4);
141
142 if (IsRestoreDr) {
143 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
144 if (VersionInfoEdx.Bits.DE != 0) {
145 //
146 // If processor supports Debugging Extensions feature
147 // by CPUID.[EAX=01H]:EDX.BIT2
148 //
149 AsmWriteDr0 (VolatileRegisters->Dr0);
150 AsmWriteDr1 (VolatileRegisters->Dr1);
151 AsmWriteDr2 (VolatileRegisters->Dr2);
152 AsmWriteDr3 (VolatileRegisters->Dr3);
153 AsmWriteDr6 (VolatileRegisters->Dr6);
154 AsmWriteDr7 (VolatileRegisters->Dr7);
155 }
156 }
157 }
158
159 /**
160 Detect whether Mwait-monitor feature is supported.
161
162 @retval TRUE Mwait-monitor feature is supported.
163 @retval FALSE Mwait-monitor feature is not supported.
164 **/
165 BOOLEAN
166 IsMwaitSupport (
167 VOID
168 )
169 {
170 CPUID_VERSION_INFO_ECX VersionInfoEcx;
171
172 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &VersionInfoEcx.Uint32, NULL);
173 return (VersionInfoEcx.Bits.MONITOR == 1) ? TRUE : FALSE;
174 }
175
176 /**
177 Get AP loop mode.
178
179 @param[out] MonitorFilterSize Returns the largest monitor-line size in bytes.
180
181 @return The AP loop mode.
182 **/
183 UINT8
184 GetApLoopMode (
185 OUT UINT32 *MonitorFilterSize
186 )
187 {
188 UINT8 ApLoopMode;
189 CPUID_MONITOR_MWAIT_EBX MonitorMwaitEbx;
190
191 ASSERT (MonitorFilterSize != NULL);
192
193 ApLoopMode = PcdGet8 (PcdCpuApLoopMode);
194 ASSERT (ApLoopMode >= ApInHltLoop && ApLoopMode <= ApInRunLoop);
195 if (ApLoopMode == ApInMwaitLoop) {
196 if (!IsMwaitSupport ()) {
197 //
198 // If processor does not support MONITOR/MWAIT feature,
199 // force AP in Hlt-loop mode
200 //
201 ApLoopMode = ApInHltLoop;
202 }
203 }
204
205 if (ApLoopMode != ApInMwaitLoop) {
206 *MonitorFilterSize = sizeof (UINT32);
207 } else {
208 //
209 // CPUID.[EAX=05H]:EBX.BIT0-15: Largest monitor-line size in bytes
210 // CPUID.[EAX=05H].EDX: C-states supported using MWAIT
211 //
212 AsmCpuid (CPUID_MONITOR_MWAIT, NULL, &MonitorMwaitEbx.Uint32, NULL, NULL);
213 *MonitorFilterSize = MonitorMwaitEbx.Bits.LargestMonitorLineSize;
214 }
215
216 return ApLoopMode;
217 }
218
219 /**
220 Enable x2APIC mode on APs.
221
222 @param[in, out] Buffer Pointer to private data buffer.
223 **/
224 VOID
225 EFIAPI
226 ApFuncEnableX2Apic (
227 IN OUT VOID *Buffer
228 )
229 {
230 SetApicMode (LOCAL_APIC_MODE_X2APIC);
231 }
232
233 /**
234 Do sync on APs.
235
236 @param[in, out] Buffer Pointer to private data buffer.
237 **/
238 VOID
239 EFIAPI
240 ApInitializeSync (
241 IN OUT VOID *Buffer
242 )
243 {
244 CPU_MP_DATA *CpuMpData;
245
246 CpuMpData = (CPU_MP_DATA *) Buffer;
247 //
248 // Sync BSP's MTRR table to AP
249 //
250 MtrrSetAllMtrrs (&CpuMpData->MtrrTable);
251 //
252 // Load microcode on AP
253 //
254 MicrocodeDetect (CpuMpData);
255 }
256
257 /**
258 Find the current Processor number by APIC ID.
259
260 @param[in] CpuMpData Pointer to PEI CPU MP Data
261 @param[in] ProcessorNumber Return the pocessor number found
262
263 @retval EFI_SUCCESS ProcessorNumber is found and returned.
264 @retval EFI_NOT_FOUND ProcessorNumber is not found.
265 **/
266 EFI_STATUS
267 GetProcessorNumber (
268 IN CPU_MP_DATA *CpuMpData,
269 OUT UINTN *ProcessorNumber
270 )
271 {
272 UINTN TotalProcessorNumber;
273 UINTN Index;
274
275 TotalProcessorNumber = CpuMpData->CpuCount;
276 for (Index = 0; Index < TotalProcessorNumber; Index ++) {
277 if (CpuMpData->CpuData[Index].ApicId == GetApicId ()) {
278 *ProcessorNumber = Index;
279 return EFI_SUCCESS;
280 }
281 }
282 return EFI_NOT_FOUND;
283 }
284
285 /**
286 This function will get CPU count in the system.
287
288 @param[in] CpuMpData Pointer to PEI CPU MP Data
289
290 @return CPU count detected
291 **/
292 UINTN
293 CollectProcessorCount (
294 IN CPU_MP_DATA *CpuMpData
295 )
296 {
297 //
298 // Send 1st broadcast IPI to APs to wakeup APs
299 //
300 CpuMpData->InitFlag = ApInitConfig;
301 CpuMpData->X2ApicEnable = FALSE;
302 WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL);
303 //
304 // Wait for AP task to complete and then exit.
305 //
306 MicroSecondDelay (PcdGet32(PcdCpuApInitTimeOutInMicroSeconds));
307 CpuMpData->InitFlag = ApInitDone;
308 ASSERT (CpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));
309 //
310 // Wait for all APs finished the initialization
311 //
312 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {
313 CpuPause ();
314 }
315
316 if (CpuMpData->X2ApicEnable) {
317 DEBUG ((DEBUG_INFO, "Force x2APIC mode!\n"));
318 //
319 // Wakeup all APs to enable x2APIC mode
320 //
321 WakeUpAP (CpuMpData, TRUE, 0, ApFuncEnableX2Apic, NULL);
322 //
323 // Wait for all known APs finished
324 //
325 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {
326 CpuPause ();
327 }
328 //
329 // Enable x2APIC on BSP
330 //
331 SetApicMode (LOCAL_APIC_MODE_X2APIC);
332 }
333 DEBUG ((DEBUG_INFO, "APIC MODE is %d\n", GetApicMode ()));
334 DEBUG ((DEBUG_INFO, "MpInitLib: Find %d processors in system.\n", CpuMpData->CpuCount));
335
336 return CpuMpData->CpuCount;
337 }
338
339 /*
340 Initialize CPU AP Data when AP is wakeup at the first time.
341
342 @param[in, out] CpuMpData Pointer to PEI CPU MP Data
343 @param[in] ProcessorNumber The handle number of processor
344 @param[in] BistData Processor BIST data
345
346 **/
347 VOID
348 InitializeApData (
349 IN OUT CPU_MP_DATA *CpuMpData,
350 IN UINTN ProcessorNumber,
351 IN UINT32 BistData
352 )
353 {
354 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;
355 CpuMpData->CpuData[ProcessorNumber].Health = BistData;
356 CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 0) ? TRUE : FALSE;
357 CpuMpData->CpuData[ProcessorNumber].ApicId = GetApicId ();
358 CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();
359 if (CpuMpData->CpuData[ProcessorNumber].InitialApicId >= 0xFF) {
360 //
361 // Set x2APIC mode if there are any logical processor reporting
362 // an Initial APIC ID of 255 or greater.
363 //
364 AcquireSpinLock(&CpuMpData->MpLock);
365 CpuMpData->X2ApicEnable = TRUE;
366 ReleaseSpinLock(&CpuMpData->MpLock);
367 }
368
369 InitializeSpinLock(&CpuMpData->CpuData[ProcessorNumber].ApLock);
370 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);
371 }
372
373 /**
374 This function will be called from AP reset code if BSP uses WakeUpAP.
375
376 @param[in] ExchangeInfo Pointer to the MP exchange info buffer
377 @param[in] NumApsExecuting Number of current executing AP
378 **/
379 VOID
380 EFIAPI
381 ApWakeupFunction (
382 IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,
383 IN UINTN NumApsExecuting
384 )
385 {
386 CPU_MP_DATA *CpuMpData;
387 UINTN ProcessorNumber;
388 EFI_AP_PROCEDURE Procedure;
389 VOID *Parameter;
390 UINT32 BistData;
391 volatile UINT32 *ApStartupSignalBuffer;
392
393 //
394 // AP finished assembly code and begin to execute C code
395 //
396 CpuMpData = ExchangeInfo->CpuMpData;
397
398 ProgramVirtualWireMode ();
399
400 while (TRUE) {
401 if (CpuMpData->InitFlag == ApInitConfig) {
402 //
403 // Add CPU number
404 //
405 InterlockedIncrement ((UINT32 *) &CpuMpData->CpuCount);
406 ProcessorNumber = NumApsExecuting;
407 //
408 // This is first time AP wakeup, get BIST information from AP stack
409 //
410 BistData = *(UINT32 *) (CpuMpData->Buffer + ProcessorNumber * CpuMpData->CpuApStackSize - sizeof (UINTN));
411 //
412 // Do some AP initialize sync
413 //
414 ApInitializeSync (CpuMpData);
415 //
416 // Sync BSP's Control registers to APs
417 //
418 RestoreVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters, FALSE);
419 InitializeApData (CpuMpData, ProcessorNumber, BistData);
420 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
421 } else {
422 //
423 // Execute AP function if AP is ready
424 //
425 GetProcessorNumber (CpuMpData, &ProcessorNumber);
426 //
427 // Clear AP start-up signal when AP waken up
428 //
429 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
430 InterlockedCompareExchange32 (
431 (UINT32 *) ApStartupSignalBuffer,
432 WAKEUP_AP_SIGNAL,
433 0
434 );
435 if (CpuMpData->ApLoopMode == ApInHltLoop) {
436 //
437 // Restore AP's volatile registers saved
438 //
439 RestoreVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE);
440 }
441
442 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateReady) {
443 Procedure = (EFI_AP_PROCEDURE)CpuMpData->CpuData[ProcessorNumber].ApFunction;
444 Parameter = (VOID *) CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument;
445 if (Procedure != NULL) {
446 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBusy);
447 //
448 // Invoke AP function here
449 //
450 Procedure (Parameter);
451 //
452 // Re-get the CPU APICID and Initial APICID
453 //
454 CpuMpData->CpuData[ProcessorNumber].ApicId = GetApicId ();
455 CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();
456 }
457 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinished);
458 }
459 }
460
461 //
462 // AP finished executing C code
463 //
464 InterlockedIncrement ((UINT32 *) &CpuMpData->FinishedCount);
465
466 //
467 // Place AP is specified loop mode
468 //
469 if (CpuMpData->ApLoopMode == ApInHltLoop) {
470 //
471 // Save AP volatile registers
472 //
473 SaveVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters);
474 //
475 // Place AP in HLT-loop
476 //
477 while (TRUE) {
478 DisableInterrupts ();
479 CpuSleep ();
480 CpuPause ();
481 }
482 }
483 while (TRUE) {
484 DisableInterrupts ();
485 if (CpuMpData->ApLoopMode == ApInMwaitLoop) {
486 //
487 // Place AP in MWAIT-loop
488 //
489 AsmMonitor ((UINTN) ApStartupSignalBuffer, 0, 0);
490 if (*ApStartupSignalBuffer != WAKEUP_AP_SIGNAL) {
491 //
492 // Check AP start-up signal again.
493 // If AP start-up signal is not set, place AP into
494 // the specified C-state
495 //
496 AsmMwait (CpuMpData->ApTargetCState << 4, 0);
497 }
498 } else if (CpuMpData->ApLoopMode == ApInRunLoop) {
499 //
500 // Place AP in Run-loop
501 //
502 CpuPause ();
503 } else {
504 ASSERT (FALSE);
505 }
506
507 //
508 // If AP start-up signal is written, AP is waken up
509 // otherwise place AP in loop again
510 //
511 if (*ApStartupSignalBuffer == WAKEUP_AP_SIGNAL) {
512 break;
513 }
514 }
515 }
516 }
517
518 /**
519 Wait for AP wakeup and write AP start-up signal till AP is waken up.
520
521 @param[in] ApStartupSignalBuffer Pointer to AP wakeup signal
522 **/
523 VOID
524 WaitApWakeup (
525 IN volatile UINT32 *ApStartupSignalBuffer
526 )
527 {
528 //
529 // If AP is waken up, StartupApSignal should be cleared.
530 // Otherwise, write StartupApSignal again till AP waken up.
531 //
532 while (InterlockedCompareExchange32 (
533 (UINT32 *) ApStartupSignalBuffer,
534 WAKEUP_AP_SIGNAL,
535 WAKEUP_AP_SIGNAL
536 ) != 0) {
537 CpuPause ();
538 }
539 }
540
541 /**
542 This function will fill the exchange info structure.
543
544 @param[in] CpuMpData Pointer to CPU MP Data
545
546 **/
547 VOID
548 FillExchangeInfoData (
549 IN CPU_MP_DATA *CpuMpData
550 )
551 {
552 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
553
554 ExchangeInfo = CpuMpData->MpCpuExchangeInfo;
555 ExchangeInfo->Lock = 0;
556 ExchangeInfo->StackStart = CpuMpData->Buffer;
557 ExchangeInfo->StackSize = CpuMpData->CpuApStackSize;
558 ExchangeInfo->BufferStart = CpuMpData->WakeupBuffer;
559 ExchangeInfo->ModeOffset = CpuMpData->AddressMap.ModeEntryOffset;
560
561 ExchangeInfo->CodeSegment = AsmReadCs ();
562 ExchangeInfo->DataSegment = AsmReadDs ();
563
564 ExchangeInfo->Cr3 = AsmReadCr3 ();
565
566 ExchangeInfo->CFunction = (UINTN) ApWakeupFunction;
567 ExchangeInfo->NumApsExecuting = 0;
568 ExchangeInfo->CpuMpData = CpuMpData;
569
570 ExchangeInfo->EnableExecuteDisable = IsBspExecuteDisableEnabled ();
571
572 //
573 // Get the BSP's data of GDT and IDT
574 //
575 AsmReadGdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->GdtrProfile);
576 AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);
577 }
578
579 /**
580 This function will be called by BSP to wakeup AP.
581
582 @param[in] CpuMpData Pointer to CPU MP Data
583 @param[in] Broadcast TRUE: Send broadcast IPI to all APs
584 FALSE: Send IPI to AP by ApicId
585 @param[in] ProcessorNumber The handle number of specified processor
586 @param[in] Procedure The function to be invoked by AP
587 @param[in] ProcedureArgument The argument to be passed into AP function
588 **/
589 VOID
590 WakeUpAP (
591 IN CPU_MP_DATA *CpuMpData,
592 IN BOOLEAN Broadcast,
593 IN UINTN ProcessorNumber,
594 IN EFI_AP_PROCEDURE Procedure, OPTIONAL
595 IN VOID *ProcedureArgument OPTIONAL
596 )
597 {
598 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
599 UINTN Index;
600 CPU_AP_DATA *CpuData;
601 BOOLEAN ResetVectorRequired;
602
603 CpuMpData->FinishedCount = 0;
604 ResetVectorRequired = FALSE;
605
606 if (CpuMpData->ApLoopMode == ApInHltLoop ||
607 CpuMpData->InitFlag != ApInitDone) {
608 ResetVectorRequired = TRUE;
609 AllocateResetVector (CpuMpData);
610 FillExchangeInfoData (CpuMpData);
611 } else if (CpuMpData->ApLoopMode == ApInMwaitLoop) {
612 //
613 // Get AP target C-state each time when waking up AP,
614 // for it maybe updated by platform again
615 //
616 CpuMpData->ApTargetCState = PcdGet8 (PcdCpuApTargetCstate);
617 }
618
619 ExchangeInfo = CpuMpData->MpCpuExchangeInfo;
620
621 if (Broadcast) {
622 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
623 if (Index != CpuMpData->BspNumber) {
624 CpuData = &CpuMpData->CpuData[Index];
625 CpuData->ApFunction = (UINTN) Procedure;
626 CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;
627 SetApState (CpuData, CpuStateReady);
628 if (CpuMpData->InitFlag != ApInitConfig) {
629 *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;
630 }
631 }
632 }
633 if (ResetVectorRequired) {
634 //
635 // Wakeup all APs
636 //
637 SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);
638 }
639 if (CpuMpData->InitFlag != ApInitConfig) {
640 //
641 // Wait all APs waken up if this is not the 1st broadcast of SIPI
642 //
643 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
644 CpuData = &CpuMpData->CpuData[Index];
645 if (Index != CpuMpData->BspNumber) {
646 WaitApWakeup (CpuData->StartupApSignal);
647 }
648 }
649 }
650 } else {
651 CpuData = &CpuMpData->CpuData[ProcessorNumber];
652 CpuData->ApFunction = (UINTN) Procedure;
653 CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;
654 SetApState (CpuData, CpuStateReady);
655 //
656 // Wakeup specified AP
657 //
658 ASSERT (CpuMpData->InitFlag != ApInitConfig);
659 *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;
660 if (ResetVectorRequired) {
661 SendInitSipiSipi (
662 CpuData->ApicId,
663 (UINT32) ExchangeInfo->BufferStart
664 );
665 }
666 //
667 // Wait specified AP waken up
668 //
669 WaitApWakeup (CpuData->StartupApSignal);
670 }
671
672 if (ResetVectorRequired) {
673 FreeResetVector (CpuMpData);
674 }
675 }
676
677 /**
678 MP Initialize Library initialization.
679
680 This service will allocate AP reset vector and wakeup all APs to do APs
681 initialization.
682
683 This service must be invoked before all other MP Initialize Library
684 service are invoked.
685
686 @retval EFI_SUCCESS MP initialization succeeds.
687 @retval Others MP initialization fails.
688
689 **/
690 EFI_STATUS
691 EFIAPI
692 MpInitLibInitialize (
693 VOID
694 )
695 {
696 UINT32 MaxLogicalProcessorNumber;
697 UINT32 ApStackSize;
698 MP_ASSEMBLY_ADDRESS_MAP AddressMap;
699 UINTN BufferSize;
700 UINT32 MonitorFilterSize;
701 VOID *MpBuffer;
702 UINTN Buffer;
703 CPU_MP_DATA *CpuMpData;
704 UINT8 ApLoopMode;
705 UINT8 *MonitorBuffer;
706 UINTN Index;
707 UINTN ApResetVectorSize;
708 UINTN BackupBufferAddr;
709 MaxLogicalProcessorNumber = PcdGet32(PcdCpuMaxLogicalProcessorNumber);
710
711 AsmGetAddressMap (&AddressMap);
712 ApResetVectorSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);
713 ApStackSize = PcdGet32(PcdCpuApStackSize);
714 ApLoopMode = GetApLoopMode (&MonitorFilterSize);
715
716 BufferSize = ApStackSize * MaxLogicalProcessorNumber;
717 BufferSize += MonitorFilterSize * MaxLogicalProcessorNumber;
718 BufferSize += sizeof (CPU_MP_DATA);
719 BufferSize += ApResetVectorSize;
720 BufferSize += (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* MaxLogicalProcessorNumber;
721 MpBuffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));
722 ASSERT (MpBuffer != NULL);
723 ZeroMem (MpBuffer, BufferSize);
724 Buffer = (UINTN) MpBuffer;
725
726 MonitorBuffer = (UINT8 *) (Buffer + ApStackSize * MaxLogicalProcessorNumber);
727 BackupBufferAddr = (UINTN) MonitorBuffer + MonitorFilterSize * MaxLogicalProcessorNumber;
728 CpuMpData = (CPU_MP_DATA *) (BackupBufferAddr + ApResetVectorSize);
729 CpuMpData->Buffer = Buffer;
730 CpuMpData->CpuApStackSize = ApStackSize;
731 CpuMpData->BackupBuffer = BackupBufferAddr;
732 CpuMpData->BackupBufferSize = ApResetVectorSize;
733 CpuMpData->EndOfPeiFlag = FALSE;
734 CpuMpData->WakeupBuffer = (UINTN) -1;
735 CpuMpData->CpuCount = 1;
736 CpuMpData->BspNumber = 0;
737 CpuMpData->WaitEvent = NULL;
738 CpuMpData->CpuData = (CPU_AP_DATA *) (CpuMpData + 1);
739 CpuMpData->CpuInfoInHob = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);
740 InitializeSpinLock(&CpuMpData->MpLock);
741 //
742 // Save BSP's Control registers to APs
743 //
744 SaveVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters);
745 //
746 // Set BSP basic information
747 //
748 InitializeApData (CpuMpData, 0, 0);
749 //
750 // Save assembly code information
751 //
752 CopyMem (&CpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));
753 //
754 // Finally set AP loop mode
755 //
756 CpuMpData->ApLoopMode = ApLoopMode;
757 DEBUG ((DEBUG_INFO, "AP Loop Mode is %d\n", CpuMpData->ApLoopMode));
758 //
759 // Set up APs wakeup signal buffer
760 //
761 for (Index = 0; Index < MaxLogicalProcessorNumber; Index++) {
762 CpuMpData->CpuData[Index].StartupApSignal =
763 (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);
764 }
765 //
766 // Load Microcode on BSP
767 //
768 MicrocodeDetect (CpuMpData);
769 //
770 // Store BSP's MTRR setting
771 //
772 MtrrGetAllMtrrs (&CpuMpData->MtrrTable);
773
774
775 //
776 // Wakeup all APs and calculate the processor count in system
777 //
778 CollectProcessorCount (CpuMpData);
779 //
780 // Initialize global data for MP support
781 //
782 InitMpGlobalData (CpuMpData);
783
784 return EFI_SUCCESS;
785 }
786
787 /**
788 Gets detailed MP-related information on the requested processor at the
789 instant this call is made. This service may only be called from the BSP.
790
791 @param[in] ProcessorNumber The handle number of processor.
792 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
793 the requested processor is deposited.
794 @param[out] HealthData Return processor health data.
795
796 @retval EFI_SUCCESS Processor information was returned.
797 @retval EFI_DEVICE_ERROR The calling processor is an AP.
798 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
799 @retval EFI_NOT_FOUND The processor with the handle specified by
800 ProcessorNumber does not exist in the platform.
801 @retval EFI_NOT_READY MP Initialize Library is not initialized.
802
803 **/
804 EFI_STATUS
805 EFIAPI
806 MpInitLibGetProcessorInfo (
807 IN UINTN ProcessorNumber,
808 OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer,
809 OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL
810 )
811 {
812 return EFI_UNSUPPORTED;
813 }
814 /**
815 This return the handle number for the calling processor. This service may be
816 called from the BSP and APs.
817
818 @param[out] ProcessorNumber Pointer to the handle number of AP.
819 The range is from 0 to the total number of
820 logical processors minus 1. The total number of
821 logical processors can be retrieved by
822 MpInitLibGetNumberOfProcessors().
823
824 @retval EFI_SUCCESS The current processor handle number was returned
825 in ProcessorNumber.
826 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
827 @retval EFI_NOT_READY MP Initialize Library is not initialized.
828
829 **/
830 EFI_STATUS
831 EFIAPI
832 MpInitLibWhoAmI (
833 OUT UINTN *ProcessorNumber
834 )
835 {
836 return EFI_UNSUPPORTED;
837 }
838 /**
839 Retrieves the number of logical processor in the platform and the number of
840 those logical processors that are enabled on this boot. This service may only
841 be called from the BSP.
842
843 @param[out] NumberOfProcessors Pointer to the total number of logical
844 processors in the system, including the BSP
845 and disabled APs.
846 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
847 processors that exist in system, including
848 the BSP.
849
850 @retval EFI_SUCCESS The number of logical processors and enabled
851 logical processors was retrieved.
852 @retval EFI_DEVICE_ERROR The calling processor is an AP.
853 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors
854 is NULL.
855 @retval EFI_NOT_READY MP Initialize Library is not initialized.
856
857 **/
858 EFI_STATUS
859 EFIAPI
860 MpInitLibGetNumberOfProcessors (
861 OUT UINTN *NumberOfProcessors, OPTIONAL
862 OUT UINTN *NumberOfEnabledProcessors OPTIONAL
863 )
864 {
865 return EFI_UNSUPPORTED;
866 }
867 /**
868 Get pointer to CPU MP Data structure from GUIDed HOB.
869
870 @return The pointer to CPU MP Data structure.
871 **/
872 CPU_MP_DATA *
873 GetCpuMpDataFromGuidedHob (
874 VOID
875 )
876 {
877 EFI_HOB_GUID_TYPE *GuidHob;
878 VOID *DataInHob;
879 CPU_MP_DATA *CpuMpData;
880
881 CpuMpData = NULL;
882 GuidHob = GetFirstGuidHob (&mCpuInitMpLibHobGuid);
883 if (GuidHob != NULL) {
884 DataInHob = GET_GUID_HOB_DATA (GuidHob);
885 CpuMpData = (CPU_MP_DATA *) (*(UINTN *) DataInHob);
886 }
887 return CpuMpData;
888 }