\r
#define CPU_TSS_GDT_SIZE (SIZE_2KB + CPU_TSS_DESC_SIZE + CPU_TSS_SIZE)\r
\r
-typedef struct {\r
- //\r
- // The address of top of known good stack reserved for *ALL* exceptions\r
- // listed in field StackSwitchExceptions.\r
- //\r
- UINTN KnownGoodStackTop;\r
- //\r
- // The size of known good stack for *ONE* exception only.\r
- //\r
- UINTN KnownGoodStackSize;\r
- //\r
- // Buffer of exception vector list for stack switch.\r
- //\r
- UINT8 *StackSwitchExceptions;\r
- //\r
- // Number of exception vectors in StackSwitchExceptions.\r
- //\r
- UINTN StackSwitchExceptionNumber;\r
- //\r
- // Buffer of IDT table. It must be type of IA32_IDT_GATE_DESCRIPTOR.\r
- // Normally there's no need to change IDT table size.\r
- //\r
- VOID *IdtTable;\r
- //\r
- // Size of buffer for IdtTable.\r
- //\r
- UINTN IdtTableSize;\r
- //\r
- // Buffer of GDT table. It must be type of IA32_SEGMENT_DESCRIPTOR.\r
- //\r
- VOID *GdtTable;\r
- //\r
- // Size of buffer for GdtTable.\r
- //\r
- UINTN GdtTableSize;\r
- //\r
- // Pointer to start address of descriptor of exception task gate in the\r
- // GDT table. It must be type of IA32_TSS_DESCRIPTOR.\r
- //\r
- VOID *ExceptionTssDesc;\r
- //\r
- // Size of buffer for ExceptionTssDesc.\r
- //\r
- UINTN ExceptionTssDescSize;\r
- //\r
- // Buffer of task-state segment for exceptions. It must be type of\r
- // IA32_TASK_STATE_SEGMENT.\r
- //\r
- VOID *ExceptionTss;\r
- //\r
- // Size of buffer for ExceptionTss.\r
- //\r
- UINTN ExceptionTssSize;\r
-} CPU_EXCEPTION_INIT_DATA;\r
-\r
//\r
// Record exception handler information\r
//\r
);\r
\r
/**\r
- Setup separate stack for specific exceptions.\r
+ Setup separate stacks for certain exception handlers.\r
\r
- @param[in] StackSwitchData Pointer to data required for setuping up\r
- stack switch.\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 exceptions have been successfully\r
- initialized with new stack.\r
- @retval EFI_INVALID_PARAMETER StackSwitchData contains invalid content.\r
+ @retval EFI_SUCCESS The stacks are assigned successfully.\r
+ @retval EFI_BUFFER_TOO_SMALL This BufferSize is too small.\r
+ @retval EFI_UNSUPPORTED This function is not supported.\r
**/\r
EFI_STATUS\r
ArchSetupExceptionStack (\r
- IN CPU_EXCEPTION_INIT_DATA *StackSwitchData\r
+ IN VOID *Buffer,\r
+ IN OUT UINTN *BufferSize\r
);\r
\r
/**\r
mExternalInterruptHandlerTable\r
};\r
\r
-UINT8 mNewStack[CPU_STACK_SWITCH_EXCEPTION_NUMBER *\r
- CPU_KNOWN_GOOD_STACK_SIZE];\r
-UINT8 mNewGdt[CPU_TSS_GDT_SIZE];\r
+UINT8 mBuffer[CPU_STACK_SWITCH_EXCEPTION_NUMBER * CPU_KNOWN_GOOD_STACK_SIZE\r
+ + CPU_TSS_GDT_SIZE];\r
\r
/**\r
Common exception handler.\r
IN OUT UINTN *BufferSize\r
)\r
{\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
- AsmReadGdtr (&Gdtr);\r
+ UINTN LocalBufferSize;\r
+ EFI_STATUS Status;\r
+\r
if ((Buffer == NULL) && (BufferSize == NULL)) {\r
- SetMem (mNewGdt, sizeof (mNewGdt), 0);\r
- StackTop = (UINTN)mNewStack + sizeof (mNewStack);\r
- NewGdtTable = mNewGdt;\r
+ SetMem (mBuffer, sizeof (mBuffer), 0);\r
+ LocalBufferSize = sizeof (mBuffer);\r
+ Status = ArchSetupExceptionStack (mBuffer, &LocalBufferSize);\r
+ ASSERT_EFI_ERROR (Status);\r
+ return Status;\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
+ return ArchSetupExceptionStack (Buffer, BufferSize);\r
}\r
-\r
- AsmReadIdtr (&Idtr);\r
- EssData.KnownGoodStackTop = StackTop;\r
- EssData.KnownGoodStackSize = CPU_KNOWN_GOOD_STACK_SIZE;\r
- EssData.StackSwitchExceptions = CPU_STACK_SWITCH_EXCEPTION_LIST;\r
- EssData.StackSwitchExceptionNumber = CPU_STACK_SWITCH_EXCEPTION_NUMBER;\r
- EssData.IdtTable = (VOID *)Idtr.Base;\r
- EssData.IdtTableSize = Idtr.Limit + 1;\r
- EssData.GdtTable = NewGdtTable;\r
- EssData.GdtTableSize = CPU_TSS_DESC_SIZE + Gdtr.Limit + 1;\r
- EssData.ExceptionTssDesc = NewGdtTable + Gdtr.Limit + 1;\r
- EssData.ExceptionTssDescSize = CPU_TSS_DESC_SIZE;\r
- EssData.ExceptionTss = NewGdtTable + Gdtr.Limit + 1 + CPU_TSS_DESC_SIZE;\r
- EssData.ExceptionTssSize = CPU_TSS_SIZE;\r
-\r
- return ArchSetupExceptionStack (&EssData);\r
}\r
}\r
\r
/**\r
- Setup separate stack for given exceptions.\r
+ Setup separate stacks for certain exception handlers.\r
\r
- @param[in] StackSwitchData Pointer to data required for setuping up\r
- stack switch.\r
-\r
- @retval EFI_SUCCESS The exceptions have been successfully\r
- initialized with new stack.\r
- @retval EFI_INVALID_PARAMETER StackSwitchData contains invalid content.\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_BUFFER_TOO_SMALL This BufferSize is too small.\r
**/\r
EFI_STATUS\r
ArchSetupExceptionStack (\r
- IN CPU_EXCEPTION_INIT_DATA *StackSwitchData\r
+ IN VOID *Buffer,\r
+ IN OUT UINTN *BufferSize\r
)\r
{\r
IA32_DESCRIPTOR Gdtr;\r
IA32_DESCRIPTOR Idtr;\r
IA32_IDT_GATE_DESCRIPTOR *IdtTable;\r
IA32_TSS_DESCRIPTOR *TssDesc;\r
+ IA32_TSS_DESCRIPTOR *TssDescBase;\r
IA32_TASK_STATE_SEGMENT *Tss;\r
+ VOID *NewGdtTable;\r
UINTN StackTop;\r
UINTN Index;\r
UINTN Vector;\r
UINTN TssBase;\r
- UINTN GdtSize;\r
+ UINT8 *StackSwitchExceptions;\r
+ UINTN NeedBufferSize;\r
EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap;\r
\r
- if ((StackSwitchData == NULL) ||\r
- (StackSwitchData->KnownGoodStackTop == 0) ||\r
- (StackSwitchData->KnownGoodStackSize == 0) ||\r
- (StackSwitchData->StackSwitchExceptions == NULL) ||\r
- (StackSwitchData->StackSwitchExceptionNumber == 0) ||\r
- (StackSwitchData->StackSwitchExceptionNumber > CPU_EXCEPTION_NUM) ||\r
- (StackSwitchData->GdtTable == NULL) ||\r
- (StackSwitchData->IdtTable == NULL) ||\r
- (StackSwitchData->ExceptionTssDesc == NULL) ||\r
- (StackSwitchData->ExceptionTss == NULL))\r
- {\r
+ if (BufferSize == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
//\r
- // The caller is responsible for that the GDT table, no matter the existing\r
- // one or newly allocated, has enough space to hold descriptors for exception\r
- // task-state segments.\r
+ // Total needed size includes stack size, new GDT table size, TSS size.\r
+ // Add another DESCRIPTOR size for alignment requiremet.\r
//\r
- if (((UINTN)StackSwitchData->GdtTable & (IA32_GDT_ALIGNMENT - 1)) != 0) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if ((UINTN)StackSwitchData->ExceptionTssDesc < (UINTN)(StackSwitchData->GdtTable)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if ((UINTN)StackSwitchData->ExceptionTssDesc + StackSwitchData->ExceptionTssDescSize >\r
- ((UINTN)(StackSwitchData->GdtTable) + StackSwitchData->GdtTableSize))\r
- {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
+ // Layout of memory needed for each processor:\r
+ // --------------------------------\r
+ // | |\r
+ // | Stack Size | X ExceptionNumber\r
+ // | |\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
- // We need one descriptor and one TSS for current task and every exception\r
- // specified.\r
- //\r
- if (StackSwitchData->ExceptionTssDescSize <\r
- sizeof (IA32_TSS_DESCRIPTOR) * (StackSwitchData->StackSwitchExceptionNumber + 1))\r
- {\r
- return EFI_INVALID_PARAMETER;\r
+ AsmReadGdtr (&Gdtr);\r
+ NeedBufferSize = CPU_STACK_SWITCH_EXCEPTION_NUMBER * CPU_KNOWN_GOOD_STACK_SIZE +\r
+ sizeof (IA32_TSS_DESCRIPTOR) +\r
+ Gdtr.Limit + 1 + CPU_TSS_DESC_SIZE +\r
+ CPU_TSS_SIZE;\r
+\r
+ if (*BufferSize < NeedBufferSize) {\r
+ *BufferSize = NeedBufferSize;\r
+ return EFI_BUFFER_TOO_SMALL;\r
}\r
\r
- if (StackSwitchData->ExceptionTssSize <\r
- sizeof (IA32_TASK_STATE_SEGMENT) * (StackSwitchData->StackSwitchExceptionNumber + 1))\r
- {\r
+ if (Buffer == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- TssDesc = StackSwitchData->ExceptionTssDesc;\r
- Tss = StackSwitchData->ExceptionTss;\r
-\r
- //\r
- // Initialize new GDT table and/or IDT table, if any\r
- //\r
AsmReadIdtr (&Idtr);\r
- AsmReadGdtr (&Gdtr);\r
-\r
- GdtSize = (UINTN)TssDesc +\r
- sizeof (IA32_TSS_DESCRIPTOR) *\r
- (StackSwitchData->StackSwitchExceptionNumber + 1) -\r
- (UINTN)(StackSwitchData->GdtTable);\r
- if ((UINTN)StackSwitchData->GdtTable != Gdtr.Base) {\r
- CopyMem (StackSwitchData->GdtTable, (VOID *)Gdtr.Base, Gdtr.Limit + 1);\r
- Gdtr.Base = (UINTN)StackSwitchData->GdtTable;\r
- Gdtr.Limit = (UINT16)GdtSize - 1;\r
- }\r
-\r
- if ((UINTN)StackSwitchData->IdtTable != Idtr.Base) {\r
- Idtr.Base = (UINTN)StackSwitchData->IdtTable;\r
- }\r
+ StackSwitchExceptions = CPU_STACK_SWITCH_EXCEPTION_LIST;\r
+ StackTop = (UINTN)Buffer + CPU_STACK_SWITCH_EXCEPTION_NUMBER * CPU_KNOWN_GOOD_STACK_SIZE;\r
+ NewGdtTable = ALIGN_POINTER (StackTop, sizeof (IA32_TSS_DESCRIPTOR));\r
+ TssDesc = (IA32_TSS_DESCRIPTOR *)((UINTN)NewGdtTable + Gdtr.Limit + 1);\r
+ Tss = (IA32_TASK_STATE_SEGMENT *)((UINTN)TssDesc + CPU_TSS_DESC_SIZE);\r
+ TssDescBase = TssDesc;\r
\r
- if (StackSwitchData->IdtTableSize > 0) {\r
- Idtr.Limit = (UINT16)(StackSwitchData->IdtTableSize - 1);\r
- }\r
+ CopyMem (NewGdtTable, (VOID *)Gdtr.Base, Gdtr.Limit + 1);\r
+ Gdtr.Base = (UINTN)NewGdtTable;\r
+ Gdtr.Limit = (UINT16)(Gdtr.Limit + CPU_TSS_DESC_SIZE);\r
\r
//\r
// Fixup current task descriptor. Task-state segment for current task will\r
// Fixup exception task descriptor and task-state segment\r
//\r
AsmGetTssTemplateMap (&TemplateMap);\r
- StackTop = StackSwitchData->KnownGoodStackTop - CPU_STACK_ALIGNMENT;\r
+ StackTop = StackTop - CPU_STACK_ALIGNMENT;\r
StackTop = (UINTN)ALIGN_POINTER (StackTop, CPU_STACK_ALIGNMENT);\r
- IdtTable = StackSwitchData->IdtTable;\r
- for (Index = 0; Index < StackSwitchData->StackSwitchExceptionNumber; ++Index) {\r
+ IdtTable = (IA32_IDT_GATE_DESCRIPTOR *)Idtr.Base;\r
+ for (Index = 0; Index < CPU_STACK_SWITCH_EXCEPTION_NUMBER; ++Index) {\r
TssDesc += 1;\r
Tss += 1;\r
\r
//\r
// Fixup TSS\r
//\r
- Vector = StackSwitchData->StackSwitchExceptions[Index];\r
+ Vector = StackSwitchExceptions[Index];\r
if ((Vector >= CPU_EXCEPTION_NUM) ||\r
(Vector >= (Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)))\r
{\r
Tss->FS = AsmReadFs ();\r
Tss->GS = AsmReadGs ();\r
\r
- StackTop -= StackSwitchData->KnownGoodStackSize;\r
+ StackTop -= CPU_KNOWN_GOOD_STACK_SIZE;\r
\r
//\r
// Update IDT to use Task Gate for given exception\r
//\r
// Load current task\r
//\r
- AsmWriteTr ((UINT16)((UINTN)StackSwitchData->ExceptionTssDesc - Gdtr.Base));\r
-\r
- //\r
- // Publish IDT\r
- //\r
- AsmWriteIdtr (&Idtr);\r
+ AsmWriteTr ((UINT16)((UINTN)TssDescBase - Gdtr.Base));\r
\r
return EFI_SUCCESS;\r
}\r
IN OUT UINTN *BufferSize\r
)\r
{\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
- 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.KnownGoodStackTop = StackTop;\r
- EssData.KnownGoodStackSize = CPU_KNOWN_GOOD_STACK_SIZE;\r
- EssData.StackSwitchExceptions = CPU_STACK_SWITCH_EXCEPTION_LIST;\r
- EssData.StackSwitchExceptionNumber = CPU_STACK_SWITCH_EXCEPTION_NUMBER;\r
- EssData.IdtTable = (VOID *)Idtr.Base;\r
- EssData.IdtTableSize = Idtr.Limit + 1;\r
- EssData.GdtTable = NewGdtTable;\r
- EssData.GdtTableSize = CPU_TSS_DESC_SIZE + Gdtr.Limit + 1;\r
- EssData.ExceptionTssDesc = NewGdtTable + Gdtr.Limit + 1;\r
- EssData.ExceptionTssDescSize = CPU_TSS_DESC_SIZE;\r
- EssData.ExceptionTss = NewGdtTable + Gdtr.Limit + 1 + CPU_TSS_DESC_SIZE;\r
- EssData.ExceptionTssSize = CPU_TSS_SIZE;\r
-\r
- return ArchSetupExceptionStack (&EssData);\r
+ return ArchSetupExceptionStack (Buffer, BufferSize);\r
}\r
## @file\r
# CPU Exception Handler library instance for SEC/PEI modules.\r
#\r
-# Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>\r
+# Copyright (c) 2012 - 2022, Intel Corporation. All rights reserved.<BR>\r
# SPDX-License-Identifier: BSD-2-Clause-Patent\r
#\r
##\r
PeCoffGetEntryPointLib\r
VmgExitLib\r
\r
+[Pcd]\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard\r
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList\r
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize\r
+\r
[FeaturePcd]\r
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard ## CONSUMES\r
\r
## @file\r
# CPU Exception Handler library instance for SMM modules.\r
#\r
-# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>\r
+# Copyright (c) 2013 - 2022, Intel Corporation. All rights reserved.<BR>\r
# SPDX-License-Identifier: BSD-2-Clause-Patent\r
#\r
##\r
DebugLib\r
VmgExitLib\r
\r
+[Pcd]\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard\r
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList\r
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize\r
+\r
[FeaturePcd]\r
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard ## CONSUMES\r
\r
}\r
\r
/**\r
- Setup separate stack for given exceptions.\r
+ Setup separate stacks for certain exception handlers.\r
\r
- @param[in] StackSwitchData Pointer to data required for setuping up\r
- stack switch.\r
-\r
- @retval EFI_SUCCESS The exceptions have been successfully\r
- initialized with new stack.\r
- @retval EFI_INVALID_PARAMETER StackSwitchData contains invalid content.\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_BUFFER_TOO_SMALL This BufferSize is too small.\r
+ @retval EFI_UNSUPPORTED This function is not supported.\r
**/\r
EFI_STATUS\r
ArchSetupExceptionStack (\r
- IN CPU_EXCEPTION_INIT_DATA *StackSwitchData\r
+ IN VOID *Buffer,\r
+ IN OUT UINTN *BufferSize\r
)\r
{\r
IA32_DESCRIPTOR Gdtr;\r
IA32_IDT_GATE_DESCRIPTOR *IdtTable;\r
IA32_TSS_DESCRIPTOR *TssDesc;\r
IA32_TASK_STATE_SEGMENT *Tss;\r
+ VOID *NewGdtTable;\r
UINTN StackTop;\r
UINTN Index;\r
UINTN Vector;\r
UINTN TssBase;\r
- UINTN GdtSize;\r
-\r
- if ((StackSwitchData == NULL) ||\r
- (StackSwitchData->KnownGoodStackTop == 0) ||\r
- (StackSwitchData->KnownGoodStackSize == 0) ||\r
- (StackSwitchData->StackSwitchExceptions == NULL) ||\r
- (StackSwitchData->StackSwitchExceptionNumber == 0) ||\r
- (StackSwitchData->StackSwitchExceptionNumber > CPU_EXCEPTION_NUM) ||\r
- (StackSwitchData->GdtTable == NULL) ||\r
- (StackSwitchData->IdtTable == NULL) ||\r
- (StackSwitchData->ExceptionTssDesc == NULL) ||\r
- (StackSwitchData->ExceptionTss == NULL))\r
- {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // The caller is responsible for that the GDT table, no matter the existing\r
- // one or newly allocated, has enough space to hold descriptors for exception\r
- // task-state segments.\r
- //\r
- if (((UINTN)StackSwitchData->GdtTable & (IA32_GDT_ALIGNMENT - 1)) != 0) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if ((UINTN)StackSwitchData->ExceptionTssDesc < (UINTN)(StackSwitchData->GdtTable)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if (((UINTN)StackSwitchData->ExceptionTssDesc + StackSwitchData->ExceptionTssDescSize) >\r
- ((UINTN)(StackSwitchData->GdtTable) + StackSwitchData->GdtTableSize))\r
- {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
+ UINT8 *StackSwitchExceptions;\r
+ UINTN NeedBufferSize;\r
\r
- //\r
- // One task gate descriptor and one task-state segment are needed.\r
- //\r
- if (StackSwitchData->ExceptionTssDescSize < sizeof (IA32_TSS_DESCRIPTOR)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if (StackSwitchData->ExceptionTssSize < sizeof (IA32_TASK_STATE_SEGMENT)) {\r
+ if (BufferSize == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
//\r
// Interrupt stack table supports only 7 vectors.\r
//\r
- TssDesc = StackSwitchData->ExceptionTssDesc;\r
- Tss = StackSwitchData->ExceptionTss;\r
- if (StackSwitchData->StackSwitchExceptionNumber > ARRAY_SIZE (Tss->IST)) {\r
- return EFI_INVALID_PARAMETER;\r
+ if (CPU_STACK_SWITCH_EXCEPTION_NUMBER > ARRAY_SIZE (Tss->IST)) {\r
+ return EFI_UNSUPPORTED;\r
}\r
\r
//\r
- // Initialize new GDT table and/or IDT table, if any\r
+ // Total needed size includes stack size, new GDT table size, TSS size.\r
+ // Add another DESCRIPTOR size for alignment requiremet.\r
+ //\r
+ // Layout of memory needed for each processor:\r
+ // --------------------------------\r
+ // | |\r
+ // | Stack Size | X ExceptionNumber\r
+ // | |\r
+ // --------------------------------\r
+ // | Alignment | (just in case)\r
+ // --------------------------------\r
+ // | |\r
+ // | Original GDT |\r
+ // | |\r
+ // --------------------------------\r
+ // | |\r
+ // | Exception task descriptors | X 1\r
+ // | |\r
+ // --------------------------------\r
+ // | |\r
+ // | Exception task-state segment | X 1\r
+ // | |\r
+ // --------------------------------\r
//\r
- AsmReadIdtr (&Idtr);\r
AsmReadGdtr (&Gdtr);\r
-\r
- GdtSize = (UINTN)TssDesc + sizeof (IA32_TSS_DESCRIPTOR) -\r
- (UINTN)(StackSwitchData->GdtTable);\r
- if ((UINTN)StackSwitchData->GdtTable != Gdtr.Base) {\r
- CopyMem (StackSwitchData->GdtTable, (VOID *)Gdtr.Base, Gdtr.Limit + 1);\r
- Gdtr.Base = (UINTN)StackSwitchData->GdtTable;\r
- Gdtr.Limit = (UINT16)GdtSize - 1;\r
+ NeedBufferSize = CPU_STACK_SWITCH_EXCEPTION_NUMBER * CPU_KNOWN_GOOD_STACK_SIZE +\r
+ sizeof (IA32_TSS_DESCRIPTOR) +\r
+ Gdtr.Limit + 1 + CPU_TSS_DESC_SIZE +\r
+ CPU_TSS_SIZE;\r
+\r
+ if (*BufferSize < NeedBufferSize) {\r
+ *BufferSize = NeedBufferSize;\r
+ return EFI_BUFFER_TOO_SMALL;\r
}\r
\r
- if ((UINTN)StackSwitchData->IdtTable != Idtr.Base) {\r
- Idtr.Base = (UINTN)StackSwitchData->IdtTable;\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
}\r
\r
- if (StackSwitchData->IdtTableSize > 0) {\r
- Idtr.Limit = (UINT16)(StackSwitchData->IdtTableSize - 1);\r
- }\r
+ AsmReadIdtr (&Idtr);\r
+ StackSwitchExceptions = CPU_STACK_SWITCH_EXCEPTION_LIST;\r
+ StackTop = (UINTN)Buffer + CPU_STACK_SWITCH_EXCEPTION_NUMBER * CPU_KNOWN_GOOD_STACK_SIZE;\r
+ NewGdtTable = ALIGN_POINTER (StackTop, sizeof (IA32_TSS_DESCRIPTOR));\r
+ TssDesc = (IA32_TSS_DESCRIPTOR *)((UINTN)NewGdtTable + Gdtr.Limit + 1);\r
+ Tss = (IA32_TASK_STATE_SEGMENT *)((UINTN)TssDesc + CPU_TSS_DESC_SIZE);\r
+\r
+ CopyMem (NewGdtTable, (VOID *)Gdtr.Base, Gdtr.Limit + 1);\r
+ Gdtr.Base = (UINTN)NewGdtTable;\r
+ Gdtr.Limit = (UINT16)(Gdtr.Limit + CPU_TSS_DESC_SIZE);\r
\r
//\r
// Fixup current task descriptor. Task-state segment for current task will\r
// Fixup exception task descriptor and task-state segment\r
//\r
ZeroMem (Tss, sizeof (*Tss));\r
- StackTop = StackSwitchData->KnownGoodStackTop - CPU_STACK_ALIGNMENT;\r
+ StackTop = StackTop - CPU_STACK_ALIGNMENT;\r
StackTop = (UINTN)ALIGN_POINTER (StackTop, CPU_STACK_ALIGNMENT);\r
- IdtTable = StackSwitchData->IdtTable;\r
- for (Index = 0; Index < StackSwitchData->StackSwitchExceptionNumber; ++Index) {\r
+ IdtTable = (IA32_IDT_GATE_DESCRIPTOR *)Idtr.Base;\r
+ for (Index = 0; Index < CPU_STACK_SWITCH_EXCEPTION_NUMBER; ++Index) {\r
//\r
// Fixup IST\r
//\r
Tss->IST[Index] = StackTop;\r
- StackTop -= StackSwitchData->KnownGoodStackSize;\r
+ StackTop -= CPU_KNOWN_GOOD_STACK_SIZE;\r
\r
//\r
// Set the IST field to enable corresponding IST\r
//\r
- Vector = StackSwitchData->StackSwitchExceptions[Index];\r
+ Vector = StackSwitchExceptions[Index];\r
if ((Vector >= CPU_EXCEPTION_NUM) ||\r
(Vector >= (Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)))\r
{\r
//\r
// Load current task\r
//\r
- AsmWriteTr ((UINT16)((UINTN)StackSwitchData->ExceptionTssDesc - Gdtr.Base));\r
-\r
- //\r
- // Publish IDT\r
- //\r
- AsmWriteIdtr (&Idtr);\r
+ AsmWriteTr ((UINT16)((UINTN)TssDesc - Gdtr.Base));\r
\r
return EFI_SUCCESS;\r
}\r
# CPU Exception Handler library instance for SEC/PEI modules.\r
#\r
# Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>\r
-# Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>\r
+# Copyright (c) 2012 - 2022, Intel Corporation. All rights reserved.<BR>\r
# SPDX-License-Identifier: BSD-2-Clause-Patent\r
#\r
# This is the XCODE5 variant of the SEC/PEI CpuExceptionHandlerLib. This\r
PeCoffGetEntryPointLib\r
VmgExitLib\r
\r
+[Pcd]\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard\r
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList\r
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize\r
+\r
[FeaturePcd]\r
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard ## CONSUMES\r
\r