Digressing:
On 07/26/17 10:53, Paolo Bonzini wrote:
On 25/07/2017 23:25, Phil Dennis-Jordan wrote:
Thanks for this, Paolo. Very interesting idea.
I couldn't get things working initially, but with a few fixups on the SeaBIOS side I can boot both legacy and modern OSes. See comments inline below for details on changes required.
Successfully booted (only a brief test):
- Windows 2000
- Windows XP (32 bit)
- Windows 7 (32 bit)
- Windows 10 (64 bit, SeaBIOS)
- Windows 10 (64 bit, OVMF)
- macOS 10.12 (patched OVMF)
Thanks Phil! You unwittingly tested the compatibility path on all these OSes, since my QEMU patch forgot to setup rsdp->length, rsdp->revision and the extended checksum. However, I've now tested Windows XP, Linux w/SeaBIOS, Linux w/patched SeaBIOS and Linux w/OVMF.
I've now found out that edk2 contains similar logic. It uses a PCD (a compile-time flag essentially) to choose between ACPI >= 2.0 tables or ACPI 1.0-compatible tables. In the latter case, edk2 takes care of producing a v1 FADT if needed (similar to this patch) and linking the RSDT to it; otherwise it keeps whatever FADT was provided by platform code and produces an XSDT.
Not exactly; the PCD controls whether the EFI_ACPI_TABLE_PROTOCOL will expose an RSDT, an XSDT, or both (with matching contents). The FADT always comes from the specific edk2 platform (i.e., OVMF client code), and it is not translated in any way, regardless of the PCD value.
From "MdeModulePkg/MdeModulePkg.dec":
## Indicates which ACPI versions are targeted by the ACPI tables exposed to the OS # These values are aligned with the definitions in MdePkg/Include/Protocol/AcpiSystemDescriptionTable.h # BIT 1 - EFI_ACPI_TABLE_VERSION_1_0B.<BR> # BIT 2 - EFI_ACPI_TABLE_VERSION_2_0.<BR> # BIT 3 - EFI_ACPI_TABLE_VERSION_3_0.<BR> # BIT 4 - EFI_ACPI_TABLE_VERSION_4_0.<BR> # BIT 5 - EFI_ACPI_TABLE_VERSION_5_0.<BR> # @Prompt Exposed ACPI table versions. gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiExposedTableVersions|0x3E|UINT32|0x0001004c
The expectation is that the specific edk2 platform overrides this PCD at build time (if necessary), and then goes on (at boot time) to install ACPI tables -- using EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable() -- that actually match the PCD setting.
From the "MdeModulePkg/Universal/Acpi/AcpiTableDxe/" driver's POV (that
is, from the EFI_ACPI_TABLE_PROTOCOL implementation's POV), the platform controls *both* the PCD and the actually installed tables like the FADT, so EFI_ACPI_TABLE_PROTOCOL expects the platform to make these consistent.
The tiny little problem is that the PCD is a build-time flag, but QEMU provides the FADT (and friends) at boot time, dynamically, in a format that is essentially opaque to OVMF. So OVMF is sticking with the default PCD (see above), resulting in both RSDT and XSDT root tables, regardless of the contents of the FADT and friends.
A somewhat (but not too much) similar situation is with the SMBIOS tables. The tables are composed / exported by QEMU over fw_cfg, and OVMF / AAVMF have to set some version-like PCDs that match the content: - PcdSmbiosDocRev - PcdSmbiosVersion
We do some ugly hacks in OVMF to ensure that these PCDs are set "in time", before the generic "MdeModulePkg/Universal/SmbiosDxe" -- providing EFI_SMBIOS_PROTOCOL -- starts up and consumes the PCDs. Namely, we have "OvmfPkg/Library/SmbiosVersionLib" which sets these PCDs based on fw_cfg, and we link this library via NULL class resolution into "MdeModulePkg/Universal/SmbiosDxe". So the PCDs will be set up just before EFI_SMBIOS_PROTOCOL is initialized and provided. In turn, "OvmfPkg/SmbiosPlatformDxe", which actually calls EFI_SMBIOS_PROTOCOL.Add() on the tables provided by QEMU, has a depex on EFI_SMBIOS_PROTOCOL -- first, this depex ensures that EFI_SMBIOS_PROTOCOL can be used by "OvmfPkg/SmbiosPlatformDxe", but second, the depex *also* ensures that the PCDs will have been set correctly by the time "OvmfPkg/SmbiosPlatformDxe" calls EFI_SMBIOS_PROTOCOL.Add() for the first time.
You might ask why we don't do the same in the ACPI case (i.e., for PcdAcpiExposedTableVersions). It's due to the following differences:
- (less importantly,) "MdeModulePkg.dec" allows platforms to pick "dynamic" for PcdSmbiosDocRev and PcdSmbiosVersion, not just "fixed at build". IOW, MdeModulePkg already expects platforms to set the SMBIOS version PCDs dynamically, if those platforms can ensure the setting occurs "early enough".
- (more importantly,) the information needed by OVMF, for setting the SMBIOS version PCDs in "OvmfPkg/Library/SmbiosVersionLib", is readily available for parsing from the separate, dedicated fw_cfg file called "etc/smbios/smbios-anchor". In fact, OVMF doesn't use this file for anything else than grabbing the versions for the PCDs. The actual "anchor" table (the smbios entry point) is produced by the EFI_SMBIOS_PROTOCOL implementation in "MdeModulePkg/Universal/SmbiosDxe", which consumes the version PCDs.
(The SMBIOS tables themselves are provided in another fw_cfg file, called "etc/smbios/smbios-tables". Incidentally, the structure of that file is also way simpler than the ACPI linker/loader blobs'; OVMF can pick it apart with a simple loop and pass the individual SMBIOS tables to EFI_SMBIOS_PROTOCOL.Add().)
Anyway, I'm calling this email a digression because it isn't really related to the FADT content that is exposed to the OS. I just wanted to clarify "PcdAcpiExposedTableVersions", and that there isn't any "deep" FADT translation in edk2, to my knowledge.
Thanks Laszlo