}\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