From 55942db1d31d8b4e3695864a673ab820b16f07e0 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Wed, 26 Feb 2020 23:11:54 +0100 Subject: [PATCH] OvmfPkg: clone CpuS3DataDxe from UefiCpuPkg MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The @file comments in UefiCpuPkg/CpuS3DataDxe say, [...] It also only supports the number of CPUs reported by the MP Services Protocol, so this module does not support hot plug CPUs. This module can be copied into a CPU specific package and customized if these additional features are required. [...] The driver is so small that the simplest way to extend it with hotplug support is indeed to clone it at first. In this patch, customize the driver only with the following no-op steps: - Update copyright notices. - Update INF_VERSION to the latest INF spec version (1.29). - Update FILE_GUID. - Drop the UNI files. - Replace EFI_D_VERBOSE with DEBUG_VERBOSE, to appease "PatchCheck.py". This patch is best reviewed with: $ git show --find-copies-harder Cc: Ard Biesheuvel Cc: Igor Mammedov Cc: Jiewen Yao Cc: Jordan Justen Cc: Michael Kinney Cc: Philippe Mathieu-Daudé Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1512 Signed-off-by: Laszlo Ersek Message-Id: <20200226221156.29589-15-lersek@redhat.com> Reviewed-by: Ard Biesheuvel Reviewed-by: Philippe Mathieu-Daude Tested-by: Boris Ostrovsky --- OvmfPkg/CpuS3DataDxe/CpuS3Data.c | 309 ++++++++++++++++++++++++++ OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf | 61 +++++ OvmfPkg/OvmfPkgIa32.dsc | 2 +- OvmfPkg/OvmfPkgIa32.fdf | 2 +- OvmfPkg/OvmfPkgIa32X64.dsc | 2 +- OvmfPkg/OvmfPkgIa32X64.fdf | 2 +- OvmfPkg/OvmfPkgX64.dsc | 2 +- OvmfPkg/OvmfPkgX64.fdf | 2 +- 8 files changed, 376 insertions(+), 6 deletions(-) create mode 100644 OvmfPkg/CpuS3DataDxe/CpuS3Data.c create mode 100644 OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf diff --git a/OvmfPkg/CpuS3DataDxe/CpuS3Data.c b/OvmfPkg/CpuS3DataDxe/CpuS3Data.c new file mode 100644 index 0000000000..2bb60d591b --- /dev/null +++ b/OvmfPkg/CpuS3DataDxe/CpuS3Data.c @@ -0,0 +1,309 @@ +/** @file +ACPI CPU Data initialization module + +This module initializes the ACPI_CPU_DATA structure and registers the address +of this structure in the PcdCpuS3DataAddress PCD. This is a generic/simple +version of this module. It does not provide a machine check handler or CPU +register initialization tables for ACPI S3 resume. It also only supports the +number of CPUs reported by the MP Services Protocol, so this module does not +support hot plug CPUs. This module can be copied into a CPU specific package +and customized if these additional features are required. + +Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.
+Copyright (c) 2015 - 2020, Red Hat, Inc. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +// +// Data structure used to allocate ACPI_CPU_DATA and its supporting structures +// +typedef struct { + ACPI_CPU_DATA AcpiCpuData; + MTRR_SETTINGS MtrrTable; + IA32_DESCRIPTOR GdtrProfile; + IA32_DESCRIPTOR IdtrProfile; +} ACPI_CPU_DATA_EX; + +/** + Allocate EfiACPIMemoryNVS memory. + + @param[in] Size Size of memory to allocate. + + @return Allocated address for output. + +**/ +VOID * +AllocateAcpiNvsMemory ( + IN UINTN Size + ) +{ + EFI_PHYSICAL_ADDRESS Address; + EFI_STATUS Status; + VOID *Buffer; + + Status = gBS->AllocatePages ( + AllocateAnyPages, + EfiACPIMemoryNVS, + EFI_SIZE_TO_PAGES (Size), + &Address + ); + if (EFI_ERROR (Status)) { + return NULL; + } + + Buffer = (VOID *)(UINTN)Address; + ZeroMem (Buffer, Size); + + return Buffer; +} + +/** + Allocate memory and clean it with zero. + + @param[in] Size Size of memory to allocate. + + @return Allocated address for output. + +**/ +VOID * +AllocateZeroPages ( + IN UINTN Size + ) +{ + VOID *Buffer; + + Buffer = AllocatePages (EFI_SIZE_TO_PAGES (Size)); + if (Buffer != NULL) { + ZeroMem (Buffer, Size); + } + + return Buffer; +} +/** + Callback function executed when the EndOfDxe event group is signaled. + + We delay allocating StartupVector and saving the MTRR settings until BDS signals EndOfDxe. + + @param[in] Event Event whose notification function is being invoked. + @param[out] Context Pointer to the MTRR_SETTINGS buffer to fill in. +**/ +VOID +EFIAPI +CpuS3DataOnEndOfDxe ( + IN EFI_EVENT Event, + OUT VOID *Context + ) +{ + EFI_STATUS Status; + ACPI_CPU_DATA_EX *AcpiCpuDataEx; + + AcpiCpuDataEx = (ACPI_CPU_DATA_EX *) Context; + // + // Allocate a 4KB reserved page below 1MB + // + AcpiCpuDataEx->AcpiCpuData.StartupVector = BASE_1MB - 1; + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiReservedMemoryType, + 1, + &AcpiCpuDataEx->AcpiCpuData.StartupVector + ); + ASSERT_EFI_ERROR (Status); + + DEBUG ((DEBUG_VERBOSE, "%a\n", __FUNCTION__)); + MtrrGetAllMtrrs (&AcpiCpuDataEx->MtrrTable); + + // + // Close event, so it will not be invoked again. + // + gBS->CloseEvent (Event); +} + +/** + The entry function of the CpuS3Data driver. + + Allocate and initialize all fields of the ACPI_CPU_DATA structure except the + MTRR settings. Register an event notification on gEfiEndOfDxeEventGroupGuid + to capture the ACPI_CPU_DATA MTRR settings. The PcdCpuS3DataAddress is set + to the address that ACPI_CPU_DATA is allocated at. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval EFI_UNSUPPORTED Do not support ACPI S3. + @retval other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +CpuS3DataInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + ACPI_CPU_DATA_EX *AcpiCpuDataEx; + ACPI_CPU_DATA *AcpiCpuData; + EFI_MP_SERVICES_PROTOCOL *MpServices; + UINTN NumberOfCpus; + UINTN NumberOfEnabledProcessors; + VOID *Stack; + UINTN TableSize; + CPU_REGISTER_TABLE *RegisterTable; + UINTN Index; + EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer; + UINTN GdtSize; + UINTN IdtSize; + VOID *Gdt; + VOID *Idt; + EFI_EVENT Event; + ACPI_CPU_DATA *OldAcpiCpuData; + + if (!PcdGetBool (PcdAcpiS3Enable)) { + return EFI_UNSUPPORTED; + } + + // + // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure + // + OldAcpiCpuData = (ACPI_CPU_DATA *) (UINTN) PcdGet64 (PcdCpuS3DataAddress); + + AcpiCpuDataEx = AllocateZeroPages (sizeof (ACPI_CPU_DATA_EX)); + ASSERT (AcpiCpuDataEx != NULL); + AcpiCpuData = &AcpiCpuDataEx->AcpiCpuData; + + // + // Get MP Services Protocol + // + Status = gBS->LocateProtocol ( + &gEfiMpServiceProtocolGuid, + NULL, + (VOID **)&MpServices + ); + ASSERT_EFI_ERROR (Status); + + // + // Get the number of CPUs + // + Status = MpServices->GetNumberOfProcessors ( + MpServices, + &NumberOfCpus, + &NumberOfEnabledProcessors + ); + ASSERT_EFI_ERROR (Status); + AcpiCpuData->NumberOfCpus = (UINT32)NumberOfCpus; + + // + // Initialize ACPI_CPU_DATA fields + // + AcpiCpuData->StackSize = PcdGet32 (PcdCpuApStackSize); + AcpiCpuData->ApMachineCheckHandlerBase = 0; + AcpiCpuData->ApMachineCheckHandlerSize = 0; + AcpiCpuData->GdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->GdtrProfile; + AcpiCpuData->IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->IdtrProfile; + AcpiCpuData->MtrrTable = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->MtrrTable; + + // + // Allocate stack space for all CPUs. + // Use ACPI NVS memory type because this data will be directly used by APs + // in S3 resume phase in long mode. Also during S3 resume, the stack buffer + // will only be used as scratch space. i.e. we won't read anything from it + // before we write to it, in PiSmmCpuDxeSmm. + // + Stack = AllocateAcpiNvsMemory (NumberOfCpus * AcpiCpuData->StackSize); + ASSERT (Stack != NULL); + AcpiCpuData->StackAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Stack; + + // + // Get the boot processor's GDT and IDT + // + AsmReadGdtr (&AcpiCpuDataEx->GdtrProfile); + AsmReadIdtr (&AcpiCpuDataEx->IdtrProfile); + + // + // Allocate GDT and IDT and copy current GDT and IDT contents + // + GdtSize = AcpiCpuDataEx->GdtrProfile.Limit + 1; + IdtSize = AcpiCpuDataEx->IdtrProfile.Limit + 1; + Gdt = AllocateZeroPages (GdtSize + IdtSize); + ASSERT (Gdt != NULL); + Idt = (VOID *)((UINTN)Gdt + GdtSize); + CopyMem (Gdt, (VOID *)AcpiCpuDataEx->GdtrProfile.Base, GdtSize); + CopyMem (Idt, (VOID *)AcpiCpuDataEx->IdtrProfile.Base, IdtSize); + AcpiCpuDataEx->GdtrProfile.Base = (UINTN)Gdt; + AcpiCpuDataEx->IdtrProfile.Base = (UINTN)Idt; + + if (OldAcpiCpuData != NULL) { + AcpiCpuData->RegisterTable = OldAcpiCpuData->RegisterTable; + AcpiCpuData->PreSmmInitRegisterTable = OldAcpiCpuData->PreSmmInitRegisterTable; + AcpiCpuData->ApLocation = OldAcpiCpuData->ApLocation; + CopyMem (&AcpiCpuData->CpuStatus, &OldAcpiCpuData->CpuStatus, sizeof (CPU_STATUS_INFORMATION)); + } else { + // + // Allocate buffer for empty RegisterTable and PreSmmInitRegisterTable for all CPUs + // + TableSize = 2 * NumberOfCpus * sizeof (CPU_REGISTER_TABLE); + RegisterTable = (CPU_REGISTER_TABLE *)AllocateZeroPages (TableSize); + ASSERT (RegisterTable != NULL); + + for (Index = 0; Index < NumberOfCpus; Index++) { + Status = MpServices->GetProcessorInfo ( + MpServices, + Index, + &ProcessorInfoBuffer + ); + ASSERT_EFI_ERROR (Status); + + RegisterTable[Index].InitialApicId = (UINT32)ProcessorInfoBuffer.ProcessorId; + RegisterTable[Index].TableLength = 0; + RegisterTable[Index].AllocatedSize = 0; + RegisterTable[Index].RegisterTableEntry = 0; + + RegisterTable[NumberOfCpus + Index].InitialApicId = (UINT32)ProcessorInfoBuffer.ProcessorId; + RegisterTable[NumberOfCpus + Index].TableLength = 0; + RegisterTable[NumberOfCpus + Index].AllocatedSize = 0; + RegisterTable[NumberOfCpus + Index].RegisterTableEntry = 0; + } + AcpiCpuData->RegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)RegisterTable; + AcpiCpuData->PreSmmInitRegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)(RegisterTable + NumberOfCpus); + } + + // + // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure + // + Status = PcdSet64S (PcdCpuS3DataAddress, (UINT64)(UINTN)AcpiCpuData); + ASSERT_EFI_ERROR (Status); + + // + // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event. + // The notification function allocates StartupVector and saves MTRRs for ACPI_CPU_DATA + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + CpuS3DataOnEndOfDxe, + AcpiCpuData, + &gEfiEndOfDxeEventGroupGuid, + &Event + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} diff --git a/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf b/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf new file mode 100644 index 0000000000..0ad8a0b35d --- /dev/null +++ b/OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf @@ -0,0 +1,61 @@ +## @file +# ACPI CPU Data initialization module +# +# This module initializes the ACPI_CPU_DATA structure and registers the address +# of this structure in the PcdCpuS3DataAddress PCD. This is a generic/simple +# version of this module. It does not provide a machine check handler or CPU +# register initialization tables for ACPI S3 resume. It also only supports the +# number of CPUs reported by the MP Services Protocol, so this module does not +# support hot plug CPUs. This module can be copied into a CPU specific package +# and customized if these additional features are required. +# +# Copyright (c) 2013-2016, Intel Corporation. All rights reserved.
+# Copyright (c) 2015-2020, Red Hat, Inc. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 1.29 + BASE_NAME = CpuS3DataDxe + FILE_GUID = 229B7EFD-DA02-46B9-93F4-E20C009F94E9 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = CpuS3DataInitialize + +# The following information is for reference only and not required by the build +# tools. +# +# VALID_ARCHITECTURES = IA32 X64 + +[Sources] + CpuS3Data.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiBootServicesTableLib + BaseMemoryLib + DebugLib + BaseLib + MtrrLib + MemoryAllocationLib + +[Guids] + gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event + +[Protocols] + gEfiMpServiceProtocolGuid ## CONSUMES + +[Pcd] + gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize ## CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuS3DataAddress ## PRODUCES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable ## CONSUMES + +[Depex] + gEfiMpServiceProtocolGuid diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc index 7a8a49af95..53f503b3ed 100644 --- a/OvmfPkg/OvmfPkgIa32.dsc +++ b/OvmfPkg/OvmfPkgIa32.dsc @@ -865,7 +865,7 @@ !if $(SMM_REQUIRE) == TRUE OvmfPkg/SmmAccess/SmmAccess2Dxe.inf OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf - UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf + OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf # # SMM Initial Program Load (a DXE_RUNTIME_DRIVER) diff --git a/OvmfPkg/OvmfPkgIa32.fdf b/OvmfPkg/OvmfPkgIa32.fdf index d58214eb80..56e3ab3df2 100644 --- a/OvmfPkg/OvmfPkgIa32.fdf +++ b/OvmfPkg/OvmfPkgIa32.fdf @@ -319,7 +319,7 @@ INF OvmfPkg/IoMmuDxe/IoMmuDxe.inf !if $(SMM_REQUIRE) == TRUE INF OvmfPkg/SmmAccess/SmmAccess2Dxe.inf INF OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf -INF UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf +INF OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf INF MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf INF MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf INF OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc index 67c1635e33..d907465752 100644 --- a/OvmfPkg/OvmfPkgIa32X64.dsc +++ b/OvmfPkg/OvmfPkgIa32X64.dsc @@ -878,7 +878,7 @@ !if $(SMM_REQUIRE) == TRUE OvmfPkg/SmmAccess/SmmAccess2Dxe.inf OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf - UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf + OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf # # SMM Initial Program Load (a DXE_RUNTIME_DRIVER) diff --git a/OvmfPkg/OvmfPkgIa32X64.fdf b/OvmfPkg/OvmfPkgIa32X64.fdf index c21c3b92d8..add188723f 100644 --- a/OvmfPkg/OvmfPkgIa32X64.fdf +++ b/OvmfPkg/OvmfPkgIa32X64.fdf @@ -326,7 +326,7 @@ INF OvmfPkg/IoMmuDxe/IoMmuDxe.inf !if $(SMM_REQUIRE) == TRUE INF OvmfPkg/SmmAccess/SmmAccess2Dxe.inf INF OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf -INF UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf +INF OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf INF MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf INF MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf INF OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc index 45014190a6..0c6582a9ed 100644 --- a/OvmfPkg/OvmfPkgX64.dsc +++ b/OvmfPkg/OvmfPkgX64.dsc @@ -876,7 +876,7 @@ !if $(SMM_REQUIRE) == TRUE OvmfPkg/SmmAccess/SmmAccess2Dxe.inf OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf - UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf + OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf # # SMM Initial Program Load (a DXE_RUNTIME_DRIVER) diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf index c21c3b92d8..add188723f 100644 --- a/OvmfPkg/OvmfPkgX64.fdf +++ b/OvmfPkg/OvmfPkgX64.fdf @@ -326,7 +326,7 @@ INF OvmfPkg/IoMmuDxe/IoMmuDxe.inf !if $(SMM_REQUIRE) == TRUE INF OvmfPkg/SmmAccess/SmmAccess2Dxe.inf INF OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf -INF UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf +INF OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf INF MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf INF MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf INF OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf -- 2.39.2