/**@file Platform PEI driver Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.
Copyright (c) 2011, Andrei Warkentin SPDX-License-Identifier: BSD-2-Clause-Patent **/ // // The package level header files this module uses // #include // // The Library classes this module consumes // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Platform.h" #include "PlatformId.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 (); if (TdIsEnabled ()) { TdxHelperBuildGuidHobForTdxMeasurement (); } 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); PlatformIdInitialization (PeiServices); } IntelTdxInitialize (); InstallFeatureControlCallback (PlatformInfoHob); if (PlatformInfoHob->SmmSmramRequire) { RelocateSmBase (); } return EFI_SUCCESS; }