1 | /** @file
|
---|
2 | MP initialize support functions for PEI phase.
|
---|
3 |
|
---|
4 | Copyright (c) 2016 - 2020, 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 | #include <Ppi/ShadowMicrocode.h>
|
---|
13 |
|
---|
14 | STATIC UINT64 mSevEsPeiWakeupBuffer = BASE_1MB;
|
---|
15 |
|
---|
16 | /**
|
---|
17 | S3 SMM Init Done notification function.
|
---|
18 |
|
---|
19 | @param PeiServices Indirect reference to the PEI Services Table.
|
---|
20 | @param NotifyDesc Address of the notification descriptor data structure.
|
---|
21 | @param InvokePpi Address of the PPI that was invoked.
|
---|
22 |
|
---|
23 | @retval EFI_SUCCESS The function completes successfully.
|
---|
24 |
|
---|
25 | **/
|
---|
26 | EFI_STATUS
|
---|
27 | EFIAPI
|
---|
28 | NotifyOnS3SmmInitDonePpi (
|
---|
29 | IN EFI_PEI_SERVICES **PeiServices,
|
---|
30 | IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
|
---|
31 | IN VOID *InvokePpi
|
---|
32 | );
|
---|
33 |
|
---|
34 | //
|
---|
35 | // Global function
|
---|
36 | //
|
---|
37 | EFI_PEI_NOTIFY_DESCRIPTOR mS3SmmInitDoneNotifyDesc = {
|
---|
38 | EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
|
---|
39 | &gEdkiiS3SmmInitDoneGuid,
|
---|
40 | NotifyOnS3SmmInitDonePpi
|
---|
41 | };
|
---|
42 |
|
---|
43 | /**
|
---|
44 | S3 SMM Init Done notification function.
|
---|
45 |
|
---|
46 | @param PeiServices Indirect reference to the PEI Services Table.
|
---|
47 | @param NotifyDesc Address of the notification descriptor data structure.
|
---|
48 | @param InvokePpi Address of the PPI that was invoked.
|
---|
49 |
|
---|
50 | @retval EFI_SUCCESS The function completes successfully.
|
---|
51 |
|
---|
52 | **/
|
---|
53 | EFI_STATUS
|
---|
54 | EFIAPI
|
---|
55 | NotifyOnS3SmmInitDonePpi (
|
---|
56 | IN EFI_PEI_SERVICES **PeiServices,
|
---|
57 | IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
|
---|
58 | IN VOID *InvokePpi
|
---|
59 | )
|
---|
60 | {
|
---|
61 | CPU_MP_DATA *CpuMpData;
|
---|
62 |
|
---|
63 | CpuMpData = GetCpuMpData ();
|
---|
64 |
|
---|
65 | //
|
---|
66 | // PiSmmCpuDxeSmm driver hardcode change the loop mode to HLT mode.
|
---|
67 | // So in this notify function, code need to check the current loop
|
---|
68 | // mode, if it is not HLT mode, code need to change loop mode back
|
---|
69 | // to the original mode.
|
---|
70 | //
|
---|
71 | if (CpuMpData->ApLoopMode != ApInHltLoop) {
|
---|
72 | CpuMpData->WakeUpByInitSipiSipi = TRUE;
|
---|
73 | }
|
---|
74 |
|
---|
75 | return EFI_SUCCESS;
|
---|
76 | }
|
---|
77 |
|
---|
78 | /**
|
---|
79 | Enable Debug Agent to support source debugging on AP function.
|
---|
80 |
|
---|
81 | **/
|
---|
82 | VOID
|
---|
83 | EnableDebugAgent (
|
---|
84 | VOID
|
---|
85 | )
|
---|
86 | {
|
---|
87 | }
|
---|
88 |
|
---|
89 | /**
|
---|
90 | Get pointer to CPU MP Data structure.
|
---|
91 | For BSP, the pointer is retrieved from HOB.
|
---|
92 | For AP, the structure is stored in the top of each AP's stack.
|
---|
93 |
|
---|
94 | @return The pointer to CPU MP Data structure.
|
---|
95 | **/
|
---|
96 | CPU_MP_DATA *
|
---|
97 | GetCpuMpData (
|
---|
98 | VOID
|
---|
99 | )
|
---|
100 | {
|
---|
101 | CPU_MP_DATA *CpuMpData;
|
---|
102 | MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
|
---|
103 | UINTN ApTopOfStack;
|
---|
104 | AP_STACK_DATA *ApStackData;
|
---|
105 |
|
---|
106 | ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
|
---|
107 | if (ApicBaseMsr.Bits.BSP == 1) {
|
---|
108 | CpuMpData = GetCpuMpDataFromGuidedHob ();
|
---|
109 | ASSERT (CpuMpData != NULL);
|
---|
110 | } else {
|
---|
111 | ApTopOfStack = ALIGN_VALUE ((UINTN)&ApTopOfStack, (UINTN)PcdGet32 (PcdCpuApStackSize));
|
---|
112 | ApStackData = (AP_STACK_DATA *)((UINTN)ApTopOfStack- sizeof (AP_STACK_DATA));
|
---|
113 | CpuMpData = (CPU_MP_DATA *)ApStackData->MpData;
|
---|
114 | }
|
---|
115 |
|
---|
116 | return CpuMpData;
|
---|
117 | }
|
---|
118 |
|
---|
119 | /**
|
---|
120 | Save the pointer to CPU MP Data structure.
|
---|
121 |
|
---|
122 | @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.
|
---|
123 | **/
|
---|
124 | VOID
|
---|
125 | SaveCpuMpData (
|
---|
126 | IN CPU_MP_DATA *CpuMpData
|
---|
127 | )
|
---|
128 | {
|
---|
129 | UINT64 Data64;
|
---|
130 | UINTN Index;
|
---|
131 | CPU_INFO_IN_HOB *CpuInfoInHob;
|
---|
132 | MP_HAND_OFF *MpHandOff;
|
---|
133 | UINTN MpHandOffSize;
|
---|
134 |
|
---|
135 | //
|
---|
136 | // When APs are in a state that can be waken up by a store operation to a memory address,
|
---|
137 | // report the MP_HAND_OFF data for DXE to use.
|
---|
138 | //
|
---|
139 | CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
|
---|
140 | MpHandOffSize = sizeof (MP_HAND_OFF) + sizeof (PROCESSOR_HAND_OFF) * CpuMpData->CpuCount;
|
---|
141 | MpHandOff = (MP_HAND_OFF *)BuildGuidHob (&mMpHandOffGuid, MpHandOffSize);
|
---|
142 | ASSERT (MpHandOff != NULL);
|
---|
143 | ZeroMem (MpHandOff, MpHandOffSize);
|
---|
144 | MpHandOff->ProcessorIndex = 0;
|
---|
145 |
|
---|
146 | MpHandOff->CpuCount = CpuMpData->CpuCount;
|
---|
147 | if (CpuMpData->ApLoopMode != ApInHltLoop) {
|
---|
148 | MpHandOff->StartupSignalValue = MP_HAND_OFF_SIGNAL;
|
---|
149 | MpHandOff->WaitLoopExecutionMode = sizeof (VOID *);
|
---|
150 | }
|
---|
151 |
|
---|
152 | for (Index = 0; Index < MpHandOff->CpuCount; Index++) {
|
---|
153 | MpHandOff->Info[Index].ApicId = CpuInfoInHob[Index].ApicId;
|
---|
154 | MpHandOff->Info[Index].Health = CpuInfoInHob[Index].Health;
|
---|
155 | if (CpuMpData->ApLoopMode != ApInHltLoop) {
|
---|
156 | MpHandOff->Info[Index].StartupSignalAddress = (UINT64)(UINTN)CpuMpData->CpuData[Index].StartupApSignal;
|
---|
157 | MpHandOff->Info[Index].StartupProcedureAddress = (UINT64)(UINTN)&CpuMpData->CpuData[Index].ApFunction;
|
---|
158 | }
|
---|
159 | }
|
---|
160 |
|
---|
161 | //
|
---|
162 | // Build location of CPU MP DATA buffer in HOB
|
---|
163 | //
|
---|
164 | Data64 = (UINT64)(UINTN)CpuMpData;
|
---|
165 | BuildGuidDataHob (
|
---|
166 | &mCpuInitMpLibHobGuid,
|
---|
167 | (VOID *)&Data64,
|
---|
168 | sizeof (UINT64)
|
---|
169 | );
|
---|
170 | }
|
---|
171 |
|
---|
172 | /**
|
---|
173 | Check if AP wakeup buffer is overlapped with existing allocated buffer.
|
---|
174 |
|
---|
175 | @param[in] WakeupBufferStart AP wakeup buffer start address.
|
---|
176 | @param[in] WakeupBufferEnd AP wakeup buffer end address.
|
---|
177 |
|
---|
178 | @retval TRUE There is overlap.
|
---|
179 | @retval FALSE There is no overlap.
|
---|
180 | **/
|
---|
181 | BOOLEAN
|
---|
182 | CheckOverlapWithAllocatedBuffer (
|
---|
183 | IN UINT64 WakeupBufferStart,
|
---|
184 | IN UINT64 WakeupBufferEnd
|
---|
185 | )
|
---|
186 | {
|
---|
187 | EFI_PEI_HOB_POINTERS Hob;
|
---|
188 | EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
|
---|
189 | BOOLEAN Overlapped;
|
---|
190 | UINT64 MemoryStart;
|
---|
191 | UINT64 MemoryEnd;
|
---|
192 |
|
---|
193 | Overlapped = FALSE;
|
---|
194 | //
|
---|
195 | // Get the HOB list for processing
|
---|
196 | //
|
---|
197 | Hob.Raw = GetHobList ();
|
---|
198 | //
|
---|
199 | // Collect memory ranges
|
---|
200 | //
|
---|
201 | while (!END_OF_HOB_LIST (Hob)) {
|
---|
202 | if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
|
---|
203 | MemoryHob = Hob.MemoryAllocation;
|
---|
204 | MemoryStart = MemoryHob->AllocDescriptor.MemoryBaseAddress;
|
---|
205 | MemoryEnd = MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength;
|
---|
206 | if (!((WakeupBufferStart >= MemoryEnd) || (WakeupBufferEnd <= MemoryStart))) {
|
---|
207 | Overlapped = TRUE;
|
---|
208 | break;
|
---|
209 | }
|
---|
210 | }
|
---|
211 |
|
---|
212 | Hob.Raw = GET_NEXT_HOB (Hob);
|
---|
213 | }
|
---|
214 |
|
---|
215 | return Overlapped;
|
---|
216 | }
|
---|
217 |
|
---|
218 | /**
|
---|
219 | Get available system memory below 1MB by specified size.
|
---|
220 |
|
---|
221 | @param[in] WakeupBufferSize Wakeup buffer size required
|
---|
222 |
|
---|
223 | @retval other Return wakeup buffer address below 1MB.
|
---|
224 | @retval -1 Cannot find free memory below 1MB.
|
---|
225 | **/
|
---|
226 | UINTN
|
---|
227 | GetWakeupBuffer (
|
---|
228 | IN UINTN WakeupBufferSize
|
---|
229 | )
|
---|
230 | {
|
---|
231 | EFI_PEI_HOB_POINTERS Hob;
|
---|
232 | UINT64 WakeupBufferStart;
|
---|
233 | UINT64 WakeupBufferEnd;
|
---|
234 |
|
---|
235 | WakeupBufferSize = (WakeupBufferSize + SIZE_4KB - 1) & ~(SIZE_4KB - 1);
|
---|
236 |
|
---|
237 | //
|
---|
238 | // Get the HOB list for processing
|
---|
239 | //
|
---|
240 | Hob.Raw = GetHobList ();
|
---|
241 |
|
---|
242 | //
|
---|
243 | // Collect memory ranges
|
---|
244 | //
|
---|
245 | while (!END_OF_HOB_LIST (Hob)) {
|
---|
246 | if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
|
---|
247 | if ((Hob.ResourceDescriptor->PhysicalStart < BASE_1MB) &&
|
---|
248 | (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&
|
---|
249 | ((Hob.ResourceDescriptor->ResourceAttribute &
|
---|
250 | (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |
|
---|
251 | EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |
|
---|
252 | EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED
|
---|
253 | )) == 0)
|
---|
254 | )
|
---|
255 | {
|
---|
256 | //
|
---|
257 | // Need memory under 1MB to be collected here
|
---|
258 | //
|
---|
259 | WakeupBufferEnd = Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength;
|
---|
260 | if (ConfidentialComputingGuestHas (CCAttrAmdSevEs) &&
|
---|
261 | (WakeupBufferEnd > mSevEsPeiWakeupBuffer))
|
---|
262 | {
|
---|
263 | //
|
---|
264 | // SEV-ES Wakeup buffer should be under 1MB and under any previous one
|
---|
265 | //
|
---|
266 | WakeupBufferEnd = mSevEsPeiWakeupBuffer;
|
---|
267 | } else if (WakeupBufferEnd > BASE_1MB) {
|
---|
268 | //
|
---|
269 | // Wakeup buffer should be under 1MB
|
---|
270 | //
|
---|
271 | WakeupBufferEnd = BASE_1MB;
|
---|
272 | }
|
---|
273 |
|
---|
274 | while (WakeupBufferEnd > WakeupBufferSize) {
|
---|
275 | //
|
---|
276 | // Wakeup buffer should be aligned on 4KB
|
---|
277 | //
|
---|
278 | WakeupBufferStart = (WakeupBufferEnd - WakeupBufferSize) & ~(SIZE_4KB - 1);
|
---|
279 | if (WakeupBufferStart < Hob.ResourceDescriptor->PhysicalStart) {
|
---|
280 | break;
|
---|
281 | }
|
---|
282 |
|
---|
283 | if (CheckOverlapWithAllocatedBuffer (WakeupBufferStart, WakeupBufferEnd)) {
|
---|
284 | //
|
---|
285 | // If this range is overlapped with existing allocated buffer, skip it
|
---|
286 | // and find the next range
|
---|
287 | //
|
---|
288 | WakeupBufferEnd -= WakeupBufferSize;
|
---|
289 | continue;
|
---|
290 | }
|
---|
291 |
|
---|
292 | DEBUG ((
|
---|
293 | DEBUG_INFO,
|
---|
294 | "WakeupBufferStart = %x, WakeupBufferSize = %x\n",
|
---|
295 | WakeupBufferStart,
|
---|
296 | WakeupBufferSize
|
---|
297 | ));
|
---|
298 |
|
---|
299 | if (ConfidentialComputingGuestHas (CCAttrAmdSevEs)) {
|
---|
300 | //
|
---|
301 | // Next SEV-ES wakeup buffer allocation must be below this
|
---|
302 | // allocation
|
---|
303 | //
|
---|
304 | mSevEsPeiWakeupBuffer = WakeupBufferStart;
|
---|
305 | }
|
---|
306 |
|
---|
307 | return (UINTN)WakeupBufferStart;
|
---|
308 | }
|
---|
309 | }
|
---|
310 | }
|
---|
311 |
|
---|
312 | //
|
---|
313 | // Find the next HOB
|
---|
314 | //
|
---|
315 | Hob.Raw = GET_NEXT_HOB (Hob);
|
---|
316 | }
|
---|
317 |
|
---|
318 | return (UINTN)-1;
|
---|
319 | }
|
---|
320 |
|
---|
321 | /**
|
---|
322 | Get available EfiBootServicesCode memory below 4GB by specified size.
|
---|
323 |
|
---|
324 | This buffer is required to safely transfer AP from real address mode to
|
---|
325 | protected mode or long mode, due to the fact that the buffer returned by
|
---|
326 | GetWakeupBuffer() may be marked as non-executable.
|
---|
327 |
|
---|
328 | @param[in] BufferSize Wakeup transition buffer size.
|
---|
329 |
|
---|
330 | @retval other Return wakeup transition buffer address below 4GB.
|
---|
331 | @retval 0 Cannot find free memory below 4GB.
|
---|
332 | **/
|
---|
333 | UINTN
|
---|
334 | AllocateCodeBuffer (
|
---|
335 | IN UINTN BufferSize
|
---|
336 | )
|
---|
337 | {
|
---|
338 | EFI_STATUS Status;
|
---|
339 | EFI_PHYSICAL_ADDRESS Address;
|
---|
340 |
|
---|
341 | Status = PeiServicesAllocatePages (EfiBootServicesCode, EFI_SIZE_TO_PAGES (BufferSize), &Address);
|
---|
342 | if (EFI_ERROR (Status)) {
|
---|
343 | Address = 0;
|
---|
344 | }
|
---|
345 |
|
---|
346 | return (UINTN)Address;
|
---|
347 | }
|
---|
348 |
|
---|
349 | /**
|
---|
350 | Return the address of the SEV-ES AP jump table.
|
---|
351 |
|
---|
352 | This buffer is required in order for an SEV-ES guest to transition from
|
---|
353 | UEFI into an OS.
|
---|
354 |
|
---|
355 | @return Return SEV-ES AP jump table buffer
|
---|
356 | **/
|
---|
357 | UINTN
|
---|
358 | GetSevEsAPMemory (
|
---|
359 | VOID
|
---|
360 | )
|
---|
361 | {
|
---|
362 | //
|
---|
363 | // PEI phase doesn't need to do such transition. So simply return 0.
|
---|
364 | //
|
---|
365 | return 0;
|
---|
366 | }
|
---|
367 |
|
---|
368 | /**
|
---|
369 | Checks APs status and updates APs status if needed.
|
---|
370 |
|
---|
371 | **/
|
---|
372 | VOID
|
---|
373 | CheckAndUpdateApsStatus (
|
---|
374 | VOID
|
---|
375 | )
|
---|
376 | {
|
---|
377 | }
|
---|
378 |
|
---|
379 | /**
|
---|
380 | Build the microcode patch HOB that contains the base address and size of the
|
---|
381 | microcode patch stored in the memory.
|
---|
382 |
|
---|
383 | @param[in] CpuMpData Pointer to the CPU_MP_DATA structure.
|
---|
384 |
|
---|
385 | **/
|
---|
386 | VOID
|
---|
387 | BuildMicrocodeCacheHob (
|
---|
388 | IN CPU_MP_DATA *CpuMpData
|
---|
389 | )
|
---|
390 | {
|
---|
391 | EDKII_MICROCODE_PATCH_HOB *MicrocodeHob;
|
---|
392 | UINTN HobDataLength;
|
---|
393 | UINT32 Index;
|
---|
394 |
|
---|
395 | HobDataLength = sizeof (EDKII_MICROCODE_PATCH_HOB) +
|
---|
396 | sizeof (UINT64) * CpuMpData->CpuCount;
|
---|
397 |
|
---|
398 | MicrocodeHob = AllocatePool (HobDataLength);
|
---|
399 | if (MicrocodeHob == NULL) {
|
---|
400 | ASSERT (FALSE);
|
---|
401 | return;
|
---|
402 | }
|
---|
403 |
|
---|
404 | //
|
---|
405 | // Store the information of the memory region that holds the microcode patches.
|
---|
406 | //
|
---|
407 | MicrocodeHob->MicrocodePatchAddress = CpuMpData->MicrocodePatchAddress;
|
---|
408 | MicrocodeHob->MicrocodePatchRegionSize = CpuMpData->MicrocodePatchRegionSize;
|
---|
409 |
|
---|
410 | //
|
---|
411 | // Store the detected microcode patch for each processor as well.
|
---|
412 | //
|
---|
413 | MicrocodeHob->ProcessorCount = CpuMpData->CpuCount;
|
---|
414 | for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
|
---|
415 | if (CpuMpData->CpuData[Index].MicrocodeEntryAddr != 0) {
|
---|
416 | MicrocodeHob->ProcessorSpecificPatchOffset[Index] =
|
---|
417 | CpuMpData->CpuData[Index].MicrocodeEntryAddr - CpuMpData->MicrocodePatchAddress;
|
---|
418 | } else {
|
---|
419 | MicrocodeHob->ProcessorSpecificPatchOffset[Index] = MAX_UINT64;
|
---|
420 | }
|
---|
421 | }
|
---|
422 |
|
---|
423 | BuildGuidDataHob (
|
---|
424 | &gEdkiiMicrocodePatchHobGuid,
|
---|
425 | MicrocodeHob,
|
---|
426 | HobDataLength
|
---|
427 | );
|
---|
428 |
|
---|
429 | return;
|
---|
430 | }
|
---|
431 |
|
---|
432 | /**
|
---|
433 | Initialize global data for MP support.
|
---|
434 |
|
---|
435 | @param[in] CpuMpData The pointer to CPU MP Data structure.
|
---|
436 | **/
|
---|
437 | VOID
|
---|
438 | InitMpGlobalData (
|
---|
439 | IN CPU_MP_DATA *CpuMpData
|
---|
440 | )
|
---|
441 | {
|
---|
442 | EFI_STATUS Status;
|
---|
443 |
|
---|
444 | BuildMicrocodeCacheHob (CpuMpData);
|
---|
445 | SaveCpuMpData (CpuMpData);
|
---|
446 |
|
---|
447 | ///
|
---|
448 | /// Install Notify
|
---|
449 | ///
|
---|
450 | Status = PeiServicesNotifyPpi (&mS3SmmInitDoneNotifyDesc);
|
---|
451 | ASSERT_EFI_ERROR (Status);
|
---|
452 | }
|
---|
453 |
|
---|
454 | /**
|
---|
455 | This service executes a caller provided function on all enabled APs.
|
---|
456 |
|
---|
457 | @param[in] Procedure A pointer to the function to be run on
|
---|
458 | enabled APs of the system. See type
|
---|
459 | EFI_AP_PROCEDURE.
|
---|
460 | @param[in] SingleThread If TRUE, then all the enabled APs execute
|
---|
461 | the function specified by Procedure one by
|
---|
462 | one, in ascending order of processor handle
|
---|
463 | number. If FALSE, then all the enabled APs
|
---|
464 | execute the function specified by Procedure
|
---|
465 | simultaneously.
|
---|
466 | @param[in] WaitEvent The event created by the caller with CreateEvent()
|
---|
467 | service. If it is NULL, then execute in
|
---|
468 | blocking mode. BSP waits until all APs finish
|
---|
469 | or TimeoutInMicroSeconds expires. If it's
|
---|
470 | not NULL, then execute in non-blocking mode.
|
---|
471 | BSP requests the function specified by
|
---|
472 | Procedure to be started on all the enabled
|
---|
473 | APs, and go on executing immediately. If
|
---|
474 | all return from Procedure, or TimeoutInMicroSeconds
|
---|
475 | expires, this event is signaled. The BSP
|
---|
476 | can use the CheckEvent() or WaitForEvent()
|
---|
477 | services to check the state of event. Type
|
---|
478 | EFI_EVENT is defined in CreateEvent() in
|
---|
479 | the Unified Extensible Firmware Interface
|
---|
480 | Specification.
|
---|
481 | @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
|
---|
482 | APs to return from Procedure, either for
|
---|
483 | blocking or non-blocking mode. Zero means
|
---|
484 | infinity. If the timeout expires before
|
---|
485 | all APs return from Procedure, then Procedure
|
---|
486 | on the failed APs is terminated. All enabled
|
---|
487 | APs are available for next function assigned
|
---|
488 | by MpInitLibStartupAllAPs() or
|
---|
489 | MPInitLibStartupThisAP().
|
---|
490 | If the timeout expires in blocking mode,
|
---|
491 | BSP returns EFI_TIMEOUT. If the timeout
|
---|
492 | expires in non-blocking mode, WaitEvent
|
---|
493 | is signaled with SignalEvent().
|
---|
494 | @param[in] ProcedureArgument The parameter passed into Procedure for
|
---|
495 | all APs.
|
---|
496 | @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,
|
---|
497 | if all APs finish successfully, then its
|
---|
498 | content is set to NULL. If not all APs
|
---|
499 | finish before timeout expires, then its
|
---|
500 | content is set to address of the buffer
|
---|
501 | holding handle numbers of the failed APs.
|
---|
502 | The buffer is allocated by MP Initialization
|
---|
503 | library, and it's the caller's responsibility to
|
---|
504 | free the buffer with FreePool() service.
|
---|
505 | In blocking mode, it is ready for consumption
|
---|
506 | when the call returns. In non-blocking mode,
|
---|
507 | it is ready when WaitEvent is signaled. The
|
---|
508 | list of failed CPU is terminated by
|
---|
509 | END_OF_CPU_LIST.
|
---|
510 |
|
---|
511 | @retval EFI_SUCCESS In blocking mode, all APs have finished before
|
---|
512 | the timeout expired.
|
---|
513 | @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
|
---|
514 | to all enabled APs.
|
---|
515 | @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
|
---|
516 | UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
|
---|
517 | signaled.
|
---|
518 | @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
|
---|
519 | supported.
|
---|
520 | @retval EFI_DEVICE_ERROR Caller processor is AP.
|
---|
521 | @retval EFI_NOT_STARTED No enabled APs exist in the system.
|
---|
522 | @retval EFI_NOT_READY Any enabled APs are busy.
|
---|
523 | @retval EFI_NOT_READY MP Initialize Library is not initialized.
|
---|
524 | @retval EFI_TIMEOUT In blocking mode, the timeout expired before
|
---|
525 | all enabled APs have finished.
|
---|
526 | @retval EFI_INVALID_PARAMETER Procedure is NULL.
|
---|
527 |
|
---|
528 | **/
|
---|
529 | EFI_STATUS
|
---|
530 | EFIAPI
|
---|
531 | MpInitLibStartupAllAPs (
|
---|
532 | IN EFI_AP_PROCEDURE Procedure,
|
---|
533 | IN BOOLEAN SingleThread,
|
---|
534 | IN EFI_EVENT WaitEvent OPTIONAL,
|
---|
535 | IN UINTN TimeoutInMicroseconds,
|
---|
536 | IN VOID *ProcedureArgument OPTIONAL,
|
---|
537 | OUT UINTN **FailedCpuList OPTIONAL
|
---|
538 | )
|
---|
539 | {
|
---|
540 | if (WaitEvent != NULL) {
|
---|
541 | return EFI_UNSUPPORTED;
|
---|
542 | }
|
---|
543 |
|
---|
544 | return StartupAllCPUsWorker (
|
---|
545 | Procedure,
|
---|
546 | SingleThread,
|
---|
547 | TRUE,
|
---|
548 | NULL,
|
---|
549 | TimeoutInMicroseconds,
|
---|
550 | ProcedureArgument,
|
---|
551 | FailedCpuList
|
---|
552 | );
|
---|
553 | }
|
---|
554 |
|
---|
555 | /**
|
---|
556 | This service lets the caller get one enabled AP to execute a caller-provided
|
---|
557 | function.
|
---|
558 |
|
---|
559 | @param[in] Procedure A pointer to the function to be run on the
|
---|
560 | designated AP of the system. See type
|
---|
561 | EFI_AP_PROCEDURE.
|
---|
562 | @param[in] ProcessorNumber The handle number of the AP. The range is
|
---|
563 | from 0 to the total number of logical
|
---|
564 | processors minus 1. The total number of
|
---|
565 | logical processors can be retrieved by
|
---|
566 | MpInitLibGetNumberOfProcessors().
|
---|
567 | @param[in] WaitEvent The event created by the caller with CreateEvent()
|
---|
568 | service. If it is NULL, then execute in
|
---|
569 | blocking mode. BSP waits until this AP finish
|
---|
570 | or TimeoutInMicroSeconds expires. If it's
|
---|
571 | not NULL, then execute in non-blocking mode.
|
---|
572 | BSP requests the function specified by
|
---|
573 | Procedure to be started on this AP,
|
---|
574 | and go on executing immediately. If this AP
|
---|
575 | return from Procedure or TimeoutInMicroSeconds
|
---|
576 | expires, this event is signaled. The BSP
|
---|
577 | can use the CheckEvent() or WaitForEvent()
|
---|
578 | services to check the state of event. Type
|
---|
579 | EFI_EVENT is defined in CreateEvent() in
|
---|
580 | the Unified Extensible Firmware Interface
|
---|
581 | Specification.
|
---|
582 | @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
|
---|
583 | this AP to finish this Procedure, either for
|
---|
584 | blocking or non-blocking mode. Zero means
|
---|
585 | infinity. If the timeout expires before
|
---|
586 | this AP returns from Procedure, then Procedure
|
---|
587 | on the AP is terminated. The
|
---|
588 | AP is available for next function assigned
|
---|
589 | by MpInitLibStartupAllAPs() or
|
---|
590 | MpInitLibStartupThisAP().
|
---|
591 | If the timeout expires in blocking mode,
|
---|
592 | BSP returns EFI_TIMEOUT. If the timeout
|
---|
593 | expires in non-blocking mode, WaitEvent
|
---|
594 | is signaled with SignalEvent().
|
---|
595 | @param[in] ProcedureArgument The parameter passed into Procedure on the
|
---|
596 | specified AP.
|
---|
597 | @param[out] Finished If NULL, this parameter is ignored. In
|
---|
598 | blocking mode, this parameter is ignored.
|
---|
599 | In non-blocking mode, if AP returns from
|
---|
600 | Procedure before the timeout expires, its
|
---|
601 | content is set to TRUE. Otherwise, the
|
---|
602 | value is set to FALSE. The caller can
|
---|
603 | determine if the AP returned from Procedure
|
---|
604 | by evaluating this value.
|
---|
605 |
|
---|
606 | @retval EFI_SUCCESS In blocking mode, specified AP finished before
|
---|
607 | the timeout expires.
|
---|
608 | @retval EFI_SUCCESS In non-blocking mode, the function has been
|
---|
609 | dispatched to specified AP.
|
---|
610 | @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
|
---|
611 | UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
|
---|
612 | signaled.
|
---|
613 | @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
|
---|
614 | supported.
|
---|
615 | @retval EFI_DEVICE_ERROR The calling processor is an AP.
|
---|
616 | @retval EFI_TIMEOUT In blocking mode, the timeout expired before
|
---|
617 | the specified AP has finished.
|
---|
618 | @retval EFI_NOT_READY The specified AP is busy.
|
---|
619 | @retval EFI_NOT_READY MP Initialize Library is not initialized.
|
---|
620 | @retval EFI_NOT_FOUND The processor with the handle specified by
|
---|
621 | ProcessorNumber does not exist.
|
---|
622 | @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
|
---|
623 | @retval EFI_INVALID_PARAMETER Procedure is NULL.
|
---|
624 |
|
---|
625 | **/
|
---|
626 | EFI_STATUS
|
---|
627 | EFIAPI
|
---|
628 | MpInitLibStartupThisAP (
|
---|
629 | IN EFI_AP_PROCEDURE Procedure,
|
---|
630 | IN UINTN ProcessorNumber,
|
---|
631 | IN EFI_EVENT WaitEvent OPTIONAL,
|
---|
632 | IN UINTN TimeoutInMicroseconds,
|
---|
633 | IN VOID *ProcedureArgument OPTIONAL,
|
---|
634 | OUT BOOLEAN *Finished OPTIONAL
|
---|
635 | )
|
---|
636 | {
|
---|
637 | if (WaitEvent != NULL) {
|
---|
638 | return EFI_UNSUPPORTED;
|
---|
639 | }
|
---|
640 |
|
---|
641 | return StartupThisAPWorker (
|
---|
642 | Procedure,
|
---|
643 | ProcessorNumber,
|
---|
644 | NULL,
|
---|
645 | TimeoutInMicroseconds,
|
---|
646 | ProcedureArgument,
|
---|
647 | Finished
|
---|
648 | );
|
---|
649 | }
|
---|
650 |
|
---|
651 | /**
|
---|
652 | This service switches the requested AP to be the BSP from that point onward.
|
---|
653 | This service changes the BSP for all purposes. This call can only be performed
|
---|
654 | by the current BSP.
|
---|
655 |
|
---|
656 | @param[in] ProcessorNumber The handle number of AP that is to become the new
|
---|
657 | BSP. The range is from 0 to the total number of
|
---|
658 | logical processors minus 1. The total number of
|
---|
659 | logical processors can be retrieved by
|
---|
660 | MpInitLibGetNumberOfProcessors().
|
---|
661 | @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
|
---|
662 | enabled AP. Otherwise, it will be disabled.
|
---|
663 |
|
---|
664 | @retval EFI_SUCCESS BSP successfully switched.
|
---|
665 | @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
|
---|
666 | this service returning.
|
---|
667 | @retval EFI_UNSUPPORTED Switching the BSP is not supported.
|
---|
668 | @retval EFI_DEVICE_ERROR The calling processor is an AP.
|
---|
669 | @retval EFI_NOT_FOUND The processor with the handle specified by
|
---|
670 | ProcessorNumber does not exist.
|
---|
671 | @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
|
---|
672 | a disabled AP.
|
---|
673 | @retval EFI_NOT_READY The specified AP is busy.
|
---|
674 | @retval EFI_NOT_READY MP Initialize Library is not initialized.
|
---|
675 |
|
---|
676 | **/
|
---|
677 | EFI_STATUS
|
---|
678 | EFIAPI
|
---|
679 | MpInitLibSwitchBSP (
|
---|
680 | IN UINTN ProcessorNumber,
|
---|
681 | IN BOOLEAN EnableOldBSP
|
---|
682 | )
|
---|
683 | {
|
---|
684 | return SwitchBSPWorker (ProcessorNumber, EnableOldBSP);
|
---|
685 | }
|
---|
686 |
|
---|
687 | /**
|
---|
688 | This service lets the caller enable or disable an AP from this point onward.
|
---|
689 | This service may only be called from the BSP.
|
---|
690 |
|
---|
691 | @param[in] ProcessorNumber The handle number of AP.
|
---|
692 | The range is from 0 to the total number of
|
---|
693 | logical processors minus 1. The total number of
|
---|
694 | logical processors can be retrieved by
|
---|
695 | MpInitLibGetNumberOfProcessors().
|
---|
696 | @param[in] EnableAP Specifies the new state for the processor for
|
---|
697 | enabled, FALSE for disabled.
|
---|
698 | @param[in] HealthFlag If not NULL, a pointer to a value that specifies
|
---|
699 | the new health status of the AP. This flag
|
---|
700 | corresponds to StatusFlag defined in
|
---|
701 | EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
|
---|
702 | the PROCESSOR_HEALTH_STATUS_BIT is used. All other
|
---|
703 | bits are ignored. If it is NULL, this parameter
|
---|
704 | is ignored.
|
---|
705 |
|
---|
706 | @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
|
---|
707 | @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
|
---|
708 | prior to this service returning.
|
---|
709 | @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
|
---|
710 | @retval EFI_DEVICE_ERROR The calling processor is an AP.
|
---|
711 | @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
|
---|
712 | does not exist.
|
---|
713 | @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
|
---|
714 | @retval EFI_NOT_READY MP Initialize Library is not initialized.
|
---|
715 |
|
---|
716 | **/
|
---|
717 | EFI_STATUS
|
---|
718 | EFIAPI
|
---|
719 | MpInitLibEnableDisableAP (
|
---|
720 | IN UINTN ProcessorNumber,
|
---|
721 | IN BOOLEAN EnableAP,
|
---|
722 | IN UINT32 *HealthFlag OPTIONAL
|
---|
723 | )
|
---|
724 | {
|
---|
725 | return EnableDisableApWorker (ProcessorNumber, EnableAP, HealthFlag);
|
---|
726 | }
|
---|
727 |
|
---|
728 | /**
|
---|
729 | This funtion will try to invoke platform specific microcode shadow logic to
|
---|
730 | relocate microcode update patches into memory.
|
---|
731 |
|
---|
732 | @param[in, out] CpuMpData The pointer to CPU MP Data structure.
|
---|
733 |
|
---|
734 | @retval EFI_SUCCESS Shadow microcode success.
|
---|
735 | @retval EFI_OUT_OF_RESOURCES No enough resource to complete the operation.
|
---|
736 | @retval EFI_UNSUPPORTED Can't find platform specific microcode shadow
|
---|
737 | PPI/Protocol.
|
---|
738 | **/
|
---|
739 | EFI_STATUS
|
---|
740 | PlatformShadowMicrocode (
|
---|
741 | IN OUT CPU_MP_DATA *CpuMpData
|
---|
742 | )
|
---|
743 | {
|
---|
744 | EFI_STATUS Status;
|
---|
745 | EDKII_PEI_SHADOW_MICROCODE_PPI *ShadowMicrocodePpi;
|
---|
746 | UINTN CpuCount;
|
---|
747 | EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuId;
|
---|
748 | UINTN Index;
|
---|
749 | UINTN BufferSize;
|
---|
750 | VOID *Buffer;
|
---|
751 |
|
---|
752 | Status = PeiServicesLocatePpi (
|
---|
753 | &gEdkiiPeiShadowMicrocodePpiGuid,
|
---|
754 | 0,
|
---|
755 | NULL,
|
---|
756 | (VOID **)&ShadowMicrocodePpi
|
---|
757 | );
|
---|
758 | if (EFI_ERROR (Status)) {
|
---|
759 | return EFI_UNSUPPORTED;
|
---|
760 | }
|
---|
761 |
|
---|
762 | CpuCount = CpuMpData->CpuCount;
|
---|
763 | MicrocodeCpuId = (EDKII_PEI_MICROCODE_CPU_ID *)AllocateZeroPool (sizeof (EDKII_PEI_MICROCODE_CPU_ID) * CpuCount);
|
---|
764 | if (MicrocodeCpuId == NULL) {
|
---|
765 | return EFI_OUT_OF_RESOURCES;
|
---|
766 | }
|
---|
767 |
|
---|
768 | for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
|
---|
769 | MicrocodeCpuId[Index].ProcessorSignature = CpuMpData->CpuData[Index].ProcessorSignature;
|
---|
770 | MicrocodeCpuId[Index].PlatformId = CpuMpData->CpuData[Index].PlatformId;
|
---|
771 | }
|
---|
772 |
|
---|
773 | Status = ShadowMicrocodePpi->ShadowMicrocode (
|
---|
774 | ShadowMicrocodePpi,
|
---|
775 | CpuCount,
|
---|
776 | MicrocodeCpuId,
|
---|
777 | &BufferSize,
|
---|
778 | &Buffer
|
---|
779 | );
|
---|
780 | FreePool (MicrocodeCpuId);
|
---|
781 | if (EFI_ERROR (Status)) {
|
---|
782 | return EFI_NOT_FOUND;
|
---|
783 | }
|
---|
784 |
|
---|
785 | CpuMpData->MicrocodePatchAddress = (UINTN)Buffer;
|
---|
786 | CpuMpData->MicrocodePatchRegionSize = BufferSize;
|
---|
787 |
|
---|
788 | DEBUG ((
|
---|
789 | DEBUG_INFO,
|
---|
790 | "%a: Required microcode patches have been loaded at 0x%lx, with size 0x%lx.\n",
|
---|
791 | __func__,
|
---|
792 | CpuMpData->MicrocodePatchAddress,
|
---|
793 | CpuMpData->MicrocodePatchRegionSize
|
---|
794 | ));
|
---|
795 |
|
---|
796 | return EFI_SUCCESS;
|
---|
797 | }
|
---|