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