]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
UefiCpuPkg: Replace BSD License with BSD+Patent License
[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 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 Initialize global data for MP support.
295
296 @param[in] CpuMpData The pointer to CPU MP Data structure.
297 **/
298 VOID
299 InitMpGlobalData (
300 IN CPU_MP_DATA *CpuMpData
301 )
302 {
303 EFI_STATUS Status;
304
305 SaveCpuMpData (CpuMpData);
306
307 ///
308 /// Install Notify
309 ///
310 Status = PeiServicesNotifyPpi (&mS3SmmInitDoneNotifyDesc);
311 ASSERT_EFI_ERROR (Status);
312 }
313
314 /**
315 This service executes a caller provided function on all enabled APs.
316
317 @param[in] Procedure A pointer to the function to be run on
318 enabled APs of the system. See type
319 EFI_AP_PROCEDURE.
320 @param[in] SingleThread If TRUE, then all the enabled APs execute
321 the function specified by Procedure one by
322 one, in ascending order of processor handle
323 number. If FALSE, then all the enabled APs
324 execute the function specified by Procedure
325 simultaneously.
326 @param[in] WaitEvent The event created by the caller with CreateEvent()
327 service. If it is NULL, then execute in
328 blocking mode. BSP waits until all APs finish
329 or TimeoutInMicroSeconds expires. If it's
330 not NULL, then execute in non-blocking mode.
331 BSP requests the function specified by
332 Procedure to be started on all the enabled
333 APs, and go on executing immediately. If
334 all return from Procedure, or TimeoutInMicroSeconds
335 expires, this event is signaled. The BSP
336 can use the CheckEvent() or WaitForEvent()
337 services to check the state of event. Type
338 EFI_EVENT is defined in CreateEvent() in
339 the Unified Extensible Firmware Interface
340 Specification.
341 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
342 APs to return from Procedure, either for
343 blocking or non-blocking mode. Zero means
344 infinity. If the timeout expires before
345 all APs return from Procedure, then Procedure
346 on the failed APs is terminated. All enabled
347 APs are available for next function assigned
348 by MpInitLibStartupAllAPs() or
349 MPInitLibStartupThisAP().
350 If the timeout expires in blocking mode,
351 BSP returns EFI_TIMEOUT. If the timeout
352 expires in non-blocking mode, WaitEvent
353 is signaled with SignalEvent().
354 @param[in] ProcedureArgument The parameter passed into Procedure for
355 all APs.
356 @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,
357 if all APs finish successfully, then its
358 content is set to NULL. If not all APs
359 finish before timeout expires, then its
360 content is set to address of the buffer
361 holding handle numbers of the failed APs.
362 The buffer is allocated by MP Initialization
363 library, and it's the caller's responsibility to
364 free the buffer with FreePool() service.
365 In blocking mode, it is ready for consumption
366 when the call returns. In non-blocking mode,
367 it is ready when WaitEvent is signaled. The
368 list of failed CPU is terminated by
369 END_OF_CPU_LIST.
370
371 @retval EFI_SUCCESS In blocking mode, all APs have finished before
372 the timeout expired.
373 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
374 to all enabled APs.
375 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
376 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
377 signaled.
378 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
379 supported.
380 @retval EFI_DEVICE_ERROR Caller processor is AP.
381 @retval EFI_NOT_STARTED No enabled APs exist in the system.
382 @retval EFI_NOT_READY Any enabled APs are busy.
383 @retval EFI_NOT_READY MP Initialize Library is not initialized.
384 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
385 all enabled APs have finished.
386 @retval EFI_INVALID_PARAMETER Procedure is NULL.
387
388 **/
389 EFI_STATUS
390 EFIAPI
391 MpInitLibStartupAllAPs (
392 IN EFI_AP_PROCEDURE Procedure,
393 IN BOOLEAN SingleThread,
394 IN EFI_EVENT WaitEvent OPTIONAL,
395 IN UINTN TimeoutInMicroseconds,
396 IN VOID *ProcedureArgument OPTIONAL,
397 OUT UINTN **FailedCpuList OPTIONAL
398 )
399 {
400 if (WaitEvent != NULL) {
401 return EFI_UNSUPPORTED;
402 }
403
404 return StartupAllAPsWorker (
405 Procedure,
406 SingleThread,
407 NULL,
408 TimeoutInMicroseconds,
409 ProcedureArgument,
410 FailedCpuList
411 );
412 }
413
414 /**
415 This service lets the caller get one enabled AP to execute a caller-provided
416 function.
417
418 @param[in] Procedure A pointer to the function to be run on the
419 designated AP of the system. See type
420 EFI_AP_PROCEDURE.
421 @param[in] ProcessorNumber The handle number of the AP. The range is
422 from 0 to the total number of logical
423 processors minus 1. The total number of
424 logical processors can be retrieved by
425 MpInitLibGetNumberOfProcessors().
426 @param[in] WaitEvent The event created by the caller with CreateEvent()
427 service. If it is NULL, then execute in
428 blocking mode. BSP waits until this AP finish
429 or TimeoutInMicroSeconds expires. If it's
430 not NULL, then execute in non-blocking mode.
431 BSP requests the function specified by
432 Procedure to be started on this AP,
433 and go on executing immediately. If this AP
434 return from Procedure or TimeoutInMicroSeconds
435 expires, this event is signaled. The BSP
436 can use the CheckEvent() or WaitForEvent()
437 services to check the state of event. Type
438 EFI_EVENT is defined in CreateEvent() in
439 the Unified Extensible Firmware Interface
440 Specification.
441 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
442 this AP to finish this Procedure, either for
443 blocking or non-blocking mode. Zero means
444 infinity. If the timeout expires before
445 this AP returns from Procedure, then Procedure
446 on the AP is terminated. The
447 AP is available for next function assigned
448 by MpInitLibStartupAllAPs() or
449 MpInitLibStartupThisAP().
450 If the timeout expires in blocking mode,
451 BSP returns EFI_TIMEOUT. If the timeout
452 expires in non-blocking mode, WaitEvent
453 is signaled with SignalEvent().
454 @param[in] ProcedureArgument The parameter passed into Procedure on the
455 specified AP.
456 @param[out] Finished If NULL, this parameter is ignored. In
457 blocking mode, this parameter is ignored.
458 In non-blocking mode, if AP returns from
459 Procedure before the timeout expires, its
460 content is set to TRUE. Otherwise, the
461 value is set to FALSE. The caller can
462 determine if the AP returned from Procedure
463 by evaluating this value.
464
465 @retval EFI_SUCCESS In blocking mode, specified AP finished before
466 the timeout expires.
467 @retval EFI_SUCCESS In non-blocking mode, the function has been
468 dispatched to specified AP.
469 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
470 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
471 signaled.
472 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
473 supported.
474 @retval EFI_DEVICE_ERROR The calling processor is an AP.
475 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
476 the specified AP has finished.
477 @retval EFI_NOT_READY The specified AP is busy.
478 @retval EFI_NOT_READY MP Initialize Library is not initialized.
479 @retval EFI_NOT_FOUND The processor with the handle specified by
480 ProcessorNumber does not exist.
481 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
482 @retval EFI_INVALID_PARAMETER Procedure is NULL.
483
484 **/
485 EFI_STATUS
486 EFIAPI
487 MpInitLibStartupThisAP (
488 IN EFI_AP_PROCEDURE Procedure,
489 IN UINTN ProcessorNumber,
490 IN EFI_EVENT WaitEvent OPTIONAL,
491 IN UINTN TimeoutInMicroseconds,
492 IN VOID *ProcedureArgument OPTIONAL,
493 OUT BOOLEAN *Finished OPTIONAL
494 )
495 {
496 if (WaitEvent != NULL) {
497 return EFI_UNSUPPORTED;
498 }
499
500 return StartupThisAPWorker (
501 Procedure,
502 ProcessorNumber,
503 NULL,
504 TimeoutInMicroseconds,
505 ProcedureArgument,
506 Finished
507 );
508 }
509
510 /**
511 This service switches the requested AP to be the BSP from that point onward.
512 This service changes the BSP for all purposes. This call can only be performed
513 by the current BSP.
514
515 @param[in] ProcessorNumber The handle number of AP that is to become the new
516 BSP. The range is from 0 to the total number of
517 logical processors minus 1. The total number of
518 logical processors can be retrieved by
519 MpInitLibGetNumberOfProcessors().
520 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
521 enabled AP. Otherwise, it will be disabled.
522
523 @retval EFI_SUCCESS BSP successfully switched.
524 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
525 this service returning.
526 @retval EFI_UNSUPPORTED Switching the BSP is not supported.
527 @retval EFI_DEVICE_ERROR The calling processor is an AP.
528 @retval EFI_NOT_FOUND The processor with the handle specified by
529 ProcessorNumber does not exist.
530 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
531 a disabled AP.
532 @retval EFI_NOT_READY The specified AP is busy.
533 @retval EFI_NOT_READY MP Initialize Library is not initialized.
534
535 **/
536 EFI_STATUS
537 EFIAPI
538 MpInitLibSwitchBSP (
539 IN UINTN ProcessorNumber,
540 IN BOOLEAN EnableOldBSP
541 )
542 {
543 return SwitchBSPWorker (ProcessorNumber, EnableOldBSP);
544 }
545
546 /**
547 This service lets the caller enable or disable an AP from this point onward.
548 This service may only be called from the BSP.
549
550 @param[in] ProcessorNumber The handle number of AP.
551 The range is from 0 to the total number of
552 logical processors minus 1. The total number of
553 logical processors can be retrieved by
554 MpInitLibGetNumberOfProcessors().
555 @param[in] EnableAP Specifies the new state for the processor for
556 enabled, FALSE for disabled.
557 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
558 the new health status of the AP. This flag
559 corresponds to StatusFlag defined in
560 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
561 the PROCESSOR_HEALTH_STATUS_BIT is used. All other
562 bits are ignored. If it is NULL, this parameter
563 is ignored.
564
565 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
566 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
567 prior to this service returning.
568 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
569 @retval EFI_DEVICE_ERROR The calling processor is an AP.
570 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
571 does not exist.
572 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
573 @retval EFI_NOT_READY MP Initialize Library is not initialized.
574
575 **/
576 EFI_STATUS
577 EFIAPI
578 MpInitLibEnableDisableAP (
579 IN UINTN ProcessorNumber,
580 IN BOOLEAN EnableAP,
581 IN UINT32 *HealthFlag OPTIONAL
582 )
583 {
584 return EnableDisableApWorker (ProcessorNumber, EnableAP, HealthFlag);
585 }
586
587