+ BuildCpuHob (mPhysMemAddressWidth, 16);\r
+\r
+ //\r
+ // Determine platform type and save Host Bridge DID to PCD\r
+ //\r
+ switch (mHostBridgeDevId) {\r
+ case INTEL_82441_DEVICE_ID:\r
+ PmCmd = POWER_MGMT_REGISTER_PIIX4 (PCI_COMMAND_OFFSET);\r
+ Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);\r
+ PmbaAndVal = ~(UINT32)PIIX4_PMBA_MASK;\r
+ PmbaOrVal = PIIX4_PMBA_VALUE;\r
+ AcpiCtlReg = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMREGMISC);\r
+ AcpiEnBit = PIIX4_PMREGMISC_PMIOSE;\r
+ break;\r
+ case INTEL_Q35_MCH_DEVICE_ID:\r
+ PmCmd = POWER_MGMT_REGISTER_Q35 (PCI_COMMAND_OFFSET);\r
+ Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);\r
+ PmbaAndVal = ~(UINT32)ICH9_PMBASE_MASK;\r
+ PmbaOrVal = ICH9_PMBASE_VALUE;\r
+ AcpiCtlReg = POWER_MGMT_REGISTER_Q35 (ICH9_ACPI_CNTL);\r
+ AcpiEnBit = ICH9_ACPI_CNTL_ACPI_EN;\r
+ break;\r
+ default:\r
+ DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",\r
+ __FUNCTION__, mHostBridgeDevId));\r
+ ASSERT (FALSE);\r
+ return;\r
+ }\r
+ PcdStatus = PcdSet16S (PcdOvmfHostBridgePciDevId, mHostBridgeDevId);\r
+ ASSERT_RETURN_ERROR (PcdStatus);\r
+\r
+ //\r
+ // If the appropriate IOspace enable bit is set, assume the ACPI PMBA\r
+ // has been configured (e.g., by Xen) and skip the setup here.\r
+ // This matches the logic in AcpiTimerLibConstructor ().\r
+ //\r
+ if ((PciRead8 (AcpiCtlReg) & AcpiEnBit) == 0) {\r
+ //\r
+ // The PEI phase should be exited with fully accessibe ACPI PM IO space:\r
+ // 1. set PMBA\r
+ //\r
+ PciAndThenOr32 (Pmba, PmbaAndVal, PmbaOrVal);\r
+\r
+ //\r
+ // 2. set PCICMD/IOSE\r
+ //\r
+ PciOr8 (PmCmd, EFI_PCI_COMMAND_IO_SPACE);\r
+\r
+ //\r
+ // 3. set ACPI PM IO enable bit (PMREGMISC:PMIOSE or ACPI_CNTL:ACPI_EN)\r
+ //\r
+ PciOr8 (AcpiCtlReg, AcpiEnBit);\r
+ }\r
+\r
+ if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {\r
+ //\r
+ // Set Root Complex Register Block BAR\r
+ //\r
+ PciWrite32 (\r
+ POWER_MGMT_REGISTER_Q35 (ICH9_RCBA),\r
+ ICH9_ROOT_COMPLEX_BASE | ICH9_RCBA_EN\r
+ );\r
+\r
+ //\r
+ // Set PCI Express Register Range Base Address\r
+ //\r
+ PciExBarInitialization ();\r
+ }\r
+}\r
+\r
+\r
+VOID\r
+BootModeInitialization (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ if (CmosRead8 (0xF) == 0xFE) {\r
+ mBootMode = BOOT_ON_S3_RESUME;\r
+ }\r
+ CmosWrite8 (0xF, 0x00);\r
+\r
+ Status = PeiServicesSetBootMode (mBootMode);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Status = PeiServicesInstallPpi (mPpiBootMode);\r
+ ASSERT_EFI_ERROR (Status);\r
+}\r
+\r
+\r
+VOID\r
+ReserveEmuVariableNvStore (\r
+ )\r
+{\r
+ EFI_PHYSICAL_ADDRESS VariableStore;\r
+ RETURN_STATUS PcdStatus;\r
+\r
+ //\r
+ // Allocate storage for NV variables early on so it will be\r
+ // at a consistent address. Since VM memory is preserved\r
+ // across reboots, this allows the NV variable storage to survive\r
+ // a VM reboot.\r
+ //\r
+ VariableStore =\r
+ (EFI_PHYSICAL_ADDRESS)(UINTN)\r
+ AllocateRuntimePages (\r
+ EFI_SIZE_TO_PAGES (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize))\r
+ );\r
+ DEBUG ((EFI_D_INFO,\r
+ "Reserved variable store memory: 0x%lX; size: %dkb\n",\r
+ VariableStore,\r
+ (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)) / 1024\r
+ ));\r
+ PcdStatus = PcdSet64S (PcdEmuVariableNvStoreReserved, VariableStore);\r
+ ASSERT_RETURN_ERROR (PcdStatus);\r
+}\r
+\r
+\r
+VOID\r
+DebugDumpCmos (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 Loop;\r
+\r
+ DEBUG ((EFI_D_INFO, "CMOS:\n"));\r
+\r
+ for (Loop = 0; Loop < 0x80; Loop++) {\r
+ if ((Loop % 0x10) == 0) {\r
+ DEBUG ((EFI_D_INFO, "%02x:", Loop));\r
+ }\r
+ DEBUG ((EFI_D_INFO, " %02x", CmosRead8 (Loop)));\r
+ if ((Loop % 0x10) == 0xf) {\r
+ DEBUG ((EFI_D_INFO, "\n"));\r
+ }\r
+ }\r
+}\r
+\r
+\r
+VOID\r
+S3Verification (\r
+ VOID\r
+ )\r
+{\r
+#if defined (MDE_CPU_X64)\r
+ if (FeaturePcdGet (PcdSmmSmramRequire) && mS3Supported) {\r
+ DEBUG ((EFI_D_ERROR,\r
+ "%a: S3Resume2Pei doesn't support X64 PEI + SMM yet.\n", __FUNCTION__));\r
+ DEBUG ((EFI_D_ERROR,\r
+ "%a: Please disable S3 on the QEMU command line (see the README),\n",\r
+ __FUNCTION__));\r
+ DEBUG ((EFI_D_ERROR,\r
+ "%a: or build OVMF with \"OvmfPkgIa32X64.dsc\".\n", __FUNCTION__));\r
+ ASSERT (FALSE);\r
+ CpuDeadLoop ();\r
+ }\r
+#endif\r
+}\r
+\r
+\r
+/**\r
+ Fetch the number of boot CPUs from QEMU and expose it to UefiCpuPkg modules.\r
+ Set the mMaxCpuCount variable.\r
+**/\r
+VOID\r
+MaxCpuCountInitialization (\r
+ VOID\r
+ )\r
+{\r
+ UINT16 ProcessorCount;\r
+ RETURN_STATUS PcdStatus;\r
+\r
+ QemuFwCfgSelectItem (QemuFwCfgItemSmpCpuCount);\r
+ ProcessorCount = QemuFwCfgRead16 ();\r
+ //\r
+ // If the fw_cfg key or fw_cfg entirely is unavailable, load mMaxCpuCount\r
+ // from the PCD default. No change to PCDs.\r
+ //\r
+ if (ProcessorCount == 0) {\r
+ mMaxCpuCount = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);\r
+ return;\r
+ }\r
+ //\r
+ // Otherwise, set mMaxCpuCount to the value reported by QEMU.\r
+ //\r
+ mMaxCpuCount = ProcessorCount;\r
+ //\r
+ // Additionally, tell UefiCpuPkg modules (a) the exact number of VCPUs, (b)\r
+ // to wait, in the initial AP bringup, exactly as long as it takes for all of\r
+ // the APs to report in. For this, we set the longest representable timeout\r
+ // (approx. 71 minutes).\r
+ //\r
+ PcdStatus = PcdSet32S (PcdCpuMaxLogicalProcessorNumber, ProcessorCount);\r
+ ASSERT_RETURN_ERROR (PcdStatus);\r
+ PcdStatus = PcdSet32S (PcdCpuApInitTimeOutInMicroSeconds, MAX_UINT32);\r
+ ASSERT_RETURN_ERROR (PcdStatus);\r
+ DEBUG ((DEBUG_INFO, "%a: QEMU reports %d processor(s)\n", __FUNCTION__,\r
+ ProcessorCount));\r