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