]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/CpuMpPei/CpuMpPei.c
40729a09b9eec651c7ea2c2632ec9f0e34e4917a
[mirror_edk2.git] / UefiCpuPkg / CpuMpPei / CpuMpPei.c
1 /** @file
2 CPU PEI Module installs CPU Multiple Processor PPI.
3
4 Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "CpuMpPei.h"
10
11 extern EDKII_PEI_MP_SERVICES2_PPI mMpServices2Ppi;
12
13 //
14 // CPU MP PPI to be installed
15 //
16 EFI_PEI_MP_SERVICES_PPI mMpServicesPpi = {
17 PeiGetNumberOfProcessors,
18 PeiGetProcessorInfo,
19 PeiStartupAllAPs,
20 PeiStartupThisAP,
21 PeiSwitchBSP,
22 PeiEnableDisableAP,
23 PeiWhoAmI,
24 };
25
26 EFI_PEI_PPI_DESCRIPTOR mPeiCpuMpPpiList[] = {
27 {
28 EFI_PEI_PPI_DESCRIPTOR_PPI,
29 &gEdkiiPeiMpServices2PpiGuid,
30 &mMpServices2Ppi
31 },
32 {
33 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
34 &gEfiPeiMpServicesPpiGuid,
35 &mMpServicesPpi
36 }
37 };
38
39 /**
40 This service retrieves the number of logical processor in the platform
41 and the number of those logical processors that are enabled on this boot.
42 This service may only be called from the BSP.
43
44 This function is used to retrieve the following information:
45 - The number of logical processors that are present in the system.
46 - The number of enabled logical processors in the system at the instant
47 this call is made.
48
49 Because MP Service Ppi provides services to enable and disable processors
50 dynamically, the number of enabled logical processors may vary during the
51 course of a boot session.
52
53 If this service is called from an AP, then EFI_DEVICE_ERROR is returned.
54 If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then
55 EFI_INVALID_PARAMETER is returned. Otherwise, the total number of processors
56 is returned in NumberOfProcessors, the number of currently enabled processor
57 is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned.
58
59 @param[in] PeiServices An indirect pointer to the PEI Services Table
60 published by the PEI Foundation.
61 @param[in] This Pointer to this instance of the PPI.
62 @param[out] NumberOfProcessors Pointer to the total number of logical processors in
63 the system, including the BSP and disabled APs.
64 @param[out] NumberOfEnabledProcessors
65 Number of processors in the system that are enabled.
66
67 @retval EFI_SUCCESS The number of logical processors and enabled
68 logical processors was retrieved.
69 @retval EFI_DEVICE_ERROR The calling processor is an AP.
70 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL.
71 NumberOfEnabledProcessors is NULL.
72 **/
73 EFI_STATUS
74 EFIAPI
75 PeiGetNumberOfProcessors (
76 IN CONST EFI_PEI_SERVICES **PeiServices,
77 IN EFI_PEI_MP_SERVICES_PPI *This,
78 OUT UINTN *NumberOfProcessors,
79 OUT UINTN *NumberOfEnabledProcessors
80 )
81 {
82 if ((NumberOfProcessors == NULL) || (NumberOfEnabledProcessors == NULL)) {
83 return EFI_INVALID_PARAMETER;
84 }
85
86 return MpInitLibGetNumberOfProcessors (
87 NumberOfProcessors,
88 NumberOfEnabledProcessors
89 );
90 }
91
92 /**
93 Gets detailed MP-related information on the requested processor at the
94 instant this call is made. This service may only be called from the BSP.
95
96 This service retrieves detailed MP-related information about any processor
97 on the platform. Note the following:
98 - The processor information may change during the course of a boot session.
99 - The information presented here is entirely MP related.
100
101 Information regarding the number of caches and their sizes, frequency of operation,
102 slot numbers is all considered platform-related information and is not provided
103 by this service.
104
105 @param[in] PeiServices An indirect pointer to the PEI Services Table
106 published by the PEI Foundation.
107 @param[in] This Pointer to this instance of the PPI.
108 @param[in] ProcessorNumber Pointer to the total number of logical processors in
109 the system, including the BSP and disabled APs.
110 @param[out] ProcessorInfoBuffer Number of processors in the system that are enabled.
111
112 @retval EFI_SUCCESS Processor information was returned.
113 @retval EFI_DEVICE_ERROR The calling processor is an AP.
114 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
115 @retval EFI_NOT_FOUND The processor with the handle specified by
116 ProcessorNumber does not exist in the platform.
117 **/
118 EFI_STATUS
119 EFIAPI
120 PeiGetProcessorInfo (
121 IN CONST EFI_PEI_SERVICES **PeiServices,
122 IN EFI_PEI_MP_SERVICES_PPI *This,
123 IN UINTN ProcessorNumber,
124 OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
125 )
126 {
127 return MpInitLibGetProcessorInfo (ProcessorNumber, ProcessorInfoBuffer, NULL);
128 }
129
130 /**
131 This service executes a caller provided function on all enabled APs. APs can
132 run either simultaneously or one at a time in sequence. This service supports
133 both blocking requests only. This service may only
134 be called from the BSP.
135
136 This function is used to dispatch all the enabled APs to the function specified
137 by Procedure. If any enabled AP is busy, then EFI_NOT_READY is returned
138 immediately and Procedure is not started on any AP.
139
140 If SingleThread is TRUE, all the enabled APs execute the function specified by
141 Procedure one by one, in ascending order of processor handle number. Otherwise,
142 all the enabled APs execute the function specified by Procedure simultaneously.
143
144 If the timeout specified by TimeoutInMicroSeconds expires before all APs return
145 from Procedure, then Procedure on the failed APs is terminated. All enabled APs
146 are always available for further calls to EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
147 and EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). If FailedCpuList is not NULL, its
148 content points to the list of processor handle numbers in which Procedure was
149 terminated.
150
151 Note: It is the responsibility of the consumer of the EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
152 to make sure that the nature of the code that is executed on the BSP and the
153 dispatched APs is well controlled. The MP Services Ppi does not guarantee
154 that the Procedure function is MP-safe. Hence, the tasks that can be run in
155 parallel are limited to certain independent tasks and well-controlled exclusive
156 code. PEI services and Ppis may not be called by APs unless otherwise
157 specified.
158
159 In blocking execution mode, BSP waits until all APs finish or
160 TimeoutInMicroSeconds expires.
161
162 @param[in] PeiServices An indirect pointer to the PEI Services Table
163 published by the PEI Foundation.
164 @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
165 @param[in] Procedure A pointer to the function to be run on enabled APs of
166 the system.
167 @param[in] SingleThread If TRUE, then all the enabled APs execute the function
168 specified by Procedure one by one, in ascending order
169 of processor handle number. If FALSE, then all the
170 enabled APs execute the function specified by Procedure
171 simultaneously.
172 @param[in] TimeoutInMicroSeconds
173 Indicates the time limit in microseconds for APs to
174 return from Procedure, for blocking mode only. Zero
175 means infinity. If the timeout expires before all APs
176 return from Procedure, then Procedure on the failed APs
177 is terminated. All enabled APs are available for next
178 function assigned by EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
179 or EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). If the
180 timeout expires in blocking mode, BSP returns
181 EFI_TIMEOUT.
182 @param[in] ProcedureArgument The parameter passed into Procedure for all APs.
183
184 @retval EFI_SUCCESS In blocking mode, all APs have finished before the
185 timeout expired.
186 @retval EFI_DEVICE_ERROR Caller processor is AP.
187 @retval EFI_NOT_STARTED No enabled APs exist in the system.
188 @retval EFI_NOT_READY Any enabled APs are busy.
189 @retval EFI_TIMEOUT In blocking mode, the timeout expired before all
190 enabled APs have finished.
191 @retval EFI_INVALID_PARAMETER Procedure is NULL.
192 **/
193 EFI_STATUS
194 EFIAPI
195 PeiStartupAllAPs (
196 IN CONST EFI_PEI_SERVICES **PeiServices,
197 IN EFI_PEI_MP_SERVICES_PPI *This,
198 IN EFI_AP_PROCEDURE Procedure,
199 IN BOOLEAN SingleThread,
200 IN UINTN TimeoutInMicroSeconds,
201 IN VOID *ProcedureArgument OPTIONAL
202 )
203 {
204 return MpInitLibStartupAllAPs (
205 Procedure,
206 SingleThread,
207 NULL,
208 TimeoutInMicroSeconds,
209 ProcedureArgument,
210 NULL
211 );
212 }
213
214 /**
215 This service lets the caller get one enabled AP to execute a caller-provided
216 function. The caller can request the BSP to wait for the completion
217 of the AP. This service may only be called from the BSP.
218
219 This function is used to dispatch one enabled AP to the function specified by
220 Procedure passing in the argument specified by ProcedureArgument.
221 The execution is in blocking mode. The BSP waits until the AP finishes or
222 TimeoutInMicroSecondss expires.
223
224 If the timeout specified by TimeoutInMicroseconds expires before the AP returns
225 from Procedure, then execution of Procedure by the AP is terminated. The AP is
226 available for subsequent calls to EFI_PEI_MP_SERVICES_PPI.StartupAllAPs() and
227 EFI_PEI_MP_SERVICES_PPI.StartupThisAP().
228
229 @param[in] PeiServices An indirect pointer to the PEI Services Table
230 published by the PEI Foundation.
231 @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
232 @param[in] Procedure A pointer to the function to be run on enabled APs of
233 the system.
234 @param[in] ProcessorNumber The handle number of the AP. The range is from 0 to the
235 total number of logical processors minus 1. The total
236 number of logical processors can be retrieved by
237 EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors().
238 @param[in] TimeoutInMicroseconds
239 Indicates the time limit in microseconds for APs to
240 return from Procedure, for blocking mode only. Zero
241 means infinity. If the timeout expires before all APs
242 return from Procedure, then Procedure on the failed APs
243 is terminated. All enabled APs are available for next
244 function assigned by EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
245 or EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). If the
246 timeout expires in blocking mode, BSP returns
247 EFI_TIMEOUT.
248 @param[in] ProcedureArgument The parameter passed into Procedure for all APs.
249
250 @retval EFI_SUCCESS In blocking mode, specified AP finished before the
251 timeout expires.
252 @retval EFI_DEVICE_ERROR The calling processor is an AP.
253 @retval EFI_TIMEOUT In blocking mode, the timeout expired before the
254 specified AP has finished.
255 @retval EFI_NOT_FOUND The processor with the handle specified by
256 ProcessorNumber does not exist.
257 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
258 @retval EFI_INVALID_PARAMETER Procedure is NULL.
259 **/
260 EFI_STATUS
261 EFIAPI
262 PeiStartupThisAP (
263 IN CONST EFI_PEI_SERVICES **PeiServices,
264 IN EFI_PEI_MP_SERVICES_PPI *This,
265 IN EFI_AP_PROCEDURE Procedure,
266 IN UINTN ProcessorNumber,
267 IN UINTN TimeoutInMicroseconds,
268 IN VOID *ProcedureArgument OPTIONAL
269 )
270 {
271 return MpInitLibStartupThisAP (
272 Procedure,
273 ProcessorNumber,
274 NULL,
275 TimeoutInMicroseconds,
276 ProcedureArgument,
277 NULL
278 );
279 }
280
281 /**
282 This service switches the requested AP to be the BSP from that point onward.
283 This service changes the BSP for all purposes. This call can only be performed
284 by the current BSP.
285
286 This service switches the requested AP to be the BSP from that point onward.
287 This service changes the BSP for all purposes. The new BSP can take over the
288 execution of the old BSP and continue seamlessly from where the old one left
289 off.
290
291 If the BSP cannot be switched prior to the return from this service, then
292 EFI_UNSUPPORTED must be returned.
293
294 @param[in] PeiServices An indirect pointer to the PEI Services Table
295 published by the PEI Foundation.
296 @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
297 @param[in] ProcessorNumber The handle number of the AP. The range is from 0 to the
298 total number of logical processors minus 1. The total
299 number of logical processors can be retrieved by
300 EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors().
301 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an enabled
302 AP. Otherwise, it will be disabled.
303
304 @retval EFI_SUCCESS BSP successfully switched.
305 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to this
306 service returning.
307 @retval EFI_UNSUPPORTED Switching the BSP is not supported.
308 @retval EFI_DEVICE_ERROR The calling processor is an AP.
309 @retval EFI_NOT_FOUND The processor with the handle specified by
310 ProcessorNumber does not exist.
311 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or a disabled
312 AP.
313 @retval EFI_NOT_READY The specified AP is busy.
314 **/
315 EFI_STATUS
316 EFIAPI
317 PeiSwitchBSP (
318 IN CONST EFI_PEI_SERVICES **PeiServices,
319 IN EFI_PEI_MP_SERVICES_PPI *This,
320 IN UINTN ProcessorNumber,
321 IN BOOLEAN EnableOldBSP
322 )
323 {
324 return MpInitLibSwitchBSP (ProcessorNumber, EnableOldBSP);
325 }
326
327 /**
328 This service lets the caller enable or disable an AP from this point onward.
329 This service may only be called from the BSP.
330
331 This service allows the caller enable or disable an AP from this point onward.
332 The caller can optionally specify the health status of the AP by Health. If
333 an AP is being disabled, then the state of the disabled AP is implementation
334 dependent. If an AP is enabled, then the implementation must guarantee that a
335 complete initialization sequence is performed on the AP, so the AP is in a state
336 that is compatible with an MP operating system.
337
338 If the enable or disable AP operation cannot be completed prior to the return
339 from this service, then EFI_UNSUPPORTED must be returned.
340
341 @param[in] PeiServices An indirect pointer to the PEI Services Table
342 published by the PEI Foundation.
343 @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
344 @param[in] ProcessorNumber The handle number of the AP. The range is from 0 to the
345 total number of logical processors minus 1. The total
346 number of logical processors can be retrieved by
347 EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors().
348 @param[in] EnableAP Specifies the new state for the processor for enabled,
349 FALSE for disabled.
350 @param[in] HealthFlag If not NULL, a pointer to a value that specifies the
351 new health status of the AP. This flag corresponds to
352 StatusFlag defined in EFI_PEI_MP_SERVICES_PPI.GetProcessorInfo().
353 Only the PROCESSOR_HEALTH_STATUS_BIT is used. All other
354 bits are ignored. If it is NULL, this parameter is
355 ignored.
356
357 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
358 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed prior
359 to this service returning.
360 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
361 @retval EFI_DEVICE_ERROR The calling processor is an AP.
362 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
363 does not exist.
364 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
365 **/
366 EFI_STATUS
367 EFIAPI
368 PeiEnableDisableAP (
369 IN CONST EFI_PEI_SERVICES **PeiServices,
370 IN EFI_PEI_MP_SERVICES_PPI *This,
371 IN UINTN ProcessorNumber,
372 IN BOOLEAN EnableAP,
373 IN UINT32 *HealthFlag OPTIONAL
374 )
375 {
376 return MpInitLibEnableDisableAP (ProcessorNumber, EnableAP, HealthFlag);
377 }
378
379 /**
380 This return the handle number for the calling processor. This service may be
381 called from the BSP and APs.
382
383 This service returns the processor handle number for the calling processor.
384 The returned value is in the range from 0 to the total number of logical
385 processors minus 1. The total number of logical processors can be retrieved
386 with EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors(). This service may be
387 called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER
388 is returned. Otherwise, the current processors handle number is returned in
389 ProcessorNumber, and EFI_SUCCESS is returned.
390
391 @param[in] PeiServices An indirect pointer to the PEI Services Table
392 published by the PEI Foundation.
393 @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
394 @param[out] ProcessorNumber The handle number of the AP. The range is from 0 to the
395 total number of logical processors minus 1. The total
396 number of logical processors can be retrieved by
397 EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors().
398
399 @retval EFI_SUCCESS The current processor handle number was returned in
400 ProcessorNumber.
401 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
402 **/
403 EFI_STATUS
404 EFIAPI
405 PeiWhoAmI (
406 IN CONST EFI_PEI_SERVICES **PeiServices,
407 IN EFI_PEI_MP_SERVICES_PPI *This,
408 OUT UINTN *ProcessorNumber
409 )
410 {
411 return MpInitLibWhoAmI (ProcessorNumber);
412 }
413
414 /**
415 Get GDT register value.
416
417 This function is mainly for AP purpose because AP may have different GDT
418 table than BSP.
419
420 @param[in,out] Buffer The pointer to private data buffer.
421
422 **/
423 VOID
424 EFIAPI
425 GetGdtr (
426 IN OUT VOID *Buffer
427 )
428 {
429 AsmReadGdtr ((IA32_DESCRIPTOR *)Buffer);
430 }
431
432 /**
433 Migrates the Global Descriptor Table (GDT) to permanent memory.
434
435 @retval EFI_SUCCESS The GDT was migrated successfully.
436 @retval EFI_OUT_OF_RESOURCES The GDT could not be migrated due to lack of available memory.
437
438 **/
439 EFI_STATUS
440 MigrateGdt (
441 VOID
442 )
443 {
444 EFI_STATUS Status;
445 UINTN GdtBufferSize;
446 IA32_DESCRIPTOR Gdtr;
447 VOID *GdtBuffer;
448
449 AsmReadGdtr ((IA32_DESCRIPTOR *) &Gdtr);
450 GdtBufferSize = sizeof (IA32_SEGMENT_DESCRIPTOR) -1 + Gdtr.Limit + 1;
451
452 Status = PeiServicesAllocatePool (
453 GdtBufferSize,
454 &GdtBuffer
455 );
456 ASSERT (GdtBuffer != NULL);
457 if (EFI_ERROR (Status)) {
458 return EFI_OUT_OF_RESOURCES;
459 }
460
461 GdtBuffer = ALIGN_POINTER (GdtBuffer, sizeof (IA32_SEGMENT_DESCRIPTOR));
462 CopyMem (GdtBuffer, (VOID *) Gdtr.Base, Gdtr.Limit + 1);
463 Gdtr.Base = (UINTN) GdtBuffer;
464 AsmWriteGdtr (&Gdtr);
465
466 return EFI_SUCCESS;
467 }
468
469 /**
470 Initializes CPU exceptions handlers for the sake of stack switch requirement.
471
472 This function is a wrapper of InitializeCpuExceptionHandlersEx. It's mainly
473 for the sake of AP's init because of EFI_AP_PROCEDURE API requirement.
474
475 @param[in,out] Buffer The pointer to private data buffer.
476
477 **/
478 VOID
479 EFIAPI
480 InitializeExceptionStackSwitchHandlers (
481 IN OUT VOID *Buffer
482 )
483 {
484 CPU_EXCEPTION_INIT_DATA *EssData;
485 IA32_DESCRIPTOR Idtr;
486 EFI_STATUS Status;
487
488 EssData = Buffer;
489 //
490 // We don't plan to replace IDT table with a new one, but we should not assume
491 // the AP's IDT is the same as BSP's IDT either.
492 //
493 AsmReadIdtr (&Idtr);
494 EssData->Ia32.IdtTable = (VOID *)Idtr.Base;
495 EssData->Ia32.IdtTableSize = Idtr.Limit + 1;
496 Status = InitializeCpuExceptionHandlersEx (NULL, EssData);
497 ASSERT_EFI_ERROR (Status);
498 }
499
500 /**
501 Initializes MP exceptions handlers for the sake of stack switch requirement.
502
503 This function will allocate required resources required to setup stack switch
504 and pass them through CPU_EXCEPTION_INIT_DATA to each logic processor.
505
506 **/
507 VOID
508 InitializeMpExceptionStackSwitchHandlers (
509 VOID
510 )
511 {
512 EFI_STATUS Status;
513 UINTN Index;
514 UINTN Bsp;
515 UINTN ExceptionNumber;
516 UINTN OldGdtSize;
517 UINTN NewGdtSize;
518 UINTN NewStackSize;
519 IA32_DESCRIPTOR Gdtr;
520 CPU_EXCEPTION_INIT_DATA EssData;
521 UINT8 *GdtBuffer;
522 UINT8 *StackTop;
523 UINTN NumberOfProcessors;
524
525 if (!PcdGetBool (PcdCpuStackGuard)) {
526 return;
527 }
528
529 MpInitLibGetNumberOfProcessors(&NumberOfProcessors, NULL);
530 MpInitLibWhoAmI (&Bsp);
531
532 ExceptionNumber = FixedPcdGetSize (PcdCpuStackSwitchExceptionList);
533 NewStackSize = FixedPcdGet32 (PcdCpuKnownGoodStackSize) * ExceptionNumber;
534
535 StackTop = AllocatePages (EFI_SIZE_TO_PAGES (NewStackSize * NumberOfProcessors));
536 ASSERT(StackTop != NULL);
537 if (StackTop == NULL) {
538 return;
539 }
540 StackTop += NewStackSize * NumberOfProcessors;
541
542 //
543 // The default exception handlers must have been initialized. Let's just skip
544 // it in this method.
545 //
546 EssData.Ia32.Revision = CPU_EXCEPTION_INIT_DATA_REV;
547 EssData.Ia32.InitDefaultHandlers = FALSE;
548
549 EssData.Ia32.StackSwitchExceptions = FixedPcdGetPtr(PcdCpuStackSwitchExceptionList);
550 EssData.Ia32.StackSwitchExceptionNumber = ExceptionNumber;
551 EssData.Ia32.KnownGoodStackSize = FixedPcdGet32(PcdCpuKnownGoodStackSize);
552
553 //
554 // Initialize Gdtr to suppress incorrect compiler/analyzer warnings.
555 //
556 Gdtr.Base = 0;
557 Gdtr.Limit = 0;
558 for (Index = 0; Index < NumberOfProcessors; ++Index) {
559 //
560 // To support stack switch, we need to re-construct GDT but not IDT.
561 //
562 if (Index == Bsp) {
563 GetGdtr(&Gdtr);
564 } else {
565 //
566 // AP might have different size of GDT from BSP.
567 //
568 MpInitLibStartupThisAP (GetGdtr, Index, NULL, 0, (VOID *)&Gdtr, NULL);
569 }
570
571 //
572 // X64 needs only one TSS of current task working for all exceptions
573 // because of its IST feature. IA32 needs one TSS for each exception
574 // in addition to current task. Since AP is not supposed to allocate
575 // memory, we have to do it in BSP. To simplify the code, we allocate
576 // memory for IA32 case to cover both IA32 and X64 exception stack
577 // switch.
578 //
579 // Layout of memory to allocate for each processor:
580 // --------------------------------
581 // | Alignment | (just in case)
582 // --------------------------------
583 // | |
584 // | Original GDT |
585 // | |
586 // --------------------------------
587 // | Current task descriptor |
588 // --------------------------------
589 // | |
590 // | Exception task descriptors | X ExceptionNumber
591 // | |
592 // --------------------------------
593 // | Current task-state segment |
594 // --------------------------------
595 // | |
596 // | Exception task-state segment | X ExceptionNumber
597 // | |
598 // --------------------------------
599 //
600 OldGdtSize = Gdtr.Limit + 1;
601 EssData.Ia32.ExceptionTssDescSize = sizeof (IA32_TSS_DESCRIPTOR) *
602 (ExceptionNumber + 1);
603 EssData.Ia32.ExceptionTssSize = sizeof (IA32_TASK_STATE_SEGMENT) *
604 (ExceptionNumber + 1);
605 NewGdtSize = sizeof (IA32_TSS_DESCRIPTOR) +
606 OldGdtSize +
607 EssData.Ia32.ExceptionTssDescSize +
608 EssData.Ia32.ExceptionTssSize;
609
610 Status = PeiServicesAllocatePool (
611 NewGdtSize,
612 (VOID **)&GdtBuffer
613 );
614 ASSERT (GdtBuffer != NULL);
615 if (EFI_ERROR (Status)) {
616 ASSERT_EFI_ERROR (Status);
617 return;
618 }
619
620 //
621 // Make sure GDT table alignment
622 //
623 EssData.Ia32.GdtTable = ALIGN_POINTER(GdtBuffer, sizeof (IA32_TSS_DESCRIPTOR));
624 NewGdtSize -= ((UINT8 *)EssData.Ia32.GdtTable - GdtBuffer);
625 EssData.Ia32.GdtTableSize = NewGdtSize;
626
627 EssData.Ia32.ExceptionTssDesc = ((UINT8 *)EssData.Ia32.GdtTable + OldGdtSize);
628 EssData.Ia32.ExceptionTss = ((UINT8 *)EssData.Ia32.GdtTable + OldGdtSize +
629 EssData.Ia32.ExceptionTssDescSize);
630
631 EssData.Ia32.KnownGoodStackTop = (UINTN)StackTop;
632 DEBUG ((DEBUG_INFO,
633 "Exception stack top[cpu%lu]: 0x%lX\n",
634 (UINT64)(UINTN)Index,
635 (UINT64)(UINTN)StackTop));
636
637 if (Index == Bsp) {
638 InitializeExceptionStackSwitchHandlers (&EssData);
639 } else {
640 MpInitLibStartupThisAP (
641 InitializeExceptionStackSwitchHandlers,
642 Index,
643 NULL,
644 0,
645 (VOID *)&EssData,
646 NULL
647 );
648 }
649
650 StackTop -= NewStackSize;
651 }
652 }
653
654 /**
655 Initializes MP and exceptions handlers.
656
657 @param PeiServices The pointer to the PEI Services Table.
658
659 @retval EFI_SUCCESS MP was successfully initialized.
660 @retval others Error occurred in MP initialization.
661
662 **/
663 EFI_STATUS
664 InitializeCpuMpWorker (
665 IN CONST EFI_PEI_SERVICES **PeiServices
666 )
667 {
668 EFI_STATUS Status;
669 EFI_VECTOR_HANDOFF_INFO *VectorInfo;
670 EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi;
671
672 //
673 // Get Vector Hand-off Info PPI
674 //
675 VectorInfo = NULL;
676 Status = PeiServicesLocatePpi (
677 &gEfiVectorHandoffInfoPpiGuid,
678 0,
679 NULL,
680 (VOID **)&VectorHandoffInfoPpi
681 );
682 if (Status == EFI_SUCCESS) {
683 VectorInfo = VectorHandoffInfoPpi->Info;
684 }
685
686 //
687 // Initialize default handlers
688 //
689 Status = InitializeCpuExceptionHandlers (VectorInfo);
690 if (EFI_ERROR (Status)) {
691 return Status;
692 }
693
694 Status = MpInitLibInitialize ();
695 if (EFI_ERROR (Status)) {
696 return Status;
697 }
698
699 //
700 // Special initialization for the sake of Stack Guard
701 //
702 InitializeMpExceptionStackSwitchHandlers ();
703
704 //
705 // Update and publish CPU BIST information
706 //
707 CollectBistDataFromPpi (PeiServices);
708
709 //
710 // Install CPU MP PPI
711 //
712 Status = PeiServicesInstallPpi(mPeiCpuMpPpiList);
713 ASSERT_EFI_ERROR (Status);
714
715 return Status;
716 }
717
718 /**
719 The Entry point of the MP CPU PEIM.
720
721 This function will wakeup APs and collect CPU AP count and install the
722 Mp Service Ppi.
723
724 @param FileHandle Handle of the file being invoked.
725 @param PeiServices Describes the list of possible PEI Services.
726
727 @retval EFI_SUCCESS MpServicePpi is installed successfully.
728
729 **/
730 EFI_STATUS
731 EFIAPI
732 CpuMpPeimInit (
733 IN EFI_PEI_FILE_HANDLE FileHandle,
734 IN CONST EFI_PEI_SERVICES **PeiServices
735 )
736 {
737 EFI_STATUS Status;
738
739 //
740 // For the sake of special initialization needing to be done right after
741 // memory discovery.
742 //
743 Status = PeiServicesNotifyPpi (&mPostMemNotifyList[0]);
744 ASSERT_EFI_ERROR (Status);
745
746 return Status;
747 }