mirror of https://github.com/acidanthera/audk.git
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:
parent
d1abb876f4
commit
76cf3d35e6
|
@ -49,61 +49,6 @@
|
||||||
|
|
||||||
#define CPU_TSS_GDT_SIZE (SIZE_2KB + CPU_TSS_DESC_SIZE + CPU_TSS_SIZE)
|
#define CPU_TSS_GDT_SIZE (SIZE_2KB + CPU_TSS_DESC_SIZE + CPU_TSS_SIZE)
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
//
|
|
||||||
// The address of top of known good stack reserved for *ALL* exceptions
|
|
||||||
// listed in field StackSwitchExceptions.
|
|
||||||
//
|
|
||||||
UINTN KnownGoodStackTop;
|
|
||||||
//
|
|
||||||
// The size of known good stack for *ONE* exception only.
|
|
||||||
//
|
|
||||||
UINTN KnownGoodStackSize;
|
|
||||||
//
|
|
||||||
// Buffer of exception vector list for stack switch.
|
|
||||||
//
|
|
||||||
UINT8 *StackSwitchExceptions;
|
|
||||||
//
|
|
||||||
// Number of exception vectors in StackSwitchExceptions.
|
|
||||||
//
|
|
||||||
UINTN StackSwitchExceptionNumber;
|
|
||||||
//
|
|
||||||
// Buffer of IDT table. It must be type of IA32_IDT_GATE_DESCRIPTOR.
|
|
||||||
// Normally there's no need to change IDT table size.
|
|
||||||
//
|
|
||||||
VOID *IdtTable;
|
|
||||||
//
|
|
||||||
// Size of buffer for IdtTable.
|
|
||||||
//
|
|
||||||
UINTN IdtTableSize;
|
|
||||||
//
|
|
||||||
// Buffer of GDT table. It must be type of IA32_SEGMENT_DESCRIPTOR.
|
|
||||||
//
|
|
||||||
VOID *GdtTable;
|
|
||||||
//
|
|
||||||
// Size of buffer for GdtTable.
|
|
||||||
//
|
|
||||||
UINTN GdtTableSize;
|
|
||||||
//
|
|
||||||
// Pointer to start address of descriptor of exception task gate in the
|
|
||||||
// GDT table. It must be type of IA32_TSS_DESCRIPTOR.
|
|
||||||
//
|
|
||||||
VOID *ExceptionTssDesc;
|
|
||||||
//
|
|
||||||
// Size of buffer for ExceptionTssDesc.
|
|
||||||
//
|
|
||||||
UINTN ExceptionTssDescSize;
|
|
||||||
//
|
|
||||||
// Buffer of task-state segment for exceptions. It must be type of
|
|
||||||
// IA32_TASK_STATE_SEGMENT.
|
|
||||||
//
|
|
||||||
VOID *ExceptionTss;
|
|
||||||
//
|
|
||||||
// Size of buffer for ExceptionTss.
|
|
||||||
//
|
|
||||||
UINTN ExceptionTssSize;
|
|
||||||
} CPU_EXCEPTION_INIT_DATA;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Record exception handler information
|
// Record exception handler information
|
||||||
//
|
//
|
||||||
|
@ -345,18 +290,22 @@ CommonExceptionHandlerWorker (
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Setup separate stack for specific exceptions.
|
Setup separate stacks for certain exception handlers.
|
||||||
|
|
||||||
@param[in] StackSwitchData Pointer to data required for setuping up
|
@param[in] Buffer Point to buffer used to separate exception stack.
|
||||||
stack switch.
|
@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 exceptions have been successfully
|
@retval EFI_SUCCESS The stacks are assigned successfully.
|
||||||
initialized with new stack.
|
@retval EFI_BUFFER_TOO_SMALL This BufferSize is too small.
|
||||||
@retval EFI_INVALID_PARAMETER StackSwitchData contains invalid content.
|
@retval EFI_UNSUPPORTED This function is not supported.
|
||||||
**/
|
**/
|
||||||
EFI_STATUS
|
EFI_STATUS
|
||||||
ArchSetupExceptionStack (
|
ArchSetupExceptionStack (
|
||||||
IN CPU_EXCEPTION_INIT_DATA *StackSwitchData
|
IN VOID *Buffer,
|
||||||
|
IN OUT UINTN *BufferSize
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -23,9 +23,8 @@ EXCEPTION_HANDLER_DATA mExceptionHandlerData = {
|
||||||
mExternalInterruptHandlerTable
|
mExternalInterruptHandlerTable
|
||||||
};
|
};
|
||||||
|
|
||||||
UINT8 mNewStack[CPU_STACK_SWITCH_EXCEPTION_NUMBER *
|
UINT8 mBuffer[CPU_STACK_SWITCH_EXCEPTION_NUMBER * CPU_KNOWN_GOOD_STACK_SIZE
|
||||||
CPU_KNOWN_GOOD_STACK_SIZE];
|
+ CPU_TSS_GDT_SIZE];
|
||||||
UINT8 mNewGdt[CPU_TSS_GDT_SIZE];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Common exception handler.
|
Common exception handler.
|
||||||
|
@ -123,85 +122,16 @@ InitializeSeparateExceptionStacks (
|
||||||
IN OUT UINTN *BufferSize
|
IN OUT UINTN *BufferSize
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
CPU_EXCEPTION_INIT_DATA EssData;
|
UINTN LocalBufferSize;
|
||||||
IA32_DESCRIPTOR Idtr;
|
EFI_STATUS Status;
|
||||||
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
|
|
||||||
// | |
|
|
||||||
// --------------------------------
|
|
||||||
//
|
|
||||||
AsmReadGdtr (&Gdtr);
|
|
||||||
if ((Buffer == NULL) && (BufferSize == NULL)) {
|
if ((Buffer == NULL) && (BufferSize == NULL)) {
|
||||||
SetMem (mNewGdt, sizeof (mNewGdt), 0);
|
SetMem (mBuffer, sizeof (mBuffer), 0);
|
||||||
StackTop = (UINTN)mNewStack + sizeof (mNewStack);
|
LocalBufferSize = sizeof (mBuffer);
|
||||||
NewGdtTable = mNewGdt;
|
Status = ArchSetupExceptionStack (mBuffer, &LocalBufferSize);
|
||||||
|
ASSERT_EFI_ERROR (Status);
|
||||||
|
return Status;
|
||||||
} else {
|
} else {
|
||||||
if (BufferSize == NULL) {
|
return ArchSetupExceptionStack (Buffer, BufferSize);
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AsmReadIdtr (&Idtr);
|
|
||||||
EssData.KnownGoodStackTop = StackTop;
|
|
||||||
EssData.KnownGoodStackSize = CPU_KNOWN_GOOD_STACK_SIZE;
|
|
||||||
EssData.StackSwitchExceptions = CPU_STACK_SWITCH_EXCEPTION_LIST;
|
|
||||||
EssData.StackSwitchExceptionNumber = CPU_STACK_SWITCH_EXCEPTION_NUMBER;
|
|
||||||
EssData.IdtTable = (VOID *)Idtr.Base;
|
|
||||||
EssData.IdtTableSize = Idtr.Limit + 1;
|
|
||||||
EssData.GdtTable = NewGdtTable;
|
|
||||||
EssData.GdtTableSize = CPU_TSS_DESC_SIZE + Gdtr.Limit + 1;
|
|
||||||
EssData.ExceptionTssDesc = NewGdtTable + Gdtr.Limit + 1;
|
|
||||||
EssData.ExceptionTssDescSize = CPU_TSS_DESC_SIZE;
|
|
||||||
EssData.ExceptionTss = NewGdtTable + Gdtr.Limit + 1 + CPU_TSS_DESC_SIZE;
|
|
||||||
EssData.ExceptionTssSize = CPU_TSS_SIZE;
|
|
||||||
|
|
||||||
return ArchSetupExceptionStack (&EssData);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,108 +104,97 @@ ArchRestoreExceptionContext (
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Setup separate stack for given exceptions.
|
Setup separate stacks for certain exception handlers.
|
||||||
|
|
||||||
@param[in] StackSwitchData Pointer to data required for setuping up
|
@param[in] Buffer Point to buffer used to separate exception stack.
|
||||||
stack switch.
|
@param[in, out] BufferSize On input, it indicates the byte size of Buffer.
|
||||||
|
If the size is not enough, the return status will
|
||||||
@retval EFI_SUCCESS The exceptions have been successfully
|
be EFI_BUFFER_TOO_SMALL, and output BufferSize
|
||||||
initialized with new stack.
|
will be the size it needs.
|
||||||
@retval EFI_INVALID_PARAMETER StackSwitchData contains invalid content.
|
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS The stacks are assigned successfully.
|
||||||
|
@retval EFI_BUFFER_TOO_SMALL This BufferSize is too small.
|
||||||
**/
|
**/
|
||||||
EFI_STATUS
|
EFI_STATUS
|
||||||
ArchSetupExceptionStack (
|
ArchSetupExceptionStack (
|
||||||
IN CPU_EXCEPTION_INIT_DATA *StackSwitchData
|
IN VOID *Buffer,
|
||||||
|
IN OUT UINTN *BufferSize
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
IA32_DESCRIPTOR Gdtr;
|
IA32_DESCRIPTOR Gdtr;
|
||||||
IA32_DESCRIPTOR Idtr;
|
IA32_DESCRIPTOR Idtr;
|
||||||
IA32_IDT_GATE_DESCRIPTOR *IdtTable;
|
IA32_IDT_GATE_DESCRIPTOR *IdtTable;
|
||||||
IA32_TSS_DESCRIPTOR *TssDesc;
|
IA32_TSS_DESCRIPTOR *TssDesc;
|
||||||
|
IA32_TSS_DESCRIPTOR *TssDescBase;
|
||||||
IA32_TASK_STATE_SEGMENT *Tss;
|
IA32_TASK_STATE_SEGMENT *Tss;
|
||||||
|
VOID *NewGdtTable;
|
||||||
UINTN StackTop;
|
UINTN StackTop;
|
||||||
UINTN Index;
|
UINTN Index;
|
||||||
UINTN Vector;
|
UINTN Vector;
|
||||||
UINTN TssBase;
|
UINTN TssBase;
|
||||||
UINTN GdtSize;
|
UINT8 *StackSwitchExceptions;
|
||||||
|
UINTN NeedBufferSize;
|
||||||
EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap;
|
EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap;
|
||||||
|
|
||||||
if ((StackSwitchData == NULL) ||
|
if (BufferSize == 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;
|
return EFI_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// The caller is responsible for that the GDT table, no matter the existing
|
// Total needed size includes stack size, new GDT table size, TSS size.
|
||||||
// one or newly allocated, has enough space to hold descriptors for exception
|
// Add another DESCRIPTOR size for alignment requiremet.
|
||||||
// task-state segments.
|
|
||||||
//
|
//
|
||||||
if (((UINTN)StackSwitchData->GdtTable & (IA32_GDT_ALIGNMENT - 1)) != 0) {
|
// Layout of memory needed for each processor:
|
||||||
return EFI_INVALID_PARAMETER;
|
// --------------------------------
|
||||||
}
|
// | |
|
||||||
|
// | Stack Size | X ExceptionNumber
|
||||||
if ((UINTN)StackSwitchData->ExceptionTssDesc < (UINTN)(StackSwitchData->GdtTable)) {
|
// | |
|
||||||
return EFI_INVALID_PARAMETER;
|
// --------------------------------
|
||||||
}
|
// | Alignment | (just in case)
|
||||||
|
// --------------------------------
|
||||||
if ((UINTN)StackSwitchData->ExceptionTssDesc + StackSwitchData->ExceptionTssDescSize >
|
// | |
|
||||||
((UINTN)(StackSwitchData->GdtTable) + StackSwitchData->GdtTableSize))
|
// | Original GDT |
|
||||||
{
|
// | |
|
||||||
return EFI_INVALID_PARAMETER;
|
// --------------------------------
|
||||||
}
|
// | Current task descriptor |
|
||||||
|
// --------------------------------
|
||||||
|
// | |
|
||||||
|
// | Exception task descriptors | X ExceptionNumber
|
||||||
|
// | |
|
||||||
|
// --------------------------------
|
||||||
|
// | Current task-state segment |
|
||||||
|
// --------------------------------
|
||||||
|
// | |
|
||||||
|
// | Exception task-state segment | X ExceptionNumber
|
||||||
|
// | |
|
||||||
|
// --------------------------------
|
||||||
//
|
//
|
||||||
// We need one descriptor and one TSS for current task and every exception
|
|
||||||
// specified.
|
|
||||||
//
|
|
||||||
if (StackSwitchData->ExceptionTssDescSize <
|
|
||||||
sizeof (IA32_TSS_DESCRIPTOR) * (StackSwitchData->StackSwitchExceptionNumber + 1))
|
|
||||||
{
|
|
||||||
return EFI_INVALID_PARAMETER;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StackSwitchData->ExceptionTssSize <
|
|
||||||
sizeof (IA32_TASK_STATE_SEGMENT) * (StackSwitchData->StackSwitchExceptionNumber + 1))
|
|
||||||
{
|
|
||||||
return EFI_INVALID_PARAMETER;
|
|
||||||
}
|
|
||||||
|
|
||||||
TssDesc = StackSwitchData->ExceptionTssDesc;
|
|
||||||
Tss = StackSwitchData->ExceptionTss;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Initialize new GDT table and/or IDT table, if any
|
|
||||||
//
|
|
||||||
AsmReadIdtr (&Idtr);
|
|
||||||
AsmReadGdtr (&Gdtr);
|
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;
|
||||||
|
|
||||||
GdtSize = (UINTN)TssDesc +
|
if (*BufferSize < NeedBufferSize) {
|
||||||
sizeof (IA32_TSS_DESCRIPTOR) *
|
*BufferSize = NeedBufferSize;
|
||||||
(StackSwitchData->StackSwitchExceptionNumber + 1) -
|
return EFI_BUFFER_TOO_SMALL;
|
||||||
(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) {
|
if (Buffer == NULL) {
|
||||||
Idtr.Base = (UINTN)StackSwitchData->IdtTable;
|
return EFI_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StackSwitchData->IdtTableSize > 0) {
|
AsmReadIdtr (&Idtr);
|
||||||
Idtr.Limit = (UINT16)(StackSwitchData->IdtTableSize - 1);
|
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);
|
||||||
|
TssDescBase = TssDesc;
|
||||||
|
|
||||||
|
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
|
// Fixup current task descriptor. Task-state segment for current task will
|
||||||
|
@ -226,10 +215,10 @@ ArchSetupExceptionStack (
|
||||||
// Fixup exception task descriptor and task-state segment
|
// Fixup exception task descriptor and task-state segment
|
||||||
//
|
//
|
||||||
AsmGetTssTemplateMap (&TemplateMap);
|
AsmGetTssTemplateMap (&TemplateMap);
|
||||||
StackTop = StackSwitchData->KnownGoodStackTop - CPU_STACK_ALIGNMENT;
|
StackTop = StackTop - CPU_STACK_ALIGNMENT;
|
||||||
StackTop = (UINTN)ALIGN_POINTER (StackTop, CPU_STACK_ALIGNMENT);
|
StackTop = (UINTN)ALIGN_POINTER (StackTop, CPU_STACK_ALIGNMENT);
|
||||||
IdtTable = StackSwitchData->IdtTable;
|
IdtTable = (IA32_IDT_GATE_DESCRIPTOR *)Idtr.Base;
|
||||||
for (Index = 0; Index < StackSwitchData->StackSwitchExceptionNumber; ++Index) {
|
for (Index = 0; Index < CPU_STACK_SWITCH_EXCEPTION_NUMBER; ++Index) {
|
||||||
TssDesc += 1;
|
TssDesc += 1;
|
||||||
Tss += 1;
|
Tss += 1;
|
||||||
|
|
||||||
|
@ -250,7 +239,7 @@ ArchSetupExceptionStack (
|
||||||
//
|
//
|
||||||
// Fixup TSS
|
// Fixup TSS
|
||||||
//
|
//
|
||||||
Vector = StackSwitchData->StackSwitchExceptions[Index];
|
Vector = StackSwitchExceptions[Index];
|
||||||
if ((Vector >= CPU_EXCEPTION_NUM) ||
|
if ((Vector >= CPU_EXCEPTION_NUM) ||
|
||||||
(Vector >= (Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)))
|
(Vector >= (Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)))
|
||||||
{
|
{
|
||||||
|
@ -270,7 +259,7 @@ ArchSetupExceptionStack (
|
||||||
Tss->FS = AsmReadFs ();
|
Tss->FS = AsmReadFs ();
|
||||||
Tss->GS = AsmReadGs ();
|
Tss->GS = AsmReadGs ();
|
||||||
|
|
||||||
StackTop -= StackSwitchData->KnownGoodStackSize;
|
StackTop -= CPU_KNOWN_GOOD_STACK_SIZE;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Update IDT to use Task Gate for given exception
|
// Update IDT to use Task Gate for given exception
|
||||||
|
@ -290,12 +279,7 @@ ArchSetupExceptionStack (
|
||||||
//
|
//
|
||||||
// Load current task
|
// Load current task
|
||||||
//
|
//
|
||||||
AsmWriteTr ((UINT16)((UINTN)StackSwitchData->ExceptionTssDesc - Gdtr.Base));
|
AsmWriteTr ((UINT16)((UINTN)TssDescBase - Gdtr.Base));
|
||||||
|
|
||||||
//
|
|
||||||
// Publish IDT
|
|
||||||
//
|
|
||||||
AsmWriteIdtr (&Idtr);
|
|
||||||
|
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,84 +170,9 @@ InitializeSeparateExceptionStacks (
|
||||||
IN OUT UINTN *BufferSize
|
IN OUT UINTN *BufferSize
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
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)) {
|
if ((Buffer == NULL) && (BufferSize == NULL)) {
|
||||||
return EFI_UNSUPPORTED;
|
return EFI_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BufferSize == NULL) {
|
return ArchSetupExceptionStack (Buffer, BufferSize);
|
||||||
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.KnownGoodStackTop = StackTop;
|
|
||||||
EssData.KnownGoodStackSize = CPU_KNOWN_GOOD_STACK_SIZE;
|
|
||||||
EssData.StackSwitchExceptions = CPU_STACK_SWITCH_EXCEPTION_LIST;
|
|
||||||
EssData.StackSwitchExceptionNumber = CPU_STACK_SWITCH_EXCEPTION_NUMBER;
|
|
||||||
EssData.IdtTable = (VOID *)Idtr.Base;
|
|
||||||
EssData.IdtTableSize = Idtr.Limit + 1;
|
|
||||||
EssData.GdtTable = NewGdtTable;
|
|
||||||
EssData.GdtTableSize = CPU_TSS_DESC_SIZE + Gdtr.Limit + 1;
|
|
||||||
EssData.ExceptionTssDesc = NewGdtTable + Gdtr.Limit + 1;
|
|
||||||
EssData.ExceptionTssDescSize = CPU_TSS_DESC_SIZE;
|
|
||||||
EssData.ExceptionTss = NewGdtTable + Gdtr.Limit + 1 + CPU_TSS_DESC_SIZE;
|
|
||||||
EssData.ExceptionTssSize = CPU_TSS_SIZE;
|
|
||||||
|
|
||||||
return ArchSetupExceptionStack (&EssData);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
## @file
|
## @file
|
||||||
# CPU Exception Handler library instance for SEC/PEI modules.
|
# CPU Exception Handler library instance for SEC/PEI modules.
|
||||||
#
|
#
|
||||||
# Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>
|
# Copyright (c) 2012 - 2022, Intel Corporation. All rights reserved.<BR>
|
||||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
#
|
#
|
||||||
##
|
##
|
||||||
|
@ -50,6 +50,11 @@
|
||||||
PeCoffGetEntryPointLib
|
PeCoffGetEntryPointLib
|
||||||
VmgExitLib
|
VmgExitLib
|
||||||
|
|
||||||
|
[Pcd]
|
||||||
|
gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard
|
||||||
|
gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList
|
||||||
|
gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize
|
||||||
|
|
||||||
[FeaturePcd]
|
[FeaturePcd]
|
||||||
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard ## CONSUMES
|
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard ## CONSUMES
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
## @file
|
## @file
|
||||||
# CPU Exception Handler library instance for SMM modules.
|
# CPU Exception Handler library instance for SMM modules.
|
||||||
#
|
#
|
||||||
# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
|
# Copyright (c) 2013 - 2022, Intel Corporation. All rights reserved.<BR>
|
||||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
#
|
#
|
||||||
##
|
##
|
||||||
|
@ -53,6 +53,11 @@
|
||||||
DebugLib
|
DebugLib
|
||||||
VmgExitLib
|
VmgExitLib
|
||||||
|
|
||||||
|
[Pcd]
|
||||||
|
gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard
|
||||||
|
gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList
|
||||||
|
gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize
|
||||||
|
|
||||||
[FeaturePcd]
|
[FeaturePcd]
|
||||||
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard ## CONSUMES
|
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard ## CONSUMES
|
||||||
|
|
||||||
|
|
|
@ -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
|
@param[in] Buffer Point to buffer used to separate exception stack.
|
||||||
stack switch.
|
@param[in, out] BufferSize On input, it indicates the byte size of Buffer.
|
||||||
|
If the size is not enough, the return status will
|
||||||
@retval EFI_SUCCESS The exceptions have been successfully
|
be EFI_BUFFER_TOO_SMALL, and output BufferSize
|
||||||
initialized with new stack.
|
will be the size it needs.
|
||||||
@retval EFI_INVALID_PARAMETER StackSwitchData contains invalid content.
|
|
||||||
|
|
||||||
|
@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
|
EFI_STATUS
|
||||||
ArchSetupExceptionStack (
|
ArchSetupExceptionStack (
|
||||||
IN CPU_EXCEPTION_INIT_DATA *StackSwitchData
|
IN VOID *Buffer,
|
||||||
|
IN OUT UINTN *BufferSize
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
IA32_DESCRIPTOR Gdtr;
|
IA32_DESCRIPTOR Gdtr;
|
||||||
|
@ -129,86 +132,75 @@ ArchSetupExceptionStack (
|
||||||
IA32_IDT_GATE_DESCRIPTOR *IdtTable;
|
IA32_IDT_GATE_DESCRIPTOR *IdtTable;
|
||||||
IA32_TSS_DESCRIPTOR *TssDesc;
|
IA32_TSS_DESCRIPTOR *TssDesc;
|
||||||
IA32_TASK_STATE_SEGMENT *Tss;
|
IA32_TASK_STATE_SEGMENT *Tss;
|
||||||
|
VOID *NewGdtTable;
|
||||||
UINTN StackTop;
|
UINTN StackTop;
|
||||||
UINTN Index;
|
UINTN Index;
|
||||||
UINTN Vector;
|
UINTN Vector;
|
||||||
UINTN TssBase;
|
UINTN TssBase;
|
||||||
UINTN GdtSize;
|
UINT8 *StackSwitchExceptions;
|
||||||
|
UINTN NeedBufferSize;
|
||||||
|
|
||||||
if ((StackSwitchData == NULL) ||
|
if (BufferSize == 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)) {
|
|
||||||
return EFI_INVALID_PARAMETER;
|
return EFI_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Interrupt stack table supports only 7 vectors.
|
// Interrupt stack table supports only 7 vectors.
|
||||||
//
|
//
|
||||||
TssDesc = StackSwitchData->ExceptionTssDesc;
|
if (CPU_STACK_SWITCH_EXCEPTION_NUMBER > ARRAY_SIZE (Tss->IST)) {
|
||||||
Tss = StackSwitchData->ExceptionTss;
|
return EFI_UNSUPPORTED;
|
||||||
if (StackSwitchData->StackSwitchExceptionNumber > ARRAY_SIZE (Tss->IST)) {
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// 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;
|
return EFI_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Initialize new GDT table and/or IDT table, if any
|
|
||||||
//
|
|
||||||
AsmReadIdtr (&Idtr);
|
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) -
|
CopyMem (NewGdtTable, (VOID *)Gdtr.Base, Gdtr.Limit + 1);
|
||||||
(UINTN)(StackSwitchData->GdtTable);
|
Gdtr.Base = (UINTN)NewGdtTable;
|
||||||
if ((UINTN)StackSwitchData->GdtTable != Gdtr.Base) {
|
Gdtr.Limit = (UINT16)(Gdtr.Limit + CPU_TSS_DESC_SIZE);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Fixup current task descriptor. Task-state segment for current task will
|
// Fixup current task descriptor. Task-state segment for current task will
|
||||||
|
@ -231,20 +223,20 @@ ArchSetupExceptionStack (
|
||||||
// Fixup exception task descriptor and task-state segment
|
// Fixup exception task descriptor and task-state segment
|
||||||
//
|
//
|
||||||
ZeroMem (Tss, sizeof (*Tss));
|
ZeroMem (Tss, sizeof (*Tss));
|
||||||
StackTop = StackSwitchData->KnownGoodStackTop - CPU_STACK_ALIGNMENT;
|
StackTop = StackTop - CPU_STACK_ALIGNMENT;
|
||||||
StackTop = (UINTN)ALIGN_POINTER (StackTop, CPU_STACK_ALIGNMENT);
|
StackTop = (UINTN)ALIGN_POINTER (StackTop, CPU_STACK_ALIGNMENT);
|
||||||
IdtTable = StackSwitchData->IdtTable;
|
IdtTable = (IA32_IDT_GATE_DESCRIPTOR *)Idtr.Base;
|
||||||
for (Index = 0; Index < StackSwitchData->StackSwitchExceptionNumber; ++Index) {
|
for (Index = 0; Index < CPU_STACK_SWITCH_EXCEPTION_NUMBER; ++Index) {
|
||||||
//
|
//
|
||||||
// Fixup IST
|
// Fixup IST
|
||||||
//
|
//
|
||||||
Tss->IST[Index] = StackTop;
|
Tss->IST[Index] = StackTop;
|
||||||
StackTop -= StackSwitchData->KnownGoodStackSize;
|
StackTop -= CPU_KNOWN_GOOD_STACK_SIZE;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Set the IST field to enable corresponding IST
|
// Set the IST field to enable corresponding IST
|
||||||
//
|
//
|
||||||
Vector = StackSwitchData->StackSwitchExceptions[Index];
|
Vector = StackSwitchExceptions[Index];
|
||||||
if ((Vector >= CPU_EXCEPTION_NUM) ||
|
if ((Vector >= CPU_EXCEPTION_NUM) ||
|
||||||
(Vector >= (Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)))
|
(Vector >= (Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)))
|
||||||
{
|
{
|
||||||
|
@ -262,12 +254,7 @@ ArchSetupExceptionStack (
|
||||||
//
|
//
|
||||||
// Load current task
|
// Load current task
|
||||||
//
|
//
|
||||||
AsmWriteTr ((UINT16)((UINTN)StackSwitchData->ExceptionTssDesc - Gdtr.Base));
|
AsmWriteTr ((UINT16)((UINTN)TssDesc - Gdtr.Base));
|
||||||
|
|
||||||
//
|
|
||||||
// Publish IDT
|
|
||||||
//
|
|
||||||
AsmWriteIdtr (&Idtr);
|
|
||||||
|
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# CPU Exception Handler library instance for SEC/PEI modules.
|
# CPU Exception Handler library instance for SEC/PEI modules.
|
||||||
#
|
#
|
||||||
# Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
|
# Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
|
||||||
# Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>
|
# Copyright (c) 2012 - 2022, Intel Corporation. All rights reserved.<BR>
|
||||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
#
|
#
|
||||||
# This is the XCODE5 variant of the SEC/PEI CpuExceptionHandlerLib. This
|
# This is the XCODE5 variant of the SEC/PEI CpuExceptionHandlerLib. This
|
||||||
|
@ -55,6 +55,11 @@
|
||||||
PeCoffGetEntryPointLib
|
PeCoffGetEntryPointLib
|
||||||
VmgExitLib
|
VmgExitLib
|
||||||
|
|
||||||
|
[Pcd]
|
||||||
|
gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard
|
||||||
|
gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList
|
||||||
|
gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize
|
||||||
|
|
||||||
[FeaturePcd]
|
[FeaturePcd]
|
||||||
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard ## CONSUMES
|
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard ## CONSUMES
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue