The StartupVector member of ACPI_CPU_DATA points to low level assembly code that starts out in real mode, and is the boot code that gets run on each AP in response to an INIT-Start-up-Start-up IPI sequence.
Importantly, *each* one of PiSmmCpuDxeSmm and CpuMpDxe (from Quark_EDKII_v1.1.0/IA32FamilyCpuBasePkg/) has its own, private startup vector implementation. They are similar, and are located in the respective "IA32/MpFuncs.S" files (named RendezvousFunnelProcStart()). With regard to the communication from CpuMpDxe to PiSmmCpuDxeSmm, PiSmmCpuDxeSmm does not reuse CpuMpDxe's startup vector on the S3 resume path (which would be unsafe anyway, unless the startup vector itself were saved in SMRAM). PiSmmCpuDxeSmm only reuses (and overwrites) the reserved memory *buffer* underneath ACPI_CPU_DATA.StartupVector that CpuMpDxe allocated. Therefore in this patch we only cover the allocation in our CpuS3DataDxe driver; we can ignore everything else that CpuMpDxe would otherwise do with its own startup vector. PiSmmCpuDxeSmm silently assumes that its startup vector (plus the BSP-AP communication structure that follows it directly) are not larger than the same pair from CpuMpDxe. Because our CpuS3DataDxe driver has no such things to key the allocation size off of, we allocate a single page (which in practice is already larger than the original pair from CpuMpDxe). PiSmmCpuDxeSmm should assert or enforce that this page is sufficient for PiSmmCpuDxeSmm's startup vector and BSP-AP communication area. The code added to CpuS3DataDxe is a little awkward; it looks like this because it is built from positionally correct snippets (modified as necessary) lifted from CpuMpDxe, preserving the original control flow: entry point (MultiProcessorInitialize() vs. CpuS3DataInitialize()) ProcessorConfiguration() WakeupAPAndCollectBist() PrepareAPStartupVector() AllocateStartupVector() // allocates mStartupVector SmmConfigurationEventNotify() SaveCpuS3Data() // sets ACPI_CPU_DATA.StartupVector to mStartupVector ReAllocateMemoryForAP() -- optionally, if CSM is present // reallocates mStartupVector from legacy region // re-sets ACPI_CPU_DATA.StartupVector to mStartupVector The CpuS3DataDxe subdirectory is supposed to be diffable against the original CpuMpDxe. (In fact the original CpuMpDxe has a bug; it *only* sets mAcpiCpuData->StartupVector to mStartupVector when the Legacy BIOS Protocol (ie. CSM) is present, and the startup vector is relocated into the E or F segment.) Starting with this patch, CpuS3DataDxe grows arch-specific dependencies, and therefore OVMF will build for Ia32 only, when -D SMM_REQUIRE is specified. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek <ler...@redhat.com> --- Notes: v2: - Drop the ASSERT() that v1 added to QuarkPort/PiSmmCpuDxeSmm, about the size of the area pre-allocated by CpuS3DataDxe. Instead, spell out this idea in the commit message; with Mike we've agreed that UefiCpuPkg/PiSmmCpuDxeSmm will verify or enforce this in the future somehow. OvmfPkg/QuarkPort/CpuS3DataDxe/CpuS3DataDxe.inf | 6 ++ OvmfPkg/QuarkPort/CpuS3DataDxe/Cpu.h | 16 +++ OvmfPkg/QuarkPort/CpuS3DataDxe/MpCommon.h | 42 ++++++++ OvmfPkg/QuarkPort/CpuS3DataDxe/{Cpu.h => IA32/ArchSpecific.c} | 34 +++---- OvmfPkg/QuarkPort/CpuS3DataDxe/MpCommon.c | 107 ++++++++++++++++++++ OvmfPkg/QuarkPort/CpuS3DataDxe/ProcessorConfig.c | 63 ++++++++++++ 6 files changed, 251 insertions(+), 17 deletions(-) diff --git a/OvmfPkg/QuarkPort/CpuS3DataDxe/CpuS3DataDxe.inf b/OvmfPkg/QuarkPort/CpuS3DataDxe/CpuS3DataDxe.inf index efb71d4..be362d8 100644 --- a/OvmfPkg/QuarkPort/CpuS3DataDxe/CpuS3DataDxe.inf +++ b/OvmfPkg/QuarkPort/CpuS3DataDxe/CpuS3DataDxe.inf @@ -56,13 +56,17 @@ [Sources] Cpu.h [Sources.Ia32] + IA32/ArchSpecific.c [Packages] MdePkg/MdePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec UefiCpuPkg/UefiCpuPkg.dec [LibraryClasses] UefiBootServicesTableLib + MemoryAllocationLib UefiDriverEntryPoint BaseMemoryLib UefiLib @@ -72,6 +76,7 @@ [LibraryClasses] [Guids] [Protocols] + gEfiLegacyBiosProtocolGuid ## SOMETIMES_CONSUMES gEfiSmmConfigurationProtocolGuid # PROTOCOL ALWAYS_CONSUMED [FeaturePcd] @@ -80,6 +85,7 @@ [FixedPcd] [Pcd] gUefiCpuPkgTokenSpaceGuid.PcdCpuS3DataAddress + gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdEbdaReservedMemorySize [Depex] TRUE diff --git a/OvmfPkg/QuarkPort/CpuS3DataDxe/Cpu.h b/OvmfPkg/QuarkPort/CpuS3DataDxe/Cpu.h index ca4816b..62faa0b 100644 --- a/OvmfPkg/QuarkPort/CpuS3DataDxe/Cpu.h +++ b/OvmfPkg/QuarkPort/CpuS3DataDxe/Cpu.h @@ -40,6 +40,22 @@ #include "MpCommon.h" +extern EFI_PHYSICAL_ADDRESS mStartupVector; + +extern ACPI_CPU_DATA *mAcpiCpuData; + +/** + Wakes up APs for the first time to count their number and collect BIST data. + + This function wakes up APs for the first time to count their number and + collect BIST data. + +**/ +VOID +WakeupAPAndCollectBist ( + VOID + ); + /** Prepare ACPI NVS memory below 4G memory for use of S3 resume. diff --git a/OvmfPkg/QuarkPort/CpuS3DataDxe/MpCommon.h b/OvmfPkg/QuarkPort/CpuS3DataDxe/MpCommon.h index ec8a4a1..beb30f4 100644 --- a/OvmfPkg/QuarkPort/CpuS3DataDxe/MpCommon.h +++ b/OvmfPkg/QuarkPort/CpuS3DataDxe/MpCommon.h @@ -42,14 +42,40 @@ #include <AcpiCpuData.h> +#include <Protocol/LegacyBios.h> #include <Protocol/SmmConfiguration.h> #include <Library/DebugLib.h> #include <Library/UefiLib.h> #include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> #include <Library/UefiBootServicesTableLib.h> /** + Allocates startup vector for APs. + + This function allocates Startup vector for APs. + + @param Size The size of startup vector. + +**/ +VOID +AllocateStartupVector ( + UINTN Size + ); + +/** + Prepares Startup Vector for APs. + + This function prepares Startup Vector for APs. + +**/ +VOID +PrepareAPStartupVector ( + VOID + ); + +/** Allocate EfiACPIMemoryNVS below 4G memory address. This function allocates EfiACPIMemoryNVS below 4G memory address. @@ -64,4 +90,20 @@ AllocateAcpiNvsMemoryBelow4G ( IN UINTN Size ); +/** + Protocol notification that is fired when LegacyBios protocol is installed. + + Re-allocate a wakeup buffer from E/F segment because the previous wakeup + buffer under 640K won't be preserved by the legacy OS. + + @param Event The triggered event. + @param Context Context for this event. +**/ +VOID +EFIAPI +ReAllocateMemoryForAP ( + IN EFI_EVENT Event, + IN VOID *Context + ); + #endif diff --git a/OvmfPkg/QuarkPort/CpuS3DataDxe/Cpu.h b/OvmfPkg/QuarkPort/CpuS3DataDxe/IA32/ArchSpecific.c similarity index 76% copy from OvmfPkg/QuarkPort/CpuS3DataDxe/Cpu.h copy to OvmfPkg/QuarkPort/CpuS3DataDxe/IA32/ArchSpecific.c index ca4816b..8bf991b 100644 --- a/OvmfPkg/QuarkPort/CpuS3DataDxe/Cpu.h +++ b/OvmfPkg/QuarkPort/CpuS3DataDxe/IA32/ArchSpecific.c @@ -1,6 +1,6 @@ /** @file - Include file for CPU DXE Module + Memory Operation Functions for IA32 Architecture. Copyright (C) 2015, Red Hat, Inc. Copyright (c) 2013-2015 Intel Corporation. @@ -31,27 +31,27 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - Module Name: Cpu.h + Module Name: ArchSpecific.c **/ -#ifndef _CPU_DXE_H_ -#define _CPU_DXE_H_ - -#include "MpCommon.h" +#include "Cpu.h" +#include "MpService.h" /** - Prepare ACPI NVS memory below 4G memory for use of S3 resume. - - This function allocates ACPI NVS memory below 4G memory for use of S3 resume, - and saves data into the memory region. + Prepares Startup Vector for APs. + + This function prepares Startup Vector for APs. - @param Context The Context save the info. - **/ VOID -SaveCpuS3Data ( - VOID *Context - ); - -#endif +PrepareAPStartupVector ( + VOID + ) +{ + // + // Allocate a 4K-aligned region under 1M for startup vector for AP. + // The region contains AP startup code and exchange data between BSP and AP. + // + AllocateStartupVector (SIZE_4KB); +} diff --git a/OvmfPkg/QuarkPort/CpuS3DataDxe/MpCommon.c b/OvmfPkg/QuarkPort/CpuS3DataDxe/MpCommon.c index 6f6ddb9..6f06628 100644 --- a/OvmfPkg/QuarkPort/CpuS3DataDxe/MpCommon.c +++ b/OvmfPkg/QuarkPort/CpuS3DataDxe/MpCommon.c @@ -36,6 +36,113 @@ **/ #include "MpService.h" +#include "Cpu.h" + +UINTN mStartupVectorSize; + +/** + Allocates startup vector for APs. + + This function allocates Startup vector for APs. + + @param Size The size of startup vector. + +**/ +VOID +AllocateStartupVector ( + UINTN Size + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS StartAddress; + + mStartupVectorSize = Size; + Status = EFI_NOT_FOUND; + + // + // Allocate wakeup buffer below 640K. Don't touch legacy region. + // Leave some room immediately below 640K in for CSM module. + // PcdEbdaReservedMemorySize has been required to be a multiple of 4KB. + // + StartAddress = 0xA0000 - PcdGet32 (PcdEbdaReservedMemorySize) - + (EFI_SIZE_TO_PAGES (Size) * EFI_PAGE_SIZE); + for (mStartupVector = StartAddress; + mStartupVector >= 0x2000; + mStartupVector -= (EFI_SIZE_TO_PAGES (Size) * EFI_PAGE_SIZE)) { + + // + // If finally no CSM in the platform, this wakeup buffer is to be used in + // S3 boot path. + // + Status = gBS->AllocatePages ( + AllocateAddress, + EfiReservedMemoryType, + EFI_SIZE_TO_PAGES (Size), + &mStartupVector + ); + + if (!EFI_ERROR (Status)) { + break; + } + } + + ASSERT_EFI_ERROR (Status); +} + +/** + Protocol notification that is fired when LegacyBios protocol is installed. + + Re-allocate a wakeup buffer from E/F segment because the previous wakeup + buffer under 640K won't be preserved by the legacy OS. + + @param Event The triggered event. + @param Context Context for this event. +**/ +VOID +EFIAPI +ReAllocateMemoryForAP ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + VOID *LegacyRegion; + EFI_STATUS Status; + + Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, + (VOID **)&LegacyBios); + if (EFI_ERROR (Status)) { + return ; + } + + // + // Allocate 4K aligned bytes from either 0xE0000 or 0xF0000. + // Note some CSM16 does not satisfy alignment request, so allocate a buffer + // of 2*4K and adjust the base address myself. + // + Status = LegacyBios->GetLegacyRegion ( + LegacyBios, + 0x2000, + 0, + 0x1000, + &LegacyRegion + ); + ASSERT_EFI_ERROR (Status); + + if ((((UINTN)LegacyRegion) & 0xfff) != 0) { + LegacyRegion = + (VOID *)(UINTN)((((UINTN)LegacyRegion) + 0xfff) & ~((UINTN)0xfff)); + } + + // + // Free original wakeup buffer + // + FreePages ((VOID *)(UINTN)mStartupVector, + EFI_SIZE_TO_PAGES (mStartupVectorSize)); + + mStartupVector = (EFI_PHYSICAL_ADDRESS)(UINTN)LegacyRegion; + mAcpiCpuData->StartupVector = mStartupVector; +} /** Allocate EfiACPIMemoryNVS below 4G memory address. diff --git a/OvmfPkg/QuarkPort/CpuS3DataDxe/ProcessorConfig.c b/OvmfPkg/QuarkPort/CpuS3DataDxe/ProcessorConfig.c index 2b5c319..9ad98ff 100644 --- a/OvmfPkg/QuarkPort/CpuS3DataDxe/ProcessorConfig.c +++ b/OvmfPkg/QuarkPort/CpuS3DataDxe/ProcessorConfig.c @@ -37,6 +37,7 @@ #include "MpService.h" #include "Cpu.h" +EFI_PHYSICAL_ADDRESS mStartupVector; ACPI_CPU_DATA *mAcpiCpuData; EFI_EVENT mSmmConfigurationNotificationEvent; EFI_HANDLE mImageHandle; @@ -60,6 +61,7 @@ SmmConfigurationEventNotify ( ) { EFI_STATUS Status; + VOID *Registration; EFI_SMM_CONFIGURATION_PROTOCOL *SmmConfiguration; // @@ -75,6 +77,40 @@ SmmConfigurationEventNotify ( // Save CPU S3 data // SaveCpuS3Data (mImageHandle); + + // + // Setup notification on Legacy BIOS Protocol to reallocate AP wakeup + // + EfiCreateProtocolNotifyEvent ( + &gEfiLegacyBiosProtocolGuid, + TPL_CALLBACK, + ReAllocateMemoryForAP, + NULL, + &Registration + ); +} + +/** + First phase MP initialization before SMM initialization. + + @retval EFI_SUCCESS First phase MP initialization was done successfully. + @retval EFI_UNSUPPORTED There is legacy APIC ID conflict and can't be + rsolved in xAPIC mode. + +**/ +EFI_STATUS +ProcessorConfiguration ( + VOID + ) +{ + // + // Wakeup APs for the first time, BSP stalls for arbitrary + // time for APs' completion. BSP then collects the number + // and BIST information of APs. + // + WakeupAPAndCollectBist (); + + return EFI_SUCCESS; } /** @@ -96,9 +132,17 @@ CpuS3DataInitialize ( IN EFI_SYSTEM_TABLE *SystemTable ) { + EFI_STATUS Status; VOID *Registration; mImageHandle = ImageHandle; + // + // Configure processors with three-phase architecture + // + Status = ProcessorConfiguration (); + if (EFI_ERROR (Status)) { + return Status; + } // // Install notification callback on SMM Configuration Protocol @@ -115,6 +159,24 @@ CpuS3DataInitialize ( } /** + Wakes up APs for the first time to count their number and collect BIST data. + + This function wakes up APs for the first time to count their number and + collect BIST data. + +**/ +VOID +WakeupAPAndCollectBist ( + VOID + ) +{ + // + // Prepare code and data for APs' startup vector + // + PrepareAPStartupVector (); +} + +/** Prepare ACPI NVS memory below 4G memory for use of S3 resume. This function allocates ACPI NVS memory below 4G memory for use of S3 resume, @@ -139,6 +201,7 @@ SaveCpuS3Data ( // Set the value for CPU data // mAcpiCpuData = &(MpCpuSavedData->AcpiCpuData); + mAcpiCpuData->StartupVector = mStartupVector; // // Set the base address of CPU S3 data to PcdCpuS3DataAddress -- 1.8.3.1 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel