\r
/**\r
Setup separate stacks for certain exception handlers.\r
+ If the input Buffer and BufferSize are both NULL, use global variable if possible.\r
\r
- InitData is optional and processor arch dependent.\r
-\r
- @param[in] InitData Pointer to data optional for information about how\r
- to assign stacks for certain exception handlers.\r
+ @param[in] Buffer Point to buffer used to separate exception stack.\r
+ @param[in, out] BufferSize On input, it indicates the byte size of Buffer.\r
+ If the size is not enough, the return status will\r
+ be EFI_BUFFER_TOO_SMALL, and output BufferSize\r
+ will be the size it needs.\r
\r
@retval EFI_SUCCESS The stacks are assigned successfully.\r
@retval EFI_UNSUPPORTED This function is not supported.\r
-\r
+ @retval EFI_BUFFER_TOO_SMALL This BufferSize is too small.\r
**/\r
EFI_STATUS\r
EFIAPI\r
InitializeSeparateExceptionStacks (\r
- IN CPU_EXCEPTION_INIT_DATA *InitData OPTIONAL\r
+ IN VOID *Buffer,\r
+ IN OUT UINTN *BufferSize\r
)\r
{\r
return EFI_SUCCESS;\r
/** @file\r
DXE Core Main Entry Point\r
\r
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>\r
SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
// Setup Stack Guard\r
//\r
if (PcdGetBool (PcdCpuStackGuard)) {\r
- Status = InitializeSeparateExceptionStacks (NULL);\r
+ Status = InitializeSeparateExceptionStacks (NULL, NULL);\r
ASSERT_EFI_ERROR (Status);\r
}\r
\r
\r
/**\r
Setup separate stacks for certain exception handlers.\r
+ If the input Buffer and BufferSize are both NULL, use global variable if possible.\r
\r
- InitData is optional and processor arch dependent.\r
-\r
- @param[in] InitData Pointer to data optional for information about how\r
- to assign stacks for certain exception handlers.\r
+ @param[in] Buffer Point to buffer used to separate exception stack.\r
+ @param[in, out] BufferSize On input, it indicates the byte size of Buffer.\r
+ If the size is not enough, the return status will\r
+ be EFI_BUFFER_TOO_SMALL, and output BufferSize\r
+ will be the size it needs.\r
\r
@retval EFI_SUCCESS The stacks are assigned successfully.\r
@retval EFI_UNSUPPORTED This function is not supported.\r
-\r
+ @retval EFI_BUFFER_TOO_SMALL This BufferSize is too small.\r
**/\r
EFI_STATUS\r
EFIAPI\r
InitializeSeparateExceptionStacks (\r
- IN CPU_EXCEPTION_INIT_DATA *InitData OPTIONAL\r
+ IN VOID *Buffer,\r
+ IN OUT UINTN *BufferSize\r
);\r
\r
/**\r
\r
/**\r
Setup separate stacks for certain exception handlers.\r
+ If the input Buffer and BufferSize are both NULL, use global variable if possible.\r
\r
- InitData is optional and processor arch dependent.\r
-\r
- @param[in] InitData Pointer to data optional for information about how\r
- to assign stacks for certain exception handlers.\r
+ @param[in] Buffer Point to buffer used to separate exception stack.\r
+ @param[in, out] BufferSize On input, it indicates the byte size of Buffer.\r
+ If the size is not enough, the return status will\r
+ be EFI_BUFFER_TOO_SMALL, and output BufferSize\r
+ will be the size it needs.\r
\r
@retval EFI_SUCCESS The stacks are assigned successfully.\r
@retval EFI_UNSUPPORTED This function is not supported.\r
-\r
+ @retval EFI_BUFFER_TOO_SMALL This BufferSize is too small.\r
**/\r
EFI_STATUS\r
EFIAPI\r
InitializeSeparateExceptionStacks (\r
- IN CPU_EXCEPTION_INIT_DATA *InitData OPTIONAL\r
+ IN VOID *Buffer,\r
+ IN OUT UINTN *BufferSize\r
)\r
{\r
return EFI_UNSUPPORTED;\r
}\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
- 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
-\r
- ExceptionNumber = FixedPcdGetSize (PcdCpuStackSwitchExceptionList);\r
- NewStackSize = FixedPcdGet32 (PcdCpuKnownGoodStackSize) * ExceptionNumber;\r
-\r
- StackTop = AllocateRuntimeZeroPool (NewStackSize * mNumberOfProcessors);\r
- ASSERT (StackTop != NULL);\r
- StackTop += NewStackSize * mNumberOfProcessors;\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
+ UINTN Index;\r
+ UINTN Bsp;\r
+ EXCEPTION_STACK_SWITCH_CONTEXT SwitchStackData;\r
+ UINTN BufferSize;\r
\r
- //\r
- // Initialize Gdtr to suppress incorrect compiler/analyzer warnings.\r
- //\r
- Gdtr.Base = 0;\r
- Gdtr.Limit = 0;\r
+ SwitchStackData.BufferSize = &BufferSize;\r
MpInitLibWhoAmI (&Bsp);\r
+\r
for (Index = 0; Index < mNumberOfProcessors; ++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
- GdtBuffer = AllocateRuntimeZeroPool (NewGdtSize);\r
- ASSERT (GdtBuffer != NULL);\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
+ if (BufferSize == 0) {\r
+ continue;\r
+ }\r
\r
- EssData.Ia32.KnownGoodStackTop = (UINTN)StackTop;\r
+ SwitchStackData.Buffer = AllocateRuntimeZeroPool (BufferSize);\r
+ ASSERT (SwitchStackData.Buffer != NULL);\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
/** @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
\r
/**\r
Setup separate stacks for certain exception handlers.\r
+ If the input Buffer and BufferSize are both NULL, use global variable if possible.\r
\r
- InitData is optional and processor arch dependent.\r
-\r
- @param[in] InitData Pointer to data optional for information about how\r
- to assign stacks for certain exception handlers.\r
+ @param[in] Buffer Point to buffer used to separate exception stack.\r
+ @param[in, out] BufferSize On input, it indicates the byte size of Buffer.\r
+ If the size is not enough, the return status will\r
+ be EFI_BUFFER_TOO_SMALL, and output BufferSize\r
+ will be the size it needs.\r
\r
@retval EFI_SUCCESS The stacks are assigned successfully.\r
@retval EFI_UNSUPPORTED This function is not supported.\r
-\r
+ @retval EFI_BUFFER_TOO_SMALL This BufferSize is too small.\r
**/\r
EFI_STATUS\r
EFIAPI\r
InitializeSeparateExceptionStacks (\r
- IN CPU_EXCEPTION_INIT_DATA *InitData OPTIONAL\r
+ IN VOID *Buffer,\r
+ IN OUT UINTN *BufferSize\r
)\r
{\r
CPU_EXCEPTION_INIT_DATA EssData;\r
IA32_DESCRIPTOR Idtr;\r
IA32_DESCRIPTOR Gdtr;\r
-\r
- if (InitData == NULL) {\r
+ UINTN NeedBufferSize;\r
+ UINTN StackTop;\r
+ UINT8 *NewGdtTable;\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. To simplify the code, we report the\r
+ // needed memory for IA32 case to cover both IA32 and X64 exception\r
+ // stack switch.\r
+ //\r
+ // Layout of memory needed 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
+ AsmReadGdtr (&Gdtr);\r
+ if ((Buffer == NULL) && (BufferSize == NULL)) {\r
SetMem (mNewGdt, sizeof (mNewGdt), 0);\r
-\r
- AsmReadIdtr (&Idtr);\r
- AsmReadGdtr (&Gdtr);\r
-\r
- EssData.X64.Revision = CPU_EXCEPTION_INIT_DATA_REV;\r
- EssData.X64.KnownGoodStackTop = (UINTN)mNewStack + sizeof (mNewStack);\r
- EssData.X64.KnownGoodStackSize = CPU_KNOWN_GOOD_STACK_SIZE;\r
- EssData.X64.StackSwitchExceptions = CPU_STACK_SWITCH_EXCEPTION_LIST;\r
- EssData.X64.StackSwitchExceptionNumber = CPU_STACK_SWITCH_EXCEPTION_NUMBER;\r
- EssData.X64.IdtTable = (VOID *)Idtr.Base;\r
- EssData.X64.IdtTableSize = Idtr.Limit + 1;\r
- EssData.X64.GdtTable = mNewGdt;\r
- EssData.X64.GdtTableSize = sizeof (mNewGdt);\r
- EssData.X64.ExceptionTssDesc = mNewGdt + Gdtr.Limit + 1;\r
- EssData.X64.ExceptionTssDescSize = CPU_TSS_DESC_SIZE;\r
- EssData.X64.ExceptionTss = mNewGdt + Gdtr.Limit + 1 + CPU_TSS_DESC_SIZE;\r
- EssData.X64.ExceptionTssSize = CPU_TSS_SIZE;\r
-\r
- InitData = &EssData;\r
+ StackTop = (UINTN)mNewStack + sizeof (mNewStack);\r
+ NewGdtTable = mNewGdt;\r
+ } else {\r
+ if (BufferSize == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Total needed size includes stack size, new GDT table size, TSS size.\r
+ // Add another DESCRIPTOR size for alignment requiremet.\r
+ //\r
+ NeedBufferSize = CPU_STACK_SWITCH_EXCEPTION_NUMBER * CPU_KNOWN_GOOD_STACK_SIZE +\r
+ CPU_TSS_DESC_SIZE + Gdtr.Limit + 1 +\r
+ CPU_TSS_SIZE +\r
+ sizeof (IA32_TSS_DESCRIPTOR);\r
+ if (*BufferSize < NeedBufferSize) {\r
+ *BufferSize = NeedBufferSize;\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ StackTop = (UINTN)Buffer + CPU_STACK_SWITCH_EXCEPTION_NUMBER * CPU_KNOWN_GOOD_STACK_SIZE;\r
+ NewGdtTable = ALIGN_POINTER (StackTop, sizeof (IA32_TSS_DESCRIPTOR));\r
}\r
\r
- return ArchSetupExceptionStack (InitData);\r
+ AsmReadIdtr (&Idtr);\r
+ EssData.X64.Revision = CPU_EXCEPTION_INIT_DATA_REV;\r
+ EssData.X64.KnownGoodStackTop = StackTop;\r
+ EssData.X64.KnownGoodStackSize = CPU_KNOWN_GOOD_STACK_SIZE;\r
+ EssData.X64.StackSwitchExceptions = CPU_STACK_SWITCH_EXCEPTION_LIST;\r
+ EssData.X64.StackSwitchExceptionNumber = CPU_STACK_SWITCH_EXCEPTION_NUMBER;\r
+ EssData.X64.IdtTable = (VOID *)Idtr.Base;\r
+ EssData.X64.IdtTableSize = Idtr.Limit + 1;\r
+ EssData.X64.GdtTable = NewGdtTable;\r
+ EssData.X64.GdtTableSize = CPU_TSS_DESC_SIZE + Gdtr.Limit + 1;\r
+ EssData.X64.ExceptionTssDesc = NewGdtTable + Gdtr.Limit + 1;\r
+ EssData.X64.ExceptionTssDescSize = CPU_TSS_DESC_SIZE;\r
+ EssData.X64.ExceptionTss = NewGdtTable + Gdtr.Limit + 1 + CPU_TSS_DESC_SIZE;\r
+ EssData.X64.ExceptionTssSize = CPU_TSS_SIZE;\r
+\r
+ return ArchSetupExceptionStack (&EssData);\r
}\r
\r
/**\r
Setup separate stacks for certain exception handlers.\r
+ If the input Buffer and BufferSize are both NULL, use global variable if possible.\r
\r
- InitData is optional and processor arch dependent.\r
-\r
- @param[in] InitData Pointer to data optional for information about how\r
- to assign stacks for certain exception handlers.\r
+ @param[in] Buffer Point to buffer used to separate exception stack.\r
+ @param[in, out] BufferSize On input, it indicates the byte size of Buffer.\r
+ If the size is not enough, the return status will\r
+ be EFI_BUFFER_TOO_SMALL, and output BufferSize\r
+ will be the size it needs.\r
\r
@retval EFI_SUCCESS The stacks are assigned successfully.\r
@retval EFI_UNSUPPORTED This function is not supported.\r
-\r
+ @retval EFI_BUFFER_TOO_SMALL This BufferSize is too small.\r
**/\r
EFI_STATUS\r
EFIAPI\r
InitializeSeparateExceptionStacks (\r
- IN CPU_EXCEPTION_INIT_DATA *InitData OPTIONAL\r
+ IN VOID *Buffer,\r
+ IN OUT UINTN *BufferSize\r
)\r
{\r
- if (InitData == NULL) {\r
+ CPU_EXCEPTION_INIT_DATA EssData;\r
+ IA32_DESCRIPTOR Idtr;\r
+ IA32_DESCRIPTOR Gdtr;\r
+ UINTN NeedBufferSize;\r
+ UINTN StackTop;\r
+ UINT8 *NewGdtTable;\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. To simplify the code, we report the\r
+ // needed memory for IA32 case to cover both IA32 and X64 exception\r
+ // stack switch.\r
+ //\r
+ // Layout of memory needed 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
+\r
+ if ((Buffer == NULL) && (BufferSize == NULL)) {\r
return EFI_UNSUPPORTED;\r
}\r
\r
- return ArchSetupExceptionStack (InitData);\r
+ if (BufferSize == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ AsmReadGdtr (&Gdtr);\r
+ //\r
+ // Total needed size includes stack size, new GDT table size, TSS size.\r
+ // Add another DESCRIPTOR size for alignment requiremet.\r
+ //\r
+ NeedBufferSize = CPU_STACK_SWITCH_EXCEPTION_NUMBER * CPU_KNOWN_GOOD_STACK_SIZE +\r
+ CPU_TSS_DESC_SIZE + Gdtr.Limit + 1 +\r
+ CPU_TSS_SIZE +\r
+ sizeof (IA32_TSS_DESCRIPTOR);\r
+ if (*BufferSize < NeedBufferSize) {\r
+ *BufferSize = NeedBufferSize;\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ StackTop = (UINTN)Buffer + CPU_STACK_SWITCH_EXCEPTION_NUMBER * CPU_KNOWN_GOOD_STACK_SIZE;\r
+ NewGdtTable = ALIGN_POINTER (StackTop, sizeof (IA32_TSS_DESCRIPTOR));\r
+\r
+ AsmReadIdtr (&Idtr);\r
+ EssData.X64.Revision = CPU_EXCEPTION_INIT_DATA_REV;\r
+ EssData.X64.KnownGoodStackTop = StackTop;\r
+ EssData.X64.KnownGoodStackSize = CPU_KNOWN_GOOD_STACK_SIZE;\r
+ EssData.X64.StackSwitchExceptions = CPU_STACK_SWITCH_EXCEPTION_LIST;\r
+ EssData.X64.StackSwitchExceptionNumber = CPU_STACK_SWITCH_EXCEPTION_NUMBER;\r
+ EssData.X64.IdtTable = (VOID *)Idtr.Base;\r
+ EssData.X64.IdtTableSize = Idtr.Limit + 1;\r
+ EssData.X64.GdtTable = NewGdtTable;\r
+ EssData.X64.GdtTableSize = CPU_TSS_DESC_SIZE + Gdtr.Limit + 1;\r
+ EssData.X64.ExceptionTssDesc = NewGdtTable + Gdtr.Limit + 1;\r
+ EssData.X64.ExceptionTssDescSize = CPU_TSS_DESC_SIZE;\r
+ EssData.X64.ExceptionTss = NewGdtTable + Gdtr.Limit + 1 + CPU_TSS_DESC_SIZE;\r
+ EssData.X64.ExceptionTssSize = CPU_TSS_SIZE;\r
+\r
+ return ArchSetupExceptionStack (&EssData);\r
}\r
## @file\r
# CPU Exception Handler library instance for PEI module.\r
#\r
-# Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+# Copyright (c) 2016 - 2022, Intel Corporation. All rights reserved.<BR>\r
# SPDX-License-Identifier: BSD-2-Clause-Patent\r
#\r
##\r
\r
[Pcd]\r
gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard # CONSUMES\r
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize\r
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList\r
\r
[FeaturePcd]\r
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard ## CONSUMES\r
\r
/**\r
Setup separate stacks for certain exception handlers.\r
+ If the input Buffer and BufferSize are both NULL, use global variable if possible.\r
\r
- InitData is optional and processor arch dependent.\r
-\r
- @param[in] InitData Pointer to data optional for information about how\r
- to assign stacks for certain exception handlers.\r
+ @param[in] Buffer Point to buffer used to separate exception stack.\r
+ @param[in, out] BufferSize On input, it indicates the byte size of Buffer.\r
+ If the size is not enough, the return status will\r
+ be EFI_BUFFER_TOO_SMALL, and output BufferSize\r
+ will be the size it needs.\r
\r
@retval EFI_SUCCESS The stacks are assigned successfully.\r
@retval EFI_UNSUPPORTED This function is not supported.\r
-\r
+ @retval EFI_BUFFER_TOO_SMALL This BufferSize is too small.\r
**/\r
EFI_STATUS\r
EFIAPI\r
InitializeSeparateExceptionStacks (\r
- IN CPU_EXCEPTION_INIT_DATA *InitData OPTIONAL\r
+ IN VOID *Buffer,\r
+ IN OUT UINTN *BufferSize\r
)\r
{\r
return EFI_UNSUPPORTED;\r
\r
/**\r
Setup separate stacks for certain exception handlers.\r
+ If the input Buffer and BufferSize are both NULL, use global variable if possible.\r
\r
- InitData is optional and processor arch dependent.\r
-\r
- @param[in] InitData Pointer to data optional for information about how\r
- to assign stacks for certain exception handlers.\r
+ @param[in] Buffer Point to buffer used to separate exception stack.\r
+ @param[in, out] BufferSize On input, it indicates the byte size of Buffer.\r
+ If the size is not enough, the return status will\r
+ be EFI_BUFFER_TOO_SMALL, and output BufferSize\r
+ will be the size it needs.\r
\r
@retval EFI_SUCCESS The stacks are assigned successfully.\r
@retval EFI_UNSUPPORTED This function is not supported.\r
-\r
+ @retval EFI_BUFFER_TOO_SMALL This BufferSize is too small.\r
**/\r
EFI_STATUS\r
EFIAPI\r
InitializeSeparateExceptionStacks (\r
- IN CPU_EXCEPTION_INIT_DATA *InitData OPTIONAL\r
+ IN VOID *Buffer,\r
+ IN OUT UINTN *BufferSize\r
)\r
{\r
return EFI_UNSUPPORTED;\r