2009-05-27 23:10:18 +02:00
|
|
|
/**@file
|
|
|
|
Platform PEI driver
|
|
|
|
|
2016-04-07 12:19:23 +02:00
|
|
|
Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
|
2011-08-05 17:43:05 +02:00
|
|
|
Copyright (c) 2011, Andrei Warkentin <andreiw@motorola.com>
|
|
|
|
|
2019-04-04 01:06:33 +02:00
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
2009-05-27 23:10:18 +02:00
|
|
|
|
|
|
|
**/
|
|
|
|
|
|
|
|
//
|
|
|
|
// The package level header files this module uses
|
|
|
|
//
|
|
|
|
#include <PiPei.h>
|
|
|
|
|
|
|
|
//
|
|
|
|
// The Library classes this module consumes
|
|
|
|
//
|
2021-12-13 09:16:56 +01:00
|
|
|
#include <Library/BaseMemoryLib.h>
|
2015-12-01 00:36:31 +01:00
|
|
|
#include <Library/BaseLib.h>
|
2009-05-27 23:10:18 +02:00
|
|
|
#include <Library/DebugLib.h>
|
|
|
|
#include <Library/HobLib.h>
|
|
|
|
#include <Library/IoLib.h>
|
2009-09-07 22:18:17 +02:00
|
|
|
#include <Library/MemoryAllocationLib.h>
|
|
|
|
#include <Library/PcdLib.h>
|
2009-05-27 23:10:18 +02:00
|
|
|
#include <Library/PciLib.h>
|
|
|
|
#include <Library/PeimEntryPoint.h>
|
2011-03-22 02:55:08 +01:00
|
|
|
#include <Library/PeiServicesLib.h>
|
2014-03-04 09:01:58 +01:00
|
|
|
#include <Library/QemuFwCfgLib.h>
|
2017-02-22 03:47:18 +01:00
|
|
|
#include <Library/QemuFwCfgS3Lib.h>
|
2020-04-24 09:53:49 +02:00
|
|
|
#include <Library/QemuFwCfgSimpleParserLib.h>
|
2009-05-27 23:10:18 +02:00
|
|
|
#include <Library/ResourcePublicationLib.h>
|
2011-03-22 02:55:08 +01:00
|
|
|
#include <Ppi/MasterBootMode.h>
|
OvmfPkg/PlatformPei: rewrite MaxCpuCountInitialization() for CPU hotplug
MaxCpuCountInitialization() currently handles the following options:
(1) QEMU does not report the boot CPU count (FW_CFG_NB_CPUS is 0)
In this case, PlatformPei makes MpInitLib enumerate APs up to the
default PcdCpuMaxLogicalProcessorNumber value (64) minus 1, or until
the default PcdCpuApInitTimeOutInMicroSeconds (50,000) elapses.
(Whichever is reached first.)
Time-limited AP enumeration had never been reliable on QEMU/KVM, which
is why commit 45a70db3c3a5 strated handling case (2) below, in OVMF.
(2) QEMU reports the boot CPU count (FW_CFG_NB_CPUS is nonzero)
In this case, PlatformPei sets
- PcdCpuMaxLogicalProcessorNumber to the reported boot CPU count
(FW_CFG_NB_CPUS, which exports "PCMachineState.boot_cpus"),
- and PcdCpuApInitTimeOutInMicroSeconds to practically "infinity"
(MAX_UINT32, ~71 minutes).
That causes MpInitLib to enumerate exactly the present (boot) APs.
With CPU hotplug in mind, this method is not good enough. Because,
using QEMU terminology, UefiCpuPkg expects
PcdCpuMaxLogicalProcessorNumber to provide the "possible CPUs" count
("MachineState.smp.max_cpus"), which includes present and not present
CPUs both (with not present CPUs being subject for hot-plugging).
FW_CFG_NB_CPUS does not include not present CPUs.
Rewrite MaxCpuCountInitialization() for handling the following cases:
(1) The behavior of case (1) does not change. (No UefiCpuPkg PCDs are set
to values different from the defaults.)
(2) QEMU reports the boot CPU count ("PCMachineState.boot_cpus", via
FW_CFG_NB_CPUS), but not the possible CPUs count
("MachineState.smp.max_cpus").
In this case, the behavior remains unchanged.
The way MpInitLib is instructed to do the same differs however: we now
set the new PcdCpuBootLogicalProcessorNumber to the boot CPU count
(while continuing to set PcdCpuMaxLogicalProcessorNumber identically).
PcdCpuApInitTimeOutInMicroSeconds becomes irrelevant.
(3) QEMU reports both the boot CPU count ("PCMachineState.boot_cpus", via
FW_CFG_NB_CPUS), and the possible CPUs count
("MachineState.smp.max_cpus").
We tell UefiCpuPkg about the possible CPUs count through
PcdCpuMaxLogicalProcessorNumber. We also tell MpInitLib the boot CPU
count for precise and quick AP enumeration, via
PcdCpuBootLogicalProcessorNumber. PcdCpuApInitTimeOutInMicroSeconds is
irrelevant again.
This patch is a pre-requisite for enabling CPU hotplug with SMM_REQUIRE.
As a side effect, the patch also enables S3 to work with CPU hotplug at
once, *without* SMM_REQUIRE.
(Without the patch, S3 resume fails, if a CPU is hot-plugged at OS
runtime, prior to suspend: the FW_CFG_NB_CPUS increase seen during resume
causes PcdCpuMaxLogicalProcessorNumber to increase as well, which is not
permitted.
With the patch, PcdCpuMaxLogicalProcessorNumber stays the same, namely
"MachineState.smp.max_cpus". Therefore, the CPU structures allocated
during normal boot can accommodate the CPUs at S3 resume that have been
hotplugged prior to S3 suspend.)
Cc: Anthony Perard <anthony.perard@citrix.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Julien Grall <julien.grall@arm.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1515
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Message-Id: <20191022221554.14963-4-lersek@redhat.com>
Acked-by: Anthony PERARD <anthony.perard@citrix.com>
Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2019-10-08 09:15:38 +02:00
|
|
|
#include <IndustryStandard/I440FxPiix4.h>
|
2021-09-08 11:01:13 +02:00
|
|
|
#include <IndustryStandard/Microvm.h>
|
OvmfPkg: enable PIIX4 IO space in the PEI phase
I. There are at least three locations in OvmfPkg that manipulate the PMBA
and related PIIX4 registers.
1. MiscInitialization() [OvmfPkg/PlatformPei/Platform.c]
module type: PEIM -- Pre-EFI Initialization Module
(a) currently sets the PMBA only: 00.01.3 / 0x40 bits [15:6]
2. AcpiTimerLibConstructor() [OvmfPkg/Library/AcpiTimerLib/AcpiTimerLib.c]
module type: BASE -- probably callable anywhere after PEI
(a) sets the PMBA if needed: 00.01.3 / 0x40 bits [15:6]
(b) sets PCICMD/IOSE if needed: 00.01.3 / 0x04 bit 0
(c) sets PMREGMISC/PMIOSE: 00.01.3 / 0x80 bit 0
3. AcpiInitialization() [OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c]
module type: DXE_DRIVER -- Driver eXecution Environment
(a) sets SCI_EN, which depends on correct PMBA setting from earlier
(
The relative order of #1 and #3 is dictated minimally by their module
types. Said relative order can be verified with the boot log:
27 Loading PEIM at 0x00000822320 EntryPoint=0x00000822580
PlatformPei.efi
28 Platform PEIM Loaded
1259 PlatformBdsInit
1270 PlatformBdsPolicyBehavior
Line 28 is printed by InitializePlatform()
[OvmfPkg/PlatformPei/Platform.c] which is the entry point of that
module. The other two lines are printed by the corresponding functions
in "OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c".
)
Currently #2 (AcpiTimerLibConstructor()) is called in a random spot
(whenever it gets loaded from the firmware image) and masks the
insufficient setup in #1. We shouldn't depend on that, PEI should finish
with IO space being fully accessibe. In addition, PEI should program the
same PMBA value as AcpiTimerLib.
II. The PEI change notwithstanding, AcpiTimerLib should stay defensive and
ensure proper PM configuration for itself (either by confirming or by
doing).
III. Considering a possible cleanup/unification of #2 and #3: timer
functions relying on AcpiTimerLibConstructor(),
- MicroSecondDelay()
- NanoSecondDelay()
- GetPerformanceCounter()
- GetPerformanceCounterProperties()
- GetTimeInNanoSecond()
may be called before #3 is reached (in Boot Device Selection phase), so we
should not move the initialization from #2 to #3. (Again, AcpiTimerLib
should contain its own setup.)
We should also not move #3 to an earlier phase -- SCI_EN is premature
unless we're about to boot real soon ("enable generation of SCI upon
assertion of PWRBTN_STS, LID_STS, THRM_STS, or GPI_STS bits").
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13722 6f19259b-4bc3-4df7-8a09-765794883524
2012-09-12 09:19:16 +02:00
|
|
|
#include <IndustryStandard/Pci22.h>
|
OvmfPkg/PlatformPei: rewrite MaxCpuCountInitialization() for CPU hotplug
MaxCpuCountInitialization() currently handles the following options:
(1) QEMU does not report the boot CPU count (FW_CFG_NB_CPUS is 0)
In this case, PlatformPei makes MpInitLib enumerate APs up to the
default PcdCpuMaxLogicalProcessorNumber value (64) minus 1, or until
the default PcdCpuApInitTimeOutInMicroSeconds (50,000) elapses.
(Whichever is reached first.)
Time-limited AP enumeration had never been reliable on QEMU/KVM, which
is why commit 45a70db3c3a5 strated handling case (2) below, in OVMF.
(2) QEMU reports the boot CPU count (FW_CFG_NB_CPUS is nonzero)
In this case, PlatformPei sets
- PcdCpuMaxLogicalProcessorNumber to the reported boot CPU count
(FW_CFG_NB_CPUS, which exports "PCMachineState.boot_cpus"),
- and PcdCpuApInitTimeOutInMicroSeconds to practically "infinity"
(MAX_UINT32, ~71 minutes).
That causes MpInitLib to enumerate exactly the present (boot) APs.
With CPU hotplug in mind, this method is not good enough. Because,
using QEMU terminology, UefiCpuPkg expects
PcdCpuMaxLogicalProcessorNumber to provide the "possible CPUs" count
("MachineState.smp.max_cpus"), which includes present and not present
CPUs both (with not present CPUs being subject for hot-plugging).
FW_CFG_NB_CPUS does not include not present CPUs.
Rewrite MaxCpuCountInitialization() for handling the following cases:
(1) The behavior of case (1) does not change. (No UefiCpuPkg PCDs are set
to values different from the defaults.)
(2) QEMU reports the boot CPU count ("PCMachineState.boot_cpus", via
FW_CFG_NB_CPUS), but not the possible CPUs count
("MachineState.smp.max_cpus").
In this case, the behavior remains unchanged.
The way MpInitLib is instructed to do the same differs however: we now
set the new PcdCpuBootLogicalProcessorNumber to the boot CPU count
(while continuing to set PcdCpuMaxLogicalProcessorNumber identically).
PcdCpuApInitTimeOutInMicroSeconds becomes irrelevant.
(3) QEMU reports both the boot CPU count ("PCMachineState.boot_cpus", via
FW_CFG_NB_CPUS), and the possible CPUs count
("MachineState.smp.max_cpus").
We tell UefiCpuPkg about the possible CPUs count through
PcdCpuMaxLogicalProcessorNumber. We also tell MpInitLib the boot CPU
count for precise and quick AP enumeration, via
PcdCpuBootLogicalProcessorNumber. PcdCpuApInitTimeOutInMicroSeconds is
irrelevant again.
This patch is a pre-requisite for enabling CPU hotplug with SMM_REQUIRE.
As a side effect, the patch also enables S3 to work with CPU hotplug at
once, *without* SMM_REQUIRE.
(Without the patch, S3 resume fails, if a CPU is hot-plugged at OS
runtime, prior to suspend: the FW_CFG_NB_CPUS increase seen during resume
causes PcdCpuMaxLogicalProcessorNumber to increase as well, which is not
permitted.
With the patch, PcdCpuMaxLogicalProcessorNumber stays the same, namely
"MachineState.smp.max_cpus". Therefore, the CPU structures allocated
during normal boot can accommodate the CPUs at S3 resume that have been
hotplugged prior to S3 suspend.)
Cc: Anthony Perard <anthony.perard@citrix.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Julien Grall <julien.grall@arm.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1515
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Message-Id: <20191022221554.14963-4-lersek@redhat.com>
Acked-by: Anthony PERARD <anthony.perard@citrix.com>
Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2019-10-08 09:15:38 +02:00
|
|
|
#include <IndustryStandard/Q35MchIch9.h>
|
|
|
|
#include <IndustryStandard/QemuCpuHotplug.h>
|
2022-03-06 03:20:36 +01:00
|
|
|
#include <Library/MemEncryptSevLib.h>
|
2014-11-14 01:37:26 +01:00
|
|
|
#include <OvmfPlatforms.h>
|
2009-05-27 23:10:18 +02:00
|
|
|
|
|
|
|
#include "Platform.h"
|
|
|
|
|
2022-03-06 03:20:36 +01:00
|
|
|
EFI_HOB_PLATFORM_INFO mPlatformInfoHob = { 0 };
|
|
|
|
|
2021-12-05 23:54:09 +01:00
|
|
|
EFI_PEI_PPI_DESCRIPTOR mPpiBootMode[] = {
|
2011-03-22 02:55:08 +01:00
|
|
|
{
|
|
|
|
EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
|
|
|
|
&gEfiPeiMasterBootModePpiGuid,
|
|
|
|
NULL
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-03-06 15:09:10 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2015-09-15 10:35:14 +02:00
|
|
|
VOID
|
|
|
|
NoexecDxeInitialization (
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
2022-03-06 15:20:22 +01:00
|
|
|
RETURN_STATUS Status;
|
|
|
|
|
|
|
|
Status = PlatformNoexecDxeInitialization (&mPlatformInfoHob);
|
|
|
|
if (!RETURN_ERROR (Status)) {
|
|
|
|
Status = PcdSetBoolS (PcdSetNxForStack, mPlatformInfoHob.PcdSetNxForStack);
|
|
|
|
ASSERT_RETURN_ERROR (Status);
|
|
|
|
}
|
2015-09-15 10:35:14 +02:00
|
|
|
}
|
2009-05-27 23:10:18 +02:00
|
|
|
|
2021-12-13 09:16:56 +01:00
|
|
|
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,
|
|
|
|
};
|
|
|
|
|
2021-12-13 09:16:55 +01:00
|
|
|
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)) {
|
2021-12-13 09:16:56 +01:00
|
|
|
DEBUG ((DEBUG_INFO, "%a: no etc/fdt found in fw_cfg, using dummy\n", __FUNCTION__));
|
|
|
|
FdtItem = 0;
|
|
|
|
FdtSize = sizeof (EmptyFdt);
|
2021-12-13 09:16:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
FdtPages = EFI_SIZE_TO_PAGES (FdtSize);
|
|
|
|
NewBase = AllocatePages (FdtPages);
|
|
|
|
if (NewBase == NULL) {
|
|
|
|
DEBUG ((DEBUG_INFO, "%a: AllocatePages failed\n", __FUNCTION__));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-12-13 09:16:56 +01:00
|
|
|
if (FdtItem) {
|
|
|
|
QemuFwCfgSelectItem (FdtItem);
|
|
|
|
QemuFwCfgReadBytes (FdtSize, NewBase);
|
|
|
|
} else {
|
|
|
|
CopyMem (NewBase, EmptyFdt, FdtSize);
|
|
|
|
}
|
2021-12-13 09:16:55 +01:00
|
|
|
|
|
|
|
FdtHobData = BuildGuidHob (&gFdtHobGuid, sizeof (*FdtHobData));
|
|
|
|
if (FdtHobData == NULL) {
|
|
|
|
DEBUG ((DEBUG_INFO, "%a: BuildGuidHob failed\n", __FUNCTION__));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUG ((
|
|
|
|
DEBUG_INFO,
|
|
|
|
"%a: fdt at 0x%x (size %d)\n",
|
|
|
|
__FUNCTION__,
|
|
|
|
NewBase,
|
|
|
|
FdtSize
|
|
|
|
));
|
|
|
|
*FdtHobData = (UINTN)NewBase;
|
|
|
|
}
|
|
|
|
|
2022-03-06 13:04:53 +01:00
|
|
|
VOID
|
|
|
|
MiscInitializationForMicrovm (
|
|
|
|
IN EFI_HOB_PLATFORM_INFO *PlatformInfoHob
|
|
|
|
)
|
|
|
|
{
|
|
|
|
RETURN_STATUS PcdStatus;
|
|
|
|
|
|
|
|
ASSERT (PlatformInfoHob->HostBridgeDevId == 0xffff);
|
|
|
|
|
|
|
|
DEBUG ((DEBUG_INFO, "%a: microvm\n", __FUNCTION__));
|
|
|
|
//
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
2022-03-06 15:35:23 +01:00
|
|
|
VOID
|
|
|
|
MiscInitialization (
|
|
|
|
IN EFI_HOB_PLATFORM_INFO *PlatformInfoHob
|
|
|
|
)
|
|
|
|
{
|
|
|
|
RETURN_STATUS PcdStatus;
|
|
|
|
|
|
|
|
PlatformMiscInitialization (PlatformInfoHob);
|
|
|
|
|
|
|
|
PcdStatus = PcdSet16S (PcdOvmfHostBridgePciDevId, PlatformInfoHob->HostBridgeDevId);
|
|
|
|
ASSERT_RETURN_ERROR (PcdStatus);
|
|
|
|
}
|
|
|
|
|
2011-03-22 02:55:08 +01:00
|
|
|
VOID
|
|
|
|
BootModeInitialization (
|
2022-03-06 03:20:36 +01:00
|
|
|
IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob
|
2011-03-22 02:55:08 +01:00
|
|
|
)
|
|
|
|
{
|
2021-12-05 23:54:09 +01:00
|
|
|
EFI_STATUS Status;
|
2014-03-04 09:01:32 +01:00
|
|
|
|
2022-02-12 07:06:46 +01:00
|
|
|
if (PlatformCmosRead8 (0xF) == 0xFE) {
|
2022-03-06 03:20:36 +01:00
|
|
|
PlatformInfoHob->BootMode = BOOT_ON_S3_RESUME;
|
2014-03-04 09:01:32 +01:00
|
|
|
}
|
2021-12-05 23:54:09 +01:00
|
|
|
|
2022-02-12 07:06:46 +01:00
|
|
|
PlatformCmosWrite8 (0xF, 0x00);
|
2011-03-22 05:54:18 +01:00
|
|
|
|
2022-03-06 03:20:36 +01:00
|
|
|
Status = PeiServicesSetBootMode (PlatformInfoHob->BootMode);
|
2011-03-22 05:54:18 +01:00
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
|
|
|
|
Status = PeiServicesInstallPpi (mPpiBootMode);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
2011-03-22 02:55:08 +01:00
|
|
|
}
|
|
|
|
|
2009-09-07 22:18:17 +02:00
|
|
|
VOID
|
|
|
|
ReserveEmuVariableNvStore (
|
|
|
|
)
|
|
|
|
{
|
2021-12-05 23:54:09 +01:00
|
|
|
EFI_PHYSICAL_ADDRESS VariableStore;
|
|
|
|
RETURN_STATUS PcdStatus;
|
2009-09-07 22:18:17 +02:00
|
|
|
|
|
|
|
//
|
|
|
|
// Allocate storage for NV variables early on so it will be
|
|
|
|
// at a consistent address. Since VM memory is preserved
|
|
|
|
// across reboots, this allows the NV variable storage to survive
|
|
|
|
// a VM reboot.
|
|
|
|
//
|
|
|
|
VariableStore =
|
|
|
|
(EFI_PHYSICAL_ADDRESS)(UINTN)
|
2021-12-05 23:54:09 +01:00
|
|
|
AllocateRuntimePages (
|
|
|
|
EFI_SIZE_TO_PAGES (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize))
|
|
|
|
);
|
|
|
|
DEBUG ((
|
|
|
|
DEBUG_INFO,
|
|
|
|
"Reserved variable store memory: 0x%lX; size: %dkb\n",
|
|
|
|
VariableStore,
|
|
|
|
(2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)) / 1024
|
|
|
|
));
|
2016-10-21 11:59:36 +02:00
|
|
|
PcdStatus = PcdSet64S (PcdEmuVariableNvStoreReserved, VariableStore);
|
|
|
|
ASSERT_RETURN_ERROR (PcdStatus);
|
2009-09-07 22:18:17 +02:00
|
|
|
}
|
|
|
|
|
2015-12-01 00:36:31 +01:00
|
|
|
VOID
|
|
|
|
S3Verification (
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
2021-12-05 23:54:09 +01:00
|
|
|
#if defined (MDE_CPU_X64)
|
2022-03-06 03:20:36 +01:00
|
|
|
if (mPlatformInfoHob.SmmSmramRequire && mPlatformInfoHob.S3Supported) {
|
2021-12-05 23:54:09 +01:00
|
|
|
DEBUG ((
|
|
|
|
DEBUG_ERROR,
|
|
|
|
"%a: S3Resume2Pei doesn't support X64 PEI + SMM yet.\n",
|
|
|
|
__FUNCTION__
|
|
|
|
));
|
|
|
|
DEBUG ((
|
|
|
|
DEBUG_ERROR,
|
2015-12-01 00:36:31 +01:00
|
|
|
"%a: Please disable S3 on the QEMU command line (see the README),\n",
|
2021-12-05 23:54:09 +01:00
|
|
|
__FUNCTION__
|
|
|
|
));
|
|
|
|
DEBUG ((
|
|
|
|
DEBUG_ERROR,
|
|
|
|
"%a: or build OVMF with \"OvmfPkgIa32X64.dsc\".\n",
|
|
|
|
__FUNCTION__
|
|
|
|
));
|
2015-12-01 00:36:31 +01:00
|
|
|
ASSERT (FALSE);
|
|
|
|
CpuDeadLoop ();
|
|
|
|
}
|
|
|
|
|
2021-12-05 23:54:09 +01:00
|
|
|
#endif
|
|
|
|
}
|
2015-12-01 00:36:31 +01:00
|
|
|
|
2019-09-20 13:36:56 +02:00
|
|
|
VOID
|
|
|
|
Q35BoardVerification (
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
2022-03-06 03:20:36 +01:00
|
|
|
if (mPlatformInfoHob.HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
|
2019-09-20 13:36:56 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUG ((
|
|
|
|
DEBUG_ERROR,
|
|
|
|
"%a: no TSEG (SMRAM) on host bridge DID=0x%04x; "
|
|
|
|
"only DID=0x%04x (Q35) is supported\n",
|
|
|
|
__FUNCTION__,
|
2022-03-06 03:20:36 +01:00
|
|
|
mPlatformInfoHob.HostBridgeDevId,
|
2019-09-20 13:36:56 +02:00
|
|
|
INTEL_Q35_MCH_DEVICE_ID
|
|
|
|
));
|
|
|
|
ASSERT (FALSE);
|
|
|
|
CpuDeadLoop ();
|
|
|
|
}
|
|
|
|
|
2022-03-06 14:40:28 +01:00
|
|
|
/**
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2022-01-20 04:04:17 +01:00
|
|
|
/**
|
|
|
|
* @brief Builds PlatformInfo Hob
|
|
|
|
*/
|
|
|
|
VOID
|
|
|
|
BuildPlatformInfoHob (
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
BuildGuidDataHob (&gUefiOvmfPkgPlatformInfoGuid, &mPlatformInfoHob, sizeof (EFI_HOB_PLATFORM_INFO));
|
|
|
|
}
|
|
|
|
|
2009-05-27 23:10:18 +02:00
|
|
|
/**
|
|
|
|
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
|
|
|
|
)
|
|
|
|
{
|
2021-12-05 23:54:09 +01:00
|
|
|
EFI_STATUS Status;
|
2016-04-07 12:19:23 +02:00
|
|
|
|
2017-09-04 20:31:21 +02:00
|
|
|
DEBUG ((DEBUG_INFO, "Platform PEIM Loaded\n"));
|
2009-05-27 23:10:18 +02:00
|
|
|
|
2022-03-06 14:31:41 +01:00
|
|
|
mPlatformInfoHob.SmmSmramRequire = FeaturePcdGet (PcdSmmSmramRequire);
|
|
|
|
mPlatformInfoHob.SevEsIsEnabled = MemEncryptSevEsIsEnabled ();
|
|
|
|
mPlatformInfoHob.PcdPciMmio64Size = PcdGet64 (PcdPciMmio64Size);
|
|
|
|
mPlatformInfoHob.DefaultMaxCpuNumber = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
|
2022-03-06 03:20:36 +01:00
|
|
|
|
2022-02-12 07:06:46 +01:00
|
|
|
PlatformDebugDumpCmos ();
|
2011-01-21 17:50:31 +01:00
|
|
|
|
2014-03-04 09:01:58 +01:00
|
|
|
if (QemuFwCfgS3Enabled ()) {
|
2020-04-29 23:53:27 +02:00
|
|
|
DEBUG ((DEBUG_INFO, "S3 support was detected on QEMU\n"));
|
2022-03-06 03:20:36 +01:00
|
|
|
mPlatformInfoHob.S3Supported = TRUE;
|
|
|
|
Status = PcdSetBoolS (PcdAcpiS3Enable, TRUE);
|
2016-04-07 12:19:23 +02:00
|
|
|
ASSERT_EFI_ERROR (Status);
|
2014-03-04 09:01:58 +01:00
|
|
|
}
|
|
|
|
|
2015-12-01 00:36:31 +01:00
|
|
|
S3Verification ();
|
2022-03-06 03:20:36 +01:00
|
|
|
BootModeInitialization (&mPlatformInfoHob);
|
2014-01-29 22:44:16 +01:00
|
|
|
|
2017-07-04 14:50:43 +02:00
|
|
|
//
|
|
|
|
// Query Host Bridge DID
|
|
|
|
//
|
2022-03-06 03:20:36 +01:00
|
|
|
mPlatformInfoHob.HostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID);
|
2022-06-02 10:42:15 +02:00
|
|
|
AddressWidthInitialization (&mPlatformInfoHob);
|
2017-07-04 14:50:43 +02:00
|
|
|
|
2022-03-06 03:20:36 +01:00
|
|
|
MaxCpuCountInitialization (&mPlatformInfoHob);
|
OvmfPkg/PlatformPei: rewrite MaxCpuCountInitialization() for CPU hotplug
MaxCpuCountInitialization() currently handles the following options:
(1) QEMU does not report the boot CPU count (FW_CFG_NB_CPUS is 0)
In this case, PlatformPei makes MpInitLib enumerate APs up to the
default PcdCpuMaxLogicalProcessorNumber value (64) minus 1, or until
the default PcdCpuApInitTimeOutInMicroSeconds (50,000) elapses.
(Whichever is reached first.)
Time-limited AP enumeration had never been reliable on QEMU/KVM, which
is why commit 45a70db3c3a5 strated handling case (2) below, in OVMF.
(2) QEMU reports the boot CPU count (FW_CFG_NB_CPUS is nonzero)
In this case, PlatformPei sets
- PcdCpuMaxLogicalProcessorNumber to the reported boot CPU count
(FW_CFG_NB_CPUS, which exports "PCMachineState.boot_cpus"),
- and PcdCpuApInitTimeOutInMicroSeconds to practically "infinity"
(MAX_UINT32, ~71 minutes).
That causes MpInitLib to enumerate exactly the present (boot) APs.
With CPU hotplug in mind, this method is not good enough. Because,
using QEMU terminology, UefiCpuPkg expects
PcdCpuMaxLogicalProcessorNumber to provide the "possible CPUs" count
("MachineState.smp.max_cpus"), which includes present and not present
CPUs both (with not present CPUs being subject for hot-plugging).
FW_CFG_NB_CPUS does not include not present CPUs.
Rewrite MaxCpuCountInitialization() for handling the following cases:
(1) The behavior of case (1) does not change. (No UefiCpuPkg PCDs are set
to values different from the defaults.)
(2) QEMU reports the boot CPU count ("PCMachineState.boot_cpus", via
FW_CFG_NB_CPUS), but not the possible CPUs count
("MachineState.smp.max_cpus").
In this case, the behavior remains unchanged.
The way MpInitLib is instructed to do the same differs however: we now
set the new PcdCpuBootLogicalProcessorNumber to the boot CPU count
(while continuing to set PcdCpuMaxLogicalProcessorNumber identically).
PcdCpuApInitTimeOutInMicroSeconds becomes irrelevant.
(3) QEMU reports both the boot CPU count ("PCMachineState.boot_cpus", via
FW_CFG_NB_CPUS), and the possible CPUs count
("MachineState.smp.max_cpus").
We tell UefiCpuPkg about the possible CPUs count through
PcdCpuMaxLogicalProcessorNumber. We also tell MpInitLib the boot CPU
count for precise and quick AP enumeration, via
PcdCpuBootLogicalProcessorNumber. PcdCpuApInitTimeOutInMicroSeconds is
irrelevant again.
This patch is a pre-requisite for enabling CPU hotplug with SMM_REQUIRE.
As a side effect, the patch also enables S3 to work with CPU hotplug at
once, *without* SMM_REQUIRE.
(Without the patch, S3 resume fails, if a CPU is hot-plugged at OS
runtime, prior to suspend: the FW_CFG_NB_CPUS increase seen during resume
causes PcdCpuMaxLogicalProcessorNumber to increase as well, which is not
permitted.
With the patch, PcdCpuMaxLogicalProcessorNumber stays the same, namely
"MachineState.smp.max_cpus". Therefore, the CPU structures allocated
during normal boot can accommodate the CPUs at S3 resume that have been
hotplugged prior to S3 suspend.)
Cc: Anthony Perard <anthony.perard@citrix.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Julien Grall <julien.grall@arm.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1515
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Message-Id: <20191022221554.14963-4-lersek@redhat.com>
Acked-by: Anthony PERARD <anthony.perard@citrix.com>
Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2019-10-08 09:15:38 +02:00
|
|
|
|
2022-03-06 03:20:36 +01:00
|
|
|
if (mPlatformInfoHob.SmmSmramRequire) {
|
2019-09-20 13:36:56 +02:00
|
|
|
Q35BoardVerification ();
|
2017-07-04 12:44:05 +02:00
|
|
|
Q35TsegMbytesInitialization ();
|
2019-09-20 14:02:14 +02:00
|
|
|
Q35SmramAtDefaultSmbaseInitialization ();
|
2017-07-04 12:44:05 +02:00
|
|
|
}
|
|
|
|
|
2014-01-29 22:44:09 +01:00
|
|
|
PublishPeiMemory ();
|
|
|
|
|
2022-03-06 14:45:58 +01:00
|
|
|
PlatformQemuUc32BaseInitialization (&mPlatformInfoHob);
|
OvmfPkg/PlatformPei: set 32-bit UC area at PciBase / PciExBarBase (pc/q35)
(This is a replacement for commit 39b9a5ffe661 ("OvmfPkg/PlatformPei: fix
MTRR for low-RAM sizes that have many bits clear", 2019-05-16).)
Reintroduce the same logic as seen in commit 39b9a5ffe661 for the pc
(i440fx) board type.
For q35, the same approach doesn't work any longer, given that (a) we'd
like to keep the PCIEXBAR in the platform DSC a fixed-at-build PCD, and
(b) QEMU expects the PCIEXBAR to reside at a lower address than the 32-bit
PCI MMIO aperture.
Therefore, introduce a helper function for determining the 32-bit
"uncacheable" (MMIO) area base address:
- On q35, this function behaves statically. Furthermore, the MTRR setup
exploits that the range [0xB000_0000, 0xFFFF_FFFF] can be marked UC with
just two variable MTRRs (one at 0xB000_0000 (size 256MB), another at
0xC000_0000 (size 1GB)).
- On pc (i440fx), the function behaves dynamically, implementing the same
logic as commit 39b9a5ffe661 did. The PciBase value is adjusted to the
value calculated, similarly to commit 39b9a5ffe661. A further
simplification is that we show that the UC32 area size truncation to a
whole power of two automatically guarantees a >=2GB base address.
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1859
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
2019-05-29 14:49:55 +02:00
|
|
|
|
2022-03-06 03:20:36 +01:00
|
|
|
InitializeRamRegions (&mPlatformInfoHob);
|
2009-05-27 23:10:18 +02:00
|
|
|
|
2022-03-06 03:20:36 +01:00
|
|
|
if (mPlatformInfoHob.BootMode != BOOT_ON_S3_RESUME) {
|
|
|
|
if (!mPlatformInfoHob.SmmSmramRequire) {
|
2017-03-12 22:01:40 +01:00
|
|
|
ReserveEmuVariableNvStore ();
|
|
|
|
}
|
2021-12-05 23:54:09 +01:00
|
|
|
|
2014-03-04 09:02:30 +01:00
|
|
|
PeiFvInitialization ();
|
OvmfPkg: improve SMM comms security with adaptive MemoryTypeInformation
* In the Intel whitepaper:
--v--
A Tour Beyond BIOS -- Secure SMM Communication
https://github.com/tianocore/tianocore.github.io/wiki/EDK-II-Security-White-Papers
https://github.com/tianocore-docs/Docs/raw/master/White_Papers/A_Tour_Beyond_BIOS_Secure_SMM_Communication.pdf
--^--
bullet#3 in section "Assumption and Recommendation", and bullet#4 in "Call
for action", recommend enabling the (adaptive) Memory Type Information
feature.
* In the Intel whitepaper:
--v--
A Tour Beyond BIOS -- Memory Map and Practices in UEFI BIOS
https://github.com/tianocore/tianocore.github.io/wiki/EDK-II-white-papers
https://github.com/tianocore-docs/Docs/raw/master/White_Papers/A_Tour_Beyond_BIOS_Memory_Map_And_Practices_in_UEFI_BIOS_V2.pdf
--^--
figure#6 describes the Memory Type Information feature in detail; namely
as a feedback loop between the Platform PEIM, the DXE IPL PEIM, the DXE
Core, and BDS.
Implement the missing PlatformPei functionality in OvmfPkg, for fulfilling
the Secure SMM Communication recommendation.
In the longer term, OVMF should install the WSMT ACPI table, and this
patch contributes to that.
Notes:
- the step in figure#6 where the UEFI variable is copied into the HOB is
covered by the DXE IPL PEIM, in the DxeLoadCore() function,
- "PcdResetOnMemoryTypeInformationChange" must be reverted to the DEC
default TRUE value, because both whitepapers indicate that BDS needs to
reset the system if the Memory Type Information changes.
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=386
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Message-Id: <20200310222739.26717-6-lersek@redhat.com>
Acked-by: Leif Lindholm <leif@nuviainc.com>
2020-03-10 23:27:39 +01:00
|
|
|
MemTypeInfoInitialization ();
|
2022-03-06 03:20:36 +01:00
|
|
|
MemMapInitialization (&mPlatformInfoHob);
|
2015-09-15 10:35:14 +02:00
|
|
|
NoexecDxeInitialization ();
|
2014-03-04 09:02:30 +01:00
|
|
|
}
|
2009-05-27 23:10:18 +02:00
|
|
|
|
2018-10-02 14:17:25 +02:00
|
|
|
InstallClearCacheCallback ();
|
OvmfPkg/PlatformPei: Set memory encryption PCD when SEV is enabled
Secure Encrypted Virtualization (SEV) guest VMs have the concept of
private and shared memory. Private memory is encrypted with the
guest-specific key, while shared memory may be encrypted with hypervisor
key. Certain types of memory (namely instruction pages and guest page
tables) are always treated as private memory by the hardware.
For data memory, SEV guest VMs can choose which pages they would like
to be private. The choice is done using the standard CPU page tables
using the C-bit. When building the initial page table we mark all the
memory as private.
The patch sets the memory encryption PCD. The PCD is consumed by the
following edk2 modules, which manipulate page tables:
- PEI phase modules: CapsulePei, DxeIplPeim, S3Resume2Pei.
CapsulePei is not used by OVMF. DxeIplPeim consumes the PCD at the
end of the PEI phase, when it builds the initial page tables for the
DXE core / DXE phase. S3Resume2Pei does not consume the PCD in its
entry point function, only when DxeIplPeim branches to the S3 resume
path at the end of the PEI phase, and calls S3Resume2Pei's
EFI_PEI_S3_RESUME2_PPI.S3RestoreConfig2() member function.
Therefore it is safe to set the PCD for these modules in PlatformPei.
- DXE phase modules: BootScriptExecutorDxe, CpuDxe, PiSmmCpuDxeSmm.
They are all dispatched after the PEI phase, so setting the PCD for
them in PlatformPei is safe. (BootScriptExecutorDxe is launched "for
real" in the PEI phase during S3 resume, but it caches the PCD into a
static variable when its entry point is originally invoked in DXE.)
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
2017-07-06 15:25:48 +02:00
|
|
|
AmdSevInitialize ();
|
2022-03-06 13:04:53 +01:00
|
|
|
if (mPlatformInfoHob.HostBridgeDevId == 0xffff) {
|
|
|
|
MiscInitializationForMicrovm (&mPlatformInfoHob);
|
|
|
|
} else {
|
|
|
|
MiscInitialization (&mPlatformInfoHob);
|
|
|
|
}
|
|
|
|
|
2022-01-20 04:04:17 +01:00
|
|
|
IntelTdxInitialize ();
|
2016-07-07 15:02:11 +02:00
|
|
|
InstallFeatureControlCallback ();
|
2022-01-20 04:04:17 +01:00
|
|
|
BuildPlatformInfoHob ();
|
2009-05-27 23:10:18 +02:00
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|