From nobody Sun Feb 8 22:50:31 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+87705+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+87705+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1647564503; cv=none; d=zohomail.com; s=zohoarc; b=D7Z8oIPfNgzVi7oAwlbiDECC0CsWokT1/yKxEhKZUeNtcM+bijvG9+mtIrgRe5qyZs88j2Ys2BPIXM4LMV+qkPRha52jrrGoK6FWsMA+B9TKqkq34T9+/3Ng8j0nghFHrCFAhHpP7ygJJHsDa2tMS46LuoAhvdtqsw19rypyA3U= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1647564503; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:References:Sender:Subject:To; bh=Debg8vANussLgZ3G/F5HIZcRQo33yDCU/Q6QGtn9bSs=; b=fEU/LjLPucHKHIRnvyAkaJ+KHUYHWOP8Ms97vaXW726PxJSMw77GNXTa0+SFTD16e4KGAokxH1TfE9GTaSW6afQ2frSGLmkwZdecQs3dwM+hmGU6AIrIKEkEZZvERjs6WVLOqd8Hw/UICbcuRESHzpliXU7QSw1sO0nF8MzcKSw= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+87705+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 1647564503144816.2488413122702; Thu, 17 Mar 2022 17:48:23 -0700 (PDT) Return-Path: X-Received: by 127.0.0.2 with SMTP id 33iqYY1788612xZwAVdsxikE; Thu, 17 Mar 2022 17:48:22 -0700 X-Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by mx.groups.io with SMTP id smtpd.web10.4356.1647564500124120641 for ; Thu, 17 Mar 2022 17:48:20 -0700 X-IronPort-AV: E=McAfee;i="6200,9189,10289"; a="281818364" X-IronPort-AV: E=Sophos;i="5.90,190,1643702400"; d="scan'208";a="281818364" X-Received: from orsmga007.jf.intel.com ([10.7.209.58]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Mar 2022 17:47:56 -0700 X-IronPort-AV: E=Sophos;i="5.90,190,1643702400"; d="scan'208";a="541603175" X-Received: from mxu9-mobl1.ccr.corp.intel.com ([10.249.172.84]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Mar 2022 17:47:52 -0700 From: "Min Xu" To: devel@edk2.groups.io Cc: Min Xu , Ard Biesheuvel , Jordan Justen , Brijesh Singh , Erdem Aktas , James Bottomley , Jiewen Yao , Tom Lendacky , Gerd Hoffmann , Sebastien Boeuf Subject: [edk2-devel] [PATCH V9 30/47] OvmfPkg/PlatformInitLib: Move functions to Platform.c Date: Fri, 18 Mar 2022 08:45:48 +0800 Message-Id: <07fcc311665a659e7cc614c00e7d63d9fe63ba5f.1647523953.git.min.m.xu@intel.com> In-Reply-To: References: MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,min.m.xu@intel.com X-Gm-Message-State: XYAqR6dqiCcoWvZdCXGhLmswx1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1647564502; bh=8dEdqPGxQ5+U8Nxgvy/OIrvgtSGu6qkClsqfFVrWxVk=; h=Cc:Date:From:Reply-To:Subject:To; b=s/ii7fFTXTvL6WB8kzNfZGKZALDZ07lHVHNxFkeBgH3PXousYuTX7KwrqMmlDVjzMcN QEw0Wn/FLj5v9JEyn9pBGzGDocO9QBdV2BeqSnbTIivEFyd6W812d0hi9oa9ngcuiY6PN hEuavX1/mVCRWd7KzLf4dgKMsDBV59ANj54= X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1647564504199100008 Content-Type: text/plain; charset="utf-8" BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3D3863 Move functions in PlatformPei/Platform.c to PlatformInitLib/Platform.c. Cc: Ard Biesheuvel Cc: Jordan Justen Cc: Brijesh Singh Cc: Erdem Aktas Cc: James Bottomley Cc: Jiewen Yao Cc: Tom Lendacky Cc: Gerd Hoffmann Cc: Sebastien Boeuf Acked-by: Gerd Hoffmann Signed-off-by: Min Xu --- OvmfPkg/Include/Library/PlatformInitLib.h | 34 ++ OvmfPkg/Library/PlatformInitLib/Platform.c | 465 +++++++++++++++++++++ OvmfPkg/PlatformPei/Platform.c | 451 -------------------- 3 files changed, 499 insertions(+), 451 deletions(-) diff --git a/OvmfPkg/Include/Library/PlatformInitLib.h b/OvmfPkg/Include/Li= brary/PlatformInitLib.h index 62020efadf37..b31f521578c2 100644 --- a/OvmfPkg/Include/Library/PlatformInitLib.h +++ b/OvmfPkg/Include/Library/PlatformInitLib.h @@ -169,4 +169,38 @@ PlatformQemuInitializeRamForS3 ( IN EFI_HOB_PLATFORM_INFO *PlatformInfoHob ); =20 +VOID +EFIAPI +PlatformMemMapInitialization ( + IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob + ); + +/** + * Fetch "opt/ovmf/PcdSetNxForStack" from QEMU + * + * @param Setting The pointer to the setting of "/opt/ovmf/PcdSetNxFor= Stack". + * @return EFI_SUCCESS Successfully fetch the settings. + */ +EFI_STATUS +EFIAPI +PlatformNoexecDxeInitialization ( + IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob + ); + +VOID +EFIAPI +PlatformMiscInitialization ( + IN EFI_HOB_PLATFORM_INFO *PlatformInfoHob + ); + +/** + Fetch the boot CPU count and the possible CPU count from QEMU, and expose + them to UefiCpuPkg modules. +**/ +VOID +EFIAPI +PlatformMaxCpuCountInitialization ( + IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob + ); + #endif // PLATFORM_INIT_LIB_H_ diff --git a/OvmfPkg/Library/PlatformInitLib/Platform.c b/OvmfPkg/Library/P= latformInitLib/Platform.c index e41f230ff563..c4fa7d445394 100644 --- a/OvmfPkg/Library/PlatformInitLib/Platform.c +++ b/OvmfPkg/Library/PlatformInitLib/Platform.c @@ -19,6 +19,18 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include =20 VOID @@ -104,3 +116,456 @@ PlatformAddMemoryRangeHob ( { PlatformAddMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryB= ase)); } + +VOID +EFIAPI +PlatformMemMapInitialization ( + IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob + ) +{ + UINT64 PciIoBase; + UINT64 PciIoSize; + UINT32 TopOfLowRam; + UINT64 PciExBarBase; + UINT32 PciBase; + UINT32 PciSize; + + PciIoBase =3D 0xC000; + PciIoSize =3D 0x4000; + + // + // Video memory + Legacy BIOS region + // + PlatformAddIoMemoryRangeHob (0x0A0000, BASE_1MB); + + if (PlatformInfoHob->HostBridgeDevId =3D=3D 0xffff /* microvm */) { + PlatformAddIoMemoryBaseSizeHob (MICROVM_GED_MMIO_BASE, SIZE_4KB); + PlatformAddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB); /* ioapic #1 */ + PlatformAddIoMemoryBaseSizeHob (0xFEC10000, SIZE_4KB); /* ioapic #2 */ + return; + } + + TopOfLowRam =3D PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); + PciExBarBase =3D 0; + if (PlatformInfoHob->HostBridgeDevId =3D=3D INTEL_Q35_MCH_DEVICE_ID) { + // + // The MMCONFIG area is expected to fall between the top of low RAM and + // the base of the 32-bit PCI host aperture. + // + PciExBarBase =3D FixedPcdGet64 (PcdPciExpressBaseAddress); + ASSERT (TopOfLowRam <=3D PciExBarBase); + ASSERT (PciExBarBase <=3D MAX_UINT32 - SIZE_256MB); + PciBase =3D (UINT32)(PciExBarBase + SIZE_256MB); + } else { + ASSERT (TopOfLowRam <=3D PlatformInfoHob->Uc32Base); + PciBase =3D PlatformInfoHob->Uc32Base; + } + + // + // address purpose size + // ------------ -------- ------------------------- + // max(top, 2g) PCI MMIO 0xFC000000 - max(top, 2g) + // 0xFC000000 gap 44 MB + // 0xFEC00000 IO-APIC 4 KB + // 0xFEC01000 gap 1020 KB + // 0xFED00000 HPET 1 KB + // 0xFED00400 gap 111 KB + // 0xFED1C000 gap (PIIX4) / RCRB (ICH9) 16 KB + // 0xFED20000 gap 896 KB + // 0xFEE00000 LAPIC 1 MB + // + PciSize =3D 0xFC000000 - PciBase; + PlatformAddIoMemoryBaseSizeHob (PciBase, PciSize); + + PlatformInfoHob->PcdPciMmio32Base =3D PciBase; + PlatformInfoHob->PcdPciMmio32Size =3D PciSize; + + PlatformAddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB); + PlatformAddIoMemoryBaseSizeHob (0xFED00000, SIZE_1KB); + if (PlatformInfoHob->HostBridgeDevId =3D=3D INTEL_Q35_MCH_DEVICE_ID) { + PlatformAddIoMemoryBaseSizeHob (ICH9_ROOT_COMPLEX_BASE, SIZE_16KB); + // + // Note: there should be an + // + // PlatformAddIoMemoryBaseSizeHob (PciExBarBase, SIZE_256MB); + // + // call below, just like the one above for RCBA. However, Linux insists + // that the MMCONFIG area be marked in the E820 or UEFI memory map as + // "reserved memory" -- Linux does not content itself with a simple gap + // in the memory map wherever the MCFG ACPI table points to. + // + // This appears to be a safety measure. The PCI Firmware Specification + // (rev 3.1) says in 4.1.2. "MCFG Table Description": "The resources c= an + // *optionally* be returned in [...] EFIGetMemoryMap as reserved memory + // [...]". (Emphasis added here.) + // + // Normally we add memory resource descriptor HOBs in + // QemuInitializeRam(), and pre-allocate from those with memory + // allocation HOBs in InitializeRamRegions(). However, the MMCONFIG ar= ea + // is most definitely not RAM; so, as an exception, cover it with + // uncacheable reserved memory right here. + // + PlatformAddReservedMemoryBaseSizeHob (PciExBarBase, SIZE_256MB, FALSE); + BuildMemoryAllocationHob ( + PciExBarBase, + SIZE_256MB, + EfiReservedMemoryType + ); + } + + PlatformAddIoMemoryBaseSizeHob (PcdGet32 (PcdCpuLocalApicBaseAddress), S= IZE_1MB); + + // + // On Q35, the IO Port space is available for PCI resource allocations f= rom + // 0x6000 up. + // + if (PlatformInfoHob->HostBridgeDevId =3D=3D INTEL_Q35_MCH_DEVICE_ID) { + PciIoBase =3D 0x6000; + PciIoSize =3D 0xA000; + ASSERT ((ICH9_PMBASE_VALUE & 0xF000) < PciIoBase); + } + + // + // Add PCI IO Port space available for PCI resource allocations. + // + BuildResourceDescriptorHob ( + EFI_RESOURCE_IO, + EFI_RESOURCE_ATTRIBUTE_PRESENT | + EFI_RESOURCE_ATTRIBUTE_INITIALIZED, + PciIoBase, + PciIoSize + ); + + PlatformInfoHob->PcdPciIoBase =3D PciIoBase; + PlatformInfoHob->PcdPciIoSize =3D PciIoSize; +} + +/** + * Fetch "opt/ovmf/PcdSetNxForStack" from QEMU + * + * @param Setting The pointer to the setting of "/opt/ovmf/PcdSetNxFor= Stack". + * @return EFI_SUCCESS Successfully fetch the settings. + */ +EFI_STATUS +EFIAPI +PlatformNoexecDxeInitialization ( + IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob + ) +{ + return QemuFwCfgParseBool ("opt/ovmf/PcdSetNxForStack", &PlatformInfoHob= ->PcdSetNxForStack); +} + +VOID +PciExBarInitialization ( + VOID + ) +{ + union { + UINT64 Uint64; + UINT32 Uint32[2]; + } PciExBarBase; + + // + // We only support the 256MB size for the MMCONFIG area: + // 256 buses * 32 devices * 8 functions * 4096 bytes config space. + // + // The masks used below enforce the Q35 requirements that the MMCONFIG a= rea + // be (a) correctly aligned -- here at 256 MB --, (b) located under 64 G= B. + // + // Note that (b) also ensures that the minimum address width we have + // determined in AddressWidthInitialization(), i.e., 36 bits, will suffi= ce + // for DXE's page tables to cover the MMCONFIG area. + // + PciExBarBase.Uint64 =3D FixedPcdGet64 (PcdPciExpressBaseAddress); + ASSERT ((PciExBarBase.Uint32[1] & MCH_PCIEXBAR_HIGHMASK) =3D=3D 0); + ASSERT ((PciExBarBase.Uint32[0] & MCH_PCIEXBAR_LOWMASK) =3D=3D 0); + + // + // Clear the PCIEXBAREN bit first, before programming the high register. + // + PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW), 0); + + // + // Program the high register. Then program the low register, setting the + // MMCONFIG area size and enabling decoding at once. + // + PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_HIGH), PciExBarBase.Uint32[= 1]); + PciWrite32 ( + DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW), + PciExBarBase.Uint32[0] | MCH_PCIEXBAR_BUS_FF | MCH_PCIEXBAR_EN + ); +} + +VOID +EFIAPI +PlatformMiscInitialization ( + IN EFI_HOB_PLATFORM_INFO *PlatformInfoHob + ) +{ + UINTN PmCmd; + UINTN Pmba; + UINT32 PmbaAndVal; + UINT32 PmbaOrVal; + UINTN AcpiCtlReg; + UINT8 AcpiEnBit; + + // + // 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 dur= ing + // S3 resume as well, so we build it unconditionally.) + // + BuildCpuHob (PlatformInfoHob->PhysMemAddressWidth, 16); + + // + // Determine platform type and save Host Bridge DID to PCD + // + switch (PlatformInfoHob->HostBridgeDevId) { + case INTEL_82441_DEVICE_ID: + PmCmd =3D POWER_MGMT_REGISTER_PIIX4 (PCI_COMMAND_OFFSET); + Pmba =3D POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA); + PmbaAndVal =3D ~(UINT32)PIIX4_PMBA_MASK; + PmbaOrVal =3D PIIX4_PMBA_VALUE; + AcpiCtlReg =3D POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMREGMISC); + AcpiEnBit =3D PIIX4_PMREGMISC_PMIOSE; + break; + case INTEL_Q35_MCH_DEVICE_ID: + PmCmd =3D POWER_MGMT_REGISTER_Q35 (PCI_COMMAND_OFFSET); + Pmba =3D POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE); + PmbaAndVal =3D ~(UINT32)ICH9_PMBASE_MASK; + PmbaOrVal =3D ICH9_PMBASE_VALUE; + AcpiCtlReg =3D POWER_MGMT_REGISTER_Q35 (ICH9_ACPI_CNTL); + AcpiEnBit =3D ICH9_ACPI_CNTL_ACPI_EN; + break; + case CLOUDHV_DEVICE_ID: + break; + default: + DEBUG (( + DEBUG_ERROR, + "%a: Unknown Host Bridge Device ID: 0x%04x\n", + __FUNCTION__, + PlatformInfoHob->HostBridgeDevId + )); + ASSERT (FALSE); + return; + } + + if (PlatformInfoHob->HostBridgeDevId =3D=3D CLOUDHV_DEVICE_ID) { + DEBUG ((DEBUG_INFO, "%a: Cloud Hypervisor is done.\n", __FUNCTION__)); + return; + } + + // + // If the appropriate IOspace enable bit is set, assume the ACPI PMBA has + // been configured and skip the setup here. This matches the logic in + // AcpiTimerLibConstructor (). + // + if ((PciRead8 (AcpiCtlReg) & AcpiEnBit) =3D=3D 0) { + // + // The PEI phase should be exited with fully accessibe ACPI PM IO spac= e: + // 1. set PMBA + // + PciAndThenOr32 (Pmba, PmbaAndVal, PmbaOrVal); + + // + // 2. set PCICMD/IOSE + // + PciOr8 (PmCmd, EFI_PCI_COMMAND_IO_SPACE); + + // + // 3. set ACPI PM IO enable bit (PMREGMISC:PMIOSE or ACPI_CNTL:ACPI_EN) + // + PciOr8 (AcpiCtlReg, AcpiEnBit); + } + + if (PlatformInfoHob->HostBridgeDevId =3D=3D INTEL_Q35_MCH_DEVICE_ID) { + // + // Set Root Complex Register Block BAR + // + PciWrite32 ( + POWER_MGMT_REGISTER_Q35 (ICH9_RCBA), + ICH9_ROOT_COMPLEX_BASE | ICH9_RCBA_EN + ); + + // + // Set PCI Express Register Range Base Address + // + PciExBarInitialization (); + } +} + +/** + Fetch the boot CPU count and the possible CPU count from QEMU, and expose + them to UefiCpuPkg modules. +**/ +VOID +EFIAPI +PlatformMaxCpuCountInitialization ( + IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob + ) +{ + UINT16 BootCpuCount; + UINT32 MaxCpuCount; + + // + // Try to fetch the boot CPU count. + // + QemuFwCfgSelectItem (QemuFwCfgItemSmpCpuCount); + BootCpuCount =3D QemuFwCfgRead16 (); + if (BootCpuCount =3D=3D 0) { + // + // QEMU doesn't report the boot CPU count. (BootCpuCount =3D=3D 0) wil= l let + // MpInitLib count APs up to (PcdCpuMaxLogicalProcessorNumber - 1), or + // until PcdCpuApInitTimeOutInMicroSeconds elapses (whichever is reach= ed + // first). + // + DEBUG ((DEBUG_WARN, "%a: boot CPU count unavailable\n", __FUNCTION__)); + MaxCpuCount =3D PlatformInfoHob->DefaultMaxCpuNumber; + } else { + // + // We will expose BootCpuCount to MpInitLib. MpInitLib will count APs = up to + // (BootCpuCount - 1) precisely, regardless of timeout. + // + // Now try to fetch the possible CPU count. + // + UINTN CpuHpBase; + UINT32 CmdData2; + + CpuHpBase =3D ((PlatformInfoHob->HostBridgeDevId =3D=3D INTEL_Q35_MCH_= DEVICE_ID) ? + ICH9_CPU_HOTPLUG_BASE : PIIX4_CPU_HOTPLUG_BASE); + + // + // If only legacy mode is available in the CPU hotplug register block,= or + // the register block is completely missing, then the writes below are + // no-ops. + // + // 1. Switch the hotplug register block to modern mode. + // + IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, 0); + // + // 2. Select a valid CPU for deterministic reading of + // QEMU_CPUHP_R_CMD_DATA2. + // + // CPU#0 is always valid; it is the always present and non-removable + // BSP. + // + IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, 0); + // + // 3. Send a command after which QEMU_CPUHP_R_CMD_DATA2 is specified to + // read as zero, and which does not invalidate the selector. (The + // selector may change, but it must not become invalid.) + // + // Send QEMU_CPUHP_CMD_GET_PENDING, as it will prove useful later. + // + IoWrite8 (CpuHpBase + QEMU_CPUHP_W_CMD, QEMU_CPUHP_CMD_GET_PENDING); + // + // 4. Read QEMU_CPUHP_R_CMD_DATA2. + // + // If the register block is entirely missing, then this is an unass= igned + // IO read, returning all-bits-one. + // + // If only legacy mode is available, then bit#0 stands for CPU#0 in= the + // "CPU present bitmap". CPU#0 is always present. + // + // Otherwise, QEMU_CPUHP_R_CMD_DATA2 is either still reserved (retu= rning + // all-bits-zero), or it is specified to read as zero after the abo= ve + // steps. Both cases confirm modern mode. + // + CmdData2 =3D IoRead32 (CpuHpBase + QEMU_CPUHP_R_CMD_DATA2); + DEBUG ((DEBUG_VERBOSE, "%a: CmdData2=3D0x%x\n", __FUNCTION__, CmdData2= )); + if (CmdData2 !=3D 0) { + // + // QEMU doesn't support the modern CPU hotplug interface. Assume tha= t the + // possible CPU count equals the boot CPU count (precluding hotplug). + // + DEBUG (( + DEBUG_WARN, + "%a: modern CPU hotplug interface unavailable\n", + __FUNCTION__ + )); + MaxCpuCount =3D BootCpuCount; + } else { + // + // Grab the possible CPU count from the modern CPU hotplug interface. + // + UINT32 Present, Possible, Selected; + + Present =3D 0; + Possible =3D 0; + + // + // We've sent QEMU_CPUHP_CMD_GET_PENDING last; this ensures + // QEMU_CPUHP_RW_CMD_DATA can now be read usefully. However, + // QEMU_CPUHP_CMD_GET_PENDING may have selected a CPU with actual pe= nding + // hotplug events; therefore, select CPU#0 forcibly. + // + IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, Possible); + + do { + UINT8 CpuStatus; + + // + // Read the status of the currently selected CPU. This will help w= ith a + // sanity check against "BootCpuCount". + // + CpuStatus =3D IoRead8 (CpuHpBase + QEMU_CPUHP_R_CPU_STAT); + if ((CpuStatus & QEMU_CPUHP_STAT_ENABLED) !=3D 0) { + ++Present; + } + + // + // Attempt to select the next CPU. + // + ++Possible; + IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, Possible); + // + // If the selection is successful, then the following read will re= turn + // the selector (which we know is positive at this point). Otherwi= se, + // the read will return 0. + // + Selected =3D IoRead32 (CpuHpBase + QEMU_CPUHP_RW_CMD_DATA); + ASSERT (Selected =3D=3D Possible || Selected =3D=3D 0); + } while (Selected > 0); + + // + // Sanity check: fw_cfg and the modern CPU hotplug interface should + // return the same boot CPU count. + // + if (BootCpuCount !=3D Present) { + DEBUG (( + DEBUG_WARN, + "%a: QEMU v2.7 reset bug: BootCpuCount=3D%d " + "Present=3D%u\n", + __FUNCTION__, + BootCpuCount, + Present + )); + // + // The handling of QemuFwCfgItemSmpCpuCount, across CPU hotplug pl= us + // platform reset (including S3), was corrected in QEMU commit + // e3cadac073a9 ("pc: fix FW_CFG_NB_CPUS to account for -device ad= ded + // CPUs", 2016-11-16), part of release v2.8.0. + // + BootCpuCount =3D (UINT16)Present; + } + + MaxCpuCount =3D Possible; + } + } + + DEBUG (( + DEBUG_INFO, + "%a: BootCpuCount=3D%d MaxCpuCount=3D%u\n", + __FUNCTION__, + BootCpuCount, + MaxCpuCount + )); + ASSERT (BootCpuCount <=3D MaxCpuCount); + + PlatformInfoHob->PcdCpuMaxLogicalProcessorNumber =3D MaxCpuCount; + PlatformInfoHob->PcdCpuBootLogicalProcessorNumber =3D BootCpuCount; +} diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c index 02697c473d01..f05aec599fcb 100644 --- a/OvmfPkg/PlatformPei/Platform.c +++ b/OvmfPkg/PlatformPei/Platform.c @@ -51,129 +51,6 @@ EFI_PEI_PPI_DESCRIPTOR mPpiBootMode[] =3D { } }; =20 -VOID -EFIAPI -PlatformMemMapInitialization ( - IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob - ) -{ - UINT64 PciIoBase; - UINT64 PciIoSize; - UINT32 TopOfLowRam; - UINT64 PciExBarBase; - UINT32 PciBase; - UINT32 PciSize; - - PciIoBase =3D 0xC000; - PciIoSize =3D 0x4000; - - // - // Video memory + Legacy BIOS region - // - PlatformAddIoMemoryRangeHob (0x0A0000, BASE_1MB); - - if (PlatformInfoHob->HostBridgeDevId =3D=3D 0xffff /* microvm */) { - PlatformAddIoMemoryBaseSizeHob (MICROVM_GED_MMIO_BASE, SIZE_4KB); - PlatformAddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB); /* ioapic #1 */ - PlatformAddIoMemoryBaseSizeHob (0xFEC10000, SIZE_4KB); /* ioapic #2 */ - return; - } - - TopOfLowRam =3D PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); - PciExBarBase =3D 0; - if (PlatformInfoHob->HostBridgeDevId =3D=3D INTEL_Q35_MCH_DEVICE_ID) { - // - // The MMCONFIG area is expected to fall between the top of low RAM and - // the base of the 32-bit PCI host aperture. - // - PciExBarBase =3D FixedPcdGet64 (PcdPciExpressBaseAddress); - ASSERT (TopOfLowRam <=3D PciExBarBase); - ASSERT (PciExBarBase <=3D MAX_UINT32 - SIZE_256MB); - PciBase =3D (UINT32)(PciExBarBase + SIZE_256MB); - } else { - ASSERT (TopOfLowRam <=3D PlatformInfoHob->Uc32Base); - PciBase =3D PlatformInfoHob->Uc32Base; - } - - // - // address purpose size - // ------------ -------- ------------------------- - // max(top, 2g) PCI MMIO 0xFC000000 - max(top, 2g) - // 0xFC000000 gap 44 MB - // 0xFEC00000 IO-APIC 4 KB - // 0xFEC01000 gap 1020 KB - // 0xFED00000 HPET 1 KB - // 0xFED00400 gap 111 KB - // 0xFED1C000 gap (PIIX4) / RCRB (ICH9) 16 KB - // 0xFED20000 gap 896 KB - // 0xFEE00000 LAPIC 1 MB - // - PciSize =3D 0xFC000000 - PciBase; - PlatformAddIoMemoryBaseSizeHob (PciBase, PciSize); - - PlatformInfoHob->PcdPciMmio32Base =3D PciBase; - PlatformInfoHob->PcdPciMmio32Size =3D PciSize; - - PlatformAddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB); - PlatformAddIoMemoryBaseSizeHob (0xFED00000, SIZE_1KB); - if (PlatformInfoHob->HostBridgeDevId =3D=3D INTEL_Q35_MCH_DEVICE_ID) { - PlatformAddIoMemoryBaseSizeHob (ICH9_ROOT_COMPLEX_BASE, SIZE_16KB); - // - // Note: there should be an - // - // PlatformAddIoMemoryBaseSizeHob (PciExBarBase, SIZE_256MB); - // - // call below, just like the one above for RCBA. However, Linux insists - // that the MMCONFIG area be marked in the E820 or UEFI memory map as - // "reserved memory" -- Linux does not content itself with a simple gap - // in the memory map wherever the MCFG ACPI table points to. - // - // This appears to be a safety measure. The PCI Firmware Specification - // (rev 3.1) says in 4.1.2. "MCFG Table Description": "The resources c= an - // *optionally* be returned in [...] EFIGetMemoryMap as reserved memory - // [...]". (Emphasis added here.) - // - // Normally we add memory resource descriptor HOBs in - // QemuInitializeRam(), and pre-allocate from those with memory - // allocation HOBs in InitializeRamRegions(). However, the MMCONFIG ar= ea - // is most definitely not RAM; so, as an exception, cover it with - // uncacheable reserved memory right here. - // - PlatformAddReservedMemoryBaseSizeHob (PciExBarBase, SIZE_256MB, FALSE); - BuildMemoryAllocationHob ( - PciExBarBase, - SIZE_256MB, - EfiReservedMemoryType - ); - } - - PlatformAddIoMemoryBaseSizeHob (PcdGet32 (PcdCpuLocalApicBaseAddress), S= IZE_1MB); - - // - // On Q35, the IO Port space is available for PCI resource allocations f= rom - // 0x6000 up. - // - if (PlatformInfoHob->HostBridgeDevId =3D=3D INTEL_Q35_MCH_DEVICE_ID) { - PciIoBase =3D 0x6000; - PciIoSize =3D 0xA000; - ASSERT ((ICH9_PMBASE_VALUE & 0xF000) < PciIoBase); - } - - // - // Add PCI IO Port space available for PCI resource allocations. - // - BuildResourceDescriptorHob ( - EFI_RESOURCE_IO, - EFI_RESOURCE_ATTRIBUTE_PRESENT | - EFI_RESOURCE_ATTRIBUTE_INITIALIZED, - PciIoBase, - PciIoSize - ); - - PlatformInfoHob->PcdPciIoBase =3D PciIoBase; - PlatformInfoHob->PcdPciIoSize =3D PciIoSize; -} - VOID MemMapInitialization ( IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob @@ -198,21 +75,6 @@ MemMapInitialization ( ASSERT_RETURN_ERROR (PcdStatus); } =20 -/** - * Fetch "opt/ovmf/PcdSetNxForStack" from QEMU - * - * @param Setting The pointer to the setting of "/opt/ovmf/PcdSetNxFor= Stack". - * @return EFI_SUCCESS Successfully fetch the settings. - */ -EFI_STATUS -EFIAPI -PlatformNoexecDxeInitialization ( - IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob - ) -{ - return QemuFwCfgParseBool ("opt/ovmf/PcdSetNxForStack", &PlatformInfoHob= ->PcdSetNxForStack); -} - VOID NoexecDxeInitialization ( VOID @@ -227,47 +89,6 @@ NoexecDxeInitialization ( } } =20 -VOID -PciExBarInitialization ( - VOID - ) -{ - union { - UINT64 Uint64; - UINT32 Uint32[2]; - } PciExBarBase; - - // - // We only support the 256MB size for the MMCONFIG area: - // 256 buses * 32 devices * 8 functions * 4096 bytes config space. - // - // The masks used below enforce the Q35 requirements that the MMCONFIG a= rea - // be (a) correctly aligned -- here at 256 MB --, (b) located under 64 G= B. - // - // Note that (b) also ensures that the minimum address width we have - // determined in AddressWidthInitialization(), i.e., 36 bits, will suffi= ce - // for DXE's page tables to cover the MMCONFIG area. - // - PciExBarBase.Uint64 =3D FixedPcdGet64 (PcdPciExpressBaseAddress); - ASSERT ((PciExBarBase.Uint32[1] & MCH_PCIEXBAR_HIGHMASK) =3D=3D 0); - ASSERT ((PciExBarBase.Uint32[0] & MCH_PCIEXBAR_LOWMASK) =3D=3D 0); - - // - // Clear the PCIEXBAREN bit first, before programming the high register. - // - PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW), 0); - - // - // Program the high register. Then program the low register, setting the - // MMCONFIG area size and enabling decoding at once. - // - PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_HIGH), PciExBarBase.Uint32[= 1]); - PciWrite32 ( - DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW), - PciExBarBase.Uint32[0] | MCH_PCIEXBAR_BUS_FF | MCH_PCIEXBAR_EN - ); -} - static const UINT8 EmptyFdt[] =3D { 0xd0, 0x0d, 0xfe, 0xed, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x48, @@ -359,107 +180,6 @@ MiscInitializationForMicrovm ( ASSERT_RETURN_ERROR (PcdStatus); } =20 -VOID -PlatformMiscInitialization ( - IN EFI_HOB_PLATFORM_INFO *PlatformInfoHob - ) -{ - UINTN PmCmd; - UINTN Pmba; - UINT32 PmbaAndVal; - UINT32 PmbaOrVal; - UINTN AcpiCtlReg; - UINT8 AcpiEnBit; - - // - // 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 dur= ing - // S3 resume as well, so we build it unconditionally.) - // - BuildCpuHob (PlatformInfoHob->PhysMemAddressWidth, 16); - - // - // Determine platform type and save Host Bridge DID to PCD - // - switch (PlatformInfoHob->HostBridgeDevId) { - case INTEL_82441_DEVICE_ID: - PmCmd =3D POWER_MGMT_REGISTER_PIIX4 (PCI_COMMAND_OFFSET); - Pmba =3D POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA); - PmbaAndVal =3D ~(UINT32)PIIX4_PMBA_MASK; - PmbaOrVal =3D PIIX4_PMBA_VALUE; - AcpiCtlReg =3D POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMREGMISC); - AcpiEnBit =3D PIIX4_PMREGMISC_PMIOSE; - break; - case INTEL_Q35_MCH_DEVICE_ID: - PmCmd =3D POWER_MGMT_REGISTER_Q35 (PCI_COMMAND_OFFSET); - Pmba =3D POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE); - PmbaAndVal =3D ~(UINT32)ICH9_PMBASE_MASK; - PmbaOrVal =3D ICH9_PMBASE_VALUE; - AcpiCtlReg =3D POWER_MGMT_REGISTER_Q35 (ICH9_ACPI_CNTL); - AcpiEnBit =3D ICH9_ACPI_CNTL_ACPI_EN; - break; - case CLOUDHV_DEVICE_ID: - break; - default: - DEBUG (( - DEBUG_ERROR, - "%a: Unknown Host Bridge Device ID: 0x%04x\n", - __FUNCTION__, - PlatformInfoHob->HostBridgeDevId - )); - ASSERT (FALSE); - return; - } - - if (PlatformInfoHob->HostBridgeDevId =3D=3D CLOUDHV_DEVICE_ID) { - DEBUG ((DEBUG_INFO, "%a: Cloud Hypervisor is done.\n", __FUNCTION__)); - return; - } - - // - // If the appropriate IOspace enable bit is set, assume the ACPI PMBA has - // been configured and skip the setup here. This matches the logic in - // AcpiTimerLibConstructor (). - // - if ((PciRead8 (AcpiCtlReg) & AcpiEnBit) =3D=3D 0) { - // - // The PEI phase should be exited with fully accessibe ACPI PM IO spac= e: - // 1. set PMBA - // - PciAndThenOr32 (Pmba, PmbaAndVal, PmbaOrVal); - - // - // 2. set PCICMD/IOSE - // - PciOr8 (PmCmd, EFI_PCI_COMMAND_IO_SPACE); - - // - // 3. set ACPI PM IO enable bit (PMREGMISC:PMIOSE or ACPI_CNTL:ACPI_EN) - // - PciOr8 (AcpiCtlReg, AcpiEnBit); - } - - if (PlatformInfoHob->HostBridgeDevId =3D=3D INTEL_Q35_MCH_DEVICE_ID) { - // - // Set Root Complex Register Block BAR - // - PciWrite32 ( - POWER_MGMT_REGISTER_Q35 (ICH9_RCBA), - ICH9_ROOT_COMPLEX_BASE | ICH9_RCBA_EN - ); - - // - // Set PCI Express Register Range Base Address - // - PciExBarInitialization (); - } -} - VOID MiscInitialization ( IN EFI_HOB_PLATFORM_INFO *PlatformInfoHob @@ -571,177 +291,6 @@ Q35BoardVerification ( CpuDeadLoop (); } =20 -/** - 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 -PlatformMaxCpuCountInitialization ( - IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob - ) -{ - UINT16 BootCpuCount; - UINT32 MaxCpuCount; - - // - // Try to fetch the boot CPU count. - // - QemuFwCfgSelectItem (QemuFwCfgItemSmpCpuCount); - BootCpuCount =3D QemuFwCfgRead16 (); - if (BootCpuCount =3D=3D 0) { - // - // QEMU doesn't report the boot CPU count. (BootCpuCount =3D=3D 0) wil= l let - // MpInitLib count APs up to (PcdCpuMaxLogicalProcessorNumber - 1), or - // until PcdCpuApInitTimeOutInMicroSeconds elapses (whichever is reach= ed - // first). - // - DEBUG ((DEBUG_WARN, "%a: boot CPU count unavailable\n", __FUNCTION__)); - MaxCpuCount =3D PlatformInfoHob->DefaultMaxCpuNumber; - } else { - // - // We will expose BootCpuCount to MpInitLib. MpInitLib will count APs = up to - // (BootCpuCount - 1) precisely, regardless of timeout. - // - // Now try to fetch the possible CPU count. - // - UINTN CpuHpBase; - UINT32 CmdData2; - - CpuHpBase =3D ((PlatformInfoHob->HostBridgeDevId =3D=3D INTEL_Q35_MCH_= DEVICE_ID) ? - ICH9_CPU_HOTPLUG_BASE : PIIX4_CPU_HOTPLUG_BASE); - - // - // If only legacy mode is available in the CPU hotplug register block,= or - // the register block is completely missing, then the writes below are - // no-ops. - // - // 1. Switch the hotplug register block to modern mode. - // - IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, 0); - // - // 2. Select a valid CPU for deterministic reading of - // QEMU_CPUHP_R_CMD_DATA2. - // - // CPU#0 is always valid; it is the always present and non-removable - // BSP. - // - IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, 0); - // - // 3. Send a command after which QEMU_CPUHP_R_CMD_DATA2 is specified to - // read as zero, and which does not invalidate the selector. (The - // selector may change, but it must not become invalid.) - // - // Send QEMU_CPUHP_CMD_GET_PENDING, as it will prove useful later. - // - IoWrite8 (CpuHpBase + QEMU_CPUHP_W_CMD, QEMU_CPUHP_CMD_GET_PENDING); - // - // 4. Read QEMU_CPUHP_R_CMD_DATA2. - // - // If the register block is entirely missing, then this is an unass= igned - // IO read, returning all-bits-one. - // - // If only legacy mode is available, then bit#0 stands for CPU#0 in= the - // "CPU present bitmap". CPU#0 is always present. - // - // Otherwise, QEMU_CPUHP_R_CMD_DATA2 is either still reserved (retu= rning - // all-bits-zero), or it is specified to read as zero after the abo= ve - // steps. Both cases confirm modern mode. - // - CmdData2 =3D IoRead32 (CpuHpBase + QEMU_CPUHP_R_CMD_DATA2); - DEBUG ((DEBUG_VERBOSE, "%a: CmdData2=3D0x%x\n", __FUNCTION__, CmdData2= )); - if (CmdData2 !=3D 0) { - // - // QEMU doesn't support the modern CPU hotplug interface. Assume tha= t the - // possible CPU count equals the boot CPU count (precluding hotplug). - // - DEBUG (( - DEBUG_WARN, - "%a: modern CPU hotplug interface unavailable\n", - __FUNCTION__ - )); - MaxCpuCount =3D BootCpuCount; - } else { - // - // Grab the possible CPU count from the modern CPU hotplug interface. - // - UINT32 Present, Possible, Selected; - - Present =3D 0; - Possible =3D 0; - - // - // We've sent QEMU_CPUHP_CMD_GET_PENDING last; this ensures - // QEMU_CPUHP_RW_CMD_DATA can now be read usefully. However, - // QEMU_CPUHP_CMD_GET_PENDING may have selected a CPU with actual pe= nding - // hotplug events; therefore, select CPU#0 forcibly. - // - IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, Possible); - - do { - UINT8 CpuStatus; - - // - // Read the status of the currently selected CPU. This will help w= ith a - // sanity check against "BootCpuCount". - // - CpuStatus =3D IoRead8 (CpuHpBase + QEMU_CPUHP_R_CPU_STAT); - if ((CpuStatus & QEMU_CPUHP_STAT_ENABLED) !=3D 0) { - ++Present; - } - - // - // Attempt to select the next CPU. - // - ++Possible; - IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, Possible); - // - // If the selection is successful, then the following read will re= turn - // the selector (which we know is positive at this point). Otherwi= se, - // the read will return 0. - // - Selected =3D IoRead32 (CpuHpBase + QEMU_CPUHP_RW_CMD_DATA); - ASSERT (Selected =3D=3D Possible || Selected =3D=3D 0); - } while (Selected > 0); - - // - // Sanity check: fw_cfg and the modern CPU hotplug interface should - // return the same boot CPU count. - // - if (BootCpuCount !=3D Present) { - DEBUG (( - DEBUG_WARN, - "%a: QEMU v2.7 reset bug: BootCpuCount=3D%d " - "Present=3D%u\n", - __FUNCTION__, - BootCpuCount, - Present - )); - // - // The handling of QemuFwCfgItemSmpCpuCount, across CPU hotplug pl= us - // platform reset (including S3), was corrected in QEMU commit - // e3cadac073a9 ("pc: fix FW_CFG_NB_CPUS to account for -device ad= ded - // CPUs", 2016-11-16), part of release v2.8.0. - // - BootCpuCount =3D (UINT16)Present; - } - - MaxCpuCount =3D Possible; - } - } - - DEBUG (( - DEBUG_INFO, - "%a: BootCpuCount=3D%d MaxCpuCount=3D%u\n", - __FUNCTION__, - BootCpuCount, - MaxCpuCount - )); - ASSERT (BootCpuCount <=3D MaxCpuCount); - - PlatformInfoHob->PcdCpuMaxLogicalProcessorNumber =3D MaxCpuCount; - PlatformInfoHob->PcdCpuBootLogicalProcessorNumber =3D BootCpuCount; -} - /** Fetch the boot CPU count and the possible CPU count from QEMU, and expose them to UefiCpuPkg modules. Set the MaxCpuCount field in PlatformInfoHob. --=20 2.29.2.windows.2 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#87705): https://edk2.groups.io/g/devel/message/87705 Mute This Topic: https://groups.io/mt/89859046/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-