On Wed, Jul 26, 2017 at 11:42:34AM +0200, Paolo Bonzini wrote: > Old operating systems would like to have a rev1 (ACPI 1.0) FADT, but > new operating systems would like to have rev3 (ACPI 2.0). > > Since old operating systems do not know about XSDTs, the > solution is to point the RSDT to a rev1 FADT and the XSDT to a > rev3 FADT. > > But, edk2 is not able to handle QEMU providing two FADTs and barfs when > it sees the second; edk2 subscribes to the view that the platform code > (meaning not only OVMF, but transitively QEMU's ACPI table builder) > should not handle such hacks; it's common edk2 code that should handle > FADT rev1 vs. rev3 and RSDT vs. XSDT.
What exactly does it do wrt RSDT? > These patches make SeaBIOS follow the same model as edk2, the only > difference being how the two identify ACPI tables from the BIOS > linker/loader script. For SeaBIOS, this task is actually much > simpler since it can just look into the RSDP: if QEMU only > provides an XSDT, SeaBIOS takes care of building the RSDT and > rev1 FADT to satisfy ACPI 1.0-compliant operating systems. > > This part makes SeaBIOS build an RSDT out of an existing XSDT, > patching the RSDP to point to the RSDT. > > Reviewed-by: Phil Dennis-Jordan <p...@philjordan.eu> > Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> > --- > src/fw/paravirt.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- > src/std/acpi.h | 11 +++++++++++ > 2 files changed, 59 insertions(+), 1 deletion(-) > > diff --git a/src/fw/paravirt.c b/src/fw/paravirt.c > index 5b23d78..927fd75 100644 > --- a/src/fw/paravirt.c > +++ b/src/fw/paravirt.c > @@ -25,6 +25,7 @@ > #include "x86.h" // cpuid > #include "xen.h" // xen_biostable_setup > #include "stacks.h" // yield > +#include "std/acpi.h" > > // Amount of continuous ram under 4Gig > u32 RamSize; > @@ -147,6 +148,50 @@ static void msr_feature_control_setup(void) > wrmsr_smp(MSR_IA32_FEATURE_CONTROL, feature_control_bits); > } > > +static void > +build_compatibility_rsdt(void) > +{ > + if (RsdpAddr->rsdt_physical_address) > + return; > + > + u64 xsdt_addr = RsdpAddr->xsdt_physical_address; > + if (xsdt_addr & ~0xffffffffULL) > + return; > + > + struct xsdt_descriptor_rev1 *xsdt = (void*)(u32)xsdt_addr; > + void *end = (void*)xsdt + xsdt->length; > + struct rsdt_descriptor_rev1 *rsdt; > + int rsdt_size = offsetof(struct rsdt_descriptor_rev1, > table_offset_entry[0]); > + int i; > + for (i=0; (void*)&xsdt->table_offset_entry[i] < end; i++) { > + u64 tbl_addr = xsdt->table_offset_entry[i]; > + if (!tbl_addr || (tbl_addr & ~0xffffffffULL)) > + continue; > + rsdt_size += 4; > + } > + > + rsdt = malloc_high(rsdt_size); > + RsdpAddr->rsdt_physical_address = (u32)rsdt; > + RsdpAddr->checksum -= checksum(RsdpAddr, > + offsetof(struct rsdp_descriptor, length)); > + RsdpAddr->extended_checksum -= checksum(RsdpAddr, > + sizeof(struct rsdp_descriptor)); > + > + memcpy(rsdt, xsdt, sizeof(struct acpi_table_header)); > + rsdt->signature = RSDT_SIGNATURE; > + rsdt->length = rsdt_size; > + rsdt->revision = 1; > + int j; > + for (i=j=0; (void*)&xsdt->table_offset_entry[i] < end; i++) { > + u64 tbl_addr = xsdt->table_offset_entry[i]; > + if (!tbl_addr || (tbl_addr & ~0xffffffffULL)) > + continue; > + rsdt->table_offset_entry[j++] = (u32)tbl_addr; > + } > + > + rsdt->checksum -= checksum(rsdt, rsdt_size); > +} > + > void > qemu_platform_setup(void) > { > @@ -186,8 +231,10 @@ qemu_platform_setup(void) > > RsdpAddr = find_acpi_rsdp(); > > - if (RsdpAddr) > + if (RsdpAddr) { > + build_compatibility_rsdt(); > return; > + } > > /* If present, loader should have installed an RSDP. > * Not installed? We might still be able to continue > diff --git a/src/std/acpi.h b/src/std/acpi.h > index c2ea707..a77b53c 100644 > --- a/src/std/acpi.h > +++ b/src/std/acpi.h > @@ -133,6 +133,17 @@ struct rsdt_descriptor_rev1 > } PACKED; > > /* > + * ACPI 2.0 Extended System Description Table (XSDT) > + */ > +#define XSDT_SIGNATURE 0x54445358 // XSDT > +struct xsdt_descriptor_rev1 > +{ > + ACPI_TABLE_HEADER_DEF /* ACPI common table header */ > + u64 table_offset_entry[0]; /* Array of pointers to other */ > + /* ACPI tables */ > +} PACKED; > + > +/* > * ACPI 1.0 Firmware ACPI Control Structure (FACS) > */ > #define FACS_SIGNATURE 0x53434146 // FACS > -- > 2.13.3 >