123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281 |
- /** @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 - 2021, 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/DebugLib.h>
- #include <Library/MemoryAllocationLib.h>
- #include <Library/MtrrLib.h>
- #include <Library/UefiBootServicesTableLib.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;
- VOID *Stack;
- 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;
- if (PcdGetBool (PcdQ35SmramAtDefaultSmbase)) {
- NumberOfCpus = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
- } else {
- UINTN NumberOfEnabledProcessors;
- //
- // 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) {
- CopyMem (&AcpiCpuData->CpuFeatureInitData, &OldAcpiCpuData->CpuFeatureInitData, sizeof (CPU_FEATURE_INIT_DATA));
- }
- //
- // 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;
- }
|