]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
6ecbed39ec4c4a54e5e73f9dd4a7b13f11201837
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / PeiMpLib.c
1 /** @file
2 MP initialize support functions for PEI phase.
3
4 Copyright (c) 2016 - 2020, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "MpLib.h"
10 #include <Library/PeiServicesLib.h>
11 #include <Guid/S3SmmInitDone.h>
12
13 /**
14 S3 SMM Init Done notification function.
15
16 @param PeiServices Indirect reference to the PEI Services Table.
17 @param NotifyDesc Address of the notification descriptor data structure.
18 @param InvokePpi Address of the PPI that was invoked.
19
20 @retval EFI_SUCCESS The function completes successfully.
21
22 **/
23 EFI_STATUS
24 EFIAPI
25 NotifyOnS3SmmInitDonePpi (
26 IN EFI_PEI_SERVICES **PeiServices,
27 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
28 IN VOID *InvokePpi
29 );
30
31
32 //
33 // Global function
34 //
35 EFI_PEI_NOTIFY_DESCRIPTOR mS3SmmInitDoneNotifyDesc = {
36 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
37 &gEdkiiS3SmmInitDoneGuid,
38 NotifyOnS3SmmInitDonePpi
39 };
40
41 /**
42 S3 SMM Init Done notification function.
43
44 @param PeiServices Indirect reference to the PEI Services Table.
45 @param NotifyDesc Address of the notification descriptor data structure.
46 @param InvokePpi Address of the PPI that was invoked.
47
48 @retval EFI_SUCCESS The function completes successfully.
49
50 **/
51 EFI_STATUS
52 EFIAPI
53 NotifyOnS3SmmInitDonePpi (
54 IN EFI_PEI_SERVICES **PeiServices,
55 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
56 IN VOID *InvokePpi
57 )
58 {
59 CPU_MP_DATA *CpuMpData;
60
61 CpuMpData = GetCpuMpData ();
62
63 //
64 // PiSmmCpuDxeSmm driver hardcode change the loop mode to HLT mode.
65 // So in this notify function, code need to check the current loop
66 // mode, if it is not HLT mode, code need to change loop mode back
67 // to the original mode.
68 //
69 if (CpuMpData->ApLoopMode != ApInHltLoop) {
70 CpuMpData->WakeUpByInitSipiSipi = TRUE;
71 }
72
73 return EFI_SUCCESS;
74 }
75
76
77 /**
78 Enable Debug Agent to support source debugging on AP function.
79
80 **/
81 VOID
82 EnableDebugAgent (
83 VOID
84 )
85 {
86 }
87
88 /**
89 Get pointer to CPU MP Data structure.
90 For BSP, the pointer is retrieved from HOB.
91 For AP, the structure is just after IDT.
92
93 @return The pointer to CPU MP Data structure.
94 **/
95 CPU_MP_DATA *
96 GetCpuMpData (
97 VOID
98 )
99 {
100 CPU_MP_DATA *CpuMpData;
101 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
102 IA32_DESCRIPTOR Idtr;
103
104 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
105 if (ApicBaseMsr.Bits.BSP == 1) {
106 CpuMpData = GetCpuMpDataFromGuidedHob ();
107 ASSERT (CpuMpData != NULL);
108 } else {
109 AsmReadIdtr (&Idtr);
110 CpuMpData = (CPU_MP_DATA *) (Idtr.Base + Idtr.Limit + 1);
111 }
112 return CpuMpData;
113 }
114
115 /**
116 Save the pointer to CPU MP Data structure.
117
118 @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.
119 **/
120 VOID
121 SaveCpuMpData (
122 IN CPU_MP_DATA *CpuMpData
123 )
124 {
125 UINT64 Data64;
126 //
127 // Build location of CPU MP DATA buffer in HOB
128 //
129 Data64 = (UINT64) (UINTN) CpuMpData;
130 BuildGuidDataHob (
131 &mCpuInitMpLibHobGuid,
132 (VOID *) &Data64,
133 sizeof (UINT64)
134 );
135 }
136
137 /**
138 Check if AP wakeup buffer is overlapped with existing allocated buffer.
139
140 @param[in] WakeupBufferStart AP wakeup buffer start address.
141 @param[in] WakeupBufferEnd AP wakeup buffer end address.
142
143 @retval TRUE There is overlap.
144 @retval FALSE There is no overlap.
145 **/
146 BOOLEAN
147 CheckOverlapWithAllocatedBuffer (
148 IN UINT64 WakeupBufferStart,
149 IN UINT64 WakeupBufferEnd
150 )
151 {
152 EFI_PEI_HOB_POINTERS Hob;
153 EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
154 BOOLEAN Overlapped;
155 UINT64 MemoryStart;
156 UINT64 MemoryEnd;
157
158 Overlapped = FALSE;
159 //
160 // Get the HOB list for processing
161 //
162 Hob.Raw = GetHobList ();
163 //
164 // Collect memory ranges
165 //
166 while (!END_OF_HOB_LIST (Hob)) {
167 if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
168 MemoryHob = Hob.MemoryAllocation;
169 MemoryStart = MemoryHob->AllocDescriptor.MemoryBaseAddress;
170 MemoryEnd = MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength;
171 if (!((WakeupBufferStart >= MemoryEnd) || (WakeupBufferEnd <= MemoryStart))) {
172 Overlapped = TRUE;
173 break;
174 }
175 }
176 Hob.Raw = GET_NEXT_HOB (Hob);
177 }
178 return Overlapped;
179 }
180
181 /**
182 Get available system memory below 1MB by specified size.
183
184 @param[in] WakeupBufferSize Wakeup buffer size required
185
186 @retval other Return wakeup buffer address below 1MB.
187 @retval -1 Cannot find free memory below 1MB.
188 **/
189 UINTN
190 GetWakeupBuffer (
191 IN UINTN WakeupBufferSize
192 )
193 {
194 EFI_PEI_HOB_POINTERS Hob;
195 UINT64 WakeupBufferStart;
196 UINT64 WakeupBufferEnd;
197
198 WakeupBufferSize = (WakeupBufferSize + SIZE_4KB - 1) & ~(SIZE_4KB - 1);
199
200 //
201 // Get the HOB list for processing
202 //
203 Hob.Raw = GetHobList ();
204
205 //
206 // Collect memory ranges
207 //
208 while (!END_OF_HOB_LIST (Hob)) {
209 if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
210 if ((Hob.ResourceDescriptor->PhysicalStart < BASE_1MB) &&
211 (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&
212 ((Hob.ResourceDescriptor->ResourceAttribute &
213 (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |
214 EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |
215 EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED
216 )) == 0)
217 ) {
218 //
219 // Need memory under 1MB to be collected here
220 //
221 WakeupBufferEnd = Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength;
222 if (WakeupBufferEnd > BASE_1MB) {
223 //
224 // Wakeup buffer should be under 1MB
225 //
226 WakeupBufferEnd = BASE_1MB;
227 }
228 while (WakeupBufferEnd > WakeupBufferSize) {
229 //
230 // Wakeup buffer should be aligned on 4KB
231 //
232 WakeupBufferStart = (WakeupBufferEnd - WakeupBufferSize) & ~(SIZE_4KB - 1);
233 if (WakeupBufferStart < Hob.ResourceDescriptor->PhysicalStart) {
234 break;
235 }
236 if (CheckOverlapWithAllocatedBuffer (WakeupBufferStart, WakeupBufferEnd)) {
237 //
238 // If this range is overlapped with existing allocated buffer, skip it
239 // and find the next range
240 //
241 WakeupBufferEnd -= WakeupBufferSize;
242 continue;
243 }
244 DEBUG ((DEBUG_INFO, "WakeupBufferStart = %x, WakeupBufferSize = %x\n",
245 WakeupBufferStart, WakeupBufferSize));
246 return (UINTN)WakeupBufferStart;
247 }
248 }
249 }
250 //
251 // Find the next HOB
252 //
253 Hob.Raw = GET_NEXT_HOB (Hob);
254 }
255
256 return (UINTN) -1;
257 }
258
259 /**
260 Get available EfiBootServicesCode memory below 4GB by specified size.
261
262 This buffer is required to safely transfer AP from real address mode to
263 protected mode or long mode, due to the fact that the buffer returned by
264 GetWakeupBuffer() may be marked as non-executable.
265
266 @param[in] BufferSize Wakeup transition buffer size.
267
268 @retval other Return wakeup transition buffer address below 4GB.
269 @retval 0 Cannot find free memory below 4GB.
270 **/
271 UINTN
272 GetModeTransitionBuffer (
273 IN UINTN BufferSize
274 )
275 {
276 //
277 // PEI phase doesn't need to do such transition. So simply return 0.
278 //
279 return 0;
280 }
281
282 /**
283 Checks APs status and updates APs status if needed.
284
285 **/
286 VOID
287 CheckAndUpdateApsStatus (
288 VOID
289 )
290 {
291 }
292
293 /**
294 Build the microcode patch HOB that contains the base address and size of the
295 microcode patch stored in the memory.
296
297 @param[in] CpuMpData Pointer to the CPU_MP_DATA structure.
298
299 **/
300 VOID
301 BuildMicrocodeCacheHob (
302 IN CPU_MP_DATA *CpuMpData
303 )
304 {
305 EDKII_MICROCODE_PATCH_HOB *MicrocodeHob;
306 UINTN HobDataLength;
307 UINT32 Index;
308
309 HobDataLength = sizeof (EDKII_MICROCODE_PATCH_HOB) +
310 sizeof (UINT64) * CpuMpData->CpuCount;
311
312 MicrocodeHob = AllocatePool (HobDataLength);
313 if (MicrocodeHob == NULL) {
314 ASSERT (FALSE);
315 return;
316 }
317
318 //
319 // Store the information of the memory region that holds the microcode patches.
320 //
321 MicrocodeHob->MicrocodePatchAddress = CpuMpData->MicrocodePatchAddress;
322 MicrocodeHob->MicrocodePatchRegionSize = CpuMpData->MicrocodePatchRegionSize;
323
324 //
325 // Store the detected microcode patch for each processor as well.
326 //
327 MicrocodeHob->ProcessorCount = CpuMpData->CpuCount;
328 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
329 if (CpuMpData->CpuData[Index].MicrocodeEntryAddr != 0) {
330 MicrocodeHob->ProcessorSpecificPatchOffset[Index] =
331 CpuMpData->CpuData[Index].MicrocodeEntryAddr - CpuMpData->MicrocodePatchAddress;
332 } else {
333 MicrocodeHob->ProcessorSpecificPatchOffset[Index] = MAX_UINT64;
334 }
335 }
336
337 BuildGuidDataHob (
338 &gEdkiiMicrocodePatchHobGuid,
339 MicrocodeHob,
340 HobDataLength
341 );
342
343 return;
344 }
345
346 /**
347 Initialize global data for MP support.
348
349 @param[in] CpuMpData The pointer to CPU MP Data structure.
350 **/
351 VOID
352 InitMpGlobalData (
353 IN CPU_MP_DATA *CpuMpData
354 )
355 {
356 EFI_STATUS Status;
357
358 BuildMicrocodeCacheHob (CpuMpData);
359 SaveCpuMpData (CpuMpData);
360
361 ///
362 /// Install Notify
363 ///
364 Status = PeiServicesNotifyPpi (&mS3SmmInitDoneNotifyDesc);
365 ASSERT_EFI_ERROR (Status);
366 }
367
368 /**
369 This service executes a caller provided function on all enabled APs.
370
371 @param[in] Procedure A pointer to the function to be run on
372 enabled APs of the system. See type
373 EFI_AP_PROCEDURE.
374 @param[in] SingleThread If TRUE, then all the enabled APs execute
375 the function specified by Procedure one by
376 one, in ascending order of processor handle
377 number. If FALSE, then all the enabled APs
378 execute the function specified by Procedure
379 simultaneously.
380 @param[in] WaitEvent The event created by the caller with CreateEvent()
381 service. If it is NULL, then execute in
382 blocking mode. BSP waits until all APs finish
383 or TimeoutInMicroSeconds expires. If it's
384 not NULL, then execute in non-blocking mode.
385 BSP requests the function specified by
386 Procedure to be started on all the enabled
387 APs, and go on executing immediately. If
388 all return from Procedure, or TimeoutInMicroSeconds
389 expires, this event is signaled. The BSP
390 can use the CheckEvent() or WaitForEvent()
391 services to check the state of event. Type
392 EFI_EVENT is defined in CreateEvent() in
393 the Unified Extensible Firmware Interface
394 Specification.
395 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
396 APs to return from Procedure, either for
397 blocking or non-blocking mode. Zero means
398 infinity. If the timeout expires before
399 all APs return from Procedure, then Procedure
400 on the failed APs is terminated. All enabled
401 APs are available for next function assigned
402 by MpInitLibStartupAllAPs() or
403 MPInitLibStartupThisAP().
404 If the timeout expires in blocking mode,
405 BSP returns EFI_TIMEOUT. If the timeout
406 expires in non-blocking mode, WaitEvent
407 is signaled with SignalEvent().
408 @param[in] ProcedureArgument The parameter passed into Procedure for
409 all APs.
410 @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,
411 if all APs finish successfully, then its
412 content is set to NULL. If not all APs
413 finish before timeout expires, then its
414 content is set to address of the buffer
415 holding handle numbers of the failed APs.
416 The buffer is allocated by MP Initialization
417 library, and it's the caller's responsibility to
418 free the buffer with FreePool() service.
419 In blocking mode, it is ready for consumption
420 when the call returns. In non-blocking mode,
421 it is ready when WaitEvent is signaled. The
422 list of failed CPU is terminated by
423 END_OF_CPU_LIST.
424
425 @retval EFI_SUCCESS In blocking mode, all APs have finished before
426 the timeout expired.
427 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
428 to all enabled APs.
429 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
430 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
431 signaled.
432 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
433 supported.
434 @retval EFI_DEVICE_ERROR Caller processor is AP.
435 @retval EFI_NOT_STARTED No enabled APs exist in the system.
436 @retval EFI_NOT_READY Any enabled APs are busy.
437 @retval EFI_NOT_READY MP Initialize Library is not initialized.
438 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
439 all enabled APs have finished.
440 @retval EFI_INVALID_PARAMETER Procedure is NULL.
441
442 **/
443 EFI_STATUS
444 EFIAPI
445 MpInitLibStartupAllAPs (
446 IN EFI_AP_PROCEDURE Procedure,
447 IN BOOLEAN SingleThread,
448 IN EFI_EVENT WaitEvent OPTIONAL,
449 IN UINTN TimeoutInMicroseconds,
450 IN VOID *ProcedureArgument OPTIONAL,
451 OUT UINTN **FailedCpuList OPTIONAL
452 )
453 {
454 if (WaitEvent != NULL) {
455 return EFI_UNSUPPORTED;
456 }
457
458 return StartupAllCPUsWorker (
459 Procedure,
460 SingleThread,
461 TRUE,
462 NULL,
463 TimeoutInMicroseconds,
464 ProcedureArgument,
465 FailedCpuList
466 );
467 }
468
469 /**
470 This service lets the caller get one enabled AP to execute a caller-provided
471 function.
472
473 @param[in] Procedure A pointer to the function to be run on the
474 designated AP of the system. See type
475 EFI_AP_PROCEDURE.
476 @param[in] ProcessorNumber The handle number of the AP. The range is
477 from 0 to the total number of logical
478 processors minus 1. The total number of
479 logical processors can be retrieved by
480 MpInitLibGetNumberOfProcessors().
481 @param[in] WaitEvent The event created by the caller with CreateEvent()
482 service. If it is NULL, then execute in
483 blocking mode. BSP waits until this AP finish
484 or TimeoutInMicroSeconds expires. If it's
485 not NULL, then execute in non-blocking mode.
486 BSP requests the function specified by
487 Procedure to be started on this AP,
488 and go on executing immediately. If this AP
489 return from Procedure or TimeoutInMicroSeconds
490 expires, this event is signaled. The BSP
491 can use the CheckEvent() or WaitForEvent()
492 services to check the state of event. Type
493 EFI_EVENT is defined in CreateEvent() in
494 the Unified Extensible Firmware Interface
495 Specification.
496 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
497 this AP to finish this Procedure, either for
498 blocking or non-blocking mode. Zero means
499 infinity. If the timeout expires before
500 this AP returns from Procedure, then Procedure
501 on the AP is terminated. The
502 AP is available for next function assigned
503 by MpInitLibStartupAllAPs() or
504 MpInitLibStartupThisAP().
505 If the timeout expires in blocking mode,
506 BSP returns EFI_TIMEOUT. If the timeout
507 expires in non-blocking mode, WaitEvent
508 is signaled with SignalEvent().
509 @param[in] ProcedureArgument The parameter passed into Procedure on the
510 specified AP.
511 @param[out] Finished If NULL, this parameter is ignored. In
512 blocking mode, this parameter is ignored.
513 In non-blocking mode, if AP returns from
514 Procedure before the timeout expires, its
515 content is set to TRUE. Otherwise, the
516 value is set to FALSE. The caller can
517 determine if the AP returned from Procedure
518 by evaluating this value.
519
520 @retval EFI_SUCCESS In blocking mode, specified AP finished before
521 the timeout expires.
522 @retval EFI_SUCCESS In non-blocking mode, the function has been
523 dispatched to specified AP.
524 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
525 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
526 signaled.
527 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
528 supported.
529 @retval EFI_DEVICE_ERROR The calling processor is an AP.
530 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
531 the specified AP has finished.
532 @retval EFI_NOT_READY The specified AP is busy.
533 @retval EFI_NOT_READY MP Initialize Library is not initialized.
534 @retval EFI_NOT_FOUND The processor with the handle specified by
535 ProcessorNumber does not exist.
536 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
537 @retval EFI_INVALID_PARAMETER Procedure is NULL.
538
539 **/
540 EFI_STATUS
541 EFIAPI
542 MpInitLibStartupThisAP (
543 IN EFI_AP_PROCEDURE Procedure,
544 IN UINTN ProcessorNumber,
545 IN EFI_EVENT WaitEvent OPTIONAL,
546 IN UINTN TimeoutInMicroseconds,
547 IN VOID *ProcedureArgument OPTIONAL,
548 OUT BOOLEAN *Finished OPTIONAL
549 )
550 {
551 if (WaitEvent != NULL) {
552 return EFI_UNSUPPORTED;
553 }
554
555 return StartupThisAPWorker (
556 Procedure,
557 ProcessorNumber,
558 NULL,
559 TimeoutInMicroseconds,
560 ProcedureArgument,
561 Finished
562 );
563 }
564
565 /**
566 This service switches the requested AP to be the BSP from that point onward.
567 This service changes the BSP for all purposes. This call can only be performed
568 by the current BSP.
569
570 @param[in] ProcessorNumber The handle number of AP that is to become the new
571 BSP. The range is from 0 to the total number of
572 logical processors minus 1. The total number of
573 logical processors can be retrieved by
574 MpInitLibGetNumberOfProcessors().
575 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
576 enabled AP. Otherwise, it will be disabled.
577
578 @retval EFI_SUCCESS BSP successfully switched.
579 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
580 this service returning.
581 @retval EFI_UNSUPPORTED Switching the BSP is not supported.
582 @retval EFI_DEVICE_ERROR The calling processor is an AP.
583 @retval EFI_NOT_FOUND The processor with the handle specified by
584 ProcessorNumber does not exist.
585 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
586 a disabled AP.
587 @retval EFI_NOT_READY The specified AP is busy.
588 @retval EFI_NOT_READY MP Initialize Library is not initialized.
589
590 **/
591 EFI_STATUS
592 EFIAPI
593 MpInitLibSwitchBSP (
594 IN UINTN ProcessorNumber,
595 IN BOOLEAN EnableOldBSP
596 )
597 {
598 return SwitchBSPWorker (ProcessorNumber, EnableOldBSP);
599 }
600
601 /**
602 This service lets the caller enable or disable an AP from this point onward.
603 This service may only be called from the BSP.
604
605 @param[in] ProcessorNumber The handle number of AP.
606 The range is from 0 to the total number of
607 logical processors minus 1. The total number of
608 logical processors can be retrieved by
609 MpInitLibGetNumberOfProcessors().
610 @param[in] EnableAP Specifies the new state for the processor for
611 enabled, FALSE for disabled.
612 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
613 the new health status of the AP. This flag
614 corresponds to StatusFlag defined in
615 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
616 the PROCESSOR_HEALTH_STATUS_BIT is used. All other
617 bits are ignored. If it is NULL, this parameter
618 is ignored.
619
620 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
621 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
622 prior to this service returning.
623 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
624 @retval EFI_DEVICE_ERROR The calling processor is an AP.
625 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
626 does not exist.
627 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
628 @retval EFI_NOT_READY MP Initialize Library is not initialized.
629
630 **/
631 EFI_STATUS
632 EFIAPI
633 MpInitLibEnableDisableAP (
634 IN UINTN ProcessorNumber,
635 IN BOOLEAN EnableAP,
636 IN UINT32 *HealthFlag OPTIONAL
637 )
638 {
639 return EnableDisableApWorker (ProcessorNumber, EnableAP, HealthFlag);
640 }
641
642