acpi/acpi: Fix Qemu's XSDT patching code

Since Qemu doesn't provide an XSDT, coreboot adds one as separate ACPI
table. Qemu only provides the smaller ACPI 1.0 RSDP, but the XSDT can
only fit into the bigger ACPI 2.0 RSDP. Currently the exsting RSDP is
being reused, without a size check, which works fine on the first boot.
However after reboot the XSDT pointer seems to be valid, even though the
checksum isn't. Since the XSDT then isn't reserved again on reboot, the
memory it's pointing to is reused by other tables, causing the
payload/OS to see an invalid XSDT.

Instead of corrupting the smaller existing RSDP, allocate a new RSDP
structure and properly fill it with both, existing RSDT and XSDT.

In addition return the correct length of allocated ACPI tables to the
calling code. It was ommiting the size of the allocated XSDT and SSDT.

TEST: Run "qemu-system-x86_64 -M q35" and reboot the virtual machine.
      With this patch applied XSDT is always valid from the OS
      point of view.

Change-Id: Ie4972230c3654714f3dcbaab46a3f70152e75163
Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/83116
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-by: Paul Menzel <paulepanter@mailbox.org>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Patrick Rudolph 2024-06-18 09:18:44 +02:00 committed by Felix Held
parent f78979007a
commit 4b43dac16b

View File

@ -1489,6 +1489,16 @@ unsigned long write_acpi_tables(const unsigned long start)
current = fw;
current = acpi_align_current(current);
if (rsdp->xsdt_address == 0) {
acpi_rsdt_t *existing_rsdt = (acpi_rsdt_t *)(uintptr_t)rsdp->rsdt_address;
/*
* Qemu only provides a smaller ACPI 1.0 RSDP, thus
* allocate a bigger ACPI 2.0 RSDP structure.
*/
rsdp = (acpi_rsdp_t *)current;
current += sizeof(acpi_rsdp_t);
coreboot_rsdp = (uintptr_t)rsdp;
xsdt = (acpi_xsdt_t *)current;
current += sizeof(acpi_xsdt_t);
current = acpi_align_current(current);
@ -1497,7 +1507,6 @@ unsigned long write_acpi_tables(const unsigned long start)
* Qemu only creates an RSDT.
* Add an XSDT based on the existing RSDT entries.
*/
acpi_rsdt_t *existing_rsdt = (acpi_rsdt_t *)(uintptr_t)rsdp->rsdt_address;
acpi_write_rsdp(rsdp, existing_rsdt, xsdt, oem_id);
acpi_write_xsdt(xsdt, oem_id, oem_table_id);
/*
@ -1537,7 +1546,7 @@ unsigned long write_acpi_tables(const unsigned long start)
acpi_add_table(rsdp, ssdt);
return fw;
return current;
}
dsdt_file = cbfs_map(CONFIG_CBFS_PREFIX "/dsdt.aml", &dsdt_size);