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