]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MpInitLib/MpLib.c
UefiCpuPkg/MpInitLib: Send INIT-SIPI-SIPI to get processor count
[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 Do sync on APs.
221
222 @param[in, out] Buffer Pointer to private data buffer.
223 **/
224 VOID
225 EFIAPI
226 ApInitializeSync (
227 IN OUT VOID *Buffer
228 )
229 {
230 CPU_MP_DATA *CpuMpData;
231
232 CpuMpData = (CPU_MP_DATA *) Buffer;
233 //
234 // Sync BSP's MTRR table to AP
235 //
236 MtrrSetAllMtrrs (&CpuMpData->MtrrTable);
237 //
238 // Load microcode on AP
239 //
240 MicrocodeDetect (CpuMpData);
241 }
242
243 /**
244 Find the current Processor number by APIC ID.
245
246 @param[in] CpuMpData Pointer to PEI CPU MP Data
247 @param[in] ProcessorNumber Return the pocessor number found
248
249 @retval EFI_SUCCESS ProcessorNumber is found and returned.
250 @retval EFI_NOT_FOUND ProcessorNumber is not found.
251 **/
252 EFI_STATUS
253 GetProcessorNumber (
254 IN CPU_MP_DATA *CpuMpData,
255 OUT UINTN *ProcessorNumber
256 )
257 {
258 UINTN TotalProcessorNumber;
259 UINTN Index;
260
261 TotalProcessorNumber = CpuMpData->CpuCount;
262 for (Index = 0; Index < TotalProcessorNumber; Index ++) {
263 if (CpuMpData->CpuData[Index].ApicId == GetApicId ()) {
264 *ProcessorNumber = Index;
265 return EFI_SUCCESS;
266 }
267 }
268 return EFI_NOT_FOUND;
269 }
270
271 /**
272 This function will get CPU count in the system.
273
274 @param[in] CpuMpData Pointer to PEI CPU MP Data
275
276 @return CPU count detected
277 **/
278 UINTN
279 CollectProcessorCount (
280 IN CPU_MP_DATA *CpuMpData
281 )
282 {
283 //
284 // Send 1st broadcast IPI to APs to wakeup APs
285 //
286 CpuMpData->InitFlag = ApInitConfig;
287 CpuMpData->X2ApicEnable = FALSE;
288 WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL);
289 //
290 // Wait for AP task to complete and then exit.
291 //
292 MicroSecondDelay (PcdGet32(PcdCpuApInitTimeOutInMicroSeconds));
293 CpuMpData->InitFlag = ApInitDone;
294 ASSERT (CpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));
295 //
296 // Wait for all APs finished the initialization
297 //
298 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {
299 CpuPause ();
300 }
301
302 DEBUG ((DEBUG_INFO, "MpInitLib: Find %d processors in system.\n", CpuMpData->CpuCount));
303
304 return CpuMpData->CpuCount;
305 }
306
307 /*
308 Initialize CPU AP Data when AP is wakeup at the first time.
309
310 @param[in, out] CpuMpData Pointer to PEI CPU MP Data
311 @param[in] ProcessorNumber The handle number of processor
312 @param[in] BistData Processor BIST data
313
314 **/
315 VOID
316 InitializeApData (
317 IN OUT CPU_MP_DATA *CpuMpData,
318 IN UINTN ProcessorNumber,
319 IN UINT32 BistData
320 )
321 {
322 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;
323 CpuMpData->CpuData[ProcessorNumber].Health = BistData;
324 CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 0) ? TRUE : FALSE;
325 CpuMpData->CpuData[ProcessorNumber].ApicId = GetApicId ();
326 CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();
327 if (CpuMpData->CpuData[ProcessorNumber].InitialApicId >= 0xFF) {
328 //
329 // Set x2APIC mode if there are any logical processor reporting
330 // an Initial APIC ID of 255 or greater.
331 //
332 AcquireSpinLock(&CpuMpData->MpLock);
333 CpuMpData->X2ApicEnable = TRUE;
334 ReleaseSpinLock(&CpuMpData->MpLock);
335 }
336
337 InitializeSpinLock(&CpuMpData->CpuData[ProcessorNumber].ApLock);
338 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);
339 }
340
341 /**
342 This function will be called from AP reset code if BSP uses WakeUpAP.
343
344 @param[in] ExchangeInfo Pointer to the MP exchange info buffer
345 @param[in] NumApsExecuting Number of current executing AP
346 **/
347 VOID
348 EFIAPI
349 ApWakeupFunction (
350 IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,
351 IN UINTN NumApsExecuting
352 )
353 {
354 CPU_MP_DATA *CpuMpData;
355 UINTN ProcessorNumber;
356 EFI_AP_PROCEDURE Procedure;
357 VOID *Parameter;
358 UINT32 BistData;
359 volatile UINT32 *ApStartupSignalBuffer;
360
361 //
362 // AP finished assembly code and begin to execute C code
363 //
364 CpuMpData = ExchangeInfo->CpuMpData;
365
366 ProgramVirtualWireMode ();
367
368 while (TRUE) {
369 if (CpuMpData->InitFlag == ApInitConfig) {
370 //
371 // Add CPU number
372 //
373 InterlockedIncrement ((UINT32 *) &CpuMpData->CpuCount);
374 ProcessorNumber = NumApsExecuting;
375 //
376 // This is first time AP wakeup, get BIST information from AP stack
377 //
378 BistData = *(UINT32 *) (CpuMpData->Buffer + ProcessorNumber * CpuMpData->CpuApStackSize - sizeof (UINTN));
379 //
380 // Do some AP initialize sync
381 //
382 ApInitializeSync (CpuMpData);
383 //
384 // Sync BSP's Control registers to APs
385 //
386 RestoreVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters, FALSE);
387 InitializeApData (CpuMpData, ProcessorNumber, BistData);
388 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
389 } else {
390 //
391 // Execute AP function if AP is ready
392 //
393 GetProcessorNumber (CpuMpData, &ProcessorNumber);
394 //
395 // Clear AP start-up signal when AP waken up
396 //
397 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
398 InterlockedCompareExchange32 (
399 (UINT32 *) ApStartupSignalBuffer,
400 WAKEUP_AP_SIGNAL,
401 0
402 );
403 if (CpuMpData->ApLoopMode == ApInHltLoop) {
404 //
405 // Restore AP's volatile registers saved
406 //
407 RestoreVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE);
408 }
409
410 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateReady) {
411 Procedure = (EFI_AP_PROCEDURE)CpuMpData->CpuData[ProcessorNumber].ApFunction;
412 Parameter = (VOID *) CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument;
413 if (Procedure != NULL) {
414 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBusy);
415 //
416 // Invoke AP function here
417 //
418 Procedure (Parameter);
419 //
420 // Re-get the CPU APICID and Initial APICID
421 //
422 CpuMpData->CpuData[ProcessorNumber].ApicId = GetApicId ();
423 CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();
424 }
425 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinished);
426 }
427 }
428
429 //
430 // AP finished executing C code
431 //
432 InterlockedIncrement ((UINT32 *) &CpuMpData->FinishedCount);
433
434 //
435 // Place AP is specified loop mode
436 //
437 if (CpuMpData->ApLoopMode == ApInHltLoop) {
438 //
439 // Save AP volatile registers
440 //
441 SaveVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters);
442 //
443 // Place AP in HLT-loop
444 //
445 while (TRUE) {
446 DisableInterrupts ();
447 CpuSleep ();
448 CpuPause ();
449 }
450 }
451 while (TRUE) {
452 DisableInterrupts ();
453 if (CpuMpData->ApLoopMode == ApInMwaitLoop) {
454 //
455 // Place AP in MWAIT-loop
456 //
457 AsmMonitor ((UINTN) ApStartupSignalBuffer, 0, 0);
458 if (*ApStartupSignalBuffer != WAKEUP_AP_SIGNAL) {
459 //
460 // Check AP start-up signal again.
461 // If AP start-up signal is not set, place AP into
462 // the specified C-state
463 //
464 AsmMwait (CpuMpData->ApTargetCState << 4, 0);
465 }
466 } else if (CpuMpData->ApLoopMode == ApInRunLoop) {
467 //
468 // Place AP in Run-loop
469 //
470 CpuPause ();
471 } else {
472 ASSERT (FALSE);
473 }
474
475 //
476 // If AP start-up signal is written, AP is waken up
477 // otherwise place AP in loop again
478 //
479 if (*ApStartupSignalBuffer == WAKEUP_AP_SIGNAL) {
480 break;
481 }
482 }
483 }
484 }
485
486 /**
487 Wait for AP wakeup and write AP start-up signal till AP is waken up.
488
489 @param[in] ApStartupSignalBuffer Pointer to AP wakeup signal
490 **/
491 VOID
492 WaitApWakeup (
493 IN volatile UINT32 *ApStartupSignalBuffer
494 )
495 {
496 //
497 // If AP is waken up, StartupApSignal should be cleared.
498 // Otherwise, write StartupApSignal again till AP waken up.
499 //
500 while (InterlockedCompareExchange32 (
501 (UINT32 *) ApStartupSignalBuffer,
502 WAKEUP_AP_SIGNAL,
503 WAKEUP_AP_SIGNAL
504 ) != 0) {
505 CpuPause ();
506 }
507 }
508
509 /**
510 This function will fill the exchange info structure.
511
512 @param[in] CpuMpData Pointer to CPU MP Data
513
514 **/
515 VOID
516 FillExchangeInfoData (
517 IN CPU_MP_DATA *CpuMpData
518 )
519 {
520 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
521
522 ExchangeInfo = CpuMpData->MpCpuExchangeInfo;
523 ExchangeInfo->Lock = 0;
524 ExchangeInfo->StackStart = CpuMpData->Buffer;
525 ExchangeInfo->StackSize = CpuMpData->CpuApStackSize;
526 ExchangeInfo->BufferStart = CpuMpData->WakeupBuffer;
527 ExchangeInfo->ModeOffset = CpuMpData->AddressMap.ModeEntryOffset;
528
529 ExchangeInfo->CodeSegment = AsmReadCs ();
530 ExchangeInfo->DataSegment = AsmReadDs ();
531
532 ExchangeInfo->Cr3 = AsmReadCr3 ();
533
534 ExchangeInfo->CFunction = (UINTN) ApWakeupFunction;
535 ExchangeInfo->NumApsExecuting = 0;
536 ExchangeInfo->CpuMpData = CpuMpData;
537
538 ExchangeInfo->EnableExecuteDisable = IsBspExecuteDisableEnabled ();
539
540 //
541 // Get the BSP's data of GDT and IDT
542 //
543 AsmReadGdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->GdtrProfile);
544 AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);
545 }
546
547 /**
548 This function will be called by BSP to wakeup AP.
549
550 @param[in] CpuMpData Pointer to CPU MP Data
551 @param[in] Broadcast TRUE: Send broadcast IPI to all APs
552 FALSE: Send IPI to AP by ApicId
553 @param[in] ProcessorNumber The handle number of specified processor
554 @param[in] Procedure The function to be invoked by AP
555 @param[in] ProcedureArgument The argument to be passed into AP function
556 **/
557 VOID
558 WakeUpAP (
559 IN CPU_MP_DATA *CpuMpData,
560 IN BOOLEAN Broadcast,
561 IN UINTN ProcessorNumber,
562 IN EFI_AP_PROCEDURE Procedure, OPTIONAL
563 IN VOID *ProcedureArgument OPTIONAL
564 )
565 {
566 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
567 UINTN Index;
568 CPU_AP_DATA *CpuData;
569 BOOLEAN ResetVectorRequired;
570
571 CpuMpData->FinishedCount = 0;
572 ResetVectorRequired = FALSE;
573
574 if (CpuMpData->ApLoopMode == ApInHltLoop ||
575 CpuMpData->InitFlag != ApInitDone) {
576 ResetVectorRequired = TRUE;
577 AllocateResetVector (CpuMpData);
578 FillExchangeInfoData (CpuMpData);
579 } else if (CpuMpData->ApLoopMode == ApInMwaitLoop) {
580 //
581 // Get AP target C-state each time when waking up AP,
582 // for it maybe updated by platform again
583 //
584 CpuMpData->ApTargetCState = PcdGet8 (PcdCpuApTargetCstate);
585 }
586
587 ExchangeInfo = CpuMpData->MpCpuExchangeInfo;
588
589 if (Broadcast) {
590 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
591 if (Index != CpuMpData->BspNumber) {
592 CpuData = &CpuMpData->CpuData[Index];
593 CpuData->ApFunction = (UINTN) Procedure;
594 CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;
595 SetApState (CpuData, CpuStateReady);
596 if (CpuMpData->InitFlag != ApInitConfig) {
597 *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;
598 }
599 }
600 }
601 if (ResetVectorRequired) {
602 //
603 // Wakeup all APs
604 //
605 SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);
606 }
607 if (CpuMpData->InitFlag != ApInitConfig) {
608 //
609 // Wait all APs waken up if this is not the 1st broadcast of SIPI
610 //
611 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
612 CpuData = &CpuMpData->CpuData[Index];
613 if (Index != CpuMpData->BspNumber) {
614 WaitApWakeup (CpuData->StartupApSignal);
615 }
616 }
617 }
618 } else {
619 CpuData = &CpuMpData->CpuData[ProcessorNumber];
620 CpuData->ApFunction = (UINTN) Procedure;
621 CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;
622 SetApState (CpuData, CpuStateReady);
623 //
624 // Wakeup specified AP
625 //
626 ASSERT (CpuMpData->InitFlag != ApInitConfig);
627 *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;
628 if (ResetVectorRequired) {
629 SendInitSipiSipi (
630 CpuData->ApicId,
631 (UINT32) ExchangeInfo->BufferStart
632 );
633 }
634 //
635 // Wait specified AP waken up
636 //
637 WaitApWakeup (CpuData->StartupApSignal);
638 }
639
640 if (ResetVectorRequired) {
641 FreeResetVector (CpuMpData);
642 }
643 }
644
645 /**
646 MP Initialize Library initialization.
647
648 This service will allocate AP reset vector and wakeup all APs to do APs
649 initialization.
650
651 This service must be invoked before all other MP Initialize Library
652 service are invoked.
653
654 @retval EFI_SUCCESS MP initialization succeeds.
655 @retval Others MP initialization fails.
656
657 **/
658 EFI_STATUS
659 EFIAPI
660 MpInitLibInitialize (
661 VOID
662 )
663 {
664 UINT32 MaxLogicalProcessorNumber;
665 UINT32 ApStackSize;
666 MP_ASSEMBLY_ADDRESS_MAP AddressMap;
667 UINTN BufferSize;
668 UINT32 MonitorFilterSize;
669 VOID *MpBuffer;
670 UINTN Buffer;
671 CPU_MP_DATA *CpuMpData;
672 UINT8 ApLoopMode;
673 UINT8 *MonitorBuffer;
674 UINTN Index;
675 UINTN ApResetVectorSize;
676 UINTN BackupBufferAddr;
677 MaxLogicalProcessorNumber = PcdGet32(PcdCpuMaxLogicalProcessorNumber);
678
679 AsmGetAddressMap (&AddressMap);
680 ApResetVectorSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);
681 ApStackSize = PcdGet32(PcdCpuApStackSize);
682 ApLoopMode = GetApLoopMode (&MonitorFilterSize);
683
684 BufferSize = ApStackSize * MaxLogicalProcessorNumber;
685 BufferSize += MonitorFilterSize * MaxLogicalProcessorNumber;
686 BufferSize += sizeof (CPU_MP_DATA);
687 BufferSize += ApResetVectorSize;
688 BufferSize += (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* MaxLogicalProcessorNumber;
689 MpBuffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));
690 ASSERT (MpBuffer != NULL);
691 ZeroMem (MpBuffer, BufferSize);
692 Buffer = (UINTN) MpBuffer;
693
694 MonitorBuffer = (UINT8 *) (Buffer + ApStackSize * MaxLogicalProcessorNumber);
695 BackupBufferAddr = (UINTN) MonitorBuffer + MonitorFilterSize * MaxLogicalProcessorNumber;
696 CpuMpData = (CPU_MP_DATA *) (BackupBufferAddr + ApResetVectorSize);
697 CpuMpData->Buffer = Buffer;
698 CpuMpData->CpuApStackSize = ApStackSize;
699 CpuMpData->BackupBuffer = BackupBufferAddr;
700 CpuMpData->BackupBufferSize = ApResetVectorSize;
701 CpuMpData->EndOfPeiFlag = FALSE;
702 CpuMpData->WakeupBuffer = (UINTN) -1;
703 CpuMpData->CpuCount = 1;
704 CpuMpData->BspNumber = 0;
705 CpuMpData->WaitEvent = NULL;
706 CpuMpData->CpuData = (CPU_AP_DATA *) (CpuMpData + 1);
707 CpuMpData->CpuInfoInHob = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);
708 InitializeSpinLock(&CpuMpData->MpLock);
709 //
710 // Save BSP's Control registers to APs
711 //
712 SaveVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters);
713 //
714 // Set BSP basic information
715 //
716 InitializeApData (CpuMpData, 0, 0);
717 //
718 // Save assembly code information
719 //
720 CopyMem (&CpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));
721 //
722 // Finally set AP loop mode
723 //
724 CpuMpData->ApLoopMode = ApLoopMode;
725 DEBUG ((DEBUG_INFO, "AP Loop Mode is %d\n", CpuMpData->ApLoopMode));
726 //
727 // Set up APs wakeup signal buffer
728 //
729 for (Index = 0; Index < MaxLogicalProcessorNumber; Index++) {
730 CpuMpData->CpuData[Index].StartupApSignal =
731 (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);
732 }
733 //
734 // Load Microcode on BSP
735 //
736 MicrocodeDetect (CpuMpData);
737 //
738 // Store BSP's MTRR setting
739 //
740 MtrrGetAllMtrrs (&CpuMpData->MtrrTable);
741
742
743 //
744 // Wakeup all APs and calculate the processor count in system
745 //
746 CollectProcessorCount (CpuMpData);
747 //
748 // Initialize global data for MP support
749 //
750 InitMpGlobalData (CpuMpData);
751
752 return EFI_SUCCESS;
753 }
754
755 /**
756 Gets detailed MP-related information on the requested processor at the
757 instant this call is made. This service may only be called from the BSP.
758
759 @param[in] ProcessorNumber The handle number of processor.
760 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
761 the requested processor is deposited.
762 @param[out] HealthData Return processor health data.
763
764 @retval EFI_SUCCESS Processor information was returned.
765 @retval EFI_DEVICE_ERROR The calling processor is an AP.
766 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
767 @retval EFI_NOT_FOUND The processor with the handle specified by
768 ProcessorNumber does not exist in the platform.
769 @retval EFI_NOT_READY MP Initialize Library is not initialized.
770
771 **/
772 EFI_STATUS
773 EFIAPI
774 MpInitLibGetProcessorInfo (
775 IN UINTN ProcessorNumber,
776 OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer,
777 OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL
778 )
779 {
780 return EFI_UNSUPPORTED;
781 }
782 /**
783 This return the handle number for the calling processor. This service may be
784 called from the BSP and APs.
785
786 @param[out] ProcessorNumber Pointer to the handle number of AP.
787 The range is from 0 to the total number of
788 logical processors minus 1. The total number of
789 logical processors can be retrieved by
790 MpInitLibGetNumberOfProcessors().
791
792 @retval EFI_SUCCESS The current processor handle number was returned
793 in ProcessorNumber.
794 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
795 @retval EFI_NOT_READY MP Initialize Library is not initialized.
796
797 **/
798 EFI_STATUS
799 EFIAPI
800 MpInitLibWhoAmI (
801 OUT UINTN *ProcessorNumber
802 )
803 {
804 return EFI_UNSUPPORTED;
805 }
806 /**
807 Retrieves the number of logical processor in the platform and the number of
808 those logical processors that are enabled on this boot. This service may only
809 be called from the BSP.
810
811 @param[out] NumberOfProcessors Pointer to the total number of logical
812 processors in the system, including the BSP
813 and disabled APs.
814 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
815 processors that exist in system, including
816 the BSP.
817
818 @retval EFI_SUCCESS The number of logical processors and enabled
819 logical processors was retrieved.
820 @retval EFI_DEVICE_ERROR The calling processor is an AP.
821 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors
822 is NULL.
823 @retval EFI_NOT_READY MP Initialize Library is not initialized.
824
825 **/
826 EFI_STATUS
827 EFIAPI
828 MpInitLibGetNumberOfProcessors (
829 OUT UINTN *NumberOfProcessors, OPTIONAL
830 OUT UINTN *NumberOfEnabledProcessors OPTIONAL
831 )
832 {
833 return EFI_UNSUPPORTED;
834 }
835 /**
836 Get pointer to CPU MP Data structure from GUIDed HOB.
837
838 @return The pointer to CPU MP Data structure.
839 **/
840 CPU_MP_DATA *
841 GetCpuMpDataFromGuidedHob (
842 VOID
843 )
844 {
845 EFI_HOB_GUID_TYPE *GuidHob;
846 VOID *DataInHob;
847 CPU_MP_DATA *CpuMpData;
848
849 CpuMpData = NULL;
850 GuidHob = GetFirstGuidHob (&mCpuInitMpLibHobGuid);
851 if (GuidHob != NULL) {
852 DataInHob = GET_GUID_HOB_DATA (GuidHob);
853 CpuMpData = (CPU_MP_DATA *) (*(UINTN *) DataInHob);
854 }
855 return CpuMpData;
856 }