UefiCpuPkg: Simplify the implementation when separate exception stacks

The API of InitializeSeparateExceptionStacks is just changed before, and
makes the struct CPU_EXCEPTION_INIT_DATA an internal definition.
Furthermore, we can even remove the struct to make core simpler.

Cc: Eric Dong <eric.dong@intel.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Signed-off-by: Zhiguang Liu <zhiguang.liu@intel.com>
This commit is contained in:
Liu, Zhiguang
2022-08-26 15:04:47 +08:00
committed by mergify[bot]
parent d1abb876f4
commit 76cf3d35e6
8 changed files with 177 additions and 387 deletions

View File

@ -109,19 +109,22 @@ ArchRestoreExceptionContext (
}
/**
Setup separate stack for given exceptions.
Setup separate stacks for certain exception handlers.
@param[in] StackSwitchData Pointer to data required for setuping up
stack switch.
@retval EFI_SUCCESS The exceptions have been successfully
initialized with new stack.
@retval EFI_INVALID_PARAMETER StackSwitchData contains invalid content.
@param[in] Buffer Point to buffer used to separate exception stack.
@param[in, out] BufferSize On input, it indicates the byte size of Buffer.
If the size is not enough, the return status will
be EFI_BUFFER_TOO_SMALL, and output BufferSize
will be the size it needs.
@retval EFI_SUCCESS The stacks are assigned successfully.
@retval EFI_BUFFER_TOO_SMALL This BufferSize is too small.
@retval EFI_UNSUPPORTED This function is not supported.
**/
EFI_STATUS
ArchSetupExceptionStack (
IN CPU_EXCEPTION_INIT_DATA *StackSwitchData
IN VOID *Buffer,
IN OUT UINTN *BufferSize
)
{
IA32_DESCRIPTOR Gdtr;
@ -129,86 +132,75 @@ ArchSetupExceptionStack (
IA32_IDT_GATE_DESCRIPTOR *IdtTable;
IA32_TSS_DESCRIPTOR *TssDesc;
IA32_TASK_STATE_SEGMENT *Tss;
VOID *NewGdtTable;
UINTN StackTop;
UINTN Index;
UINTN Vector;
UINTN TssBase;
UINTN GdtSize;
UINT8 *StackSwitchExceptions;
UINTN NeedBufferSize;
if ((StackSwitchData == NULL) ||
(StackSwitchData->KnownGoodStackTop == 0) ||
(StackSwitchData->KnownGoodStackSize == 0) ||
(StackSwitchData->StackSwitchExceptions == NULL) ||
(StackSwitchData->StackSwitchExceptionNumber == 0) ||
(StackSwitchData->StackSwitchExceptionNumber > CPU_EXCEPTION_NUM) ||
(StackSwitchData->GdtTable == NULL) ||
(StackSwitchData->IdtTable == NULL) ||
(StackSwitchData->ExceptionTssDesc == NULL) ||
(StackSwitchData->ExceptionTss == NULL))
{
return EFI_INVALID_PARAMETER;
}
//
// The caller is responsible for that the GDT table, no matter the existing
// one or newly allocated, has enough space to hold descriptors for exception
// task-state segments.
//
if (((UINTN)StackSwitchData->GdtTable & (IA32_GDT_ALIGNMENT - 1)) != 0) {
return EFI_INVALID_PARAMETER;
}
if ((UINTN)StackSwitchData->ExceptionTssDesc < (UINTN)(StackSwitchData->GdtTable)) {
return EFI_INVALID_PARAMETER;
}
if (((UINTN)StackSwitchData->ExceptionTssDesc + StackSwitchData->ExceptionTssDescSize) >
((UINTN)(StackSwitchData->GdtTable) + StackSwitchData->GdtTableSize))
{
return EFI_INVALID_PARAMETER;
}
//
// One task gate descriptor and one task-state segment are needed.
//
if (StackSwitchData->ExceptionTssDescSize < sizeof (IA32_TSS_DESCRIPTOR)) {
return EFI_INVALID_PARAMETER;
}
if (StackSwitchData->ExceptionTssSize < sizeof (IA32_TASK_STATE_SEGMENT)) {
if (BufferSize == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Interrupt stack table supports only 7 vectors.
//
TssDesc = StackSwitchData->ExceptionTssDesc;
Tss = StackSwitchData->ExceptionTss;
if (StackSwitchData->StackSwitchExceptionNumber > ARRAY_SIZE (Tss->IST)) {
if (CPU_STACK_SWITCH_EXCEPTION_NUMBER > ARRAY_SIZE (Tss->IST)) {
return EFI_UNSUPPORTED;
}
//
// Total needed size includes stack size, new GDT table size, TSS size.
// Add another DESCRIPTOR size for alignment requiremet.
//
// Layout of memory needed for each processor:
// --------------------------------
// | |
// | Stack Size | X ExceptionNumber
// | |
// --------------------------------
// | Alignment | (just in case)
// --------------------------------
// | |
// | Original GDT |
// | |
// --------------------------------
// | |
// | Exception task descriptors | X 1
// | |
// --------------------------------
// | |
// | Exception task-state segment | X 1
// | |
// --------------------------------
//
AsmReadGdtr (&Gdtr);
NeedBufferSize = CPU_STACK_SWITCH_EXCEPTION_NUMBER * CPU_KNOWN_GOOD_STACK_SIZE +
sizeof (IA32_TSS_DESCRIPTOR) +
Gdtr.Limit + 1 + CPU_TSS_DESC_SIZE +
CPU_TSS_SIZE;
if (*BufferSize < NeedBufferSize) {
*BufferSize = NeedBufferSize;
return EFI_BUFFER_TOO_SMALL;
}
if (Buffer == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Initialize new GDT table and/or IDT table, if any
//
AsmReadIdtr (&Idtr);
AsmReadGdtr (&Gdtr);
StackSwitchExceptions = CPU_STACK_SWITCH_EXCEPTION_LIST;
StackTop = (UINTN)Buffer + CPU_STACK_SWITCH_EXCEPTION_NUMBER * CPU_KNOWN_GOOD_STACK_SIZE;
NewGdtTable = ALIGN_POINTER (StackTop, sizeof (IA32_TSS_DESCRIPTOR));
TssDesc = (IA32_TSS_DESCRIPTOR *)((UINTN)NewGdtTable + Gdtr.Limit + 1);
Tss = (IA32_TASK_STATE_SEGMENT *)((UINTN)TssDesc + CPU_TSS_DESC_SIZE);
GdtSize = (UINTN)TssDesc + sizeof (IA32_TSS_DESCRIPTOR) -
(UINTN)(StackSwitchData->GdtTable);
if ((UINTN)StackSwitchData->GdtTable != Gdtr.Base) {
CopyMem (StackSwitchData->GdtTable, (VOID *)Gdtr.Base, Gdtr.Limit + 1);
Gdtr.Base = (UINTN)StackSwitchData->GdtTable;
Gdtr.Limit = (UINT16)GdtSize - 1;
}
if ((UINTN)StackSwitchData->IdtTable != Idtr.Base) {
Idtr.Base = (UINTN)StackSwitchData->IdtTable;
}
if (StackSwitchData->IdtTableSize > 0) {
Idtr.Limit = (UINT16)(StackSwitchData->IdtTableSize - 1);
}
CopyMem (NewGdtTable, (VOID *)Gdtr.Base, Gdtr.Limit + 1);
Gdtr.Base = (UINTN)NewGdtTable;
Gdtr.Limit = (UINT16)(Gdtr.Limit + CPU_TSS_DESC_SIZE);
//
// Fixup current task descriptor. Task-state segment for current task will
@ -231,20 +223,20 @@ ArchSetupExceptionStack (
// Fixup exception task descriptor and task-state segment
//
ZeroMem (Tss, sizeof (*Tss));
StackTop = StackSwitchData->KnownGoodStackTop - CPU_STACK_ALIGNMENT;
StackTop = StackTop - CPU_STACK_ALIGNMENT;
StackTop = (UINTN)ALIGN_POINTER (StackTop, CPU_STACK_ALIGNMENT);
IdtTable = StackSwitchData->IdtTable;
for (Index = 0; Index < StackSwitchData->StackSwitchExceptionNumber; ++Index) {
IdtTable = (IA32_IDT_GATE_DESCRIPTOR *)Idtr.Base;
for (Index = 0; Index < CPU_STACK_SWITCH_EXCEPTION_NUMBER; ++Index) {
//
// Fixup IST
//
Tss->IST[Index] = StackTop;
StackTop -= StackSwitchData->KnownGoodStackSize;
StackTop -= CPU_KNOWN_GOOD_STACK_SIZE;
//
// Set the IST field to enable corresponding IST
//
Vector = StackSwitchData->StackSwitchExceptions[Index];
Vector = StackSwitchExceptions[Index];
if ((Vector >= CPU_EXCEPTION_NUM) ||
(Vector >= (Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)))
{
@ -262,12 +254,7 @@ ArchSetupExceptionStack (
//
// Load current task
//
AsmWriteTr ((UINT16)((UINTN)StackSwitchData->ExceptionTssDesc - Gdtr.Base));
//
// Publish IDT
//
AsmWriteIdtr (&Idtr);
AsmWriteTr ((UINT16)((UINTN)TssDesc - Gdtr.Base));
return EFI_SUCCESS;
}