This module initializes the ACPI_CPU_DATA structure and registers the address of this structure in the PcdCpuS3DataAddress PCD. This is simplest version of this module. It does not provide a machine check handler or CPU register initialization tables for ACPI S3 resume. This module can be copied into a CPU specific package and customized if those additional features are required.
Cc: Laszlo Ersek <ler...@redhat.com> Cc: "Yao, Jiewen" <jiewen....@intel.com> Cc: "Fan, Jeff" <jeff....@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney <michael.d.kin...@intel.com> --- UefiCpuPkg/CpuS3DataDxe/CpuS3Data.c | 267 +++++++++++++++++++++++++++++++ UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf | 62 +++++++ UefiCpuPkg/UefiCpuPkg.dsc | 1 + 3 files changed, 330 insertions(+) create mode 100644 UefiCpuPkg/CpuS3DataDxe/CpuS3Data.c create mode 100644 UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf diff --git a/UefiCpuPkg/CpuS3DataDxe/CpuS3Data.c b/UefiCpuPkg/CpuS3DataDxe/CpuS3Data.c new file mode 100644 index 0000000..924136f --- /dev/null +++ b/UefiCpuPkg/CpuS3DataDxe/CpuS3Data.c @@ -0,0 +1,267 @@ +/** @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 simplest version of +this module. It does not provide a machine check handler or CPU register +initialization tables for ACPI S3 resume. This module can be copied into a +CPU specific package and customized if those additional features are required. + +Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2015, Red Hat, Inc. + +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#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 <Protocol/MpService.h> +#include <Guid/EventGroup.h> + +// +// Data structure used to allocate ACPI_CPU_DATA and its supporting structures +// +typedef struct { + ACPI_CPU_DATA AcpuCpuData; + MTRR_SETTINGS MtrrTable; + IA32_DESCRIPTOR GdtrProfile; + IA32_DESCRIPTOR IdtrProfile; +} ACPI_CPU_DATA_EX; + +/** + Allocate EfiACPIMemoryNVS below 4G memory address. + + This function allocates EfiACPIMemoryNVS below 4G memory address. + + @param[in] Size Size of memory to allocate. + + @return Allocated address for output. + +**/ +VOID * +AllocateAcpiNvsMemoryBelow4G ( + IN UINTN Size + ) +{ + EFI_PHYSICAL_ADDRESS Address; + EFI_STATUS Status; + VOID *Buffer; + + Address = BASE_4GB - 1; + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiACPIMemoryNVS, + EFI_SIZE_TO_PAGES (Size), + &Address + ); + if (EFI_ERROR (Status)) { + return NULL; + } + + Buffer = (VOID *)(UINTN)Address; + ZeroMem (Buffer, Size); + + return Buffer; +} + +/** + Callback function executed when the EndOfDxe event group is signaled. + + We delay 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 +SaveMtrrsOnEndOfDxe ( + IN EFI_EVENT Event, + OUT VOID *Context + ) +{ + DEBUG ((EFI_D_VERBOSE, "%a\n", __FUNCTION__)); + MtrrGetAllMtrrs (Context); +} + +/** + The entry function for QNCInit driver. + + This function just call initialization function for PciHostBridge, + LegacyRegion and QNCSmmAccess module. + + @param[in] ImageHandle The driver image handle for GmchInit driver + @param[in] SystemTable The pointer to System Table + + @retval EFI_SUCCESS Success to initialize every module for GMCH driver. + @return EFI_STATUS The status of initialization work. + +**/ +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; + UINTN TableSize; + CPU_REGISTER_TABLE *RegisterTable; + CPU_REGISTER_TABLE_ENTRY *RegisterTableEntry; + UINTN Index; + EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer; + UINTN GdtSize; + UINTN IdtSize; + VOID *Gdt; + VOID *Idt; + EFI_EVENT Event; + + // + // Allocate ACPI NVS memory below 4G memory for use of S3 resume. + // + AcpiCpuDataEx = AllocateAcpiNvsMemoryBelow4G (sizeof (ACPI_CPU_DATA_EX)); + ASSERT (AcpiCpuDataEx != NULL); + AcpiCpuData = &AcpiCpuDataEx->AcpuCpuData; + + // + // 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 + // + if (NumberOfCpus > 1) { + // + // If there are 1 or more APs, then allocate a 4KB reserved page belowe 1MB + // + AcpiCpuData->StartupVector = BASE_1MB - 1; + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiReservedMemoryType, + 1, + &AcpiCpuData->StartupVector + ); + ASSERT_EFI_ERROR (Status); + } else { + // + // If there are 0 APs, then set StartupVector to 0 + // + AcpiCpuData->StartupVector = 0; + } + 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 + // + AcpiCpuData->StackAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateAcpiNvsMemoryBelow4G ( + NumberOfCpus * AcpiCpuData->StackSize + ); + + // + // Get the boot processor's GDT and IDT + // + AsmReadGdtr ((IA32_DESCRIPTOR *)&AcpiCpuDataEx->GdtrProfile); + AsmReadIdtr ((IA32_DESCRIPTOR *)&AcpiCpuDataEx->IdtrProfile); + + // + // Allocate GDT and IDT in ACPI NVS and copy current GDT and IDT contents + // + GdtSize = AcpiCpuDataEx->GdtrProfile.Limit + 1; + IdtSize = AcpiCpuDataEx->IdtrProfile.Limit + 1; + Gdt = AllocateAcpiNvsMemoryBelow4G (GdtSize + IdtSize); + 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; + + // + // Allocate buffer for empty RegisterTable and PreSmmInitRegisterTable for all CPUs + // + TableSize = 2 * NumberOfCpus * (sizeof (CPU_REGISTER_TABLE) + sizeof (CPU_REGISTER_TABLE_ENTRY)); + RegisterTable = (CPU_REGISTER_TABLE *)AllocateAcpiNvsMemoryBelow4G (TableSize); + RegisterTableEntry = (CPU_REGISTER_TABLE_ENTRY *)(RegisterTable + 2 * NumberOfCpus); + 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 = sizeof (CPU_REGISTER_TABLE_ENTRY); + RegisterTable[Index].RegisterTableEntry = &RegisterTableEntry[Index]; + + RegisterTable[NumberOfCpus + Index].InitialApicId = (UINT32)ProcessorInfoBuffer.ProcessorId; + RegisterTable[NumberOfCpus + Index].TableLength = 0; + RegisterTable[NumberOfCpus + Index].AllocatedSize = sizeof (CPU_REGISTER_TABLE_ENTRY); + RegisterTable[NumberOfCpus + Index].RegisterTableEntry = &RegisterTableEntry[NumberOfCpus + Index]; + } + AcpiCpuData->RegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)RegisterTable; + AcpiCpuData->PreSmmInitRegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)(RegisterTable + NumberOfCpus); + + // + // Set the base address of CPU S3 data to PcdCpuS3DataAddress + // + Status = PcdSet64S (PcdCpuS3DataAddress, (UINT64)(UINTN)AcpiCpuData); + ASSERT_EFI_ERROR (Status); + + // + // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event. + // The notification function saves MTRRs for ACPI_CPU_DATA + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + SaveMtrrsOnEndOfDxe, + &AcpiCpuDataEx->MtrrTable, + &gEfiEndOfDxeEventGroupGuid, + &Event + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} diff --git a/UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf b/UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf new file mode 100644 index 0000000..c0a552e --- /dev/null +++ b/UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf @@ -0,0 +1,62 @@ +## @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 simplest version of +# this module. It does not provide a machine check handler or CPU register +# initialization tables for ACPI S3 resume. This module can be copied into a +# CPU specific package and customized if those additional features are required. +# +# Copyright (c) 2013-2015, Intel Corporation. All rights reserved.<BR> +# Copyright (c) 2015, Red Hat, Inc. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = CpuS3DataDxe + FILE_GUID = 4D2E57EE-0E3F-44DD-93C4-D3B57E96945D + 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 + UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiBootServicesTableLib + BaseMemoryLib + DebugLib + BaseLib + MtrrLib + +[Guids] + gEfiEndOfDxeEventGroupGuid ## CONSUMES + +[Protocols] + gEfiMpServiceProtocolGuid ## CONSUMES + +[Pcd] + gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize ## CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuS3DataAddress ## PRODUCES + +[Depex] + gEfiMpServiceProtocolGuid diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc index 756645f..4061050 100644 --- a/UefiCpuPkg/UefiCpuPkg.dsc +++ b/UefiCpuPkg/UefiCpuPkg.dsc @@ -101,6 +101,7 @@ UefiCpuPkg/CpuDxe/CpuDxe.inf UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf UefiCpuPkg/CpuMpPei/CpuMpPei.inf + UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.inf UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf -- 2.6.3.windows.1 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel