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