Not needed any more, SMM + 64-bit PEI + S3 suspend works now. Fixed by commits: -8bd2028f9a("MdeModulePkg: Supporting S3 in 64bit PEI") -6acf72901a("UefiCpuPkg: Supporting S3 in 64bit PEI") See also https://bugzilla.tianocore.org/show_bug.cgi?id=4195 Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Reviewed-by: Laszlo Ersek <lersek@redhat.com> Reviewed-by: Ray Ni <ray.ni@intel.com>
		
			
				
	
	
		
			373 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			373 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/**@file
 | 
						|
  Platform PEI driver
 | 
						|
 | 
						|
  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
 | 
						|
  Copyright (c) 2011, Andrei Warkentin <andreiw@motorola.com>
 | 
						|
 | 
						|
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
//
 | 
						|
// The package level header files this module uses
 | 
						|
//
 | 
						|
#include <PiPei.h>
 | 
						|
 | 
						|
//
 | 
						|
// The Library classes this module consumes
 | 
						|
//
 | 
						|
#include <Library/BaseMemoryLib.h>
 | 
						|
#include <Library/BaseLib.h>
 | 
						|
#include <Library/DebugLib.h>
 | 
						|
#include <Library/HobLib.h>
 | 
						|
#include <Library/IoLib.h>
 | 
						|
#include <Library/MemoryAllocationLib.h>
 | 
						|
#include <Library/PcdLib.h>
 | 
						|
#include <Library/PciLib.h>
 | 
						|
#include <Library/PeimEntryPoint.h>
 | 
						|
#include <Library/PeiServicesLib.h>
 | 
						|
#include <Library/QemuFwCfgLib.h>
 | 
						|
#include <Library/QemuFwCfgS3Lib.h>
 | 
						|
#include <Library/QemuFwCfgSimpleParserLib.h>
 | 
						|
#include <Library/ResourcePublicationLib.h>
 | 
						|
#include <Ppi/MasterBootMode.h>
 | 
						|
#include <IndustryStandard/I440FxPiix4.h>
 | 
						|
#include <IndustryStandard/Microvm.h>
 | 
						|
#include <IndustryStandard/Pci22.h>
 | 
						|
#include <IndustryStandard/Q35MchIch9.h>
 | 
						|
#include <IndustryStandard/QemuCpuHotplug.h>
 | 
						|
#include <Library/MemEncryptSevLib.h>
 | 
						|
#include <OvmfPlatforms.h>
 | 
						|
 | 
						|
#include "Platform.h"
 | 
						|
 | 
						|
EFI_PEI_PPI_DESCRIPTOR  mPpiBootMode[] = {
 | 
						|
  {
 | 
						|
    EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
 | 
						|
    &gEfiPeiMasterBootModePpiGuid,
 | 
						|
    NULL
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
VOID
 | 
						|
MemMapInitialization (
 | 
						|
  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
 | 
						|
  )
 | 
						|
{
 | 
						|
  RETURN_STATUS  PcdStatus;
 | 
						|
 | 
						|
  PlatformMemMapInitialization (PlatformInfoHob);
 | 
						|
 | 
						|
  if (PlatformInfoHob->HostBridgeDevId == 0xffff /* microvm */) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  PcdStatus = PcdSet64S (PcdPciMmio32Base, PlatformInfoHob->PcdPciMmio32Base);
 | 
						|
  ASSERT_RETURN_ERROR (PcdStatus);
 | 
						|
  PcdStatus = PcdSet64S (PcdPciMmio32Size, PlatformInfoHob->PcdPciMmio32Size);
 | 
						|
  ASSERT_RETURN_ERROR (PcdStatus);
 | 
						|
 | 
						|
  PcdStatus = PcdSet64S (PcdPciIoBase, PlatformInfoHob->PcdPciIoBase);
 | 
						|
  ASSERT_RETURN_ERROR (PcdStatus);
 | 
						|
  PcdStatus = PcdSet64S (PcdPciIoSize, PlatformInfoHob->PcdPciIoSize);
 | 
						|
  ASSERT_RETURN_ERROR (PcdStatus);
 | 
						|
}
 | 
						|
 | 
						|
STATIC
 | 
						|
VOID
 | 
						|
NoexecDxeInitialization (
 | 
						|
  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
 | 
						|
  )
 | 
						|
{
 | 
						|
  RETURN_STATUS  Status;
 | 
						|
 | 
						|
  Status = PlatformNoexecDxeInitialization (PlatformInfoHob);
 | 
						|
  if (!RETURN_ERROR (Status)) {
 | 
						|
    Status = PcdSetBoolS (PcdSetNxForStack, PlatformInfoHob->PcdSetNxForStack);
 | 
						|
    ASSERT_RETURN_ERROR (Status);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static const UINT8  EmptyFdt[] = {
 | 
						|
  0xd0, 0x0d, 0xfe, 0xed, 0x00, 0x00, 0x00, 0x48,
 | 
						|
  0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x48,
 | 
						|
  0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x11,
 | 
						|
  0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
 | 
						|
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
 | 
						|
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
						|
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
						|
  0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
 | 
						|
  0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09,
 | 
						|
};
 | 
						|
 | 
						|
VOID
 | 
						|
MicrovmInitialization (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  FIRMWARE_CONFIG_ITEM  FdtItem;
 | 
						|
  UINTN                 FdtSize;
 | 
						|
  UINTN                 FdtPages;
 | 
						|
  EFI_STATUS            Status;
 | 
						|
  UINT64                *FdtHobData;
 | 
						|
  VOID                  *NewBase;
 | 
						|
 | 
						|
  Status = QemuFwCfgFindFile ("etc/fdt", &FdtItem, &FdtSize);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((DEBUG_INFO, "%a: no etc/fdt found in fw_cfg, using dummy\n", __func__));
 | 
						|
    FdtItem = 0;
 | 
						|
    FdtSize = sizeof (EmptyFdt);
 | 
						|
  }
 | 
						|
 | 
						|
  FdtPages = EFI_SIZE_TO_PAGES (FdtSize);
 | 
						|
  NewBase  = AllocatePages (FdtPages);
 | 
						|
  if (NewBase == NULL) {
 | 
						|
    DEBUG ((DEBUG_INFO, "%a: AllocatePages failed\n", __func__));
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (FdtItem) {
 | 
						|
    QemuFwCfgSelectItem (FdtItem);
 | 
						|
    QemuFwCfgReadBytes (FdtSize, NewBase);
 | 
						|
  } else {
 | 
						|
    CopyMem (NewBase, EmptyFdt, FdtSize);
 | 
						|
  }
 | 
						|
 | 
						|
  FdtHobData = BuildGuidHob (&gFdtHobGuid, sizeof (*FdtHobData));
 | 
						|
  if (FdtHobData == NULL) {
 | 
						|
    DEBUG ((DEBUG_INFO, "%a: BuildGuidHob failed\n", __func__));
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG ((
 | 
						|
    DEBUG_INFO,
 | 
						|
    "%a: fdt at 0x%x (size %d)\n",
 | 
						|
    __func__,
 | 
						|
    NewBase,
 | 
						|
    FdtSize
 | 
						|
    ));
 | 
						|
  *FdtHobData = (UINTN)NewBase;
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
MiscInitializationForMicrovm (
 | 
						|
  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
 | 
						|
  )
 | 
						|
{
 | 
						|
  RETURN_STATUS  PcdStatus;
 | 
						|
 | 
						|
  ASSERT (PlatformInfoHob->HostBridgeDevId == 0xffff);
 | 
						|
 | 
						|
  DEBUG ((DEBUG_INFO, "%a: microvm\n", __func__));
 | 
						|
  //
 | 
						|
  // Disable A20 Mask
 | 
						|
  //
 | 
						|
  IoOr8 (0x92, BIT1);
 | 
						|
 | 
						|
  //
 | 
						|
  // Build the CPU HOB with guest RAM size dependent address width and 16-bits
 | 
						|
  // of IO space. (Side note: unlike other HOBs, the CPU HOB is needed during
 | 
						|
  // S3 resume as well, so we build it unconditionally.)
 | 
						|
  //
 | 
						|
  BuildCpuHob (PlatformInfoHob->PhysMemAddressWidth, 16);
 | 
						|
 | 
						|
  MicrovmInitialization ();
 | 
						|
  PcdStatus = PcdSet16S (
 | 
						|
                PcdOvmfHostBridgePciDevId,
 | 
						|
                MICROVM_PSEUDO_DEVICE_ID
 | 
						|
                );
 | 
						|
  ASSERT_RETURN_ERROR (PcdStatus);
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
MiscInitialization (
 | 
						|
  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
 | 
						|
  )
 | 
						|
{
 | 
						|
  RETURN_STATUS  PcdStatus;
 | 
						|
 | 
						|
  PlatformMiscInitialization (PlatformInfoHob);
 | 
						|
 | 
						|
  PcdStatus = PcdSet16S (PcdOvmfHostBridgePciDevId, PlatformInfoHob->HostBridgeDevId);
 | 
						|
  ASSERT_RETURN_ERROR (PcdStatus);
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
BootModeInitialization (
 | 
						|
  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  if (PlatformCmosRead8 (0xF) == 0xFE) {
 | 
						|
    PlatformInfoHob->BootMode = BOOT_ON_S3_RESUME;
 | 
						|
  }
 | 
						|
 | 
						|
  PlatformCmosWrite8 (0xF, 0x00);
 | 
						|
 | 
						|
  Status = PeiServicesSetBootMode (PlatformInfoHob->BootMode);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  Status = PeiServicesInstallPpi (mPpiBootMode);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
ReserveEmuVariableNvStore (
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_PHYSICAL_ADDRESS  VariableStore;
 | 
						|
  RETURN_STATUS         PcdStatus;
 | 
						|
 | 
						|
  VariableStore = (EFI_PHYSICAL_ADDRESS)(UINTN)PlatformReserveEmuVariableNvStore ();
 | 
						|
  PcdStatus     = PcdSet64S (PcdEmuVariableNvStoreReserved, VariableStore);
 | 
						|
 | 
						|
  if (FeaturePcdGet (PcdSecureBootSupported)) {
 | 
						|
    // restore emulated VarStore from pristine ROM copy
 | 
						|
    PlatformInitEmuVariableNvStore ((VOID *)(UINTN)VariableStore);
 | 
						|
  }
 | 
						|
 | 
						|
  ASSERT_RETURN_ERROR (PcdStatus);
 | 
						|
}
 | 
						|
 | 
						|
STATIC
 | 
						|
VOID
 | 
						|
Q35BoardVerification (
 | 
						|
  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (PlatformInfoHob->HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG ((
 | 
						|
    DEBUG_ERROR,
 | 
						|
    "%a: no TSEG (SMRAM) on host bridge DID=0x%04x; "
 | 
						|
    "only DID=0x%04x (Q35) is supported\n",
 | 
						|
    __func__,
 | 
						|
    PlatformInfoHob->HostBridgeDevId,
 | 
						|
    INTEL_Q35_MCH_DEVICE_ID
 | 
						|
    ));
 | 
						|
  ASSERT (FALSE);
 | 
						|
  CpuDeadLoop ();
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Fetch the boot CPU count and the possible CPU count from QEMU, and expose
 | 
						|
  them to UefiCpuPkg modules. Set the MaxCpuCount field in PlatformInfoHob.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
MaxCpuCountInitialization (
 | 
						|
  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
 | 
						|
  )
 | 
						|
{
 | 
						|
  RETURN_STATUS  PcdStatus;
 | 
						|
 | 
						|
  PlatformMaxCpuCountInitialization (PlatformInfoHob);
 | 
						|
 | 
						|
  PcdStatus = PcdSet32S (PcdCpuBootLogicalProcessorNumber, PlatformInfoHob->PcdCpuBootLogicalProcessorNumber);
 | 
						|
  ASSERT_RETURN_ERROR (PcdStatus);
 | 
						|
  PcdStatus = PcdSet32S (PcdCpuMaxLogicalProcessorNumber, PlatformInfoHob->PcdCpuMaxLogicalProcessorNumber);
 | 
						|
  ASSERT_RETURN_ERROR (PcdStatus);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * @brief Builds PlatformInfo Hob
 | 
						|
 */
 | 
						|
EFI_HOB_PLATFORM_INFO *
 | 
						|
BuildPlatformInfoHob (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_HOB_PLATFORM_INFO  PlatformInfoHob;
 | 
						|
  EFI_HOB_GUID_TYPE      *GuidHob;
 | 
						|
 | 
						|
  ZeroMem (&PlatformInfoHob, sizeof PlatformInfoHob);
 | 
						|
  BuildGuidDataHob (&gUefiOvmfPkgPlatformInfoGuid, &PlatformInfoHob, sizeof (EFI_HOB_PLATFORM_INFO));
 | 
						|
  GuidHob = GetFirstGuidHob (&gUefiOvmfPkgPlatformInfoGuid);
 | 
						|
  return (EFI_HOB_PLATFORM_INFO *)GET_GUID_HOB_DATA (GuidHob);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Perform Platform PEI initialization.
 | 
						|
 | 
						|
  @param  FileHandle      Handle of the file being invoked.
 | 
						|
  @param  PeiServices     Describes the list of possible PEI Services.
 | 
						|
 | 
						|
  @return EFI_SUCCESS     The PEIM initialized successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
InitializePlatform (
 | 
						|
  IN       EFI_PEI_FILE_HANDLE  FileHandle,
 | 
						|
  IN CONST EFI_PEI_SERVICES     **PeiServices
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_HOB_PLATFORM_INFO  *PlatformInfoHob;
 | 
						|
  EFI_STATUS             Status;
 | 
						|
 | 
						|
  DEBUG ((DEBUG_INFO, "Platform PEIM Loaded\n"));
 | 
						|
  PlatformInfoHob = BuildPlatformInfoHob ();
 | 
						|
 | 
						|
  PlatformInfoHob->SmmSmramRequire     = FeaturePcdGet (PcdSmmSmramRequire);
 | 
						|
  PlatformInfoHob->SevEsIsEnabled      = MemEncryptSevEsIsEnabled ();
 | 
						|
  PlatformInfoHob->PcdPciMmio64Size    = PcdGet64 (PcdPciMmio64Size);
 | 
						|
  PlatformInfoHob->DefaultMaxCpuNumber = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
 | 
						|
 | 
						|
  PlatformDebugDumpCmos ();
 | 
						|
 | 
						|
  if (QemuFwCfgS3Enabled ()) {
 | 
						|
    DEBUG ((DEBUG_INFO, "S3 support was detected on QEMU\n"));
 | 
						|
    PlatformInfoHob->S3Supported = TRUE;
 | 
						|
    Status                       = PcdSetBoolS (PcdAcpiS3Enable, TRUE);
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
  }
 | 
						|
 | 
						|
  BootModeInitialization (PlatformInfoHob);
 | 
						|
 | 
						|
  //
 | 
						|
  // Query Host Bridge DID
 | 
						|
  //
 | 
						|
  PlatformInfoHob->HostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID);
 | 
						|
  AddressWidthInitialization (PlatformInfoHob);
 | 
						|
 | 
						|
  MaxCpuCountInitialization (PlatformInfoHob);
 | 
						|
 | 
						|
  if (PlatformInfoHob->SmmSmramRequire) {
 | 
						|
    Q35BoardVerification (PlatformInfoHob);
 | 
						|
    Q35TsegMbytesInitialization (PlatformInfoHob);
 | 
						|
    Q35SmramAtDefaultSmbaseInitialization (PlatformInfoHob);
 | 
						|
  }
 | 
						|
 | 
						|
  PublishPeiMemory (PlatformInfoHob);
 | 
						|
 | 
						|
  PlatformQemuUc32BaseInitialization (PlatformInfoHob);
 | 
						|
 | 
						|
  InitializeRamRegions (PlatformInfoHob);
 | 
						|
 | 
						|
  if (PlatformInfoHob->BootMode != BOOT_ON_S3_RESUME) {
 | 
						|
    if (!PlatformInfoHob->SmmSmramRequire) {
 | 
						|
      ReserveEmuVariableNvStore ();
 | 
						|
    }
 | 
						|
 | 
						|
    PeiFvInitialization (PlatformInfoHob);
 | 
						|
    MemTypeInfoInitialization (PlatformInfoHob);
 | 
						|
    MemMapInitialization (PlatformInfoHob);
 | 
						|
    NoexecDxeInitialization (PlatformInfoHob);
 | 
						|
  }
 | 
						|
 | 
						|
  InstallClearCacheCallback ();
 | 
						|
  AmdSevInitialize (PlatformInfoHob);
 | 
						|
  if (PlatformInfoHob->HostBridgeDevId == 0xffff) {
 | 
						|
    MiscInitializationForMicrovm (PlatformInfoHob);
 | 
						|
  } else {
 | 
						|
    MiscInitialization (PlatformInfoHob);
 | 
						|
  }
 | 
						|
 | 
						|
  IntelTdxInitialize ();
 | 
						|
  InstallFeatureControlCallback (PlatformInfoHob);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 |