UefiCpuPkg: Simplify InitializeSeparateExceptionStacks

Hide the Exception implementation details in CpuExcetionHandlerLib and
caller only need to provide buffer

Cc: Eric Dong <eric.dong@intel.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Dandan Bi <dandan.bi@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Reviewed-by: Sami Mujawar <sami.mujawar@arm.com>
Signed-off-by: Zhiguang Liu <zhiguang.liu@intel.com>
This commit is contained in:
Liu, Zhiguang
2022-08-09 09:25:35 +08:00
committed by mergify[bot]
parent 1da2012d93
commit 0f7bccf584
11 changed files with 285 additions and 336 deletions

View File

@ -151,25 +151,104 @@ InitializeCpuExceptionHandlers (
/**
Setup separate stacks for certain exception handlers.
If the input Buffer and BufferSize are both NULL, use global variable if possible.
InitData is optional and processor arch dependent.
@param[in] InitData Pointer to data optional for information about how
to assign stacks for certain exception handlers.
@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_UNSUPPORTED This function is not supported.
@retval EFI_BUFFER_TOO_SMALL This BufferSize is too small.
**/
EFI_STATUS
EFIAPI
InitializeSeparateExceptionStacks (
IN CPU_EXCEPTION_INIT_DATA *InitData OPTIONAL
IN VOID *Buffer,
IN OUT UINTN *BufferSize
)
{
if (InitData == NULL) {
CPU_EXCEPTION_INIT_DATA EssData;
IA32_DESCRIPTOR Idtr;
IA32_DESCRIPTOR Gdtr;
UINTN NeedBufferSize;
UINTN StackTop;
UINT8 *NewGdtTable;
//
// X64 needs only one TSS of current task working for all exceptions
// because of its IST feature. IA32 needs one TSS for each exception
// in addition to current task. To simplify the code, we report the
// needed memory for IA32 case to cover both IA32 and X64 exception
// stack switch.
//
// Layout of memory needed for each processor:
// --------------------------------
// | Alignment | (just in case)
// --------------------------------
// | |
// | Original GDT |
// | |
// --------------------------------
// | Current task descriptor |
// --------------------------------
// | |
// | Exception task descriptors | X ExceptionNumber
// | |
// --------------------------------
// | Current task-state segment |
// --------------------------------
// | |
// | Exception task-state segment | X ExceptionNumber
// | |
// --------------------------------
//
if ((Buffer == NULL) && (BufferSize == NULL)) {
return EFI_UNSUPPORTED;
}
return ArchSetupExceptionStack (InitData);
if (BufferSize == NULL) {
return EFI_INVALID_PARAMETER;
}
AsmReadGdtr (&Gdtr);
//
// Total needed size includes stack size, new GDT table size, TSS size.
// Add another DESCRIPTOR size for alignment requiremet.
//
NeedBufferSize = CPU_STACK_SWITCH_EXCEPTION_NUMBER * CPU_KNOWN_GOOD_STACK_SIZE +
CPU_TSS_DESC_SIZE + Gdtr.Limit + 1 +
CPU_TSS_SIZE +
sizeof (IA32_TSS_DESCRIPTOR);
if (*BufferSize < NeedBufferSize) {
*BufferSize = NeedBufferSize;
return EFI_BUFFER_TOO_SMALL;
}
if (Buffer == NULL) {
return EFI_INVALID_PARAMETER;
}
StackTop = (UINTN)Buffer + CPU_STACK_SWITCH_EXCEPTION_NUMBER * CPU_KNOWN_GOOD_STACK_SIZE;
NewGdtTable = ALIGN_POINTER (StackTop, sizeof (IA32_TSS_DESCRIPTOR));
AsmReadIdtr (&Idtr);
EssData.X64.Revision = CPU_EXCEPTION_INIT_DATA_REV;
EssData.X64.KnownGoodStackTop = StackTop;
EssData.X64.KnownGoodStackSize = CPU_KNOWN_GOOD_STACK_SIZE;
EssData.X64.StackSwitchExceptions = CPU_STACK_SWITCH_EXCEPTION_LIST;
EssData.X64.StackSwitchExceptionNumber = CPU_STACK_SWITCH_EXCEPTION_NUMBER;
EssData.X64.IdtTable = (VOID *)Idtr.Base;
EssData.X64.IdtTableSize = Idtr.Limit + 1;
EssData.X64.GdtTable = NewGdtTable;
EssData.X64.GdtTableSize = CPU_TSS_DESC_SIZE + Gdtr.Limit + 1;
EssData.X64.ExceptionTssDesc = NewGdtTable + Gdtr.Limit + 1;
EssData.X64.ExceptionTssDescSize = CPU_TSS_DESC_SIZE;
EssData.X64.ExceptionTss = NewGdtTable + Gdtr.Limit + 1 + CPU_TSS_DESC_SIZE;
EssData.X64.ExceptionTssSize = CPU_TSS_SIZE;
return ArchSetupExceptionStack (&EssData);
}