/** @file\r
CPU PEI Module installs CPU Multiple Processor PPI.\r
\r
- Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>\r
+ Copyright (c) 2015 - 2022, Intel Corporation. All rights reserved.<BR>\r
SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
return MpInitLibWhoAmI (ProcessorNumber);\r
}\r
\r
-/**\r
- Get GDT register value.\r
-\r
- This function is mainly for AP purpose because AP may have different GDT\r
- table than BSP.\r
-\r
- @param[in,out] Buffer The pointer to private data buffer.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-GetGdtr (\r
- IN OUT VOID *Buffer\r
- )\r
-{\r
- AsmReadGdtr ((IA32_DESCRIPTOR *)Buffer);\r
-}\r
+//\r
+// Structure for InitializeSeparateExceptionStacks\r
+//\r
+typedef struct {\r
+ VOID *Buffer;\r
+ UINTN *BufferSize;\r
+} EXCEPTION_STACK_SWITCH_CONTEXT;\r
\r
/**\r
Initializes CPU exceptions handlers for the sake of stack switch requirement.\r
IN OUT VOID *Buffer\r
)\r
{\r
- CPU_EXCEPTION_INIT_DATA *EssData;\r
- IA32_DESCRIPTOR Idtr;\r
- EFI_STATUS Status;\r
+ EXCEPTION_STACK_SWITCH_CONTEXT *SwitchStackData;\r
\r
- EssData = Buffer;\r
- //\r
- // We don't plan to replace IDT table with a new one, but we should not assume\r
- // the AP's IDT is the same as BSP's IDT either.\r
- //\r
- AsmReadIdtr (&Idtr);\r
- EssData->Ia32.IdtTable = (VOID *)Idtr.Base;\r
- EssData->Ia32.IdtTableSize = Idtr.Limit + 1;\r
- Status = InitializeSeparateExceptionStacks (EssData);\r
- ASSERT_EFI_ERROR (Status);\r
+ SwitchStackData = (EXCEPTION_STACK_SWITCH_CONTEXT *)Buffer;\r
+ InitializeSeparateExceptionStacks (SwitchStackData->Buffer, SwitchStackData->BufferSize);\r
}\r
\r
/**\r
Initializes MP exceptions handlers for the sake of stack switch requirement.\r
\r
This function will allocate required resources required to setup stack switch\r
- and pass them through CPU_EXCEPTION_INIT_DATA to each logic processor.\r
+ and pass them through SwitchStackData to each logic processor.\r
\r
**/\r
VOID\r
VOID\r
)\r
{\r
- EFI_STATUS Status;\r
- UINTN Index;\r
- UINTN Bsp;\r
- UINTN ExceptionNumber;\r
- UINTN OldGdtSize;\r
- UINTN NewGdtSize;\r
- UINTN NewStackSize;\r
- IA32_DESCRIPTOR Gdtr;\r
- CPU_EXCEPTION_INIT_DATA EssData;\r
- UINT8 *GdtBuffer;\r
- UINT8 *StackTop;\r
- UINTN NumberOfProcessors;\r
+ UINTN Index;\r
+ UINTN Bsp;\r
+ EXCEPTION_STACK_SWITCH_CONTEXT SwitchStackData;\r
+ UINTN BufferSize;\r
+ UINTN NumberOfProcessors;\r
\r
if (!PcdGetBool (PcdCpuStackGuard)) {\r
return;\r
}\r
\r
+ SwitchStackData.BufferSize = &BufferSize;\r
MpInitLibGetNumberOfProcessors (&NumberOfProcessors, NULL);\r
MpInitLibWhoAmI (&Bsp);\r
\r
- ExceptionNumber = FixedPcdGetSize (PcdCpuStackSwitchExceptionList);\r
- NewStackSize = FixedPcdGet32 (PcdCpuKnownGoodStackSize) * ExceptionNumber;\r
-\r
- StackTop = AllocatePages (EFI_SIZE_TO_PAGES (NewStackSize * NumberOfProcessors));\r
- ASSERT (StackTop != NULL);\r
- if (StackTop == NULL) {\r
- return;\r
- }\r
-\r
- StackTop += NewStackSize * NumberOfProcessors;\r
-\r
- //\r
- // The default exception handlers must have been initialized. Let's just skip\r
- // it in this method.\r
- //\r
- EssData.Ia32.Revision = CPU_EXCEPTION_INIT_DATA_REV;\r
- EssData.Ia32.InitDefaultHandlers = FALSE;\r
-\r
- EssData.Ia32.StackSwitchExceptions = FixedPcdGetPtr (PcdCpuStackSwitchExceptionList);\r
- EssData.Ia32.StackSwitchExceptionNumber = ExceptionNumber;\r
- EssData.Ia32.KnownGoodStackSize = FixedPcdGet32 (PcdCpuKnownGoodStackSize);\r
-\r
- //\r
- // Initialize Gdtr to suppress incorrect compiler/analyzer warnings.\r
- //\r
- Gdtr.Base = 0;\r
- Gdtr.Limit = 0;\r
for (Index = 0; Index < NumberOfProcessors; ++Index) {\r
- //\r
- // To support stack switch, we need to re-construct GDT but not IDT.\r
- //\r
+ SwitchStackData.Buffer = NULL;\r
+ BufferSize = 0;\r
+\r
if (Index == Bsp) {\r
- GetGdtr (&Gdtr);\r
+ InitializeExceptionStackSwitchHandlers (&SwitchStackData);\r
} else {\r
//\r
- // AP might have different size of GDT from BSP.\r
+ // AP might need different buffer size from BSP.\r
//\r
- MpInitLibStartupThisAP (GetGdtr, Index, NULL, 0, (VOID *)&Gdtr, NULL);\r
+ MpInitLibStartupThisAP (InitializeExceptionStackSwitchHandlers, Index, NULL, 0, (VOID *)&SwitchStackData, NULL);\r
}\r
\r
- //\r
- // X64 needs only one TSS of current task working for all exceptions\r
- // because of its IST feature. IA32 needs one TSS for each exception\r
- // in addition to current task. Since AP is not supposed to allocate\r
- // memory, we have to do it in BSP. To simplify the code, we allocate\r
- // memory for IA32 case to cover both IA32 and X64 exception stack\r
- // switch.\r
- //\r
- // Layout of memory to allocate for each processor:\r
- // --------------------------------\r
- // | Alignment | (just in case)\r
- // --------------------------------\r
- // | |\r
- // | Original GDT |\r
- // | |\r
- // --------------------------------\r
- // | Current task descriptor |\r
- // --------------------------------\r
- // | |\r
- // | Exception task descriptors | X ExceptionNumber\r
- // | |\r
- // --------------------------------\r
- // | Current task-state segment |\r
- // --------------------------------\r
- // | |\r
- // | Exception task-state segment | X ExceptionNumber\r
- // | |\r
- // --------------------------------\r
- //\r
- OldGdtSize = Gdtr.Limit + 1;\r
- EssData.Ia32.ExceptionTssDescSize = sizeof (IA32_TSS_DESCRIPTOR) *\r
- (ExceptionNumber + 1);\r
- EssData.Ia32.ExceptionTssSize = sizeof (IA32_TASK_STATE_SEGMENT) *\r
- (ExceptionNumber + 1);\r
- NewGdtSize = sizeof (IA32_TSS_DESCRIPTOR) +\r
- OldGdtSize +\r
- EssData.Ia32.ExceptionTssDescSize +\r
- EssData.Ia32.ExceptionTssSize;\r
-\r
- Status = PeiServicesAllocatePool (\r
- NewGdtSize,\r
- (VOID **)&GdtBuffer\r
- );\r
- ASSERT (GdtBuffer != NULL);\r
- if (EFI_ERROR (Status)) {\r
- ASSERT_EFI_ERROR (Status);\r
- return;\r
+ if (BufferSize == 0) {\r
+ continue;\r
}\r
\r
- //\r
- // Make sure GDT table alignment\r
- //\r
- EssData.Ia32.GdtTable = ALIGN_POINTER (GdtBuffer, sizeof (IA32_TSS_DESCRIPTOR));\r
- NewGdtSize -= ((UINT8 *)EssData.Ia32.GdtTable - GdtBuffer);\r
- EssData.Ia32.GdtTableSize = NewGdtSize;\r
-\r
- EssData.Ia32.ExceptionTssDesc = ((UINT8 *)EssData.Ia32.GdtTable + OldGdtSize);\r
- EssData.Ia32.ExceptionTss = ((UINT8 *)EssData.Ia32.GdtTable + OldGdtSize +\r
- EssData.Ia32.ExceptionTssDescSize);\r
-\r
- EssData.Ia32.KnownGoodStackTop = (UINTN)StackTop;\r
+ SwitchStackData.Buffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));\r
+ ASSERT (SwitchStackData.Buffer != NULL);\r
+ ZeroMem (SwitchStackData.Buffer, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (BufferSize)));\r
DEBUG ((\r
DEBUG_INFO,\r
- "Exception stack top[cpu%lu]: 0x%lX\n",\r
+ "Buffer[cpu%lu] for InitializeExceptionStackSwitchHandlers: 0x%lX with size 0x%x\n",\r
(UINT64)(UINTN)Index,\r
- (UINT64)(UINTN)StackTop\r
+ (UINT64)(UINTN)SwitchStackData.Buffer,\r
+ (UINT32)BufferSize\r
));\r
\r
if (Index == Bsp) {\r
- InitializeExceptionStackSwitchHandlers (&EssData);\r
+ InitializeExceptionStackSwitchHandlers (&SwitchStackData);\r
} else {\r
MpInitLibStartupThisAP (\r
InitializeExceptionStackSwitchHandlers,\r
Index,\r
NULL,\r
0,\r
- (VOID *)&EssData,\r
+ (VOID *)&SwitchStackData,\r
NULL\r
);\r
}\r
-\r
- StackTop -= NewStackSize;\r
}\r
}\r
\r