Skip to content

Commit

Permalink
[CHERRY-PICK] UefiCpuPkg: x86 CpuDxe: Allocate AP Exception Stack Bel…
Browse files Browse the repository at this point in the history
…ow 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]>
  • Loading branch information
os-d committed Dec 18, 2024
1 parent 33473bd commit a40e166
Showing 1 changed file with 25 additions and 3 deletions.
28 changes: 25 additions & 3 deletions UefiCpuPkg/CpuDxe/CpuMp.c
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,12 @@ InitializeMpExceptionStackSwitchHandlers (
UINT8 *Buffer;

SwitchStackData = AllocateZeroPool (mNumberOfProcessors * sizeof (EXCEPTION_STACK_SWITCH_CONTEXT));
ASSERT (SwitchStackData != NULL);
if (SwitchStackData == NULL) {
DEBUG ((DEBUG_ERROR, "%a Failed to allocate buffer for SwitchStackData\n", __func__));
ASSERT (SwitchStackData != NULL);
return;
}

for (Index = 0; Index < mNumberOfProcessors; ++Index) {
//
// Because the procedure may runs multiple times, use the status EFI_NOT_STARTED
Expand Down Expand Up @@ -691,8 +696,24 @@ InitializeMpExceptionStackSwitchHandlers (
}

if (BufferSize != 0) {
Buffer = AllocateRuntimeZeroPool (BufferSize);
ASSERT (Buffer != NULL);
// we are allocating the buffer that will hold the new GDT and IDT for the APs. These must be allocated below
// 4GB as they are used by protected mode code on the APs when they are started up after this point. If they are
// above 4GB, the APs will triple fault because the 32 bit code segment is invalid
Buffer = (UINT8 *)(UINTN)(BASE_4GB - 1);
Status = gBS->AllocatePages (
AllocateMaxAddress,
EfiRuntimeServicesData,
EFI_SIZE_TO_PAGES (BufferSize),
(EFI_PHYSICAL_ADDRESS *)&Buffer
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Failed to allocate buffer for InitializeExceptionStackSwitchHandlers Status %r\n", Status));
ASSERT_EFI_ERROR (Status);
goto Exit;
}

ZeroMem (Buffer, BufferSize);

BufferSize = 0;
for (Index = 0; Index < mNumberOfProcessors; ++Index) {
if (SwitchStackData[Index].Status == EFI_BUFFER_TOO_SMALL) {
Expand All @@ -719,6 +740,7 @@ InitializeMpExceptionStackSwitchHandlers (
}
}

Exit:
FreePool (SwitchStackData);
}

Expand Down

0 comments on commit a40e166

Please sign in to comment.