diff options
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmFuncsArch.c')
-rw-r--r-- | src/VBox/Devices/EFI/Firmware/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmFuncsArch.c | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmFuncsArch.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmFuncsArch.c new file mode 100644 index 00000000..b7f4949c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmFuncsArch.c @@ -0,0 +1,204 @@ +/** @file + SMM CPU misc functions for Ia32 arch specific. + +Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "PiSmmCpuDxeSmm.h" + +extern UINT64 gTaskGateDescriptor; + +EFI_PHYSICAL_ADDRESS mGdtBuffer; +UINTN mGdtBufferSize; + +extern BOOLEAN mCetSupported; +extern UINTN mSmmShadowStackSize; + +X86_ASSEMBLY_PATCH_LABEL mPatchCetPl0Ssp; +X86_ASSEMBLY_PATCH_LABEL mPatchCetInterruptSsp; +UINT32 mCetPl0Ssp; +UINT32 mCetInterruptSsp; + +/** + Initialize IDT for SMM Stack Guard. + +**/ +VOID +EFIAPI +InitializeIDTSmmStackGuard ( + VOID + ) +{ + IA32_IDT_GATE_DESCRIPTOR *IdtGate; + + // + // If SMM Stack Guard feature is enabled, the Page Fault Exception entry in IDT + // is a Task Gate Descriptor so that when a Page Fault Exception occurs, + // the processors can use a known good stack in case stack is ran out. + // + IdtGate = (IA32_IDT_GATE_DESCRIPTOR *)gcSmiIdtr.Base; + IdtGate += EXCEPT_IA32_PAGE_FAULT; + IdtGate->Uint64 = gTaskGateDescriptor; +} + +/** + Initialize Gdt for all processors. + + @param[in] Cr3 CR3 value. + @param[out] GdtStepSize The step size for GDT table. + + @return GdtBase for processor 0. + GdtBase for processor X is: GdtBase + (GdtStepSize * X) +**/ +VOID * +InitGdt ( + IN UINTN Cr3, + OUT UINTN *GdtStepSize + ) +{ + UINTN Index; + IA32_SEGMENT_DESCRIPTOR *GdtDescriptor; + UINTN TssBase; + UINTN GdtTssTableSize; + UINT8 *GdtTssTables; + UINTN GdtTableStepSize; + UINTN InterruptShadowStack; + + if (FeaturePcdGet (PcdCpuSmmStackGuard)) { + // + // For IA32 SMM, if SMM Stack Guard feature is enabled, we use 2 TSS. + // in this case, we allocate separate GDT/TSS for each CPUs to avoid TSS load contention + // on each SMI entry. + // + + // + // Enlarge GDT to contain 2 TSS descriptors + // + gcSmiGdtr.Limit += (UINT16)(2 * sizeof (IA32_SEGMENT_DESCRIPTOR)); + + GdtTssTableSize = (gcSmiGdtr.Limit + 1 + TSS_SIZE + EXCEPTION_TSS_SIZE + 7) & ~7; // 8 bytes aligned + mGdtBufferSize = GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; + // + // IA32 Stack Guard need use task switch to switch stack that need + // write GDT and TSS, so AllocateCodePages() could not be used here + // as code pages will be set to RO. + // + GdtTssTables = (UINT8*)AllocatePages (EFI_SIZE_TO_PAGES (mGdtBufferSize)); + ASSERT (GdtTssTables != NULL); + mGdtBuffer = (UINTN)GdtTssTables; + GdtTableStepSize = GdtTssTableSize; + + for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) { + CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID*)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1 + TSS_SIZE + EXCEPTION_TSS_SIZE); + // + // Fixup TSS descriptors + // + TssBase = (UINTN)(GdtTssTables + GdtTableStepSize * Index + gcSmiGdtr.Limit + 1); + GdtDescriptor = (IA32_SEGMENT_DESCRIPTOR *)(TssBase) - 2; + GdtDescriptor->Bits.BaseLow = (UINT16)TssBase; + GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16); + GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24); + + TssBase += TSS_SIZE; + GdtDescriptor++; + GdtDescriptor->Bits.BaseLow = (UINT16)TssBase; + GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16); + GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24); + // + // Fixup TSS segments + // + // ESP as known good stack + // + *(UINTN *)(TssBase + TSS_IA32_ESP_OFFSET) = mSmmStackArrayBase + EFI_PAGE_SIZE + Index * mSmmStackSize; + *(UINT32 *)(TssBase + TSS_IA32_CR3_OFFSET) = Cr3; + + // + // Setup ShadowStack for stack switch + // + if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported) { + InterruptShadowStack = (UINTN)(mSmmStackArrayBase + mSmmStackSize + EFI_PAGES_TO_SIZE (1) - sizeof(UINT64) + (mSmmStackSize + mSmmShadowStackSize) * Index); + *(UINT32 *)(TssBase + TSS_IA32_SSP_OFFSET) = (UINT32)InterruptShadowStack; + } + } + } else { + // + // Just use original table, AllocatePage and copy them here to make sure GDTs are covered in page memory. + // + GdtTssTableSize = gcSmiGdtr.Limit + 1; + mGdtBufferSize = GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; + GdtTssTables = (UINT8*)AllocateCodePages (EFI_SIZE_TO_PAGES (mGdtBufferSize)); + ASSERT (GdtTssTables != NULL); + mGdtBuffer = (UINTN)GdtTssTables; + GdtTableStepSize = GdtTssTableSize; + + for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) { + CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID*)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1); + } + } + + *GdtStepSize = GdtTableStepSize; + return GdtTssTables; +} + +/** + Transfer AP to safe hlt-loop after it finished restore CPU features on S3 patch. + + @param[in] ApHltLoopCode The address of the safe hlt-loop function. + @param[in] TopOfStack A pointer to the new stack to use for the ApHltLoopCode. + @param[in] NumberToFinishAddress Address of Semaphore of APs finish count. + +**/ +VOID +TransferApToSafeState ( + IN UINTN ApHltLoopCode, + IN UINTN TopOfStack, + IN UINTN NumberToFinishAddress + ) +{ + SwitchStack ( + (SWITCH_STACK_ENTRY_POINT)ApHltLoopCode, + (VOID *)NumberToFinishAddress, + NULL, + (VOID *)TopOfStack + ); + // + // It should never reach here + // + ASSERT (FALSE); +} + +/** + Initialize the shadow stack related data structure. + + @param CpuIndex The index of CPU. + @param ShadowStack The bottom of the shadow stack for this CPU. +**/ +VOID +InitShadowStack ( + IN UINTN CpuIndex, + IN VOID *ShadowStack + ) +{ + UINTN SmmShadowStackSize; + + if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported) { + SmmShadowStackSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmShadowStackSize))); + if (FeaturePcdGet (PcdCpuSmmStackGuard)) { + SmmShadowStackSize += EFI_PAGES_TO_SIZE (2); + } + mCetPl0Ssp = (UINT32)((UINTN)ShadowStack + SmmShadowStackSize - sizeof(UINT64)); + PatchInstructionX86 (mPatchCetPl0Ssp, mCetPl0Ssp, 4); + DEBUG ((DEBUG_INFO, "mCetPl0Ssp - 0x%x\n", mCetPl0Ssp)); + DEBUG ((DEBUG_INFO, "ShadowStack - 0x%x\n", ShadowStack)); + DEBUG ((DEBUG_INFO, " SmmShadowStackSize - 0x%x\n", SmmShadowStackSize)); + + if (FeaturePcdGet (PcdCpuSmmStackGuard)) { + mCetInterruptSsp = (UINT32)((UINTN)ShadowStack + EFI_PAGES_TO_SIZE(1) - sizeof(UINT64)); + PatchInstructionX86 (mPatchCetInterruptSsp, mCetInterruptSsp, 4); + DEBUG ((DEBUG_INFO, "mCetInterruptSsp - 0x%x\n", mCetInterruptSsp)); + } + } +} + |