]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MpInitLib/MpLib.c
UefiCpuPkg/MpInitLib: Add ApWakeupFunction() executed by assembly code
[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 Get the Application Processors state.
21
22 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
23
24 @return The AP status
25 **/
26 CPU_STATE
27 GetApState (
28 IN CPU_AP_DATA *CpuData
29 )
30 {
31 return CpuData->State;
32 }
33
34 /**
35 Set the Application Processors state.
36
37 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
38 @param[in] State The AP status
39 **/
40 VOID
41 SetApState (
42 IN CPU_AP_DATA *CpuData,
43 IN CPU_STATE State
44 )
45 {
46 AcquireSpinLock (&CpuData->ApLock);
47 CpuData->State = State;
48 ReleaseSpinLock (&CpuData->ApLock);
49 }
50
51 /**
52 Save the volatile registers required to be restored following INIT IPI.
53
54 @param[out] VolatileRegisters Returns buffer saved the volatile resisters
55 **/
56 VOID
57 SaveVolatileRegisters (
58 OUT CPU_VOLATILE_REGISTERS *VolatileRegisters
59 )
60 {
61 CPUID_VERSION_INFO_EDX VersionInfoEdx;
62
63 VolatileRegisters->Cr0 = AsmReadCr0 ();
64 VolatileRegisters->Cr3 = AsmReadCr3 ();
65 VolatileRegisters->Cr4 = AsmReadCr4 ();
66
67 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
68 if (VersionInfoEdx.Bits.DE != 0) {
69 //
70 // If processor supports Debugging Extensions feature
71 // by CPUID.[EAX=01H]:EDX.BIT2
72 //
73 VolatileRegisters->Dr0 = AsmReadDr0 ();
74 VolatileRegisters->Dr1 = AsmReadDr1 ();
75 VolatileRegisters->Dr2 = AsmReadDr2 ();
76 VolatileRegisters->Dr3 = AsmReadDr3 ();
77 VolatileRegisters->Dr6 = AsmReadDr6 ();
78 VolatileRegisters->Dr7 = AsmReadDr7 ();
79 }
80 }
81
82 /**
83 Restore the volatile registers following INIT IPI.
84
85 @param[in] VolatileRegisters Pointer to volatile resisters
86 @param[in] IsRestoreDr TRUE: Restore DRx if supported
87 FALSE: Do not restore DRx
88 **/
89 VOID
90 RestoreVolatileRegisters (
91 IN CPU_VOLATILE_REGISTERS *VolatileRegisters,
92 IN BOOLEAN IsRestoreDr
93 )
94 {
95 CPUID_VERSION_INFO_EDX VersionInfoEdx;
96
97 AsmWriteCr0 (VolatileRegisters->Cr0);
98 AsmWriteCr3 (VolatileRegisters->Cr3);
99 AsmWriteCr4 (VolatileRegisters->Cr4);
100
101 if (IsRestoreDr) {
102 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
103 if (VersionInfoEdx.Bits.DE != 0) {
104 //
105 // If processor supports Debugging Extensions feature
106 // by CPUID.[EAX=01H]:EDX.BIT2
107 //
108 AsmWriteDr0 (VolatileRegisters->Dr0);
109 AsmWriteDr1 (VolatileRegisters->Dr1);
110 AsmWriteDr2 (VolatileRegisters->Dr2);
111 AsmWriteDr3 (VolatileRegisters->Dr3);
112 AsmWriteDr6 (VolatileRegisters->Dr6);
113 AsmWriteDr7 (VolatileRegisters->Dr7);
114 }
115 }
116 }
117
118 /**
119 Detect whether Mwait-monitor feature is supported.
120
121 @retval TRUE Mwait-monitor feature is supported.
122 @retval FALSE Mwait-monitor feature is not supported.
123 **/
124 BOOLEAN
125 IsMwaitSupport (
126 VOID
127 )
128 {
129 CPUID_VERSION_INFO_ECX VersionInfoEcx;
130
131 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &VersionInfoEcx.Uint32, NULL);
132 return (VersionInfoEcx.Bits.MONITOR == 1) ? TRUE : FALSE;
133 }
134
135 /**
136 Get AP loop mode.
137
138 @param[out] MonitorFilterSize Returns the largest monitor-line size in bytes.
139
140 @return The AP loop mode.
141 **/
142 UINT8
143 GetApLoopMode (
144 OUT UINT32 *MonitorFilterSize
145 )
146 {
147 UINT8 ApLoopMode;
148 CPUID_MONITOR_MWAIT_EBX MonitorMwaitEbx;
149
150 ASSERT (MonitorFilterSize != NULL);
151
152 ApLoopMode = PcdGet8 (PcdCpuApLoopMode);
153 ASSERT (ApLoopMode >= ApInHltLoop && ApLoopMode <= ApInRunLoop);
154 if (ApLoopMode == ApInMwaitLoop) {
155 if (!IsMwaitSupport ()) {
156 //
157 // If processor does not support MONITOR/MWAIT feature,
158 // force AP in Hlt-loop mode
159 //
160 ApLoopMode = ApInHltLoop;
161 }
162 }
163
164 if (ApLoopMode != ApInMwaitLoop) {
165 *MonitorFilterSize = sizeof (UINT32);
166 } else {
167 //
168 // CPUID.[EAX=05H]:EBX.BIT0-15: Largest monitor-line size in bytes
169 // CPUID.[EAX=05H].EDX: C-states supported using MWAIT
170 //
171 AsmCpuid (CPUID_MONITOR_MWAIT, NULL, &MonitorMwaitEbx.Uint32, NULL, NULL);
172 *MonitorFilterSize = MonitorMwaitEbx.Bits.LargestMonitorLineSize;
173 }
174
175 return ApLoopMode;
176 }
177
178 /**
179 Do sync on APs.
180
181 @param[in, out] Buffer Pointer to private data buffer.
182 **/
183 VOID
184 EFIAPI
185 ApInitializeSync (
186 IN OUT VOID *Buffer
187 )
188 {
189 CPU_MP_DATA *CpuMpData;
190
191 CpuMpData = (CPU_MP_DATA *) Buffer;
192 //
193 // Sync BSP's MTRR table to AP
194 //
195 MtrrSetAllMtrrs (&CpuMpData->MtrrTable);
196 //
197 // Load microcode on AP
198 //
199 MicrocodeDetect (CpuMpData);
200 }
201
202 /**
203 Find the current Processor number by APIC ID.
204
205 @param[in] CpuMpData Pointer to PEI CPU MP Data
206 @param[in] ProcessorNumber Return the pocessor number found
207
208 @retval EFI_SUCCESS ProcessorNumber is found and returned.
209 @retval EFI_NOT_FOUND ProcessorNumber is not found.
210 **/
211 EFI_STATUS
212 GetProcessorNumber (
213 IN CPU_MP_DATA *CpuMpData,
214 OUT UINTN *ProcessorNumber
215 )
216 {
217 UINTN TotalProcessorNumber;
218 UINTN Index;
219
220 TotalProcessorNumber = CpuMpData->CpuCount;
221 for (Index = 0; Index < TotalProcessorNumber; Index ++) {
222 if (CpuMpData->CpuData[Index].ApicId == GetApicId ()) {
223 *ProcessorNumber = Index;
224 return EFI_SUCCESS;
225 }
226 }
227 return EFI_NOT_FOUND;
228 }
229
230 /*
231 Initialize CPU AP Data when AP is wakeup at the first time.
232
233 @param[in, out] CpuMpData Pointer to PEI CPU MP Data
234 @param[in] ProcessorNumber The handle number of processor
235 @param[in] BistData Processor BIST data
236
237 **/
238 VOID
239 InitializeApData (
240 IN OUT CPU_MP_DATA *CpuMpData,
241 IN UINTN ProcessorNumber,
242 IN UINT32 BistData
243 )
244 {
245 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;
246 CpuMpData->CpuData[ProcessorNumber].Health = BistData;
247 CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 0) ? TRUE : FALSE;
248 CpuMpData->CpuData[ProcessorNumber].ApicId = GetApicId ();
249 CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();
250 if (CpuMpData->CpuData[ProcessorNumber].InitialApicId >= 0xFF) {
251 //
252 // Set x2APIC mode if there are any logical processor reporting
253 // an Initial APIC ID of 255 or greater.
254 //
255 AcquireSpinLock(&CpuMpData->MpLock);
256 CpuMpData->X2ApicEnable = TRUE;
257 ReleaseSpinLock(&CpuMpData->MpLock);
258 }
259
260 InitializeSpinLock(&CpuMpData->CpuData[ProcessorNumber].ApLock);
261 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);
262 }
263
264 /**
265 This function will be called from AP reset code if BSP uses WakeUpAP.
266
267 @param[in] ExchangeInfo Pointer to the MP exchange info buffer
268 @param[in] NumApsExecuting Number of current executing AP
269 **/
270 VOID
271 EFIAPI
272 ApWakeupFunction (
273 IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,
274 IN UINTN NumApsExecuting
275 )
276 {
277 CPU_MP_DATA *CpuMpData;
278 UINTN ProcessorNumber;
279 EFI_AP_PROCEDURE Procedure;
280 VOID *Parameter;
281 UINT32 BistData;
282 volatile UINT32 *ApStartupSignalBuffer;
283
284 //
285 // AP finished assembly code and begin to execute C code
286 //
287 CpuMpData = ExchangeInfo->CpuMpData;
288
289 ProgramVirtualWireMode ();
290
291 while (TRUE) {
292 if (CpuMpData->InitFlag == ApInitConfig) {
293 //
294 // Add CPU number
295 //
296 InterlockedIncrement ((UINT32 *) &CpuMpData->CpuCount);
297 ProcessorNumber = NumApsExecuting;
298 //
299 // This is first time AP wakeup, get BIST information from AP stack
300 //
301 BistData = *(UINT32 *) (CpuMpData->Buffer + ProcessorNumber * CpuMpData->CpuApStackSize - sizeof (UINTN));
302 //
303 // Do some AP initialize sync
304 //
305 ApInitializeSync (CpuMpData);
306 //
307 // Sync BSP's Control registers to APs
308 //
309 RestoreVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters, FALSE);
310 InitializeApData (CpuMpData, ProcessorNumber, BistData);
311 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
312 } else {
313 //
314 // Execute AP function if AP is ready
315 //
316 GetProcessorNumber (CpuMpData, &ProcessorNumber);
317 //
318 // Clear AP start-up signal when AP waken up
319 //
320 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
321 InterlockedCompareExchange32 (
322 (UINT32 *) ApStartupSignalBuffer,
323 WAKEUP_AP_SIGNAL,
324 0
325 );
326 if (CpuMpData->ApLoopMode == ApInHltLoop) {
327 //
328 // Restore AP's volatile registers saved
329 //
330 RestoreVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE);
331 }
332
333 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateReady) {
334 Procedure = (EFI_AP_PROCEDURE)CpuMpData->CpuData[ProcessorNumber].ApFunction;
335 Parameter = (VOID *) CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument;
336 if (Procedure != NULL) {
337 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBusy);
338 //
339 // Invoke AP function here
340 //
341 Procedure (Parameter);
342 //
343 // Re-get the CPU APICID and Initial APICID
344 //
345 CpuMpData->CpuData[ProcessorNumber].ApicId = GetApicId ();
346 CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();
347 }
348 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinished);
349 }
350 }
351
352 //
353 // AP finished executing C code
354 //
355 InterlockedIncrement ((UINT32 *) &CpuMpData->FinishedCount);
356
357 //
358 // Place AP is specified loop mode
359 //
360 if (CpuMpData->ApLoopMode == ApInHltLoop) {
361 //
362 // Save AP volatile registers
363 //
364 SaveVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters);
365 //
366 // Place AP in HLT-loop
367 //
368 while (TRUE) {
369 DisableInterrupts ();
370 CpuSleep ();
371 CpuPause ();
372 }
373 }
374 while (TRUE) {
375 DisableInterrupts ();
376 if (CpuMpData->ApLoopMode == ApInMwaitLoop) {
377 //
378 // Place AP in MWAIT-loop
379 //
380 AsmMonitor ((UINTN) ApStartupSignalBuffer, 0, 0);
381 if (*ApStartupSignalBuffer != WAKEUP_AP_SIGNAL) {
382 //
383 // Check AP start-up signal again.
384 // If AP start-up signal is not set, place AP into
385 // the specified C-state
386 //
387 AsmMwait (CpuMpData->ApTargetCState << 4, 0);
388 }
389 } else if (CpuMpData->ApLoopMode == ApInRunLoop) {
390 //
391 // Place AP in Run-loop
392 //
393 CpuPause ();
394 } else {
395 ASSERT (FALSE);
396 }
397
398 //
399 // If AP start-up signal is written, AP is waken up
400 // otherwise place AP in loop again
401 //
402 if (*ApStartupSignalBuffer == WAKEUP_AP_SIGNAL) {
403 break;
404 }
405 }
406 }
407 }
408
409 /**
410 MP Initialize Library initialization.
411
412 This service will allocate AP reset vector and wakeup all APs to do APs
413 initialization.
414
415 This service must be invoked before all other MP Initialize Library
416 service are invoked.
417
418 @retval EFI_SUCCESS MP initialization succeeds.
419 @retval Others MP initialization fails.
420
421 **/
422 EFI_STATUS
423 EFIAPI
424 MpInitLibInitialize (
425 VOID
426 )
427 {
428 UINT32 MaxLogicalProcessorNumber;
429 UINT32 ApStackSize;
430 MP_ASSEMBLY_ADDRESS_MAP AddressMap;
431 UINTN BufferSize;
432 UINT32 MonitorFilterSize;
433 VOID *MpBuffer;
434 UINTN Buffer;
435 CPU_MP_DATA *CpuMpData;
436 UINT8 ApLoopMode;
437 UINT8 *MonitorBuffer;
438 UINTN Index;
439 UINTN ApResetVectorSize;
440 UINTN BackupBufferAddr;
441 MaxLogicalProcessorNumber = PcdGet32(PcdCpuMaxLogicalProcessorNumber);
442
443 AsmGetAddressMap (&AddressMap);
444 ApResetVectorSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);
445 ApStackSize = PcdGet32(PcdCpuApStackSize);
446 ApLoopMode = GetApLoopMode (&MonitorFilterSize);
447
448 BufferSize = ApStackSize * MaxLogicalProcessorNumber;
449 BufferSize += MonitorFilterSize * MaxLogicalProcessorNumber;
450 BufferSize += sizeof (CPU_MP_DATA);
451 BufferSize += ApResetVectorSize;
452 BufferSize += (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* MaxLogicalProcessorNumber;
453 MpBuffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));
454 ASSERT (MpBuffer != NULL);
455 ZeroMem (MpBuffer, BufferSize);
456 Buffer = (UINTN) MpBuffer;
457
458 MonitorBuffer = (UINT8 *) (Buffer + ApStackSize * MaxLogicalProcessorNumber);
459 BackupBufferAddr = (UINTN) MonitorBuffer + MonitorFilterSize * MaxLogicalProcessorNumber;
460 CpuMpData = (CPU_MP_DATA *) (BackupBufferAddr + ApResetVectorSize);
461 CpuMpData->Buffer = Buffer;
462 CpuMpData->CpuApStackSize = ApStackSize;
463 CpuMpData->BackupBuffer = BackupBufferAddr;
464 CpuMpData->BackupBufferSize = ApResetVectorSize;
465 CpuMpData->EndOfPeiFlag = FALSE;
466 CpuMpData->WakeupBuffer = (UINTN) -1;
467 CpuMpData->CpuCount = 1;
468 CpuMpData->BspNumber = 0;
469 CpuMpData->WaitEvent = NULL;
470 CpuMpData->CpuData = (CPU_AP_DATA *) (CpuMpData + 1);
471 CpuMpData->CpuInfoInHob = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);
472 InitializeSpinLock(&CpuMpData->MpLock);
473 //
474 // Save BSP's Control registers to APs
475 //
476 SaveVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters);
477 //
478 // Set BSP basic information
479 //
480 InitializeApData (CpuMpData, 0, 0);
481 //
482 // Save assembly code information
483 //
484 CopyMem (&CpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));
485 //
486 // Finally set AP loop mode
487 //
488 CpuMpData->ApLoopMode = ApLoopMode;
489 DEBUG ((DEBUG_INFO, "AP Loop Mode is %d\n", CpuMpData->ApLoopMode));
490 //
491 // Set up APs wakeup signal buffer
492 //
493 for (Index = 0; Index < MaxLogicalProcessorNumber; Index++) {
494 CpuMpData->CpuData[Index].StartupApSignal =
495 (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);
496 }
497 //
498 // Load Microcode on BSP
499 //
500 MicrocodeDetect (CpuMpData);
501 //
502 // Store BSP's MTRR setting
503 //
504 MtrrGetAllMtrrs (&CpuMpData->MtrrTable);
505
506
507 //
508 // Initialize global data for MP support
509 //
510 InitMpGlobalData (CpuMpData);
511
512 return EFI_SUCCESS;
513 }
514
515 /**
516 Gets detailed MP-related information on the requested processor at the
517 instant this call is made. This service may only be called from the BSP.
518
519 @param[in] ProcessorNumber The handle number of processor.
520 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
521 the requested processor is deposited.
522 @param[out] HealthData Return processor health data.
523
524 @retval EFI_SUCCESS Processor information was returned.
525 @retval EFI_DEVICE_ERROR The calling processor is an AP.
526 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
527 @retval EFI_NOT_FOUND The processor with the handle specified by
528 ProcessorNumber does not exist in the platform.
529 @retval EFI_NOT_READY MP Initialize Library is not initialized.
530
531 **/
532 EFI_STATUS
533 EFIAPI
534 MpInitLibGetProcessorInfo (
535 IN UINTN ProcessorNumber,
536 OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer,
537 OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL
538 )
539 {
540 return EFI_UNSUPPORTED;
541 }
542 /**
543 This return the handle number for the calling processor. This service may be
544 called from the BSP and APs.
545
546 @param[out] ProcessorNumber Pointer to the handle number of AP.
547 The range is from 0 to the total number of
548 logical processors minus 1. The total number of
549 logical processors can be retrieved by
550 MpInitLibGetNumberOfProcessors().
551
552 @retval EFI_SUCCESS The current processor handle number was returned
553 in ProcessorNumber.
554 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
555 @retval EFI_NOT_READY MP Initialize Library is not initialized.
556
557 **/
558 EFI_STATUS
559 EFIAPI
560 MpInitLibWhoAmI (
561 OUT UINTN *ProcessorNumber
562 )
563 {
564 return EFI_UNSUPPORTED;
565 }
566 /**
567 Retrieves the number of logical processor in the platform and the number of
568 those logical processors that are enabled on this boot. This service may only
569 be called from the BSP.
570
571 @param[out] NumberOfProcessors Pointer to the total number of logical
572 processors in the system, including the BSP
573 and disabled APs.
574 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
575 processors that exist in system, including
576 the BSP.
577
578 @retval EFI_SUCCESS The number of logical processors and enabled
579 logical processors was retrieved.
580 @retval EFI_DEVICE_ERROR The calling processor is an AP.
581 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors
582 is NULL.
583 @retval EFI_NOT_READY MP Initialize Library is not initialized.
584
585 **/
586 EFI_STATUS
587 EFIAPI
588 MpInitLibGetNumberOfProcessors (
589 OUT UINTN *NumberOfProcessors, OPTIONAL
590 OUT UINTN *NumberOfEnabledProcessors OPTIONAL
591 )
592 {
593 return EFI_UNSUPPORTED;
594 }
595 /**
596 Get pointer to CPU MP Data structure from GUIDed HOB.
597
598 @return The pointer to CPU MP Data structure.
599 **/
600 CPU_MP_DATA *
601 GetCpuMpDataFromGuidedHob (
602 VOID
603 )
604 {
605 EFI_HOB_GUID_TYPE *GuidHob;
606 VOID *DataInHob;
607 CPU_MP_DATA *CpuMpData;
608
609 CpuMpData = NULL;
610 GuidHob = GetFirstGuidHob (&mCpuInitMpLibHobGuid);
611 if (GuidHob != NULL) {
612 DataInHob = GET_GUID_HOB_DATA (GuidHob);
613 CpuMpData = (CPU_MP_DATA *) (*(UINTN *) DataInHob);
614 }
615 return CpuMpData;
616 }