Skip to content

Commit a40e166

Browse files
committed
[CHERRY-PICK] UefiCpuPkg: x86 CpuDxe: Allocate AP Exception Stack Below 4GB
When setting up the APs' exception stacks, the x86 CpuDxe allocates any range and then copies over the existing GDT and IDT and adds the appropriate new entries for this AP, then installs them. This can cause an issue if the allocated buffer is over 4GB because the next time the AP is started, it goes through an INIT-SIPI-SIPI, stepping through real mode -> protected mode -> long mode and when it is in protected mode it needs a 32 code segment descriptor or else it will fault when trying to execute. If the GDT lives above 4GB, it cannot be accessed by the protected mode code and the triple fault is seen. This patch updates CpuDxe's MP management code to allocate the exception stacks for all APs below 4GB explicitly to avoid this problem, such as it does with the BSP's GDT that first gets populated to the APs. Signed-off-by: Oliver Smith-Denny <[email protected]>
1 parent 33473bd commit a40e166

File tree

1 file changed

+25
-3
lines changed

1 file changed

+25
-3
lines changed

UefiCpuPkg/CpuDxe/CpuMp.c

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -663,7 +663,12 @@ InitializeMpExceptionStackSwitchHandlers (
663663
UINT8 *Buffer;
664664

665665
SwitchStackData = AllocateZeroPool (mNumberOfProcessors * sizeof (EXCEPTION_STACK_SWITCH_CONTEXT));
666-
ASSERT (SwitchStackData != NULL);
666+
if (SwitchStackData == NULL) {
667+
DEBUG ((DEBUG_ERROR, "%a Failed to allocate buffer for SwitchStackData\n", __func__));
668+
ASSERT (SwitchStackData != NULL);
669+
return;
670+
}
671+
667672
for (Index = 0; Index < mNumberOfProcessors; ++Index) {
668673
//
669674
// Because the procedure may runs multiple times, use the status EFI_NOT_STARTED
@@ -691,8 +696,24 @@ InitializeMpExceptionStackSwitchHandlers (
691696
}
692697

693698
if (BufferSize != 0) {
694-
Buffer = AllocateRuntimeZeroPool (BufferSize);
695-
ASSERT (Buffer != NULL);
699+
// we are allocating the buffer that will hold the new GDT and IDT for the APs. These must be allocated below
700+
// 4GB as they are used by protected mode code on the APs when they are started up after this point. If they are
701+
// above 4GB, the APs will triple fault because the 32 bit code segment is invalid
702+
Buffer = (UINT8 *)(UINTN)(BASE_4GB - 1);
703+
Status = gBS->AllocatePages (
704+
AllocateMaxAddress,
705+
EfiRuntimeServicesData,
706+
EFI_SIZE_TO_PAGES (BufferSize),
707+
(EFI_PHYSICAL_ADDRESS *)&Buffer
708+
);
709+
if (EFI_ERROR (Status)) {
710+
DEBUG ((DEBUG_ERROR, "Failed to allocate buffer for InitializeExceptionStackSwitchHandlers Status %r\n", Status));
711+
ASSERT_EFI_ERROR (Status);
712+
goto Exit;
713+
}
714+
715+
ZeroMem (Buffer, BufferSize);
716+
696717
BufferSize = 0;
697718
for (Index = 0; Index < mNumberOfProcessors; ++Index) {
698719
if (SwitchStackData[Index].Status == EFI_BUFFER_TOO_SMALL) {
@@ -719,6 +740,7 @@ InitializeMpExceptionStackSwitchHandlers (
719740
}
720741
}
721742

743+
Exit:
722744
FreePool (SwitchStackData);
723745
}
724746

0 commit comments

Comments
 (0)