summaryrefslogtreecommitdiffstats
path: root/UefiCpuPkg/Library
diff options
context:
space:
mode:
authorLiu, Zhiguang <Zhiguang.Liu@intel.com>2022-08-09 09:25:35 +0800
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2022-08-09 04:12:28 +0000
commit0f7bccf584d93b2642c0a413a47fc821d1f5dbfd (patch)
tree7a00d3cc937a3e676f9aeedb61ff500fa20213ad /UefiCpuPkg/Library
parent1da2012d938f141821740324e2dceee1b4cfa76d (diff)
downloadedk2-0f7bccf584d93b2642c0a413a47fc821d1f5dbfd.tar.gz
edk2-0f7bccf584d93b2642c0a413a47fc821d1f5dbfd.tar.bz2
edk2-0f7bccf584d93b2642c0a413a47fc821d1f5dbfd.zip
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>
Diffstat (limited to 'UefiCpuPkg/Library')
-rw-r--r--UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeException.c113
-rw-r--r--UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuException.c95
-rw-r--r--UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf4
-rw-r--r--UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c15
-rw-r--r--UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmException.c15
5 files changed, 193 insertions, 49 deletions
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeException.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeException.c
index e62bb5e6c0..04e8409922 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeException.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeException.c
@@ -104,48 +104,105 @@ RegisterCpuInterruptHandler (
/**
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
)
{
CPU_EXCEPTION_INIT_DATA EssData;
IA32_DESCRIPTOR Idtr;
IA32_DESCRIPTOR Gdtr;
-
- if (InitData == NULL) {
+ 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
+ // | |
+ // --------------------------------
+ //
+ AsmReadGdtr (&Gdtr);
+ if ((Buffer == NULL) && (BufferSize == NULL)) {
SetMem (mNewGdt, sizeof (mNewGdt), 0);
-
- AsmReadIdtr (&Idtr);
- AsmReadGdtr (&Gdtr);
-
- EssData.X64.Revision = CPU_EXCEPTION_INIT_DATA_REV;
- EssData.X64.KnownGoodStackTop = (UINTN)mNewStack + sizeof (mNewStack);
- 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 = mNewGdt;
- EssData.X64.GdtTableSize = sizeof (mNewGdt);
- EssData.X64.ExceptionTssDesc = mNewGdt + Gdtr.Limit + 1;
- EssData.X64.ExceptionTssDescSize = CPU_TSS_DESC_SIZE;
- EssData.X64.ExceptionTss = mNewGdt + Gdtr.Limit + 1 + CPU_TSS_DESC_SIZE;
- EssData.X64.ExceptionTssSize = CPU_TSS_SIZE;
-
- InitData = &EssData;
+ StackTop = (UINTN)mNewStack + sizeof (mNewStack);
+ NewGdtTable = mNewGdt;
+ } else {
+ if (BufferSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // 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));
}
- return ArchSetupExceptionStack (InitData);
+ 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);
}
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuException.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuException.c
index 494c2ab433..52ec0fb803 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuException.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuException.c
@@ -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);
}
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
index cf5bfe4083..7c2ec3b2db 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
@@ -1,7 +1,7 @@
## @file
# CPU Exception Handler library instance for PEI module.
#
-# Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2016 - 2022, Intel Corporation. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
##
@@ -56,6 +56,8 @@
[Pcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard # CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList
[FeaturePcd]
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard ## CONSUMES
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c
index 4313cc5582..ad5e0e9ed4 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c
@@ -201,20 +201,23 @@ RegisterCpuInterruptHandler (
/**
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
)
{
return EFI_UNSUPPORTED;
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmException.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmException.c
index 1c97dab926..46a86ad2c6 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmException.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmException.c
@@ -97,20 +97,23 @@ RegisterCpuInterruptHandler (
/**
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
)
{
return EFI_UNSUPPORTED;