summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--OvmfPkg/CpuS3DataDxe/CpuS3Data.c309
-rw-r--r--OvmfPkg/CpuS3DataDxe/CpuS3DataDxe.inf61
-rw-r--r--OvmfPkg/OvmfPkgIa32.dsc2
-rw-r--r--OvmfPkg/OvmfPkgIa32.fdf2
-rw-r--r--OvmfPkg/OvmfPkgIa32X64.dsc2
-rw-r--r--OvmfPkg/OvmfPkgIa32X64.fdf2
-rw-r--r--OvmfPkg/OvmfPkgX64.dsc2
-rw-r--r--OvmfPkg/OvmfPkgX64.fdf2
8 files changed, 376 insertions, 6 deletions
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.<BR>
+Copyright (c) 2015 - 2020, Red Hat, Inc.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <AcpiCpuData.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MtrrLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <Protocol/MpService.h>
+#include <Guid/EventGroup.h>
+
+//
+// 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.<BR>
+# 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