Subject: [PATCH] firmware: FIRMWARE Targets VMAware check: FIRMWARE ACPI table fingerprints: PCI link-device names, PNP0A06 resource stubs, the FADT C-state latencies and the AML the checker string-matches on. Applies to QEMU v11.1.1. Apply from the source root with: patch -p1 < 01-firmware.patch --- diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 8837b69..4001d9d 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -165,8 +165,8 @@ static void init_common_fadt_data(MachineState *ms, Object *o, (1 << ACPI_FADT_F_FORCE_APIC_CLUSTER_MODEL) : 0), .int_model = 1 /* Multiple APIC */, .rtc_century = RTC_CENTURY, - .plvl2_lat = 0xfff /* C2 state not supported */, - .plvl3_lat = 0xfff /* C3 state not supported */, + .plvl2_lat = 0xffe /* C2 state not supported */, + .plvl3_lat = 0xffe /* C3 state not supported */, .smi_cmd = smm_enabled ? ACPI_PORT_SMI_CMD : 0, .sci_int = object_property_get_uint(o, ACPI_PM_PROP_SCI_INT, NULL), .acpi_enable_cmd = @@ -748,9 +748,9 @@ static void build_q35_pci0_int(Aml *table) aml_append(table, method); aml_append(pci0_scope, - aml_name_decl("PRTP", build_q35_routing_table("LNK"))); + aml_name_decl("IRQP", build_q35_routing_table("LNK"))); aml_append(pci0_scope, - aml_name_decl("PRTA", build_q35_routing_table("GSI"))); + aml_name_decl("IRQA", build_q35_routing_table("APC"))); method = aml_method("_PRT", 0, AML_NOTSERIALIZED); { @@ -762,10 +762,10 @@ static void build_q35_pci0_int(Aml *table) /* Note: we provide the same info as the PCI routing table of the Bochs BIOS */ if_ctx = aml_if(aml_equal(aml_name("PICF"), aml_int(0))); - aml_append(if_ctx, aml_return(aml_name("PRTP"))); + aml_append(if_ctx, aml_return(aml_name("IRQP"))); aml_append(method, if_ctx); else_ctx = aml_else(); - aml_append(else_ctx, aml_return(aml_name("PRTA"))); + aml_append(else_ctx, aml_return(aml_name("IRQA"))); aml_append(method, else_ctx); } aml_append(pci0_scope, method); @@ -783,14 +783,14 @@ static void build_q35_pci0_int(Aml *table) aml_append(sb_scope, build_link_dev("LNKG", 6, aml_name("PRQG"))); aml_append(sb_scope, build_link_dev("LNKH", 7, aml_name("PRQH"))); - aml_append(sb_scope, build_gsi_link_dev("GSIA", 0x10, 0x10)); - aml_append(sb_scope, build_gsi_link_dev("GSIB", 0x11, 0x11)); - aml_append(sb_scope, build_gsi_link_dev("GSIC", 0x12, 0x12)); - aml_append(sb_scope, build_gsi_link_dev("GSID", 0x13, 0x13)); - aml_append(sb_scope, build_gsi_link_dev("GSIE", 0x14, 0x14)); - aml_append(sb_scope, build_gsi_link_dev("GSIF", 0x15, 0x15)); - aml_append(sb_scope, build_gsi_link_dev("GSIG", 0x16, 0x16)); - aml_append(sb_scope, build_gsi_link_dev("GSIH", 0x17, 0x17)); + aml_append(sb_scope, build_gsi_link_dev("APCA", 0x10, 0x10)); + aml_append(sb_scope, build_gsi_link_dev("APCB", 0x11, 0x11)); + aml_append(sb_scope, build_gsi_link_dev("APCC", 0x12, 0x12)); + aml_append(sb_scope, build_gsi_link_dev("APCD", 0x13, 0x13)); + aml_append(sb_scope, build_gsi_link_dev("APCE", 0x14, 0x14)); + aml_append(sb_scope, build_gsi_link_dev("APCF", 0x15, 0x15)); + aml_append(sb_scope, build_gsi_link_dev("APCG", 0x16, 0x16)); + aml_append(sb_scope, build_gsi_link_dev("APCH", 0x17, 0x17)); aml_append(table, sb_scope); } @@ -801,7 +801,7 @@ static Aml *build_q35_dram_controller(const AcpiMcfgInfo *mcfg) Aml *resource_template; /* DRAM controller */ - dev = aml_device("DRAC"); + dev = aml_device("MCFG"); aml_append(dev, aml_name_decl("_HID", aml_string("PNP0C01"))); resource_template = aml_resource_template(); @@ -885,7 +885,6 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, acpi_table_begin(&table, table_data); dsdt = init_aml_allocator(); - build_dbg_aml(dsdt); if (i440fx) { sb_scope = aml_scope("_SB"); dev = aml_device("PCI0"); @@ -901,6 +900,36 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, build_piix4_pci0_int(dsdt); } else if (q35) { sb_scope = aml_scope("_SB"); + + /* + * Emulate Windows ACPI OSYS/_OSI logic in DSDT. + * Adds Windows 2001/2006/2009/2012/2013/2015. + */ + static const struct { + const char *osi; + uint32_t osys; + } win_osi[] = { + { "Windows 2001", 0x07D1 }, + { "Windows 2001 SP1", 0x07D1 }, + { "Windows 2001 SP2", 0x07D2 }, + { "Windows 2001.1", 0x07D3 }, + { "Windows 2006", 0x07D6 }, + { "Windows 2009", 0x07D9 }, + { "Windows 2012", 0x07DC }, + { "Windows 2013", 0x07DD }, + { "Windows 2015", 0x07DF }, + }; + + aml_append(sb_scope, aml_name_decl("OSYS", aml_int(0x03E8))); + + for (unsigned n = 0; n < ARRAY_SIZE(win_osi); n++) { + Aml *osi = aml_if(aml_equal( + aml_call1("_OSI", aml_string("%s", win_osi[n].osi)), aml_int(1))); + aml_append(osi, aml_store(aml_int(win_osi[n].osys), + aml_name("OSYS"))); + aml_append(sb_scope, osi); + } + dev = aml_device("PCI0"); aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08"))); aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03"))); @@ -916,7 +945,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, /* reserve SMI block resources, IO ports 0xB2, 0xB3 */ dev = aml_device("PCI0.SMI0"); aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A06"))); - aml_append(dev, aml_name_decl("_UID", aml_string("SMI resources"))); + aml_append(dev, aml_name_decl("_UID", aml_string("Reserved resources A"))); crs = aml_resource_template(); aml_append(crs, aml_io( @@ -967,22 +996,6 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, } aml_append(dsdt, scope); - { - CPUHotplugFeatures opts = { - .acpi_1_compatible = true, - .smi_path = pm->smi_on_cpuhp ? "\\_SB.PCI0.SMI0.SMIC" : NULL, - .fw_unplugs_cpu = pm->smi_on_cpu_unplug, - }; - build_cpus_aml(dsdt, machine, opts, pc_madt_cpu_entry, - pm->cpu_hp_io_base, "\\_SB.PCI0", "\\_GPE._E02", - AML_SYSTEM_IO); - } - - if (pcms->memhp_io_base && nr_mem) { - build_memory_hotplug_aml(dsdt, nr_mem, "\\_SB.PCI0", - "\\_GPE._E03", AML_SYSTEM_IO, - pcms->memhp_io_base); - } crs_range_set_init(&crs_range_set); bus = PC_MACHINE(machine)->pcibus; @@ -1133,9 +1146,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(scope, aml_name_decl("_CRS", crs)); /* reserve GPE0 block resources */ - dev = aml_device("GPE0"); + dev = aml_device("RSRA"); aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A06"))); - aml_append(dev, aml_name_decl("_UID", aml_string("GPE0 resources"))); + aml_append(dev, aml_name_decl("_UID", aml_int(0))); /* device present, functioning, decoding, not shown in UI */ aml_append(dev, aml_name_decl("_STA", aml_int(0xB))); crs = aml_resource_template(); @@ -1188,12 +1201,6 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(scope, aml_name_decl("_S5", pkg)); aml_append(dsdt, scope); - /* create fw_cfg node, unconditionally */ - { - scope = aml_scope("\\_SB.PCI0"); - fw_cfg_add_acpi_dsdt(scope, x86ms->fw_cfg); - aml_append(dsdt, scope); - } sb_scope = aml_scope("\\_SB"); { @@ -2168,8 +2175,6 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) x86ms->oem_id, x86ms->oem_table_id, &pcms->cxl_devices_state); } - acpi_add_table(table_offsets, tables_blob); - build_waet(tables_blob, tables->linker, x86ms->oem_id, x86ms->oem_table_id); if (pcms->wdat_enabled == true) { g_assert(pm.tco_io_base); diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index 87162ff..4c303cb 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -687,10 +687,10 @@ void build_append_pcihp_resources(Aml *scope /* \\_SB.PCI0 */, { Aml *dev, *crs; - dev = aml_device("PHPR"); + dev = aml_device("RSRB"); aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A06"))); aml_append(dev, - aml_name_decl("_UID", aml_string("PCI Hotplug resources"))); + aml_name_decl("_UID", aml_string("Reserved resources B"))); /* device present, functioning, decoding, not shown in UI */ aml_append(dev, aml_name_decl("_STA", aml_int(0xB))); crs = aml_resource_template(); @@ -699,6 +699,83 @@ void build_append_pcihp_resources(Aml *scope /* \\_SB.PCI0 */, aml_append(scope, dev); } +/* + * Helper to generate "Real Hardware" looking ACPI names. + * This removes the "S" signature and ensures unique naming + * for multifunction devices. + */ +static void get_mimic_pci_name(char *name, int devfn) { + int slot = PCI_SLOT(devfn); + int func = PCI_FUNC(devfn); + + switch (slot) { + case 0: + // Host Bridge is almost always Slot 0, Function 0 (and also bus 0 but we cant access bus number in this context) + if (func == 0) sprintf(name, "MCHC"); + else sprintf(name, "H%X", func); + break; + + case 2: + // Slot 2: Graphics + associated HDMI Audio + if (func == 0) sprintf(name, "GFX0"); // Primary GPU + else if (func == 1) sprintf(name, "HDAU"); // HDMI Audio + else sprintf(name, "GFX%X", func); // Fallback uniqueness + break; + + case 3: + // Slot 3: Network + if (func == 0) sprintf(name, "GLAN"); + else sprintf(name, "NET%X", func); + break; + + case 4: + // Slot 4: Multimedia / Audio + if (func == 0) sprintf(name, "HDEF"); + else sprintf(name, "MM%02X", func); + break; + + case 5: + // Slot 5: USB XHCI (QEMU default often) + if (func == 0) sprintf(name, "XHC1"); + else sprintf(name, "XHC%X", func); + break; + + case 6: + // Slot 6: SATA (AHCI) + if (func == 0) sprintf(name, "SAT0"); + else sprintf(name, "SAT%X", func); + break; + + case 29: + // Slot 29 (0x1D): USB EHCI (Intel Standard) + if (func == 0) sprintf(name, "EHC1"); + else sprintf(name, "EHC%X", func); + break; + + case 20: + // Slot 20 (0x14): LPC / SMBus / SATA 2 + if (func == 0) sprintf(name, "LPCB"); // ISA Bridge + else if (func == 2) sprintf(name, "SAT1"); // 2nd SATA + else if (func == 3) sprintf(name, "SBUS"); // SMBus + else sprintf(name, "S20%X", func); // Fallback + break; + + default: + /* + * For generic slots, we use "RP" (Root Port) + devfn (Hex). + * + * Why 'devfn' and not 'slot'? + * - Slot 10, Func 0 (devfn 0x50) -> RP50 + * - Slot 10, Func 1 (devfn 0x51) -> RP51 + * + * This guarantees ACPI uniqueness for multifunction devices + * while completely breaking the "S" + hex signature. + */ + sprintf(name, "RP%02X", devfn); + break; + } +} + bool build_append_notification_callback(Aml *parent_scope, const PCIBus *bus) { Aml *method; @@ -912,7 +989,11 @@ void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus) } /* start to compose PCI device descriptor */ - dev = aml_device("S%.02X", devfn); + + char mimic_name[5]; + get_mimic_pci_name(mimic_name, devfn); + dev = aml_device("%s", mimic_name); + aml_append(dev, aml_name_decl("_ADR", aml_int(adr))); call_dev_aml_func(DEVICE(bus->devices[devfn]), dev); diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index 990abc6..01c8fc4 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -1751,15 +1751,14 @@ void acpi_table_begin(AcpiTable *desc, GArray *array) * reserve space for Length field, which will be patched by * acpi_table_end() when the table creation is finished. */ - build_append_int_noprefix(array, 0, 4); /* Length */ - build_append_int_noprefix(array, desc->rev, 1); /* Revision */ - build_append_int_noprefix(array, 0, 1); /* Checksum */ - build_append_padded_str(array, desc->oem_id, 6, '\0'); /* OEMID */ - /* OEM Table ID */ - build_append_padded_str(array, desc->oem_table_id, 8, '\0'); - build_append_int_noprefix(array, 1, 4); /* OEM Revision */ - g_array_append_vals(array, ACPI_BUILD_APPNAME8, 4); /* Creator ID */ - build_append_int_noprefix(array, 1, 4); /* Creator Revision */ + build_append_int_noprefix(array, 0, 4); /* Length */ + build_append_int_noprefix(array, desc->rev, 1); /* Revision */ + build_append_int_noprefix(array, 0, 1); /* Checksum */ + build_append_padded_str(array, ACPI_BUILD_APPNAME6, 6, '\0'); /* OEMID */ + build_append_padded_str(array, ACPI_BUILD_APPNAME8, 8, '\0'); /* OEM Table ID */ + build_append_int_noprefix(array, 1, 4); /* OEM Revision */ + g_array_append_vals(array, "ACPI", 4); /* Creator ID */ + build_append_int_noprefix(array, 1, 4); /* Creator Revision */ } void acpi_table_end(BIOSLinker *linker, AcpiTable *desc) @@ -2488,7 +2487,7 @@ void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f, /* ACPI1.0: INT_MODEL, ACPI2.0+: Reserved */ build_append_int_noprefix(tbl, f->int_model /* Multiple APIC */, 1); /* Preferred_PM_Profile */ - build_append_int_noprefix(tbl, 0 /* Unspecified */, 1); + build_append_int_noprefix(tbl, 1 /* Desktop */, 1); build_append_int_noprefix(tbl, f->sci_int, 2); /* SCI_INT */ build_append_int_noprefix(tbl, f->smi_cmd, 4); /* SMI_CMD */ build_append_int_noprefix(tbl, f->acpi_enable_cmd, 1); /* ACPI_ENABLE */ @@ -2585,7 +2584,7 @@ void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f, } /* Hypervisor Vendor Identity */ - build_append_padded_str(tbl, "QEMU", 8, '\0'); + build_append_int_noprefix(tbl, 0, 8); /* TODO: extra fields need to be added to support revisions above rev6 */ assert(f->rev == 6); diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h index eaff025..9c3b434 100644 --- a/include/hw/acpi/aml-build.h +++ b/include/hw/acpi/aml-build.h @@ -5,8 +5,8 @@ #include "hw/acpi/bios-linker-loader.h" #include "hw/core/cpu.h" -#define ACPI_BUILD_APPNAME6 "BOCHS " -#define ACPI_BUILD_APPNAME8 "BXPC " +#define ACPI_BUILD_APPNAME6 "ALASKA" +#define ACPI_BUILD_APPNAME8 "A M I " #define ACPI_BUILD_TABLE_FILE "etc/acpi/tables" #define ACPI_BUILD_RSDP_FILE "etc/acpi/rsdp" diff --git a/include/hw/i386/x86.h b/include/hw/i386/x86.h index 71fe6b5..755c9d8 100644 --- a/include/hw/i386/x86.h +++ b/include/hw/i386/x86.h @@ -136,7 +136,7 @@ bool x86_machine_is_acpi_enabled(const X86MachineState *x86ms); /* Global System Interrupts */ -#define ACPI_BUILD_PCI_IRQS ((1<<5) | (1<<9) | (1<<10) | (1<<11)) +#define ACPI_BUILD_PCI_IRQS ((1<<4) | (1<<5) | (1<<6) | (1<<10) | (1<<11) | (1<<14) | (1<<15)) typedef struct GSIState { qemu_irq i8259_irq[ISA_NUM_IRQS]; diff --git a/hw/pci-host/gpex.c b/hw/pci-host/gpex.c index e66784c..8f748f9 100644 --- a/hw/pci-host/gpex.c +++ b/hw/pci-host/gpex.c @@ -243,8 +243,8 @@ static void gpex_root_class_init(ObjectClass *klass, const void *data) dc->desc = "QEMU generic PCIe host bridge"; dc->vmsd = &vmstate_gpex_root; - k->vendor_id = PCI_VENDOR_ID_REDHAT; - k->device_id = PCI_DEVICE_ID_REDHAT_PCIE_HOST; + k->vendor_id = PCI_VENDOR_ID_AMD; + k->device_id = PCI_DEVICE_ID_INTEL_P35_MCH; k->revision = 0; k->class_id = PCI_CLASS_BRIDGE_HOST; /*