__FUNCTION__ is a pre-standard extension that gcc and Visual C++ among others support, while __func__ was standardized in C99. Since it's more standard, replace __FUNCTION__ with __func__ throughout OvmfPkg. Signed-off-by: Rebecca Cran <rebecca@bsdio.com> Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Ard Biesheuvel <ardb@kernel.org> Reviewed-by: Sunil V L <sunilvl@ventanamicro.com>
		
			
				
	
	
		
			282 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			282 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @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", __func__));
 | 
						|
  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;
 | 
						|
}
 |