172c194f7SMichael S. Tsirkin /* Support for generating ACPI tables and passing them to Guests 272c194f7SMichael S. Tsirkin * 372c194f7SMichael S. Tsirkin * Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net> 472c194f7SMichael S. Tsirkin * Copyright (C) 2006 Fabrice Bellard 572c194f7SMichael S. Tsirkin * Copyright (C) 2013 Red Hat Inc 672c194f7SMichael S. Tsirkin * 772c194f7SMichael S. Tsirkin * Author: Michael S. Tsirkin <mst@redhat.com> 872c194f7SMichael S. Tsirkin * 972c194f7SMichael S. Tsirkin * This program is free software; you can redistribute it and/or modify 1072c194f7SMichael S. Tsirkin * it under the terms of the GNU General Public License as published by 1172c194f7SMichael S. Tsirkin * the Free Software Foundation; either version 2 of the License, or 1272c194f7SMichael S. Tsirkin * (at your option) any later version. 1372c194f7SMichael S. Tsirkin 1472c194f7SMichael S. Tsirkin * This program is distributed in the hope that it will be useful, 1572c194f7SMichael S. Tsirkin * but WITHOUT ANY WARRANTY; without even the implied warranty of 1672c194f7SMichael S. Tsirkin * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1772c194f7SMichael S. Tsirkin * GNU General Public License for more details. 1872c194f7SMichael S. Tsirkin 1972c194f7SMichael S. Tsirkin * You should have received a copy of the GNU General Public License along 2072c194f7SMichael S. Tsirkin * with this program; if not, see <http://www.gnu.org/licenses/>. 2172c194f7SMichael S. Tsirkin */ 2272c194f7SMichael S. Tsirkin 23b6a0aa05SPeter Maydell #include "qemu/osdep.h" 24da34e65cSMarkus Armbruster #include "qapi/error.h" 2515280c36SMarkus Armbruster #include "qapi/qmp/qnum.h" 2672c194f7SMichael S. Tsirkin #include "acpi-build.h" 27eb66ffabSGerd Hoffmann #include "acpi-common.h" 2872c194f7SMichael S. Tsirkin #include "qemu/bitmap.h" 2907fb6176SPaolo Bonzini #include "qemu/error-report.h" 3072c194f7SMichael S. Tsirkin #include "hw/pci/pci.h" 312e5b09fdSMarkus Armbruster #include "hw/core/cpu.h" 32fcf5ef2aSThomas Huth #include "target/i386/cpu.h" 330d5d8a3aSPhilippe Mathieu-Daudé #include "hw/misc/pvpanic.h" 3472c194f7SMichael S. Tsirkin #include "hw/timer/hpet.h" 35395e5fb4SShannon Zhao #include "hw/acpi/acpi-defs.h" 3672c194f7SMichael S. Tsirkin #include "hw/acpi/acpi.h" 37679dd1a9SIgor Mammedov #include "hw/acpi/cpu.h" 3872c194f7SMichael S. Tsirkin #include "hw/nvram/fw_cfg.h" 390058ae1dSMichael S. Tsirkin #include "hw/acpi/bios-linker-loader.h" 4015bce1b7SGabriel L. Somlo #include "hw/isa/isa.h" 4127b9fc54SRoman Kagan #include "hw/block/fdc.h" 42bef3492dSIgor Mammedov #include "hw/acpi/memory_hotplug.h" 43711b20b4SStefan Berger #include "sysemu/tpm.h" 44711b20b4SStefan Berger #include "hw/acpi/tpm.h" 45d03637bcSBen Warren #include "hw/acpi/vmgenid.h" 460e11fc69SLike Xu #include "hw/boards.h" 475cb18b3dSStefan Berger #include "sysemu/tpm_backend.h" 48bcdb9064SPhilippe Mathieu-Daudé #include "hw/rtc/mc146818rtc_regs.h" 49d6454270SMarkus Armbruster #include "migration/vmstate.h" 502cc0e2e8SDavid Hildenbrand #include "hw/mem/memory-device.h" 514b997690SPhilippe Mathieu-Daudé #include "hw/mem/nvdimm.h" 521f3aba37SIgor Mammedov #include "sysemu/numa.h" 5371e8a915SMarkus Armbruster #include "sysemu/reset.h" 546775d15dSJon Doron #include "hw/hyperv/vmbus-bridge.h" 5572c194f7SMichael S. Tsirkin 5672c194f7SMichael S. Tsirkin /* Supported chipsets: */ 57fff123b8SPhilippe Mathieu-Daudé #include "hw/southbridge/piix.h" 5899fd437dSMichael S. Tsirkin #include "hw/acpi/pcihp.h" 5989a289c7SPaolo Bonzini #include "hw/i386/fw_cfg.h" 6072c194f7SMichael S. Tsirkin #include "hw/i386/ich9.h" 6172c194f7SMichael S. Tsirkin #include "hw/pci/pci_bus.h" 6272c194f7SMichael S. Tsirkin #include "hw/pci-host/q35.h" 631cf5fd57SPeter Xu #include "hw/i386/x86-iommu.h" 6472c194f7SMichael S. Tsirkin 6519934e0eSIgor Mammedov #include "hw/acpi/aml-build.h" 6682f76c67SWei Yang #include "hw/acpi/utils.h" 6748cefd94SWei Yang #include "hw/acpi/pci.h" 6819934e0eSIgor Mammedov 6972c194f7SMichael S. Tsirkin #include "qom/qom-qobject.h" 70fb9f5926SDavid Kiarie #include "hw/i386/amd_iommu.h" 71fb9f5926SDavid Kiarie #include "hw/i386/intel_iommu.h" 7272c194f7SMichael S. Tsirkin 7386e91dd7SCorey Minyard #include "hw/acpi/ipmi.h" 74e6f123c3SLiu Jingqi #include "hw/acpi/hmat.h" 7586e91dd7SCorey Minyard 7607fb6176SPaolo Bonzini /* These are used to size the ACPI tables for -M pc-i440fx-1.7 and 7707fb6176SPaolo Bonzini * -M pc-i440fx-2.0. Even if the actual amount of AML generated grows 7807fb6176SPaolo Bonzini * a little bit, there should be plenty of free space since the DSDT 7907fb6176SPaolo Bonzini * shrunk by ~1.5k between QEMU 2.0 and QEMU 2.1. 8007fb6176SPaolo Bonzini */ 8107fb6176SPaolo Bonzini #define ACPI_BUILD_LEGACY_CPU_AML_SIZE 97 8207fb6176SPaolo Bonzini #define ACPI_BUILD_ALIGN_SIZE 0x1000 8307fb6176SPaolo Bonzini 84868270f2SMichael S. Tsirkin #define ACPI_BUILD_TABLE_SIZE 0x20000 8518045fb9SPaolo Bonzini 868b310fc4SGonglei /* #define DEBUG_ACPI_BUILD */ 878b310fc4SGonglei #ifdef DEBUG_ACPI_BUILD 888b310fc4SGonglei #define ACPI_BUILD_DPRINTF(fmt, ...) \ 898b310fc4SGonglei do {printf("ACPI_BUILD: " fmt, ## __VA_ARGS__); } while (0) 908b310fc4SGonglei #else 918b310fc4SGonglei #define ACPI_BUILD_DPRINTF(fmt, ...) 928b310fc4SGonglei #endif 938b310fc4SGonglei 9472c194f7SMichael S. Tsirkin typedef struct AcpiPmInfo { 9572c194f7SMichael S. Tsirkin bool s3_disabled; 9672c194f7SMichael S. Tsirkin bool s4_disabled; 97133a2da4SIgor Mammedov bool pcihp_bridge_en; 986d837f1fSIgor Mammedov bool smi_on_cpuhp; 99892aae74SIgor Mammedov bool smi_on_cpu_unplug; 100df4008c9SAni Sinha bool pcihp_root_en; 10172c194f7SMichael S. Tsirkin uint8_t s4_val; 102937d1b58SIgor Mammedov AcpiFadtData fadt; 103ddf1ec2fSIgor Mammedov uint16_t cpu_hp_io_base; 104500b11eaSIgor Mammedov uint16_t pcihp_io_base; 105500b11eaSIgor Mammedov uint16_t pcihp_io_len; 10672c194f7SMichael S. Tsirkin } AcpiPmInfo; 10772c194f7SMichael S. Tsirkin 10872c194f7SMichael S. Tsirkin typedef struct AcpiMiscInfo { 109e4db2798SIgor Mammedov bool is_piix4; 11072c194f7SMichael S. Tsirkin bool has_hpet; 1115cb18b3dSStefan Berger TPMVersion tpm_version; 11272c194f7SMichael S. Tsirkin const unsigned char *dsdt_code; 11372c194f7SMichael S. Tsirkin unsigned dsdt_size; 11472c194f7SMichael S. Tsirkin uint16_t pvpanic_port; 1158ac6f7a6SIgor Mammedov uint16_t applesmc_io_base; 11672c194f7SMichael S. Tsirkin } AcpiMiscInfo; 11772c194f7SMichael S. Tsirkin 11899fd437dSMichael S. Tsirkin typedef struct AcpiBuildPciBusHotplugState { 11999fd437dSMichael S. Tsirkin GArray *device_table; 12099fd437dSMichael S. Tsirkin GArray *notify_table; 12199fd437dSMichael S. Tsirkin struct AcpiBuildPciBusHotplugState *parent; 122133a2da4SIgor Mammedov bool pcihp_bridge_en; 12399fd437dSMichael S. Tsirkin } AcpiBuildPciBusHotplugState; 12499fd437dSMichael S. Tsirkin 1250fe24669SStefan Berger typedef struct FwCfgTPMConfig { 1260fe24669SStefan Berger uint32_t tpmppi_address; 1270fe24669SStefan Berger uint8_t tpm_version; 1280fe24669SStefan Berger uint8_t tpmppi_version; 1290fe24669SStefan Berger } QEMU_PACKED FwCfgTPMConfig; 1300fe24669SStefan Berger 1314a441836SGerd Hoffmann static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg); 1324a441836SGerd Hoffmann 1335c94b826SKwangwoo Lee const struct AcpiGenericAddress x86_nvdimm_acpi_dsmio = { 1345c94b826SKwangwoo Lee .space_id = AML_AS_SYSTEM_IO, 1355c94b826SKwangwoo Lee .address = NVDIMM_ACPI_IO_BASE, 1365c94b826SKwangwoo Lee .bit_width = NVDIMM_ACPI_IO_LEN << 3 1375c94b826SKwangwoo Lee }; 1385c94b826SKwangwoo Lee 1390e11fc69SLike Xu static void init_common_fadt_data(MachineState *ms, Object *o, 1400e11fc69SLike Xu AcpiFadtData *data) 141937d1b58SIgor Mammedov { 14233b44fdaSIsaku Yamahata X86MachineState *x86ms = X86_MACHINE(ms); 14333b44fdaSIsaku Yamahata /* 14433b44fdaSIsaku Yamahata * "ICH9-LPC" or "PIIX4_PM" has "smm-compat" property to keep the old 14533b44fdaSIsaku Yamahata * behavior for compatibility irrelevant to smm_enabled, which doesn't 14633b44fdaSIsaku Yamahata * comforms to ACPI spec. 14733b44fdaSIsaku Yamahata */ 14833b44fdaSIsaku Yamahata bool smm_enabled = object_property_get_bool(o, "smm-compat", NULL) ? 14933b44fdaSIsaku Yamahata true : x86_machine_is_smm_enabled(x86ms); 150937d1b58SIgor Mammedov uint32_t io = object_property_get_uint(o, ACPI_PM_PROP_PM_IO_BASE, NULL); 151937d1b58SIgor Mammedov AmlAddressSpace as = AML_AS_SYSTEM_IO; 152937d1b58SIgor Mammedov AcpiFadtData fadt = { 153937d1b58SIgor Mammedov .rev = 3, 154937d1b58SIgor Mammedov .flags = 155937d1b58SIgor Mammedov (1 << ACPI_FADT_F_WBINVD) | 156937d1b58SIgor Mammedov (1 << ACPI_FADT_F_PROC_C1) | 157937d1b58SIgor Mammedov (1 << ACPI_FADT_F_SLP_BUTTON) | 158937d1b58SIgor Mammedov (1 << ACPI_FADT_F_RTC_S4) | 159937d1b58SIgor Mammedov (1 << ACPI_FADT_F_USE_PLATFORM_CLOCK) | 160937d1b58SIgor Mammedov /* APIC destination mode ("Flat Logical") has an upper limit of 8 161937d1b58SIgor Mammedov * CPUs for more than 8 CPUs, "Clustered Logical" mode has to be 162937d1b58SIgor Mammedov * used 163937d1b58SIgor Mammedov */ 1640e11fc69SLike Xu ((ms->smp.max_cpus > 8) ? 1650e11fc69SLike Xu (1 << ACPI_FADT_F_FORCE_APIC_CLUSTER_MODEL) : 0), 166937d1b58SIgor Mammedov .int_model = 1 /* Multiple APIC */, 167937d1b58SIgor Mammedov .rtc_century = RTC_CENTURY, 168937d1b58SIgor Mammedov .plvl2_lat = 0xfff /* C2 state not supported */, 169937d1b58SIgor Mammedov .plvl3_lat = 0xfff /* C3 state not supported */, 17033b44fdaSIsaku Yamahata .smi_cmd = smm_enabled ? ACPI_PORT_SMI_CMD : 0, 171937d1b58SIgor Mammedov .sci_int = object_property_get_uint(o, ACPI_PM_PROP_SCI_INT, NULL), 172937d1b58SIgor Mammedov .acpi_enable_cmd = 17333b44fdaSIsaku Yamahata smm_enabled ? 17433b44fdaSIsaku Yamahata object_property_get_uint(o, ACPI_PM_PROP_ACPI_ENABLE_CMD, NULL) : 17533b44fdaSIsaku Yamahata 0, 176937d1b58SIgor Mammedov .acpi_disable_cmd = 17733b44fdaSIsaku Yamahata smm_enabled ? 17833b44fdaSIsaku Yamahata object_property_get_uint(o, ACPI_PM_PROP_ACPI_DISABLE_CMD, NULL) : 17933b44fdaSIsaku Yamahata 0, 180937d1b58SIgor Mammedov .pm1a_evt = { .space_id = as, .bit_width = 4 * 8, .address = io }, 181937d1b58SIgor Mammedov .pm1a_cnt = { .space_id = as, .bit_width = 2 * 8, 182937d1b58SIgor Mammedov .address = io + 0x04 }, 183937d1b58SIgor Mammedov .pm_tmr = { .space_id = as, .bit_width = 4 * 8, .address = io + 0x08 }, 184937d1b58SIgor Mammedov .gpe0_blk = { .space_id = as, .bit_width = 185937d1b58SIgor Mammedov object_property_get_uint(o, ACPI_PM_PROP_GPE0_BLK_LEN, NULL) * 8, 186937d1b58SIgor Mammedov .address = object_property_get_uint(o, ACPI_PM_PROP_GPE0_BLK, NULL) 187937d1b58SIgor Mammedov }, 188937d1b58SIgor Mammedov }; 189937d1b58SIgor Mammedov *data = fadt; 190937d1b58SIgor Mammedov } 191937d1b58SIgor Mammedov 19281c48dd7SPhilippe Mathieu-Daudé static Object *object_resolve_type_unambiguous(const char *typename) 19381c48dd7SPhilippe Mathieu-Daudé { 19481c48dd7SPhilippe Mathieu-Daudé bool ambig; 19581c48dd7SPhilippe Mathieu-Daudé Object *o = object_resolve_path_type("", typename, &ambig); 19681c48dd7SPhilippe Mathieu-Daudé 19781c48dd7SPhilippe Mathieu-Daudé if (ambig || !o) { 19881c48dd7SPhilippe Mathieu-Daudé return NULL; 19981c48dd7SPhilippe Mathieu-Daudé } 20081c48dd7SPhilippe Mathieu-Daudé return o; 20181c48dd7SPhilippe Mathieu-Daudé } 20281c48dd7SPhilippe Mathieu-Daudé 2030e11fc69SLike Xu static void acpi_get_pm_info(MachineState *machine, AcpiPmInfo *pm) 20472c194f7SMichael S. Tsirkin { 20581c48dd7SPhilippe Mathieu-Daudé Object *piix = object_resolve_type_unambiguous(TYPE_PIIX4_PM); 20681c48dd7SPhilippe Mathieu-Daudé Object *lpc = object_resolve_type_unambiguous(TYPE_ICH9_LPC_DEVICE); 207697155cdSIgor Mammedov Object *obj = piix ? piix : lpc; 20872c194f7SMichael S. Tsirkin QObject *o; 20994aaca64SDaniel P. Berrange pm->cpu_hp_io_base = 0; 210500b11eaSIgor Mammedov pm->pcihp_io_base = 0; 211500b11eaSIgor Mammedov pm->pcihp_io_len = 0; 2126d837f1fSIgor Mammedov pm->smi_on_cpuhp = false; 213892aae74SIgor Mammedov pm->smi_on_cpu_unplug = false; 214937d1b58SIgor Mammedov 2156fa5171fSPhilippe Mathieu-Daudé assert(obj); 216a0628599SLike Xu init_common_fadt_data(machine, obj, &pm->fadt); 21772c194f7SMichael S. Tsirkin if (piix) { 2183a3fcc75SIgor Mammedov /* w2k requires FADT(rev1) or it won't boot, keep PC compatible */ 219937d1b58SIgor Mammedov pm->fadt.rev = 1; 220ddf1ec2fSIgor Mammedov pm->cpu_hp_io_base = PIIX4_CPU_HOTPLUG_IO_BASE; 221500b11eaSIgor Mammedov pm->pcihp_io_base = 22235f91e50SMarc-André Lureau object_property_get_uint(obj, ACPI_PCIHP_IO_BASE_PROP, NULL); 223500b11eaSIgor Mammedov pm->pcihp_io_len = 22435f91e50SMarc-André Lureau object_property_get_uint(obj, ACPI_PCIHP_IO_LEN_PROP, NULL); 22572c194f7SMichael S. Tsirkin } 22672c194f7SMichael S. Tsirkin if (lpc) { 2276d837f1fSIgor Mammedov uint64_t smi_features = object_property_get_uint(lpc, 2286d837f1fSIgor Mammedov ICH9_LPC_SMI_NEGOTIATED_FEAT_PROP, NULL); 229937d1b58SIgor Mammedov struct AcpiGenericAddress r = { .space_id = AML_AS_SYSTEM_IO, 230937d1b58SIgor Mammedov .bit_width = 8, .address = ICH9_RST_CNT_IOPORT }; 231937d1b58SIgor Mammedov pm->fadt.reset_reg = r; 232937d1b58SIgor Mammedov pm->fadt.reset_val = 0xf; 233937d1b58SIgor Mammedov pm->fadt.flags |= 1 << ACPI_FADT_F_RESET_REG_SUP; 234ddf1ec2fSIgor Mammedov pm->cpu_hp_io_base = ICH9_CPU_HOTPLUG_IO_BASE; 2356d837f1fSIgor Mammedov pm->smi_on_cpuhp = 2366d837f1fSIgor Mammedov !!(smi_features & BIT_ULL(ICH9_LPC_SMI_F_CPU_HOTPLUG_BIT)); 237892aae74SIgor Mammedov pm->smi_on_cpu_unplug = 238892aae74SIgor Mammedov !!(smi_features & BIT_ULL(ICH9_LPC_SMI_F_CPU_HOT_UNPLUG_BIT)); 23972c194f7SMichael S. Tsirkin } 24072c194f7SMichael S. Tsirkin 241937d1b58SIgor Mammedov /* The above need not be conditional on machine type because the reset port 242937d1b58SIgor Mammedov * happens to be the same on PIIX (pc) and ICH9 (q35). */ 2430063454aSPhilippe Mathieu-Daudé QEMU_BUILD_BUG_ON(ICH9_RST_CNT_IOPORT != PIIX_RCR_IOPORT); 244937d1b58SIgor Mammedov 24572c194f7SMichael S. Tsirkin /* Fill in optional s3/s4 related properties */ 24672c194f7SMichael S. Tsirkin o = object_property_get_qobject(obj, ACPI_PM_PROP_S3_DISABLED, NULL); 24772c194f7SMichael S. Tsirkin if (o) { 2487dc847ebSMax Reitz pm->s3_disabled = qnum_get_uint(qobject_to(QNum, o)); 24972c194f7SMichael S. Tsirkin } else { 25072c194f7SMichael S. Tsirkin pm->s3_disabled = false; 25172c194f7SMichael S. Tsirkin } 252cb3e7f08SMarc-André Lureau qobject_unref(o); 25372c194f7SMichael S. Tsirkin o = object_property_get_qobject(obj, ACPI_PM_PROP_S4_DISABLED, NULL); 25472c194f7SMichael S. Tsirkin if (o) { 2557dc847ebSMax Reitz pm->s4_disabled = qnum_get_uint(qobject_to(QNum, o)); 25672c194f7SMichael S. Tsirkin } else { 25772c194f7SMichael S. Tsirkin pm->s4_disabled = false; 25872c194f7SMichael S. Tsirkin } 259cb3e7f08SMarc-André Lureau qobject_unref(o); 26072c194f7SMichael S. Tsirkin o = object_property_get_qobject(obj, ACPI_PM_PROP_S4_VAL, NULL); 26172c194f7SMichael S. Tsirkin if (o) { 2627dc847ebSMax Reitz pm->s4_val = qnum_get_uint(qobject_to(QNum, o)); 26372c194f7SMichael S. Tsirkin } else { 26472c194f7SMichael S. Tsirkin pm->s4_val = false; 26572c194f7SMichael S. Tsirkin } 266cb3e7f08SMarc-André Lureau qobject_unref(o); 26772c194f7SMichael S. Tsirkin 268133a2da4SIgor Mammedov pm->pcihp_bridge_en = 269133a2da4SIgor Mammedov object_property_get_bool(obj, "acpi-pci-hotplug-with-bridge-support", 270133a2da4SIgor Mammedov NULL); 271df4008c9SAni Sinha pm->pcihp_root_en = 272df4008c9SAni Sinha object_property_get_bool(obj, "acpi-root-pci-hotplug", 273df4008c9SAni Sinha NULL); 27472c194f7SMichael S. Tsirkin } 27572c194f7SMichael S. Tsirkin 27672c194f7SMichael S. Tsirkin static void acpi_get_misc_info(AcpiMiscInfo *info) 27772c194f7SMichael S. Tsirkin { 27881c48dd7SPhilippe Mathieu-Daudé Object *piix = object_resolve_type_unambiguous(TYPE_PIIX4_PM); 27981c48dd7SPhilippe Mathieu-Daudé Object *lpc = object_resolve_type_unambiguous(TYPE_ICH9_LPC_DEVICE); 2803db119daSIgor Mammedov assert(!!piix != !!lpc); 2813db119daSIgor Mammedov 2823db119daSIgor Mammedov if (piix) { 2833db119daSIgor Mammedov info->is_piix4 = true; 2843db119daSIgor Mammedov } 2853db119daSIgor Mammedov if (lpc) { 2863db119daSIgor Mammedov info->is_piix4 = false; 2873db119daSIgor Mammedov } 2883db119daSIgor Mammedov 28972c194f7SMichael S. Tsirkin info->has_hpet = hpet_find(); 2903dfd5a2aSMarc-André Lureau info->tpm_version = tpm_get_version(tpm_find()); 29172c194f7SMichael S. Tsirkin info->pvpanic_port = pvpanic_port(); 2928ac6f7a6SIgor Mammedov info->applesmc_io_base = applesmc_port(); 29372c194f7SMichael S. Tsirkin } 29472c194f7SMichael S. Tsirkin 295ca6c1855SMarcel Apfelbaum /* 296ca6c1855SMarcel Apfelbaum * Because of the PXB hosts we cannot simply query TYPE_PCI_HOST_BRIDGE. 297ca6c1855SMarcel Apfelbaum * On i386 arch we only have two pci hosts, so we can look only for them. 298ca6c1855SMarcel Apfelbaum */ 299ca6c1855SMarcel Apfelbaum static Object *acpi_get_i386_pci_host(void) 300ca6c1855SMarcel Apfelbaum { 301ca6c1855SMarcel Apfelbaum PCIHostState *host; 302ca6c1855SMarcel Apfelbaum 303ca6c1855SMarcel Apfelbaum host = OBJECT_CHECK(PCIHostState, 304ca6c1855SMarcel Apfelbaum object_resolve_path("/machine/i440fx", NULL), 305ca6c1855SMarcel Apfelbaum TYPE_PCI_HOST_BRIDGE); 306ca6c1855SMarcel Apfelbaum if (!host) { 307ca6c1855SMarcel Apfelbaum host = OBJECT_CHECK(PCIHostState, 308ca6c1855SMarcel Apfelbaum object_resolve_path("/machine/q35", NULL), 309ca6c1855SMarcel Apfelbaum TYPE_PCI_HOST_BRIDGE); 310ca6c1855SMarcel Apfelbaum } 311ca6c1855SMarcel Apfelbaum 312ca6c1855SMarcel Apfelbaum return OBJECT(host); 313ca6c1855SMarcel Apfelbaum } 314ca6c1855SMarcel Apfelbaum 31501c9742dSMarkus Armbruster static void acpi_get_pci_holes(Range *hole, Range *hole64) 31672c194f7SMichael S. Tsirkin { 31772c194f7SMichael S. Tsirkin Object *pci_host; 31872c194f7SMichael S. Tsirkin 319ca6c1855SMarcel Apfelbaum pci_host = acpi_get_i386_pci_host(); 32072c194f7SMichael S. Tsirkin g_assert(pci_host); 32172c194f7SMichael S. Tsirkin 322a0efbf16SMarkus Armbruster range_set_bounds1(hole, 32360555365SMarc-André Lureau object_property_get_uint(pci_host, 32472c194f7SMichael S. Tsirkin PCI_HOST_PROP_PCI_HOLE_START, 325a0efbf16SMarkus Armbruster NULL), 32660555365SMarc-André Lureau object_property_get_uint(pci_host, 32772c194f7SMichael S. Tsirkin PCI_HOST_PROP_PCI_HOLE_END, 328a0efbf16SMarkus Armbruster NULL)); 329a0efbf16SMarkus Armbruster range_set_bounds1(hole64, 33060555365SMarc-André Lureau object_property_get_uint(pci_host, 33172c194f7SMichael S. Tsirkin PCI_HOST_PROP_PCI_HOLE64_START, 332a0efbf16SMarkus Armbruster NULL), 33360555365SMarc-André Lureau object_property_get_uint(pci_host, 33472c194f7SMichael S. Tsirkin PCI_HOST_PROP_PCI_HOLE64_END, 335a0efbf16SMarkus Armbruster NULL)); 33672c194f7SMichael S. Tsirkin } 33772c194f7SMichael S. Tsirkin 33872c194f7SMichael S. Tsirkin static void acpi_align_size(GArray *blob, unsigned align) 33972c194f7SMichael S. Tsirkin { 34072c194f7SMichael S. Tsirkin /* Align size to multiple of given size. This reduces the chance 34172c194f7SMichael S. Tsirkin * we need to change size in the future (breaking cross version migration). 34272c194f7SMichael S. Tsirkin */ 343134d42d6SMichael S. Tsirkin g_array_set_size(blob, ROUND_UP(acpi_data_len(blob), align)); 34472c194f7SMichael S. Tsirkin } 34572c194f7SMichael S. Tsirkin 34672c194f7SMichael S. Tsirkin /* FACS */ 34772c194f7SMichael S. Tsirkin static void 348009180bdSWei Yang build_facs(GArray *table_data) 34972c194f7SMichael S. Tsirkin { 35072c194f7SMichael S. Tsirkin AcpiFacsDescriptorRev1 *facs = acpi_data_push(table_data, sizeof *facs); 351821e3227SMichael S. Tsirkin memcpy(&facs->signature, "FACS", 4); 35272c194f7SMichael S. Tsirkin facs->length = cpu_to_le32(sizeof(*facs)); 35372c194f7SMichael S. Tsirkin } 35472c194f7SMichael S. Tsirkin 35562b52c26SIgor Mammedov static void build_append_pcihp_notify_entry(Aml *method, int slot) 356b23046abSIgor Mammedov { 35762b52c26SIgor Mammedov Aml *if_ctx; 35862b52c26SIgor Mammedov int32_t devfn = PCI_DEVFN(slot, 0); 359b23046abSIgor Mammedov 3605530427fSIgor Mammedov if_ctx = aml_if(aml_and(aml_arg(0), aml_int(0x1U << slot), NULL)); 36162b52c26SIgor Mammedov aml_append(if_ctx, aml_notify(aml_name("S%.02X", devfn), aml_arg(1))); 36262b52c26SIgor Mammedov aml_append(method, if_ctx); 363b23046abSIgor Mammedov } 364b23046abSIgor Mammedov 36562b52c26SIgor Mammedov static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, 366133a2da4SIgor Mammedov bool pcihp_bridge_en) 36799fd437dSMichael S. Tsirkin { 3687dc847ebSMax Reitz Aml *dev, *notify_method = NULL, *method; 36999fd437dSMichael S. Tsirkin QObject *bsel; 370b23046abSIgor Mammedov PCIBus *sec; 371b23046abSIgor Mammedov int i; 372133a2da4SIgor Mammedov 37399fd437dSMichael S. Tsirkin bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL); 37499fd437dSMichael S. Tsirkin if (bsel) { 3757dc847ebSMax Reitz uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel)); 37662b52c26SIgor Mammedov 37762b52c26SIgor Mammedov aml_append(parent_scope, aml_name_decl("BSEL", aml_int(bsel_val))); 3784dbfc881SXiao Guangrong notify_method = aml_method("DVNT", 2, AML_NOTSERIALIZED); 3798dcf525aSMichael S. Tsirkin } 38099fd437dSMichael S. Tsirkin 3818dcf525aSMichael S. Tsirkin for (i = 0; i < ARRAY_SIZE(bus->devices); i += PCI_FUNC_MAX) { 3822897ae02SIgor Mammedov DeviceClass *dc; 38399fd437dSMichael S. Tsirkin PCIDeviceClass *pc; 38499fd437dSMichael S. Tsirkin PCIDevice *pdev = bus->devices[i]; 3858dcf525aSMichael S. Tsirkin int slot = PCI_SLOT(i); 386b23046abSIgor Mammedov bool hotplug_enabled_dev; 387093a35e5SMichael S. Tsirkin bool bridge_in_acpi; 38815a5b254SAni Sinha bool cold_plugged_bridge; 38999fd437dSMichael S. Tsirkin 39099fd437dSMichael S. Tsirkin if (!pdev) { 391b23046abSIgor Mammedov if (bsel) { /* add hotplug slots for non present devices */ 39262b52c26SIgor Mammedov dev = aml_device("S%.02X", PCI_DEVFN(slot, 0)); 39362b52c26SIgor Mammedov aml_append(dev, aml_name_decl("_SUN", aml_int(slot))); 39462b52c26SIgor Mammedov aml_append(dev, aml_name_decl("_ADR", aml_int(slot << 16))); 3954dbfc881SXiao Guangrong method = aml_method("_EJ0", 1, AML_NOTSERIALIZED); 39662b52c26SIgor Mammedov aml_append(method, 39762b52c26SIgor Mammedov aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN")) 39862b52c26SIgor Mammedov ); 39962b52c26SIgor Mammedov aml_append(dev, method); 400*b7f23f62SIgor Mammedov method = aml_method("_DSM", 4, AML_SERIALIZED); 401*b7f23f62SIgor Mammedov aml_append(method, 402*b7f23f62SIgor Mammedov aml_return(aml_call6("PDSM", aml_arg(0), aml_arg(1), 403*b7f23f62SIgor Mammedov aml_arg(2), aml_arg(3), 404*b7f23f62SIgor Mammedov aml_name("BSEL"), aml_name("_SUN"))) 405*b7f23f62SIgor Mammedov ); 406*b7f23f62SIgor Mammedov aml_append(dev, method); 40762b52c26SIgor Mammedov aml_append(parent_scope, dev); 408b23046abSIgor Mammedov 40962b52c26SIgor Mammedov build_append_pcihp_notify_entry(notify_method, slot); 410b23046abSIgor Mammedov } 41199fd437dSMichael S. Tsirkin continue; 41299fd437dSMichael S. Tsirkin } 41399fd437dSMichael S. Tsirkin 41499fd437dSMichael S. Tsirkin pc = PCI_DEVICE_GET_CLASS(pdev); 4152897ae02SIgor Mammedov dc = DEVICE_GET_CLASS(pdev); 41699fd437dSMichael S. Tsirkin 41715a5b254SAni Sinha /* 41815a5b254SAni Sinha * Cold plugged bridges aren't themselves hot-pluggable. 419a20275faSMichael S. Tsirkin * Hotplugged bridges *are* hot-pluggable. 420093a35e5SMichael S. Tsirkin */ 42115a5b254SAni Sinha cold_plugged_bridge = pc->is_bridge && !DEVICE(pdev)->hotplugged; 42215a5b254SAni Sinha bridge_in_acpi = cold_plugged_bridge && pcihp_bridge_en; 423093a35e5SMichael S. Tsirkin 42415a5b254SAni Sinha hotplug_enabled_dev = bsel && dc->hotpluggable && !cold_plugged_bridge; 425b23046abSIgor Mammedov 426b23046abSIgor Mammedov if (pc->class_id == PCI_CLASS_BRIDGE_ISA) { 427b23046abSIgor Mammedov continue; 4288dcf525aSMichael S. Tsirkin } 42999fd437dSMichael S. Tsirkin 43062b52c26SIgor Mammedov /* start to compose PCI slot descriptor */ 43162b52c26SIgor Mammedov dev = aml_device("S%.02X", PCI_DEVFN(slot, 0)); 43262b52c26SIgor Mammedov aml_append(dev, aml_name_decl("_ADR", aml_int(slot << 16))); 43362b52c26SIgor Mammedov 434*b7f23f62SIgor Mammedov if (bsel) { 435*b7f23f62SIgor Mammedov aml_append(dev, aml_name_decl("_SUN", aml_int(slot))); 436*b7f23f62SIgor Mammedov method = aml_method("_DSM", 4, AML_SERIALIZED); 437*b7f23f62SIgor Mammedov aml_append(method, aml_return( 438*b7f23f62SIgor Mammedov aml_call6("PDSM", aml_arg(0), aml_arg(1), aml_arg(2), 439*b7f23f62SIgor Mammedov aml_arg(3), aml_name("BSEL"), aml_name("_SUN")) 440*b7f23f62SIgor Mammedov )); 441*b7f23f62SIgor Mammedov aml_append(dev, method); 442*b7f23f62SIgor Mammedov } 443*b7f23f62SIgor Mammedov 4448dcf525aSMichael S. Tsirkin if (pc->class_id == PCI_CLASS_DISPLAY_VGA) { 44562b52c26SIgor Mammedov /* add VGA specific AML methods */ 44662b52c26SIgor Mammedov int s3d; 44762b52c26SIgor Mammedov 4488dcf525aSMichael S. Tsirkin if (object_dynamic_cast(OBJECT(pdev), "qxl-vga")) { 44962b52c26SIgor Mammedov s3d = 3; 450b23046abSIgor Mammedov } else { 45162b52c26SIgor Mammedov s3d = 0; 452b23046abSIgor Mammedov } 45362b52c26SIgor Mammedov 4544dbfc881SXiao Guangrong method = aml_method("_S1D", 0, AML_NOTSERIALIZED); 45562b52c26SIgor Mammedov aml_append(method, aml_return(aml_int(0))); 45662b52c26SIgor Mammedov aml_append(dev, method); 45762b52c26SIgor Mammedov 4584dbfc881SXiao Guangrong method = aml_method("_S2D", 0, AML_NOTSERIALIZED); 45962b52c26SIgor Mammedov aml_append(method, aml_return(aml_int(0))); 46062b52c26SIgor Mammedov aml_append(dev, method); 46162b52c26SIgor Mammedov 4624dbfc881SXiao Guangrong method = aml_method("_S3D", 0, AML_NOTSERIALIZED); 46362b52c26SIgor Mammedov aml_append(method, aml_return(aml_int(s3d))); 46462b52c26SIgor Mammedov aml_append(dev, method); 465b23046abSIgor Mammedov } else if (hotplug_enabled_dev) { 466*b7f23f62SIgor Mammedov /* add _EJ0 to make slot hotpluggable */ 4674dbfc881SXiao Guangrong method = aml_method("_EJ0", 1, AML_NOTSERIALIZED); 46862b52c26SIgor Mammedov aml_append(method, 46962b52c26SIgor Mammedov aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN")) 47062b52c26SIgor Mammedov ); 47162b52c26SIgor Mammedov aml_append(dev, method); 472b23046abSIgor Mammedov 47362b52c26SIgor Mammedov if (bsel) { 47462b52c26SIgor Mammedov build_append_pcihp_notify_entry(notify_method, slot); 47599fd437dSMichael S. Tsirkin } 47662b52c26SIgor Mammedov } else if (bridge_in_acpi) { 47762b52c26SIgor Mammedov /* 47862b52c26SIgor Mammedov * device is coldplugged bridge, 47962b52c26SIgor Mammedov * add child device descriptions into its scope 48062b52c26SIgor Mammedov */ 48162b52c26SIgor Mammedov PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(pdev)); 48262b52c26SIgor Mammedov 48362b52c26SIgor Mammedov build_append_pci_bus_devices(dev, sec_bus, pcihp_bridge_en); 48462b52c26SIgor Mammedov } 48562b52c26SIgor Mammedov /* slot descriptor has been composed, add it into parent context */ 48662b52c26SIgor Mammedov aml_append(parent_scope, dev); 48799fd437dSMichael S. Tsirkin } 48899fd437dSMichael S. Tsirkin 4898dcf525aSMichael S. Tsirkin if (bsel) { 49062b52c26SIgor Mammedov aml_append(parent_scope, notify_method); 49199fd437dSMichael S. Tsirkin } 49299fd437dSMichael S. Tsirkin 49399fd437dSMichael S. Tsirkin /* Append PCNT method to notify about events on local and child buses. 494df4008c9SAni Sinha * Add this method for root bus only when hotplug is enabled since DSDT 495df4008c9SAni Sinha * expects it. 49699fd437dSMichael S. Tsirkin */ 497df4008c9SAni Sinha if (bsel || pcihp_bridge_en) { 4984dbfc881SXiao Guangrong method = aml_method("PCNT", 0, AML_NOTSERIALIZED); 499811c74fbSPhilippe Mathieu-Daudé 50099fd437dSMichael S. Tsirkin /* If bus supports hotplug select it and notify about local events */ 50199fd437dSMichael S. Tsirkin if (bsel) { 5027dc847ebSMax Reitz uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel)); 50301b2ffceSMarc-André Lureau 50462b52c26SIgor Mammedov aml_append(method, aml_store(aml_int(bsel_val), aml_name("BNUM"))); 505811c74fbSPhilippe Mathieu-Daudé aml_append(method, aml_call2("DVNT", aml_name("PCIU"), 506811c74fbSPhilippe Mathieu-Daudé aml_int(1))); /* Device Check */ 507811c74fbSPhilippe Mathieu-Daudé aml_append(method, aml_call2("DVNT", aml_name("PCID"), 508811c74fbSPhilippe Mathieu-Daudé aml_int(3))); /* Eject Request */ 50999fd437dSMichael S. Tsirkin } 51099fd437dSMichael S. Tsirkin 51199fd437dSMichael S. Tsirkin /* Notify about child bus events in any case */ 512b23046abSIgor Mammedov if (pcihp_bridge_en) { 513b23046abSIgor Mammedov QLIST_FOREACH(sec, &bus->child, sibling) { 51462b52c26SIgor Mammedov int32_t devfn = sec->parent_dev->devfn; 51562b52c26SIgor Mammedov 516c99cb18eSMarcel Apfelbaum if (pci_bus_is_root(sec) || pci_bus_is_express(sec)) { 517c99cb18eSMarcel Apfelbaum continue; 518c99cb18eSMarcel Apfelbaum } 519c99cb18eSMarcel Apfelbaum 52062b52c26SIgor Mammedov aml_append(method, aml_name("^S%.02X.PCNT", devfn)); 521b23046abSIgor Mammedov } 522b23046abSIgor Mammedov } 523df4008c9SAni Sinha 52462b52c26SIgor Mammedov aml_append(parent_scope, method); 525df4008c9SAni Sinha } 526cb3e7f08SMarc-André Lureau qobject_unref(bsel); 52772c194f7SMichael S. Tsirkin } 52872c194f7SMichael S. Tsirkin 529*b7f23f62SIgor Mammedov Aml *aml_pci_device_dsm(void) 530*b7f23f62SIgor Mammedov { 531*b7f23f62SIgor Mammedov Aml *method, *UUID, *ifctx, *ifctx1, *ifctx2, *ifctx3, *elsectx; 532*b7f23f62SIgor Mammedov Aml *acpi_index = aml_local(0); 533*b7f23f62SIgor Mammedov Aml *zero = aml_int(0); 534*b7f23f62SIgor Mammedov Aml *bnum = aml_arg(4); 535*b7f23f62SIgor Mammedov Aml *func = aml_arg(2); 536*b7f23f62SIgor Mammedov Aml *rev = aml_arg(1); 537*b7f23f62SIgor Mammedov Aml *sun = aml_arg(5); 538*b7f23f62SIgor Mammedov 539*b7f23f62SIgor Mammedov method = aml_method("PDSM", 6, AML_SERIALIZED); 540*b7f23f62SIgor Mammedov 541*b7f23f62SIgor Mammedov /* 542*b7f23f62SIgor Mammedov * PCI Firmware Specification 3.1 543*b7f23f62SIgor Mammedov * 4.6. _DSM Definitions for PCI 544*b7f23f62SIgor Mammedov */ 545*b7f23f62SIgor Mammedov UUID = aml_touuid("E5C937D0-3553-4D7A-9117-EA4D19C3434D"); 546*b7f23f62SIgor Mammedov ifctx = aml_if(aml_equal(aml_arg(0), UUID)); 547*b7f23f62SIgor Mammedov { 548*b7f23f62SIgor Mammedov aml_append(ifctx, aml_store(aml_call2("AIDX", bnum, sun), acpi_index)); 549*b7f23f62SIgor Mammedov ifctx1 = aml_if(aml_equal(func, zero)); 550*b7f23f62SIgor Mammedov { 551*b7f23f62SIgor Mammedov uint8_t byte_list[1]; 552*b7f23f62SIgor Mammedov 553*b7f23f62SIgor Mammedov ifctx2 = aml_if(aml_equal(rev, aml_int(2))); 554*b7f23f62SIgor Mammedov { 555*b7f23f62SIgor Mammedov /* 556*b7f23f62SIgor Mammedov * advertise function 7 if device has acpi-index 557*b7f23f62SIgor Mammedov * acpi_index values: 558*b7f23f62SIgor Mammedov * 0: not present (default value) 559*b7f23f62SIgor Mammedov * FFFFFFFF: not supported (old QEMU without PIDX reg) 560*b7f23f62SIgor Mammedov * other: device's acpi-index 561*b7f23f62SIgor Mammedov */ 562*b7f23f62SIgor Mammedov ifctx3 = aml_if(aml_lnot( 563*b7f23f62SIgor Mammedov aml_or(aml_equal(acpi_index, zero), 564*b7f23f62SIgor Mammedov aml_equal(acpi_index, aml_int(0xFFFFFFFF)), NULL) 565*b7f23f62SIgor Mammedov )); 566*b7f23f62SIgor Mammedov { 567*b7f23f62SIgor Mammedov byte_list[0] = 568*b7f23f62SIgor Mammedov 1 /* have supported functions */ | 569*b7f23f62SIgor Mammedov 1 << 7 /* support for function 7 */ 570*b7f23f62SIgor Mammedov ; 571*b7f23f62SIgor Mammedov aml_append(ifctx3, aml_return(aml_buffer(1, byte_list))); 572*b7f23f62SIgor Mammedov } 573*b7f23f62SIgor Mammedov aml_append(ifctx2, ifctx3); 574*b7f23f62SIgor Mammedov } 575*b7f23f62SIgor Mammedov aml_append(ifctx1, ifctx2); 576*b7f23f62SIgor Mammedov 577*b7f23f62SIgor Mammedov byte_list[0] = 0; /* nothing supported */ 578*b7f23f62SIgor Mammedov aml_append(ifctx1, aml_return(aml_buffer(1, byte_list))); 579*b7f23f62SIgor Mammedov } 580*b7f23f62SIgor Mammedov aml_append(ifctx, ifctx1); 581*b7f23f62SIgor Mammedov elsectx = aml_else(); 582*b7f23f62SIgor Mammedov /* 583*b7f23f62SIgor Mammedov * PCI Firmware Specification 3.1 584*b7f23f62SIgor Mammedov * 4.6.7. _DSM for Naming a PCI or PCI Express Device Under 585*b7f23f62SIgor Mammedov * Operating Systems 586*b7f23f62SIgor Mammedov */ 587*b7f23f62SIgor Mammedov ifctx1 = aml_if(aml_equal(func, aml_int(7))); 588*b7f23f62SIgor Mammedov { 589*b7f23f62SIgor Mammedov Aml *pkg = aml_package(2); 590*b7f23f62SIgor Mammedov Aml *ret = aml_local(1); 591*b7f23f62SIgor Mammedov 592*b7f23f62SIgor Mammedov aml_append(pkg, zero); 593*b7f23f62SIgor Mammedov /* 594*b7f23f62SIgor Mammedov * optional, if not impl. should return null string 595*b7f23f62SIgor Mammedov */ 596*b7f23f62SIgor Mammedov aml_append(pkg, aml_string("%s", "")); 597*b7f23f62SIgor Mammedov aml_append(ifctx1, aml_store(pkg, ret)); 598*b7f23f62SIgor Mammedov /* 599*b7f23f62SIgor Mammedov * update acpi-index to actual value 600*b7f23f62SIgor Mammedov */ 601*b7f23f62SIgor Mammedov aml_append(ifctx1, aml_store(acpi_index, aml_index(ret, zero))); 602*b7f23f62SIgor Mammedov aml_append(ifctx1, aml_return(ret)); 603*b7f23f62SIgor Mammedov } 604*b7f23f62SIgor Mammedov aml_append(elsectx, ifctx1); 605*b7f23f62SIgor Mammedov aml_append(ifctx, elsectx); 606*b7f23f62SIgor Mammedov } 607*b7f23f62SIgor Mammedov aml_append(method, ifctx); 608*b7f23f62SIgor Mammedov return method; 609*b7f23f62SIgor Mammedov } 610*b7f23f62SIgor Mammedov 611196e2137SIgor Mammedov /** 612196e2137SIgor Mammedov * build_prt_entry: 613196e2137SIgor Mammedov * @link_name: link name for PCI route entry 614196e2137SIgor Mammedov * 615196e2137SIgor Mammedov * build AML package containing a PCI route entry for @link_name 616196e2137SIgor Mammedov */ 617196e2137SIgor Mammedov static Aml *build_prt_entry(const char *link_name) 618196e2137SIgor Mammedov { 619196e2137SIgor Mammedov Aml *a_zero = aml_int(0); 620196e2137SIgor Mammedov Aml *pkg = aml_package(4); 621196e2137SIgor Mammedov aml_append(pkg, a_zero); 622196e2137SIgor Mammedov aml_append(pkg, a_zero); 623196e2137SIgor Mammedov aml_append(pkg, aml_name("%s", link_name)); 624196e2137SIgor Mammedov aml_append(pkg, a_zero); 625196e2137SIgor Mammedov return pkg; 626196e2137SIgor Mammedov } 627196e2137SIgor Mammedov 6280d8935e3SMarcel Apfelbaum /* 6290d8935e3SMarcel Apfelbaum * initialize_route - Initialize the interrupt routing rule 6300d8935e3SMarcel Apfelbaum * through a specific LINK: 6310d8935e3SMarcel Apfelbaum * if (lnk_idx == idx) 6320d8935e3SMarcel Apfelbaum * route using link 'link_name' 6330d8935e3SMarcel Apfelbaum */ 6340d8935e3SMarcel Apfelbaum static Aml *initialize_route(Aml *route, const char *link_name, 6350d8935e3SMarcel Apfelbaum Aml *lnk_idx, int idx) 6360d8935e3SMarcel Apfelbaum { 6370d8935e3SMarcel Apfelbaum Aml *if_ctx = aml_if(aml_equal(lnk_idx, aml_int(idx))); 638196e2137SIgor Mammedov Aml *pkg = build_prt_entry(link_name); 6390d8935e3SMarcel Apfelbaum 6400d8935e3SMarcel Apfelbaum aml_append(if_ctx, aml_store(pkg, route)); 6410d8935e3SMarcel Apfelbaum 6420d8935e3SMarcel Apfelbaum return if_ctx; 6430d8935e3SMarcel Apfelbaum } 6440d8935e3SMarcel Apfelbaum 6450d8935e3SMarcel Apfelbaum /* 6460d8935e3SMarcel Apfelbaum * build_prt - Define interrupt rounting rules 6470d8935e3SMarcel Apfelbaum * 6480d8935e3SMarcel Apfelbaum * Returns an array of 128 routes, one for each device, 6490d8935e3SMarcel Apfelbaum * based on device location. 6500d8935e3SMarcel Apfelbaum * The main goal is to equaly distribute the interrupts 6510d8935e3SMarcel Apfelbaum * over the 4 existing ACPI links (works only for i440fx). 6520d8935e3SMarcel Apfelbaum * The hash function is (slot + pin) & 3 -> "LNK[D|A|B|C]". 6530d8935e3SMarcel Apfelbaum * 6540d8935e3SMarcel Apfelbaum */ 655196e2137SIgor Mammedov static Aml *build_prt(bool is_pci0_prt) 6560d8935e3SMarcel Apfelbaum { 6570d8935e3SMarcel Apfelbaum Aml *method, *while_ctx, *pin, *res; 6580d8935e3SMarcel Apfelbaum 6594dbfc881SXiao Guangrong method = aml_method("_PRT", 0, AML_NOTSERIALIZED); 6600d8935e3SMarcel Apfelbaum res = aml_local(0); 6610d8935e3SMarcel Apfelbaum pin = aml_local(1); 6620d8935e3SMarcel Apfelbaum aml_append(method, aml_store(aml_package(128), res)); 6630d8935e3SMarcel Apfelbaum aml_append(method, aml_store(aml_int(0), pin)); 6640d8935e3SMarcel Apfelbaum 6650d8935e3SMarcel Apfelbaum /* while (pin < 128) */ 6660d8935e3SMarcel Apfelbaum while_ctx = aml_while(aml_lless(pin, aml_int(128))); 6670d8935e3SMarcel Apfelbaum { 6680d8935e3SMarcel Apfelbaum Aml *slot = aml_local(2); 6690d8935e3SMarcel Apfelbaum Aml *lnk_idx = aml_local(3); 6700d8935e3SMarcel Apfelbaum Aml *route = aml_local(4); 6710d8935e3SMarcel Apfelbaum 6720d8935e3SMarcel Apfelbaum /* slot = pin >> 2 */ 6730d8935e3SMarcel Apfelbaum aml_append(while_ctx, 674c360639aSIgor Mammedov aml_store(aml_shiftright(pin, aml_int(2), NULL), slot)); 6750d8935e3SMarcel Apfelbaum /* lnk_idx = (slot + pin) & 3 */ 6760d8935e3SMarcel Apfelbaum aml_append(while_ctx, 6775530427fSIgor Mammedov aml_store(aml_and(aml_add(pin, slot, NULL), aml_int(3), NULL), 6785530427fSIgor Mammedov lnk_idx)); 6790d8935e3SMarcel Apfelbaum 6800d8935e3SMarcel Apfelbaum /* route[2] = "LNK[D|A|B|C]", selection based on pin % 3 */ 6810d8935e3SMarcel Apfelbaum aml_append(while_ctx, initialize_route(route, "LNKD", lnk_idx, 0)); 682196e2137SIgor Mammedov if (is_pci0_prt) { 683196e2137SIgor Mammedov Aml *if_device_1, *if_pin_4, *else_pin_4; 684196e2137SIgor Mammedov 685196e2137SIgor Mammedov /* device 1 is the power-management device, needs SCI */ 686196e2137SIgor Mammedov if_device_1 = aml_if(aml_equal(lnk_idx, aml_int(1))); 687196e2137SIgor Mammedov { 688196e2137SIgor Mammedov if_pin_4 = aml_if(aml_equal(pin, aml_int(4))); 689196e2137SIgor Mammedov { 690196e2137SIgor Mammedov aml_append(if_pin_4, 691196e2137SIgor Mammedov aml_store(build_prt_entry("LNKS"), route)); 692196e2137SIgor Mammedov } 693196e2137SIgor Mammedov aml_append(if_device_1, if_pin_4); 694196e2137SIgor Mammedov else_pin_4 = aml_else(); 695196e2137SIgor Mammedov { 696196e2137SIgor Mammedov aml_append(else_pin_4, 697196e2137SIgor Mammedov aml_store(build_prt_entry("LNKA"), route)); 698196e2137SIgor Mammedov } 699196e2137SIgor Mammedov aml_append(if_device_1, else_pin_4); 700196e2137SIgor Mammedov } 701196e2137SIgor Mammedov aml_append(while_ctx, if_device_1); 702196e2137SIgor Mammedov } else { 7030d8935e3SMarcel Apfelbaum aml_append(while_ctx, initialize_route(route, "LNKA", lnk_idx, 1)); 704196e2137SIgor Mammedov } 7050d8935e3SMarcel Apfelbaum aml_append(while_ctx, initialize_route(route, "LNKB", lnk_idx, 2)); 7060d8935e3SMarcel Apfelbaum aml_append(while_ctx, initialize_route(route, "LNKC", lnk_idx, 3)); 7070d8935e3SMarcel Apfelbaum 7080d8935e3SMarcel Apfelbaum /* route[0] = 0x[slot]FFFF */ 7090d8935e3SMarcel Apfelbaum aml_append(while_ctx, 710ca3df95dSIgor Mammedov aml_store(aml_or(aml_shiftleft(slot, aml_int(16)), aml_int(0xFFFF), 711ca3df95dSIgor Mammedov NULL), 7120d8935e3SMarcel Apfelbaum aml_index(route, aml_int(0)))); 7130d8935e3SMarcel Apfelbaum /* route[1] = pin & 3 */ 7140d8935e3SMarcel Apfelbaum aml_append(while_ctx, 7155530427fSIgor Mammedov aml_store(aml_and(pin, aml_int(3), NULL), 7165530427fSIgor Mammedov aml_index(route, aml_int(1)))); 7170d8935e3SMarcel Apfelbaum /* res[pin] = route */ 7180d8935e3SMarcel Apfelbaum aml_append(while_ctx, aml_store(route, aml_index(res, pin))); 7190d8935e3SMarcel Apfelbaum /* pin++ */ 7200d8935e3SMarcel Apfelbaum aml_append(while_ctx, aml_increment(pin)); 7210d8935e3SMarcel Apfelbaum } 7220d8935e3SMarcel Apfelbaum aml_append(method, while_ctx); 7230d8935e3SMarcel Apfelbaum /* return res*/ 7240d8935e3SMarcel Apfelbaum aml_append(method, aml_return(res)); 7250d8935e3SMarcel Apfelbaum 7260d8935e3SMarcel Apfelbaum return method; 7270d8935e3SMarcel Apfelbaum } 7280d8935e3SMarcel Apfelbaum 729a57d708dSIgor Mammedov static void build_hpet_aml(Aml *table) 730a57d708dSIgor Mammedov { 731a57d708dSIgor Mammedov Aml *crs; 732a57d708dSIgor Mammedov Aml *field; 733a57d708dSIgor Mammedov Aml *method; 734a57d708dSIgor Mammedov Aml *if_ctx; 735a57d708dSIgor Mammedov Aml *scope = aml_scope("_SB"); 736a57d708dSIgor Mammedov Aml *dev = aml_device("HPET"); 737a57d708dSIgor Mammedov Aml *zero = aml_int(0); 738a57d708dSIgor Mammedov Aml *id = aml_local(0); 739a57d708dSIgor Mammedov Aml *period = aml_local(1); 740a57d708dSIgor Mammedov 741a57d708dSIgor Mammedov aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0103"))); 742a57d708dSIgor Mammedov aml_append(dev, aml_name_decl("_UID", zero)); 743a57d708dSIgor Mammedov 744a57d708dSIgor Mammedov aml_append(dev, 7453f3009c0SXiao Guangrong aml_operation_region("HPTM", AML_SYSTEM_MEMORY, aml_int(HPET_BASE), 7463f3009c0SXiao Guangrong HPET_LEN)); 747a57d708dSIgor Mammedov field = aml_field("HPTM", AML_DWORD_ACC, AML_LOCK, AML_PRESERVE); 748a57d708dSIgor Mammedov aml_append(field, aml_named_field("VEND", 32)); 749a57d708dSIgor Mammedov aml_append(field, aml_named_field("PRD", 32)); 750a57d708dSIgor Mammedov aml_append(dev, field); 751a57d708dSIgor Mammedov 752a57d708dSIgor Mammedov method = aml_method("_STA", 0, AML_NOTSERIALIZED); 753a57d708dSIgor Mammedov aml_append(method, aml_store(aml_name("VEND"), id)); 754a57d708dSIgor Mammedov aml_append(method, aml_store(aml_name("PRD"), period)); 755a57d708dSIgor Mammedov aml_append(method, aml_shiftright(id, aml_int(16), id)); 756a57d708dSIgor Mammedov if_ctx = aml_if(aml_lor(aml_equal(id, zero), 757a57d708dSIgor Mammedov aml_equal(id, aml_int(0xffff)))); 758a57d708dSIgor Mammedov { 759a57d708dSIgor Mammedov aml_append(if_ctx, aml_return(zero)); 760a57d708dSIgor Mammedov } 761a57d708dSIgor Mammedov aml_append(method, if_ctx); 762a57d708dSIgor Mammedov 763a57d708dSIgor Mammedov if_ctx = aml_if(aml_lor(aml_equal(period, zero), 764a57d708dSIgor Mammedov aml_lgreater(period, aml_int(100000000)))); 765a57d708dSIgor Mammedov { 766a57d708dSIgor Mammedov aml_append(if_ctx, aml_return(zero)); 767a57d708dSIgor Mammedov } 768a57d708dSIgor Mammedov aml_append(method, if_ctx); 769a57d708dSIgor Mammedov 770a57d708dSIgor Mammedov aml_append(method, aml_return(aml_int(0x0F))); 771a57d708dSIgor Mammedov aml_append(dev, method); 772a57d708dSIgor Mammedov 773a57d708dSIgor Mammedov crs = aml_resource_template(); 774a57d708dSIgor Mammedov aml_append(crs, aml_memory32_fixed(HPET_BASE, HPET_LEN, AML_READ_ONLY)); 775a57d708dSIgor Mammedov aml_append(dev, aml_name_decl("_CRS", crs)); 776a57d708dSIgor Mammedov 777a57d708dSIgor Mammedov aml_append(scope, dev); 778a57d708dSIgor Mammedov aml_append(table, scope); 779a57d708dSIgor Mammedov } 780a57d708dSIgor Mammedov 7816775d15dSJon Doron static Aml *build_vmbus_device_aml(VMBusBridge *vmbus_bridge) 7826775d15dSJon Doron { 7836775d15dSJon Doron Aml *dev; 7846775d15dSJon Doron Aml *method; 7856775d15dSJon Doron Aml *crs; 7866775d15dSJon Doron 7876775d15dSJon Doron dev = aml_device("VMBS"); 7886775d15dSJon Doron aml_append(dev, aml_name_decl("STA", aml_int(0xF))); 7896775d15dSJon Doron aml_append(dev, aml_name_decl("_HID", aml_string("VMBus"))); 7906775d15dSJon Doron aml_append(dev, aml_name_decl("_UID", aml_int(0x0))); 7916775d15dSJon Doron aml_append(dev, aml_name_decl("_DDN", aml_string("VMBUS"))); 7926775d15dSJon Doron 7936775d15dSJon Doron method = aml_method("_DIS", 0, AML_NOTSERIALIZED); 7946775d15dSJon Doron aml_append(method, aml_store(aml_and(aml_name("STA"), aml_int(0xD), NULL), 7956775d15dSJon Doron aml_name("STA"))); 7966775d15dSJon Doron aml_append(dev, method); 7976775d15dSJon Doron 7986775d15dSJon Doron method = aml_method("_PS0", 0, AML_NOTSERIALIZED); 7996775d15dSJon Doron aml_append(method, aml_store(aml_or(aml_name("STA"), aml_int(0xF), NULL), 8006775d15dSJon Doron aml_name("STA"))); 8016775d15dSJon Doron aml_append(dev, method); 8026775d15dSJon Doron 8036775d15dSJon Doron method = aml_method("_STA", 0, AML_NOTSERIALIZED); 8046775d15dSJon Doron aml_append(method, aml_return(aml_name("STA"))); 8056775d15dSJon Doron aml_append(dev, method); 8066775d15dSJon Doron 8076775d15dSJon Doron aml_append(dev, aml_name_decl("_PS3", aml_int(0x0))); 8086775d15dSJon Doron 8096775d15dSJon Doron crs = aml_resource_template(); 8108f06f22fSJon Doron aml_append(crs, aml_irq_no_flags(vmbus_bridge->irq)); 8116775d15dSJon Doron aml_append(dev, aml_name_decl("_CRS", crs)); 8126775d15dSJon Doron 8136775d15dSJon Doron return dev; 8146775d15dSJon Doron } 8156775d15dSJon Doron 816ee135849SIgor Mammedov static void build_isa_devices_aml(Aml *table) 817ee135849SIgor Mammedov { 81886e91dd7SCorey Minyard bool ambiguous; 81986e91dd7SCorey Minyard Object *obj = object_resolve_path_type("", TYPE_ISA_BUS, &ambiguous); 82013371f9bSGerd Hoffmann Aml *scope; 821ee135849SIgor Mammedov 82213371f9bSGerd Hoffmann assert(obj && !ambiguous); 82313371f9bSGerd Hoffmann 82413371f9bSGerd Hoffmann scope = aml_scope("_SB.PCI0.ISA"); 825576d05b6SCorey Minyard build_acpi_ipmi_devices(scope, BUS(obj), "\\_SB.PCI0.ISA"); 826a53e581eSGerd Hoffmann isa_build_aml(ISA_BUS(obj), scope); 82786e91dd7SCorey Minyard 828ee135849SIgor Mammedov aml_append(table, scope); 829ee135849SIgor Mammedov } 830ee135849SIgor Mammedov 8313892a2b7SIgor Mammedov static void build_dbg_aml(Aml *table) 8323892a2b7SIgor Mammedov { 8333892a2b7SIgor Mammedov Aml *field; 8343892a2b7SIgor Mammedov Aml *method; 8353892a2b7SIgor Mammedov Aml *while_ctx; 8363892a2b7SIgor Mammedov Aml *scope = aml_scope("\\"); 8373892a2b7SIgor Mammedov Aml *buf = aml_local(0); 8383892a2b7SIgor Mammedov Aml *len = aml_local(1); 8393892a2b7SIgor Mammedov Aml *idx = aml_local(2); 8403892a2b7SIgor Mammedov 8413892a2b7SIgor Mammedov aml_append(scope, 8423f3009c0SXiao Guangrong aml_operation_region("DBG", AML_SYSTEM_IO, aml_int(0x0402), 0x01)); 8433892a2b7SIgor Mammedov field = aml_field("DBG", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE); 8443892a2b7SIgor Mammedov aml_append(field, aml_named_field("DBGB", 8)); 8453892a2b7SIgor Mammedov aml_append(scope, field); 8463892a2b7SIgor Mammedov 8473892a2b7SIgor Mammedov method = aml_method("DBUG", 1, AML_NOTSERIALIZED); 8483892a2b7SIgor Mammedov 8493892a2b7SIgor Mammedov aml_append(method, aml_to_hexstring(aml_arg(0), buf)); 8503892a2b7SIgor Mammedov aml_append(method, aml_to_buffer(buf, buf)); 8513892a2b7SIgor Mammedov aml_append(method, aml_subtract(aml_sizeof(buf), aml_int(1), len)); 8523892a2b7SIgor Mammedov aml_append(method, aml_store(aml_int(0), idx)); 8533892a2b7SIgor Mammedov 8543892a2b7SIgor Mammedov while_ctx = aml_while(aml_lless(idx, len)); 8553892a2b7SIgor Mammedov aml_append(while_ctx, 8563892a2b7SIgor Mammedov aml_store(aml_derefof(aml_index(buf, idx)), aml_name("DBGB"))); 8573892a2b7SIgor Mammedov aml_append(while_ctx, aml_increment(idx)); 8583892a2b7SIgor Mammedov aml_append(method, while_ctx); 8593892a2b7SIgor Mammedov 8603892a2b7SIgor Mammedov aml_append(method, aml_store(aml_int(0x0A), aml_name("DBGB"))); 8613892a2b7SIgor Mammedov aml_append(scope, method); 8623892a2b7SIgor Mammedov 8633892a2b7SIgor Mammedov aml_append(table, scope); 8643892a2b7SIgor Mammedov } 8653892a2b7SIgor Mammedov 866c35b6e80SIgor Mammedov static Aml *build_link_dev(const char *name, uint8_t uid, Aml *reg) 867c35b6e80SIgor Mammedov { 868c35b6e80SIgor Mammedov Aml *dev; 869c35b6e80SIgor Mammedov Aml *crs; 870c35b6e80SIgor Mammedov Aml *method; 871c35b6e80SIgor Mammedov uint32_t irqs[] = {5, 10, 11}; 872c35b6e80SIgor Mammedov 873c35b6e80SIgor Mammedov dev = aml_device("%s", name); 874c35b6e80SIgor Mammedov aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C0F"))); 875c35b6e80SIgor Mammedov aml_append(dev, aml_name_decl("_UID", aml_int(uid))); 876c35b6e80SIgor Mammedov 877c35b6e80SIgor Mammedov crs = aml_resource_template(); 878c35b6e80SIgor Mammedov aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, 879c35b6e80SIgor Mammedov AML_SHARED, irqs, ARRAY_SIZE(irqs))); 880c35b6e80SIgor Mammedov aml_append(dev, aml_name_decl("_PRS", crs)); 881c35b6e80SIgor Mammedov 882c35b6e80SIgor Mammedov method = aml_method("_STA", 0, AML_NOTSERIALIZED); 883c35b6e80SIgor Mammedov aml_append(method, aml_return(aml_call1("IQST", reg))); 884c35b6e80SIgor Mammedov aml_append(dev, method); 885c35b6e80SIgor Mammedov 886c35b6e80SIgor Mammedov method = aml_method("_DIS", 0, AML_NOTSERIALIZED); 887c35b6e80SIgor Mammedov aml_append(method, aml_or(reg, aml_int(0x80), reg)); 888c35b6e80SIgor Mammedov aml_append(dev, method); 889c35b6e80SIgor Mammedov 890c35b6e80SIgor Mammedov method = aml_method("_CRS", 0, AML_NOTSERIALIZED); 891c35b6e80SIgor Mammedov aml_append(method, aml_return(aml_call1("IQCR", reg))); 892c35b6e80SIgor Mammedov aml_append(dev, method); 893c35b6e80SIgor Mammedov 894c35b6e80SIgor Mammedov method = aml_method("_SRS", 1, AML_NOTSERIALIZED); 895c35b6e80SIgor Mammedov aml_append(method, aml_create_dword_field(aml_arg(0), aml_int(5), "PRRI")); 896c35b6e80SIgor Mammedov aml_append(method, aml_store(aml_name("PRRI"), reg)); 897c35b6e80SIgor Mammedov aml_append(dev, method); 898c35b6e80SIgor Mammedov 899c35b6e80SIgor Mammedov return dev; 900c35b6e80SIgor Mammedov } 901c35b6e80SIgor Mammedov 90280b32df5SIgor Mammedov static Aml *build_gsi_link_dev(const char *name, uint8_t uid, uint8_t gsi) 90380b32df5SIgor Mammedov { 90480b32df5SIgor Mammedov Aml *dev; 90580b32df5SIgor Mammedov Aml *crs; 90680b32df5SIgor Mammedov Aml *method; 90780b32df5SIgor Mammedov uint32_t irqs; 90880b32df5SIgor Mammedov 90980b32df5SIgor Mammedov dev = aml_device("%s", name); 91080b32df5SIgor Mammedov aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C0F"))); 91180b32df5SIgor Mammedov aml_append(dev, aml_name_decl("_UID", aml_int(uid))); 91280b32df5SIgor Mammedov 91380b32df5SIgor Mammedov crs = aml_resource_template(); 91480b32df5SIgor Mammedov irqs = gsi; 91580b32df5SIgor Mammedov aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, 91680b32df5SIgor Mammedov AML_SHARED, &irqs, 1)); 91780b32df5SIgor Mammedov aml_append(dev, aml_name_decl("_PRS", crs)); 91880b32df5SIgor Mammedov 91980b32df5SIgor Mammedov aml_append(dev, aml_name_decl("_CRS", crs)); 92080b32df5SIgor Mammedov 921c82f503dSMarcel Apfelbaum /* 922c82f503dSMarcel Apfelbaum * _DIS can be no-op because the interrupt cannot be disabled. 923c82f503dSMarcel Apfelbaum */ 924c82f503dSMarcel Apfelbaum method = aml_method("_DIS", 0, AML_NOTSERIALIZED); 925c82f503dSMarcel Apfelbaum aml_append(dev, method); 926c82f503dSMarcel Apfelbaum 92780b32df5SIgor Mammedov method = aml_method("_SRS", 1, AML_NOTSERIALIZED); 92880b32df5SIgor Mammedov aml_append(dev, method); 92980b32df5SIgor Mammedov 93080b32df5SIgor Mammedov return dev; 93180b32df5SIgor Mammedov } 93280b32df5SIgor Mammedov 93316682a9dSIgor Mammedov /* _CRS method - get current settings */ 93416682a9dSIgor Mammedov static Aml *build_iqcr_method(bool is_piix4) 93516682a9dSIgor Mammedov { 93616682a9dSIgor Mammedov Aml *if_ctx; 93716682a9dSIgor Mammedov uint32_t irqs; 93816682a9dSIgor Mammedov Aml *method = aml_method("IQCR", 1, AML_SERIALIZED); 93916682a9dSIgor Mammedov Aml *crs = aml_resource_template(); 94016682a9dSIgor Mammedov 94116682a9dSIgor Mammedov irqs = 0; 94216682a9dSIgor Mammedov aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, 94316682a9dSIgor Mammedov AML_ACTIVE_HIGH, AML_SHARED, &irqs, 1)); 94416682a9dSIgor Mammedov aml_append(method, aml_name_decl("PRR0", crs)); 94516682a9dSIgor Mammedov 94616682a9dSIgor Mammedov aml_append(method, 94716682a9dSIgor Mammedov aml_create_dword_field(aml_name("PRR0"), aml_int(5), "PRRI")); 94816682a9dSIgor Mammedov 94916682a9dSIgor Mammedov if (is_piix4) { 95016682a9dSIgor Mammedov if_ctx = aml_if(aml_lless(aml_arg(0), aml_int(0x80))); 95116682a9dSIgor Mammedov aml_append(if_ctx, aml_store(aml_arg(0), aml_name("PRRI"))); 95216682a9dSIgor Mammedov aml_append(method, if_ctx); 95316682a9dSIgor Mammedov } else { 95416682a9dSIgor Mammedov aml_append(method, 95516682a9dSIgor Mammedov aml_store(aml_and(aml_arg(0), aml_int(0xF), NULL), 95616682a9dSIgor Mammedov aml_name("PRRI"))); 95716682a9dSIgor Mammedov } 95816682a9dSIgor Mammedov 95916682a9dSIgor Mammedov aml_append(method, aml_return(aml_name("PRR0"))); 96016682a9dSIgor Mammedov return method; 96116682a9dSIgor Mammedov } 96216682a9dSIgor Mammedov 96378e1ad05SIgor Mammedov /* _STA method - get status */ 96478e1ad05SIgor Mammedov static Aml *build_irq_status_method(void) 96578e1ad05SIgor Mammedov { 96678e1ad05SIgor Mammedov Aml *if_ctx; 96778e1ad05SIgor Mammedov Aml *method = aml_method("IQST", 1, AML_NOTSERIALIZED); 96878e1ad05SIgor Mammedov 96978e1ad05SIgor Mammedov if_ctx = aml_if(aml_and(aml_int(0x80), aml_arg(0), NULL)); 97078e1ad05SIgor Mammedov aml_append(if_ctx, aml_return(aml_int(0x09))); 97178e1ad05SIgor Mammedov aml_append(method, if_ctx); 97278e1ad05SIgor Mammedov aml_append(method, aml_return(aml_int(0x0B))); 97378e1ad05SIgor Mammedov return method; 97478e1ad05SIgor Mammedov } 97578e1ad05SIgor Mammedov 976e4db2798SIgor Mammedov static void build_piix4_pci0_int(Aml *table) 977e4db2798SIgor Mammedov { 978c35b6e80SIgor Mammedov Aml *dev; 979c35b6e80SIgor Mammedov Aml *crs; 980e4db2798SIgor Mammedov Aml *field; 981c35b6e80SIgor Mammedov Aml *method; 982c35b6e80SIgor Mammedov uint32_t irqs; 983e4db2798SIgor Mammedov Aml *sb_scope = aml_scope("_SB"); 984196e2137SIgor Mammedov Aml *pci0_scope = aml_scope("PCI0"); 985196e2137SIgor Mammedov 986196e2137SIgor Mammedov aml_append(pci0_scope, build_prt(true)); 987196e2137SIgor Mammedov aml_append(sb_scope, pci0_scope); 988e4db2798SIgor Mammedov 989e4db2798SIgor Mammedov field = aml_field("PCI0.ISA.P40C", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE); 990e4db2798SIgor Mammedov aml_append(field, aml_named_field("PRQ0", 8)); 991e4db2798SIgor Mammedov aml_append(field, aml_named_field("PRQ1", 8)); 992e4db2798SIgor Mammedov aml_append(field, aml_named_field("PRQ2", 8)); 993e4db2798SIgor Mammedov aml_append(field, aml_named_field("PRQ3", 8)); 994e4db2798SIgor Mammedov aml_append(sb_scope, field); 995e4db2798SIgor Mammedov 99678e1ad05SIgor Mammedov aml_append(sb_scope, build_irq_status_method()); 99716682a9dSIgor Mammedov aml_append(sb_scope, build_iqcr_method(true)); 998100681ccSIgor Mammedov 999c35b6e80SIgor Mammedov aml_append(sb_scope, build_link_dev("LNKA", 0, aml_name("PRQ0"))); 1000c35b6e80SIgor Mammedov aml_append(sb_scope, build_link_dev("LNKB", 1, aml_name("PRQ1"))); 1001c35b6e80SIgor Mammedov aml_append(sb_scope, build_link_dev("LNKC", 2, aml_name("PRQ2"))); 1002c35b6e80SIgor Mammedov aml_append(sb_scope, build_link_dev("LNKD", 3, aml_name("PRQ3"))); 1003c35b6e80SIgor Mammedov 1004c35b6e80SIgor Mammedov dev = aml_device("LNKS"); 1005c35b6e80SIgor Mammedov { 1006c35b6e80SIgor Mammedov aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C0F"))); 1007c35b6e80SIgor Mammedov aml_append(dev, aml_name_decl("_UID", aml_int(4))); 1008c35b6e80SIgor Mammedov 1009c35b6e80SIgor Mammedov crs = aml_resource_template(); 1010c35b6e80SIgor Mammedov irqs = 9; 1011c35b6e80SIgor Mammedov aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, 1012c35b6e80SIgor Mammedov AML_ACTIVE_HIGH, AML_SHARED, 1013c35b6e80SIgor Mammedov &irqs, 1)); 1014c35b6e80SIgor Mammedov aml_append(dev, aml_name_decl("_PRS", crs)); 1015c35b6e80SIgor Mammedov 1016c35b6e80SIgor Mammedov /* The SCI cannot be disabled and is always attached to GSI 9, 1017c35b6e80SIgor Mammedov * so these are no-ops. We only need this link to override the 1018c35b6e80SIgor Mammedov * polarity to active high and match the content of the MADT. 1019c35b6e80SIgor Mammedov */ 1020c35b6e80SIgor Mammedov method = aml_method("_STA", 0, AML_NOTSERIALIZED); 1021c35b6e80SIgor Mammedov aml_append(method, aml_return(aml_int(0x0b))); 1022c35b6e80SIgor Mammedov aml_append(dev, method); 1023c35b6e80SIgor Mammedov 1024c35b6e80SIgor Mammedov method = aml_method("_DIS", 0, AML_NOTSERIALIZED); 1025c35b6e80SIgor Mammedov aml_append(dev, method); 1026c35b6e80SIgor Mammedov 1027c35b6e80SIgor Mammedov method = aml_method("_CRS", 0, AML_NOTSERIALIZED); 1028c35b6e80SIgor Mammedov aml_append(method, aml_return(aml_name("_PRS"))); 1029c35b6e80SIgor Mammedov aml_append(dev, method); 1030c35b6e80SIgor Mammedov 1031c35b6e80SIgor Mammedov method = aml_method("_SRS", 1, AML_NOTSERIALIZED); 1032c35b6e80SIgor Mammedov aml_append(dev, method); 1033c35b6e80SIgor Mammedov } 1034c35b6e80SIgor Mammedov aml_append(sb_scope, dev); 1035c35b6e80SIgor Mammedov 1036e4db2798SIgor Mammedov aml_append(table, sb_scope); 1037e4db2798SIgor Mammedov } 1038e4db2798SIgor Mammedov 103922b5b8bfSIgor Mammedov static void append_q35_prt_entry(Aml *ctx, uint32_t nr, const char *name) 104022b5b8bfSIgor Mammedov { 104122b5b8bfSIgor Mammedov int i; 104222b5b8bfSIgor Mammedov int head; 104322b5b8bfSIgor Mammedov Aml *pkg; 104422b5b8bfSIgor Mammedov char base = name[3] < 'E' ? 'A' : 'E'; 104522b5b8bfSIgor Mammedov char *s = g_strdup(name); 104622b5b8bfSIgor Mammedov Aml *a_nr = aml_int((nr << 16) | 0xffff); 104722b5b8bfSIgor Mammedov 104822b5b8bfSIgor Mammedov assert(strlen(s) == 4); 104922b5b8bfSIgor Mammedov 105022b5b8bfSIgor Mammedov head = name[3] - base; 105122b5b8bfSIgor Mammedov for (i = 0; i < 4; i++) { 105222b5b8bfSIgor Mammedov if (head + i > 3) { 105322b5b8bfSIgor Mammedov head = i * -1; 105422b5b8bfSIgor Mammedov } 105522b5b8bfSIgor Mammedov s[3] = base + head + i; 105622b5b8bfSIgor Mammedov pkg = aml_package(4); 105722b5b8bfSIgor Mammedov aml_append(pkg, a_nr); 105822b5b8bfSIgor Mammedov aml_append(pkg, aml_int(i)); 105922b5b8bfSIgor Mammedov aml_append(pkg, aml_name("%s", s)); 106022b5b8bfSIgor Mammedov aml_append(pkg, aml_int(0)); 106122b5b8bfSIgor Mammedov aml_append(ctx, pkg); 106222b5b8bfSIgor Mammedov } 106322b5b8bfSIgor Mammedov g_free(s); 106422b5b8bfSIgor Mammedov } 106522b5b8bfSIgor Mammedov 106622b5b8bfSIgor Mammedov static Aml *build_q35_routing_table(const char *str) 106722b5b8bfSIgor Mammedov { 106822b5b8bfSIgor Mammedov int i; 106922b5b8bfSIgor Mammedov Aml *pkg; 107022b5b8bfSIgor Mammedov char *name = g_strdup_printf("%s ", str); 107122b5b8bfSIgor Mammedov 107222b5b8bfSIgor Mammedov pkg = aml_package(128); 107322b5b8bfSIgor Mammedov for (i = 0; i < 0x18; i++) { 107422b5b8bfSIgor Mammedov name[3] = 'E' + (i & 0x3); 107522b5b8bfSIgor Mammedov append_q35_prt_entry(pkg, i, name); 107622b5b8bfSIgor Mammedov } 107722b5b8bfSIgor Mammedov 107822b5b8bfSIgor Mammedov name[3] = 'E'; 107922b5b8bfSIgor Mammedov append_q35_prt_entry(pkg, 0x18, name); 108022b5b8bfSIgor Mammedov 108122b5b8bfSIgor Mammedov /* INTA -> PIRQA for slot 25 - 31, see the default value of D<N>IR */ 108222b5b8bfSIgor Mammedov for (i = 0x0019; i < 0x1e; i++) { 108322b5b8bfSIgor Mammedov name[3] = 'A'; 108422b5b8bfSIgor Mammedov append_q35_prt_entry(pkg, i, name); 108522b5b8bfSIgor Mammedov } 108622b5b8bfSIgor Mammedov 108722b5b8bfSIgor Mammedov /* PCIe->PCI bridge. use PIRQ[E-H] */ 108822b5b8bfSIgor Mammedov name[3] = 'E'; 108922b5b8bfSIgor Mammedov append_q35_prt_entry(pkg, 0x1e, name); 109022b5b8bfSIgor Mammedov name[3] = 'A'; 109122b5b8bfSIgor Mammedov append_q35_prt_entry(pkg, 0x1f, name); 109222b5b8bfSIgor Mammedov 109322b5b8bfSIgor Mammedov g_free(name); 109422b5b8bfSIgor Mammedov return pkg; 109522b5b8bfSIgor Mammedov } 109622b5b8bfSIgor Mammedov 109780b32df5SIgor Mammedov static void build_q35_pci0_int(Aml *table) 109880b32df5SIgor Mammedov { 109941f95a52SIgor Mammedov Aml *field; 11000dafe3b3SIgor Mammedov Aml *method; 110180b32df5SIgor Mammedov Aml *sb_scope = aml_scope("_SB"); 11020dafe3b3SIgor Mammedov Aml *pci0_scope = aml_scope("PCI0"); 11030dafe3b3SIgor Mammedov 1104e9fce798SIgor Mammedov /* Zero => PIC mode, One => APIC Mode */ 1105e9fce798SIgor Mammedov aml_append(table, aml_name_decl("PICF", aml_int(0))); 1106e9fce798SIgor Mammedov method = aml_method("_PIC", 1, AML_NOTSERIALIZED); 1107e9fce798SIgor Mammedov { 1108e9fce798SIgor Mammedov aml_append(method, aml_store(aml_arg(0), aml_name("PICF"))); 1109e9fce798SIgor Mammedov } 1110e9fce798SIgor Mammedov aml_append(table, method); 1111e9fce798SIgor Mammedov 111222b5b8bfSIgor Mammedov aml_append(pci0_scope, 111365aef4deSIgor Mammedov aml_name_decl("PRTP", build_q35_routing_table("LNK"))); 111465aef4deSIgor Mammedov aml_append(pci0_scope, 111522b5b8bfSIgor Mammedov aml_name_decl("PRTA", build_q35_routing_table("GSI"))); 111622b5b8bfSIgor Mammedov 11170dafe3b3SIgor Mammedov method = aml_method("_PRT", 0, AML_NOTSERIALIZED); 11180dafe3b3SIgor Mammedov { 11190dafe3b3SIgor Mammedov Aml *if_ctx; 11200dafe3b3SIgor Mammedov Aml *else_ctx; 11210dafe3b3SIgor Mammedov 11220dafe3b3SIgor Mammedov /* PCI IRQ routing table, example from ACPI 2.0a specification, 11230dafe3b3SIgor Mammedov section 6.2.8.1 */ 11240dafe3b3SIgor Mammedov /* Note: we provide the same info as the PCI routing 11250dafe3b3SIgor Mammedov table of the Bochs BIOS */ 11260dafe3b3SIgor Mammedov if_ctx = aml_if(aml_equal(aml_name("PICF"), aml_int(0))); 11270dafe3b3SIgor Mammedov aml_append(if_ctx, aml_return(aml_name("PRTP"))); 11280dafe3b3SIgor Mammedov aml_append(method, if_ctx); 11290dafe3b3SIgor Mammedov else_ctx = aml_else(); 11300dafe3b3SIgor Mammedov aml_append(else_ctx, aml_return(aml_name("PRTA"))); 11310dafe3b3SIgor Mammedov aml_append(method, else_ctx); 11320dafe3b3SIgor Mammedov } 11330dafe3b3SIgor Mammedov aml_append(pci0_scope, method); 11340dafe3b3SIgor Mammedov aml_append(sb_scope, pci0_scope); 113580b32df5SIgor Mammedov 113641f95a52SIgor Mammedov field = aml_field("PCI0.ISA.PIRQ", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE); 113741f95a52SIgor Mammedov aml_append(field, aml_named_field("PRQA", 8)); 113841f95a52SIgor Mammedov aml_append(field, aml_named_field("PRQB", 8)); 113941f95a52SIgor Mammedov aml_append(field, aml_named_field("PRQC", 8)); 114041f95a52SIgor Mammedov aml_append(field, aml_named_field("PRQD", 8)); 114141f95a52SIgor Mammedov aml_append(field, aml_reserved_field(0x20)); 114241f95a52SIgor Mammedov aml_append(field, aml_named_field("PRQE", 8)); 114341f95a52SIgor Mammedov aml_append(field, aml_named_field("PRQF", 8)); 114441f95a52SIgor Mammedov aml_append(field, aml_named_field("PRQG", 8)); 114541f95a52SIgor Mammedov aml_append(field, aml_named_field("PRQH", 8)); 114641f95a52SIgor Mammedov aml_append(sb_scope, field); 114741f95a52SIgor Mammedov 114878e1ad05SIgor Mammedov aml_append(sb_scope, build_irq_status_method()); 114916682a9dSIgor Mammedov aml_append(sb_scope, build_iqcr_method(false)); 115016682a9dSIgor Mammedov 115112e3b1f7SIgor Mammedov aml_append(sb_scope, build_link_dev("LNKA", 0, aml_name("PRQA"))); 115212e3b1f7SIgor Mammedov aml_append(sb_scope, build_link_dev("LNKB", 1, aml_name("PRQB"))); 115312e3b1f7SIgor Mammedov aml_append(sb_scope, build_link_dev("LNKC", 2, aml_name("PRQC"))); 115412e3b1f7SIgor Mammedov aml_append(sb_scope, build_link_dev("LNKD", 3, aml_name("PRQD"))); 115512e3b1f7SIgor Mammedov aml_append(sb_scope, build_link_dev("LNKE", 4, aml_name("PRQE"))); 115612e3b1f7SIgor Mammedov aml_append(sb_scope, build_link_dev("LNKF", 5, aml_name("PRQF"))); 115712e3b1f7SIgor Mammedov aml_append(sb_scope, build_link_dev("LNKG", 6, aml_name("PRQG"))); 115812e3b1f7SIgor Mammedov aml_append(sb_scope, build_link_dev("LNKH", 7, aml_name("PRQH"))); 115912e3b1f7SIgor Mammedov 11606a991e07SMarcel Apfelbaum aml_append(sb_scope, build_gsi_link_dev("GSIA", 0x10, 0x10)); 11616a991e07SMarcel Apfelbaum aml_append(sb_scope, build_gsi_link_dev("GSIB", 0x11, 0x11)); 11626a991e07SMarcel Apfelbaum aml_append(sb_scope, build_gsi_link_dev("GSIC", 0x12, 0x12)); 11636a991e07SMarcel Apfelbaum aml_append(sb_scope, build_gsi_link_dev("GSID", 0x13, 0x13)); 11646a991e07SMarcel Apfelbaum aml_append(sb_scope, build_gsi_link_dev("GSIE", 0x14, 0x14)); 11656a991e07SMarcel Apfelbaum aml_append(sb_scope, build_gsi_link_dev("GSIF", 0x15, 0x15)); 11666a991e07SMarcel Apfelbaum aml_append(sb_scope, build_gsi_link_dev("GSIG", 0x16, 0x16)); 11676a991e07SMarcel Apfelbaum aml_append(sb_scope, build_gsi_link_dev("GSIH", 0x17, 0x17)); 116880b32df5SIgor Mammedov 116980b32df5SIgor Mammedov aml_append(table, sb_scope); 117080b32df5SIgor Mammedov } 117180b32df5SIgor Mammedov 1172e3fb55f0SIsaku Yamahata static Aml *build_q35_dram_controller(const AcpiMcfgInfo *mcfg) 1173e3fb55f0SIsaku Yamahata { 1174e3fb55f0SIsaku Yamahata Aml *dev; 1175e3fb55f0SIsaku Yamahata Aml *resource_template; 1176e3fb55f0SIsaku Yamahata 1177e3fb55f0SIsaku Yamahata /* DRAM controller */ 1178e3fb55f0SIsaku Yamahata dev = aml_device("DRAC"); 1179e3fb55f0SIsaku Yamahata aml_append(dev, aml_name_decl("_HID", aml_string("PNP0C01"))); 1180e3fb55f0SIsaku Yamahata 1181e3fb55f0SIsaku Yamahata resource_template = aml_resource_template(); 1182e3fb55f0SIsaku Yamahata if (mcfg->base + mcfg->size - 1 >= (1ULL << 32)) { 1183e3fb55f0SIsaku Yamahata aml_append(resource_template, 1184e3fb55f0SIsaku Yamahata aml_qword_memory(AML_POS_DECODE, 1185e3fb55f0SIsaku Yamahata AML_MIN_FIXED, 1186e3fb55f0SIsaku Yamahata AML_MAX_FIXED, 1187e3fb55f0SIsaku Yamahata AML_NON_CACHEABLE, 1188e3fb55f0SIsaku Yamahata AML_READ_WRITE, 1189e3fb55f0SIsaku Yamahata 0x0000000000000000, 1190e3fb55f0SIsaku Yamahata mcfg->base, 1191e3fb55f0SIsaku Yamahata mcfg->base + mcfg->size - 1, 1192e3fb55f0SIsaku Yamahata 0x0000000000000000, 1193e3fb55f0SIsaku Yamahata mcfg->size)); 1194e3fb55f0SIsaku Yamahata } else { 1195e3fb55f0SIsaku Yamahata aml_append(resource_template, 1196e3fb55f0SIsaku Yamahata aml_dword_memory(AML_POS_DECODE, 1197e3fb55f0SIsaku Yamahata AML_MIN_FIXED, 1198e3fb55f0SIsaku Yamahata AML_MAX_FIXED, 1199e3fb55f0SIsaku Yamahata AML_NON_CACHEABLE, 1200e3fb55f0SIsaku Yamahata AML_READ_WRITE, 1201e3fb55f0SIsaku Yamahata 0x0000000000000000, 1202e3fb55f0SIsaku Yamahata mcfg->base, 1203e3fb55f0SIsaku Yamahata mcfg->base + mcfg->size - 1, 1204e3fb55f0SIsaku Yamahata 0x0000000000000000, 1205e3fb55f0SIsaku Yamahata mcfg->size)); 1206e3fb55f0SIsaku Yamahata } 1207e3fb55f0SIsaku Yamahata aml_append(dev, aml_name_decl("_CRS", resource_template)); 1208e3fb55f0SIsaku Yamahata 1209e3fb55f0SIsaku Yamahata return dev; 1210e3fb55f0SIsaku Yamahata } 1211e3fb55f0SIsaku Yamahata 121241f95a52SIgor Mammedov static void build_q35_isa_bridge(Aml *table) 121341f95a52SIgor Mammedov { 121441f95a52SIgor Mammedov Aml *dev; 121541f95a52SIgor Mammedov Aml *scope; 121641f95a52SIgor Mammedov 121741f95a52SIgor Mammedov scope = aml_scope("_SB.PCI0"); 121841f95a52SIgor Mammedov dev = aml_device("ISA"); 121941f95a52SIgor Mammedov aml_append(dev, aml_name_decl("_ADR", aml_int(0x001F0000))); 122041f95a52SIgor Mammedov 122141f95a52SIgor Mammedov /* ICH9 PCI to ISA irq remapping */ 122241f95a52SIgor Mammedov aml_append(dev, aml_operation_region("PIRQ", AML_PCI_CONFIG, 12233f3009c0SXiao Guangrong aml_int(0x60), 0x0C)); 122441f95a52SIgor Mammedov 122541f95a52SIgor Mammedov aml_append(scope, dev); 122641f95a52SIgor Mammedov aml_append(table, scope); 122741f95a52SIgor Mammedov } 122841f95a52SIgor Mammedov 1229e4db2798SIgor Mammedov static void build_piix4_isa_bridge(Aml *table) 1230e4db2798SIgor Mammedov { 1231e4db2798SIgor Mammedov Aml *dev; 1232e4db2798SIgor Mammedov Aml *scope; 1233e4db2798SIgor Mammedov 1234e4db2798SIgor Mammedov scope = aml_scope("_SB.PCI0"); 1235e4db2798SIgor Mammedov dev = aml_device("ISA"); 1236e4db2798SIgor Mammedov aml_append(dev, aml_name_decl("_ADR", aml_int(0x00010000))); 1237e4db2798SIgor Mammedov 1238e4db2798SIgor Mammedov /* PIIX PCI to ISA irq remapping */ 1239e4db2798SIgor Mammedov aml_append(dev, aml_operation_region("P40C", AML_PCI_CONFIG, 12403f3009c0SXiao Guangrong aml_int(0x60), 0x04)); 1241e4db2798SIgor Mammedov 1242e4db2798SIgor Mammedov aml_append(scope, dev); 1243e4db2798SIgor Mammedov aml_append(table, scope); 1244e4db2798SIgor Mammedov } 1245e4db2798SIgor Mammedov 1246b616ec4dSIgor Mammedov static void build_piix4_pci_hotplug(Aml *table) 1247b616ec4dSIgor Mammedov { 1248b616ec4dSIgor Mammedov Aml *scope; 1249b616ec4dSIgor Mammedov Aml *field; 1250b616ec4dSIgor Mammedov Aml *method; 1251b616ec4dSIgor Mammedov 1252b616ec4dSIgor Mammedov scope = aml_scope("_SB.PCI0"); 1253b616ec4dSIgor Mammedov 1254b616ec4dSIgor Mammedov aml_append(scope, 12553f3009c0SXiao Guangrong aml_operation_region("PCST", AML_SYSTEM_IO, aml_int(0xae00), 0x08)); 1256b616ec4dSIgor Mammedov field = aml_field("PCST", AML_DWORD_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS); 1257b616ec4dSIgor Mammedov aml_append(field, aml_named_field("PCIU", 32)); 1258b616ec4dSIgor Mammedov aml_append(field, aml_named_field("PCID", 32)); 1259b616ec4dSIgor Mammedov aml_append(scope, field); 1260b616ec4dSIgor Mammedov 1261b616ec4dSIgor Mammedov aml_append(scope, 12623f3009c0SXiao Guangrong aml_operation_region("SEJ", AML_SYSTEM_IO, aml_int(0xae08), 0x04)); 1263b616ec4dSIgor Mammedov field = aml_field("SEJ", AML_DWORD_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS); 1264b616ec4dSIgor Mammedov aml_append(field, aml_named_field("B0EJ", 32)); 1265b616ec4dSIgor Mammedov aml_append(scope, field); 1266b616ec4dSIgor Mammedov 1267b616ec4dSIgor Mammedov aml_append(scope, 1268b32bd763SIgor Mammedov aml_operation_region("BNMR", AML_SYSTEM_IO, aml_int(0xae10), 0x08)); 1269b616ec4dSIgor Mammedov field = aml_field("BNMR", AML_DWORD_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS); 1270b616ec4dSIgor Mammedov aml_append(field, aml_named_field("BNUM", 32)); 1271b32bd763SIgor Mammedov aml_append(field, aml_named_field("PIDX", 32)); 1272b616ec4dSIgor Mammedov aml_append(scope, field); 1273b616ec4dSIgor Mammedov 1274b616ec4dSIgor Mammedov aml_append(scope, aml_mutex("BLCK", 0)); 1275b616ec4dSIgor Mammedov 1276b616ec4dSIgor Mammedov method = aml_method("PCEJ", 2, AML_NOTSERIALIZED); 1277b616ec4dSIgor Mammedov aml_append(method, aml_acquire(aml_name("BLCK"), 0xFFFF)); 1278b616ec4dSIgor Mammedov aml_append(method, aml_store(aml_arg(0), aml_name("BNUM"))); 1279b616ec4dSIgor Mammedov aml_append(method, 1280b616ec4dSIgor Mammedov aml_store(aml_shiftleft(aml_int(1), aml_arg(1)), aml_name("B0EJ"))); 1281b616ec4dSIgor Mammedov aml_append(method, aml_release(aml_name("BLCK"))); 1282b616ec4dSIgor Mammedov aml_append(method, aml_return(aml_int(0))); 1283b616ec4dSIgor Mammedov aml_append(scope, method); 1284b616ec4dSIgor Mammedov 1285b32bd763SIgor Mammedov method = aml_method("AIDX", 2, AML_NOTSERIALIZED); 1286b32bd763SIgor Mammedov aml_append(method, aml_acquire(aml_name("BLCK"), 0xFFFF)); 1287b32bd763SIgor Mammedov aml_append(method, aml_store(aml_arg(0), aml_name("BNUM"))); 1288b32bd763SIgor Mammedov aml_append(method, 1289b32bd763SIgor Mammedov aml_store(aml_shiftleft(aml_int(1), aml_arg(1)), aml_name("PIDX"))); 1290b32bd763SIgor Mammedov aml_append(method, aml_store(aml_name("PIDX"), aml_local(0))); 1291b32bd763SIgor Mammedov aml_append(method, aml_release(aml_name("BLCK"))); 1292b32bd763SIgor Mammedov aml_append(method, aml_return(aml_local(0))); 1293b32bd763SIgor Mammedov aml_append(scope, method); 1294b32bd763SIgor Mammedov 1295*b7f23f62SIgor Mammedov aml_append(scope, aml_pci_device_dsm()); 1296*b7f23f62SIgor Mammedov 1297b616ec4dSIgor Mammedov aml_append(table, scope); 1298b616ec4dSIgor Mammedov } 1299b616ec4dSIgor Mammedov 1300f97a88a8SIgor Mammedov static Aml *build_q35_osc_method(void) 1301f97a88a8SIgor Mammedov { 1302f97a88a8SIgor Mammedov Aml *if_ctx; 1303f97a88a8SIgor Mammedov Aml *if_ctx2; 1304f97a88a8SIgor Mammedov Aml *else_ctx; 1305f97a88a8SIgor Mammedov Aml *method; 1306f97a88a8SIgor Mammedov Aml *a_cwd1 = aml_name("CDW1"); 1307b3c782dbSMichael S. Tsirkin Aml *a_ctrl = aml_local(0); 1308f97a88a8SIgor Mammedov 1309f97a88a8SIgor Mammedov method = aml_method("_OSC", 4, AML_NOTSERIALIZED); 1310f97a88a8SIgor Mammedov aml_append(method, aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1")); 1311f97a88a8SIgor Mammedov 1312f97a88a8SIgor Mammedov if_ctx = aml_if(aml_equal( 1313f97a88a8SIgor Mammedov aml_arg(0), aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766"))); 1314f97a88a8SIgor Mammedov aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2")); 1315f97a88a8SIgor Mammedov aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3")); 1316f97a88a8SIgor Mammedov 1317f97a88a8SIgor Mammedov aml_append(if_ctx, aml_store(aml_name("CDW3"), a_ctrl)); 1318f97a88a8SIgor Mammedov 1319f97a88a8SIgor Mammedov /* 1320f97a88a8SIgor Mammedov * Always allow native PME, AER (no dependencies) 1321a41c78c1SAleksandr Bezzubikov * Allow SHPC (PCI bridges can have SHPC controller) 1322f97a88a8SIgor Mammedov */ 1323a41c78c1SAleksandr Bezzubikov aml_append(if_ctx, aml_and(a_ctrl, aml_int(0x1F), a_ctrl)); 1324f97a88a8SIgor Mammedov 1325f97a88a8SIgor Mammedov if_ctx2 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(1)))); 1326f97a88a8SIgor Mammedov /* Unknown revision */ 1327f97a88a8SIgor Mammedov aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x08), a_cwd1)); 1328f97a88a8SIgor Mammedov aml_append(if_ctx, if_ctx2); 1329f97a88a8SIgor Mammedov 1330f97a88a8SIgor Mammedov if_ctx2 = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), a_ctrl))); 1331f97a88a8SIgor Mammedov /* Capabilities bits were masked */ 1332f97a88a8SIgor Mammedov aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x10), a_cwd1)); 1333f97a88a8SIgor Mammedov aml_append(if_ctx, if_ctx2); 1334f97a88a8SIgor Mammedov 1335f97a88a8SIgor Mammedov /* Update DWORD3 in the buffer */ 1336f97a88a8SIgor Mammedov aml_append(if_ctx, aml_store(a_ctrl, aml_name("CDW3"))); 1337f97a88a8SIgor Mammedov aml_append(method, if_ctx); 1338f97a88a8SIgor Mammedov 1339f97a88a8SIgor Mammedov else_ctx = aml_else(); 1340f97a88a8SIgor Mammedov /* Unrecognized UUID */ 1341f97a88a8SIgor Mammedov aml_append(else_ctx, aml_or(a_cwd1, aml_int(4), a_cwd1)); 1342f97a88a8SIgor Mammedov aml_append(method, else_ctx); 1343f97a88a8SIgor Mammedov 1344f97a88a8SIgor Mammedov aml_append(method, aml_return(aml_arg(3))); 1345f97a88a8SIgor Mammedov return method; 1346f97a88a8SIgor Mammedov } 1347b616ec4dSIgor Mammedov 1348ebe15582SCorey Minyard static void build_smb0(Aml *table, I2CBus *smbus, int devnr, int func) 1349ebe15582SCorey Minyard { 1350ebe15582SCorey Minyard Aml *scope = aml_scope("_SB.PCI0"); 1351ebe15582SCorey Minyard Aml *dev = aml_device("SMB0"); 1352ebe15582SCorey Minyard 1353ebe15582SCorey Minyard aml_append(dev, aml_name_decl("_ADR", aml_int(devnr << 16 | func))); 1354ebe15582SCorey Minyard build_acpi_ipmi_devices(dev, BUS(smbus), "\\_SB.PCI0.SMB0"); 1355ebe15582SCorey Minyard aml_append(scope, dev); 1356ebe15582SCorey Minyard aml_append(table, scope); 1357ebe15582SCorey Minyard } 1358ebe15582SCorey Minyard 135972c194f7SMichael S. Tsirkin static void 13600e9b9edaSIgor Mammedov build_dsdt(GArray *table_data, BIOSLinker *linker, 1361adcb89d5SIgor Mammedov AcpiPmInfo *pm, AcpiMiscInfo *misc, 136201c9742dSMarkus Armbruster Range *pci_hole, Range *pci_hole64, MachineState *machine) 136372c194f7SMichael S. Tsirkin { 136441fa5c04SIgor Mammedov CrsRangeEntry *entry; 136541fa5c04SIgor Mammedov Aml *dsdt, *sb_scope, *scope, *dev, *method, *field, *pkg, *crs; 13662df5a7b5SMarcel Apfelbaum CrsRangeSet crs_range_set; 1367fb306ffeSEduardo Habkost PCMachineState *pcms = PC_MACHINE(machine); 1368679dd1a9SIgor Mammedov PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(machine); 1369f0bb276bSPaolo Bonzini X86MachineState *x86ms = X86_MACHINE(machine); 13704a441836SGerd Hoffmann AcpiMcfgInfo mcfg; 1371e3fb55f0SIsaku Yamahata bool mcfg_valid = !!acpi_get_mcfg(&mcfg); 1372bef3492dSIgor Mammedov uint32_t nr_mem = machine->ram_slots; 1373dcdca296SMarcel Apfelbaum int root_bus_limit = 0xFF; 137441fa5c04SIgor Mammedov PCIBus *bus = NULL; 1375ac6dd31eSStefan Berger TPMIf *tpm = tpm_find(); 137672c194f7SMichael S. Tsirkin int i; 13778f814ea1SJon Doron VMBusBridge *vmbus_bridge = vmbus_bridge_find(); 137872c194f7SMichael S. Tsirkin 137941fa5c04SIgor Mammedov dsdt = init_aml_allocator(); 13802fd71f1bSLaszlo Ersek 13814ec8d2b3SIgor Mammedov /* Reserve space for header */ 138241fa5c04SIgor Mammedov acpi_data_push(dsdt->buf, sizeof(AcpiTableHeader)); 138341fa5c04SIgor Mammedov 138441fa5c04SIgor Mammedov build_dbg_aml(dsdt); 138541fa5c04SIgor Mammedov if (misc->is_piix4) { 138641fa5c04SIgor Mammedov sb_scope = aml_scope("_SB"); 138741fa5c04SIgor Mammedov dev = aml_device("PCI0"); 138841fa5c04SIgor Mammedov aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A03"))); 138941fa5c04SIgor Mammedov aml_append(dev, aml_name_decl("_ADR", aml_int(0))); 13900a343a5aSVitaly Cheptsov aml_append(dev, aml_name_decl("_UID", aml_int(pcmc->pci_root_uid))); 139141fa5c04SIgor Mammedov aml_append(sb_scope, dev); 139241fa5c04SIgor Mammedov aml_append(dsdt, sb_scope); 139341fa5c04SIgor Mammedov 139451124bbfSSean Christopherson if (misc->has_hpet) { 139541fa5c04SIgor Mammedov build_hpet_aml(dsdt); 139651124bbfSSean Christopherson } 139741fa5c04SIgor Mammedov build_piix4_isa_bridge(dsdt); 139841fa5c04SIgor Mammedov build_isa_devices_aml(dsdt); 1399df4008c9SAni Sinha if (pm->pcihp_bridge_en || pm->pcihp_root_en) { 140041fa5c04SIgor Mammedov build_piix4_pci_hotplug(dsdt); 1401df4008c9SAni Sinha } 140241fa5c04SIgor Mammedov build_piix4_pci0_int(dsdt); 140341fa5c04SIgor Mammedov } else { 140441fa5c04SIgor Mammedov sb_scope = aml_scope("_SB"); 140541fa5c04SIgor Mammedov dev = aml_device("PCI0"); 140641fa5c04SIgor Mammedov aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08"))); 140741fa5c04SIgor Mammedov aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03"))); 140841fa5c04SIgor Mammedov aml_append(dev, aml_name_decl("_ADR", aml_int(0))); 14090a343a5aSVitaly Cheptsov aml_append(dev, aml_name_decl("_UID", aml_int(pcmc->pci_root_uid))); 141041fa5c04SIgor Mammedov aml_append(dev, build_q35_osc_method()); 141141fa5c04SIgor Mammedov aml_append(sb_scope, dev); 1412e3fb55f0SIsaku Yamahata if (mcfg_valid) { 1413e3fb55f0SIsaku Yamahata aml_append(sb_scope, build_q35_dram_controller(&mcfg)); 1414e3fb55f0SIsaku Yamahata } 1415998ba950SIgor Mammedov 1416998ba950SIgor Mammedov if (pm->smi_on_cpuhp) { 1417998ba950SIgor Mammedov /* reserve SMI block resources, IO ports 0xB2, 0xB3 */ 1418998ba950SIgor Mammedov dev = aml_device("PCI0.SMI0"); 1419998ba950SIgor Mammedov aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A06"))); 1420998ba950SIgor Mammedov aml_append(dev, aml_name_decl("_UID", aml_string("SMI resources"))); 1421998ba950SIgor Mammedov crs = aml_resource_template(); 1422998ba950SIgor Mammedov aml_append(crs, 1423998ba950SIgor Mammedov aml_io( 1424998ba950SIgor Mammedov AML_DECODE16, 1425998ba950SIgor Mammedov ACPI_PORT_SMI_CMD, 1426998ba950SIgor Mammedov ACPI_PORT_SMI_CMD, 1427998ba950SIgor Mammedov 1, 1428998ba950SIgor Mammedov 2) 1429998ba950SIgor Mammedov ); 1430998ba950SIgor Mammedov aml_append(dev, aml_name_decl("_CRS", crs)); 1431998ba950SIgor Mammedov aml_append(dev, aml_operation_region("SMIR", AML_SYSTEM_IO, 1432998ba950SIgor Mammedov aml_int(ACPI_PORT_SMI_CMD), 2)); 1433998ba950SIgor Mammedov field = aml_field("SMIR", AML_BYTE_ACC, AML_NOLOCK, 1434998ba950SIgor Mammedov AML_WRITE_AS_ZEROS); 1435998ba950SIgor Mammedov aml_append(field, aml_named_field("SMIC", 8)); 1436998ba950SIgor Mammedov aml_append(field, aml_reserved_field(8)); 1437998ba950SIgor Mammedov aml_append(dev, field); 1438998ba950SIgor Mammedov aml_append(sb_scope, dev); 1439998ba950SIgor Mammedov } 1440998ba950SIgor Mammedov 144141fa5c04SIgor Mammedov aml_append(dsdt, sb_scope); 144241fa5c04SIgor Mammedov 144351124bbfSSean Christopherson if (misc->has_hpet) { 144441fa5c04SIgor Mammedov build_hpet_aml(dsdt); 144551124bbfSSean Christopherson } 144641fa5c04SIgor Mammedov build_q35_isa_bridge(dsdt); 144741fa5c04SIgor Mammedov build_isa_devices_aml(dsdt); 144841fa5c04SIgor Mammedov build_q35_pci0_int(dsdt); 1449ebe15582SCorey Minyard if (pcms->smbus && !pcmc->do_not_add_smb_acpi) { 1450ebe15582SCorey Minyard build_smb0(dsdt, pcms->smbus, ICH9_SMB_DEV, ICH9_SMB_FUNC); 1451ebe15582SCorey Minyard } 145241fa5c04SIgor Mammedov } 145341fa5c04SIgor Mammedov 14548f814ea1SJon Doron if (vmbus_bridge) { 14558f814ea1SJon Doron sb_scope = aml_scope("_SB"); 14568f814ea1SJon Doron aml_append(sb_scope, build_vmbus_device_aml(vmbus_bridge)); 14578f814ea1SJon Doron aml_append(dsdt, sb_scope); 14588f814ea1SJon Doron } 14598f814ea1SJon Doron 1460679dd1a9SIgor Mammedov if (pcmc->legacy_cpu_hotplug) { 1461ebd8ea82SIgor Mammedov build_legacy_cpu_hotplug_aml(dsdt, machine, pm->cpu_hp_io_base); 1462679dd1a9SIgor Mammedov } else { 1463679dd1a9SIgor Mammedov CPUHotplugFeatures opts = { 1464998ba950SIgor Mammedov .acpi_1_compatible = true, .has_legacy_cphp = true, 1465998ba950SIgor Mammedov .smi_path = pm->smi_on_cpuhp ? "\\_SB.PCI0.SMI0.SMIC" : NULL, 146669dea9d6SIgor Mammedov .fw_unplugs_cpu = pm->smi_on_cpu_unplug, 1467679dd1a9SIgor Mammedov }; 1468679dd1a9SIgor Mammedov build_cpus_aml(dsdt, machine, opts, pm->cpu_hp_io_base, 1469679dd1a9SIgor Mammedov "\\_SB.PCI0", "\\_GPE._E02"); 1470679dd1a9SIgor Mammedov } 1471091c466eSShameer Kolothum 1472091c466eSShameer Kolothum if (pcms->memhp_io_base && nr_mem) { 1473091c466eSShameer Kolothum build_memory_hotplug_aml(dsdt, nr_mem, "\\_SB.PCI0", 1474091c466eSShameer Kolothum "\\_GPE._E03", AML_SYSTEM_IO, 1475091c466eSShameer Kolothum pcms->memhp_io_base); 1476091c466eSShameer Kolothum } 147741fa5c04SIgor Mammedov 147841fa5c04SIgor Mammedov scope = aml_scope("_GPE"); 147941fa5c04SIgor Mammedov { 148041fa5c04SIgor Mammedov aml_append(scope, aml_name_decl("_HID", aml_string("ACPI0006"))); 148141fa5c04SIgor Mammedov 1482df4008c9SAni Sinha if (misc->is_piix4 && (pm->pcihp_bridge_en || pm->pcihp_root_en)) { 148341fa5c04SIgor Mammedov method = aml_method("_E01", 0, AML_NOTSERIALIZED); 148441fa5c04SIgor Mammedov aml_append(method, 148541fa5c04SIgor Mammedov aml_acquire(aml_name("\\_SB.PCI0.BLCK"), 0xFFFF)); 148641fa5c04SIgor Mammedov aml_append(method, aml_call0("\\_SB.PCI0.PCNT")); 148741fa5c04SIgor Mammedov aml_append(method, aml_release(aml_name("\\_SB.PCI0.BLCK"))); 148841fa5c04SIgor Mammedov aml_append(scope, method); 148941fa5c04SIgor Mammedov } 149041fa5c04SIgor Mammedov 1491f6a0d06bSEric Auger if (machine->nvdimms_state->is_enabled) { 1492b097cc52SXiao Guangrong method = aml_method("_E04", 0, AML_NOTSERIALIZED); 1493b097cc52SXiao Guangrong aml_append(method, aml_notify(aml_name("\\_SB.NVDR"), 1494b097cc52SXiao Guangrong aml_int(0x80))); 1495b097cc52SXiao Guangrong aml_append(scope, method); 1496b097cc52SXiao Guangrong } 149741fa5c04SIgor Mammedov } 149841fa5c04SIgor Mammedov aml_append(dsdt, scope); 149972c194f7SMichael S. Tsirkin 15002df5a7b5SMarcel Apfelbaum crs_range_set_init(&crs_range_set); 150181ed6482SMarcel Apfelbaum bus = PC_MACHINE(machine)->bus; 1502a4894206SMarcel Apfelbaum if (bus) { 1503a4894206SMarcel Apfelbaum QLIST_FOREACH(bus, &bus->child, sibling) { 1504a4894206SMarcel Apfelbaum uint8_t bus_num = pci_bus_num(bus); 15050e79e51aSMarcel Apfelbaum uint8_t numa_node = pci_bus_numa_node(bus); 1506a4894206SMarcel Apfelbaum 1507a4894206SMarcel Apfelbaum /* look only for expander root buses */ 1508a4894206SMarcel Apfelbaum if (!pci_bus_is_root(bus)) { 1509a4894206SMarcel Apfelbaum continue; 1510a4894206SMarcel Apfelbaum } 1511a4894206SMarcel Apfelbaum 1512dcdca296SMarcel Apfelbaum if (bus_num < root_bus_limit) { 1513dcdca296SMarcel Apfelbaum root_bus_limit = bus_num - 1; 1514dcdca296SMarcel Apfelbaum } 1515dcdca296SMarcel Apfelbaum 1516a4894206SMarcel Apfelbaum scope = aml_scope("\\_SB"); 1517a4894206SMarcel Apfelbaum dev = aml_device("PC%.02X", bus_num); 1518c96d9286SLaszlo Ersek aml_append(dev, aml_name_decl("_UID", aml_int(bus_num))); 1519a4894206SMarcel Apfelbaum aml_append(dev, aml_name_decl("_BBN", aml_int(bus_num))); 1520077dd742SMarcel Apfelbaum if (pci_bus_is_express(bus)) { 1521ee4b0c86SEvgeny Yakovlev aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08"))); 1522ee4b0c86SEvgeny Yakovlev aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03"))); 1523077dd742SMarcel Apfelbaum aml_append(dev, build_q35_osc_method()); 1524ee4b0c86SEvgeny Yakovlev } else { 1525ee4b0c86SEvgeny Yakovlev aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A03"))); 1526077dd742SMarcel Apfelbaum } 15270e79e51aSMarcel Apfelbaum 15280e79e51aSMarcel Apfelbaum if (numa_node != NUMA_NODE_UNASSIGNED) { 15290e79e51aSMarcel Apfelbaum aml_append(dev, aml_name_decl("_PXM", aml_int(numa_node))); 15300e79e51aSMarcel Apfelbaum } 15310e79e51aSMarcel Apfelbaum 1532196e2137SIgor Mammedov aml_append(dev, build_prt(false)); 1533e41ee855SJiahui Cen crs = build_crs(PCI_HOST_BRIDGE(BUS(bus)->parent), &crs_range_set, 1534e41ee855SJiahui Cen 0, 0, 0, 0); 1535a43c6e27SMarcel Apfelbaum aml_append(dev, aml_name_decl("_CRS", crs)); 1536a4894206SMarcel Apfelbaum aml_append(scope, dev); 153741fa5c04SIgor Mammedov aml_append(dsdt, scope); 1538a4894206SMarcel Apfelbaum } 1539a4894206SMarcel Apfelbaum } 1540a4894206SMarcel Apfelbaum 15414a441836SGerd Hoffmann /* 15424a441836SGerd Hoffmann * At this point crs_range_set has all the ranges used by pci 15434a441836SGerd Hoffmann * busses *other* than PCI0. These ranges will be excluded from 15444a441836SGerd Hoffmann * the PCI0._CRS. Add mmconfig to the set so it will be excluded 15454a441836SGerd Hoffmann * too. 15464a441836SGerd Hoffmann */ 1547e3fb55f0SIsaku Yamahata if (mcfg_valid) { 15484a441836SGerd Hoffmann crs_range_insert(crs_range_set.mem_ranges, 15494a441836SGerd Hoffmann mcfg.base, mcfg.base + mcfg.size - 1); 15504a441836SGerd Hoffmann } 15514a441836SGerd Hoffmann 1552500b11eaSIgor Mammedov scope = aml_scope("\\_SB.PCI0"); 155360efd429SIgor Mammedov /* build PCI0._CRS */ 155460efd429SIgor Mammedov crs = aml_resource_template(); 155560efd429SIgor Mammedov aml_append(crs, 1556ff80dc7fSShannon Zhao aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE, 1557dcdca296SMarcel Apfelbaum 0x0000, 0x0, root_bus_limit, 1558dcdca296SMarcel Apfelbaum 0x0000, root_bus_limit + 1)); 1559ff80dc7fSShannon Zhao aml_append(crs, aml_io(AML_DECODE16, 0x0CF8, 0x0CF8, 0x01, 0x08)); 156060efd429SIgor Mammedov 156160efd429SIgor Mammedov aml_append(crs, 1562ff80dc7fSShannon Zhao aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED, 1563ff80dc7fSShannon Zhao AML_POS_DECODE, AML_ENTIRE_RANGE, 156460efd429SIgor Mammedov 0x0000, 0x0000, 0x0CF7, 0x0000, 0x0CF8)); 1565dcdca296SMarcel Apfelbaum 15662df5a7b5SMarcel Apfelbaum crs_replace_with_free_ranges(crs_range_set.io_ranges, 0x0D00, 0xFFFF); 15672df5a7b5SMarcel Apfelbaum for (i = 0; i < crs_range_set.io_ranges->len; i++) { 15682df5a7b5SMarcel Apfelbaum entry = g_ptr_array_index(crs_range_set.io_ranges, i); 156960efd429SIgor Mammedov aml_append(crs, 1570ff80dc7fSShannon Zhao aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED, 1571ff80dc7fSShannon Zhao AML_POS_DECODE, AML_ENTIRE_RANGE, 1572dcdca296SMarcel Apfelbaum 0x0000, entry->base, entry->limit, 1573dcdca296SMarcel Apfelbaum 0x0000, entry->limit - entry->base + 1)); 1574dcdca296SMarcel Apfelbaum } 1575dcdca296SMarcel Apfelbaum 157660efd429SIgor Mammedov aml_append(crs, 1577ff80dc7fSShannon Zhao aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, 1578ff80dc7fSShannon Zhao AML_CACHEABLE, AML_READ_WRITE, 157960efd429SIgor Mammedov 0, 0x000A0000, 0x000BFFFF, 0, 0x00020000)); 1580dcdca296SMarcel Apfelbaum 15812df5a7b5SMarcel Apfelbaum crs_replace_with_free_ranges(crs_range_set.mem_ranges, 1582a0efbf16SMarkus Armbruster range_lob(pci_hole), 1583a0efbf16SMarkus Armbruster range_upb(pci_hole)); 15842df5a7b5SMarcel Apfelbaum for (i = 0; i < crs_range_set.mem_ranges->len; i++) { 15852df5a7b5SMarcel Apfelbaum entry = g_ptr_array_index(crs_range_set.mem_ranges, i); 158660efd429SIgor Mammedov aml_append(crs, 1587ff80dc7fSShannon Zhao aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, 1588ff80dc7fSShannon Zhao AML_NON_CACHEABLE, AML_READ_WRITE, 1589dcdca296SMarcel Apfelbaum 0, entry->base, entry->limit, 1590dcdca296SMarcel Apfelbaum 0, entry->limit - entry->base + 1)); 1591dcdca296SMarcel Apfelbaum } 1592dcdca296SMarcel Apfelbaum 1593a0efbf16SMarkus Armbruster if (!range_is_empty(pci_hole64)) { 159416de88a4SMarcel Apfelbaum crs_replace_with_free_ranges(crs_range_set.mem_64bit_ranges, 159516de88a4SMarcel Apfelbaum range_lob(pci_hole64), 159616de88a4SMarcel Apfelbaum range_upb(pci_hole64)); 159716de88a4SMarcel Apfelbaum for (i = 0; i < crs_range_set.mem_64bit_ranges->len; i++) { 159816de88a4SMarcel Apfelbaum entry = g_ptr_array_index(crs_range_set.mem_64bit_ranges, i); 159960efd429SIgor Mammedov aml_append(crs, 160016de88a4SMarcel Apfelbaum aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, 160116de88a4SMarcel Apfelbaum AML_MAX_FIXED, 1602ff80dc7fSShannon Zhao AML_CACHEABLE, AML_READ_WRITE, 160316de88a4SMarcel Apfelbaum 0, entry->base, entry->limit, 160416de88a4SMarcel Apfelbaum 0, entry->limit - entry->base + 1)); 160516de88a4SMarcel Apfelbaum } 160660efd429SIgor Mammedov } 16072b1c2e8eSIgor Mammedov 160843bc7f84SEric Auger if (TPM_IS_TIS_ISA(tpm_find())) { 16092b1c2e8eSIgor Mammedov aml_append(crs, aml_memory32_fixed(TPM_TIS_ADDR_BASE, 16102b1c2e8eSIgor Mammedov TPM_TIS_ADDR_SIZE, AML_READ_WRITE)); 16112b1c2e8eSIgor Mammedov } 161260efd429SIgor Mammedov aml_append(scope, aml_name_decl("_CRS", crs)); 161360efd429SIgor Mammedov 1614d31c909eSIgor Mammedov /* reserve GPE0 block resources */ 1615d31c909eSIgor Mammedov dev = aml_device("GPE0"); 1616d31c909eSIgor Mammedov aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A06"))); 1617d31c909eSIgor Mammedov aml_append(dev, aml_name_decl("_UID", aml_string("GPE0 resources"))); 1618d31c909eSIgor Mammedov /* device present, functioning, decoding, not shown in UI */ 1619d31c909eSIgor Mammedov aml_append(dev, aml_name_decl("_STA", aml_int(0xB))); 1620d31c909eSIgor Mammedov crs = aml_resource_template(); 1621d31c909eSIgor Mammedov aml_append(crs, 1622937d1b58SIgor Mammedov aml_io( 1623937d1b58SIgor Mammedov AML_DECODE16, 1624937d1b58SIgor Mammedov pm->fadt.gpe0_blk.address, 1625937d1b58SIgor Mammedov pm->fadt.gpe0_blk.address, 1626937d1b58SIgor Mammedov 1, 1627937d1b58SIgor Mammedov pm->fadt.gpe0_blk.bit_width / 8) 1628d31c909eSIgor Mammedov ); 1629d31c909eSIgor Mammedov aml_append(dev, aml_name_decl("_CRS", crs)); 1630d31c909eSIgor Mammedov aml_append(scope, dev); 1631d31c909eSIgor Mammedov 16322df5a7b5SMarcel Apfelbaum crs_range_set_free(&crs_range_set); 1633dcdca296SMarcel Apfelbaum 1634500b11eaSIgor Mammedov /* reserve PCIHP resources */ 1635df4008c9SAni Sinha if (pm->pcihp_io_len && (pm->pcihp_bridge_en || pm->pcihp_root_en)) { 1636500b11eaSIgor Mammedov dev = aml_device("PHPR"); 1637500b11eaSIgor Mammedov aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A06"))); 1638500b11eaSIgor Mammedov aml_append(dev, 1639500b11eaSIgor Mammedov aml_name_decl("_UID", aml_string("PCI Hotplug resources"))); 1640500b11eaSIgor Mammedov /* device present, functioning, decoding, not shown in UI */ 1641500b11eaSIgor Mammedov aml_append(dev, aml_name_decl("_STA", aml_int(0xB))); 1642500b11eaSIgor Mammedov crs = aml_resource_template(); 1643500b11eaSIgor Mammedov aml_append(crs, 1644ff80dc7fSShannon Zhao aml_io(AML_DECODE16, pm->pcihp_io_base, pm->pcihp_io_base, 1, 1645500b11eaSIgor Mammedov pm->pcihp_io_len) 1646500b11eaSIgor Mammedov ); 1647500b11eaSIgor Mammedov aml_append(dev, aml_name_decl("_CRS", crs)); 1648500b11eaSIgor Mammedov aml_append(scope, dev); 1649500b11eaSIgor Mammedov } 165041fa5c04SIgor Mammedov aml_append(dsdt, scope); 1651500b11eaSIgor Mammedov 1652ebc3028fSIgor Mammedov /* create S3_ / S4_ / S5_ packages if necessary */ 1653ebc3028fSIgor Mammedov scope = aml_scope("\\"); 1654ebc3028fSIgor Mammedov if (!pm->s3_disabled) { 1655ebc3028fSIgor Mammedov pkg = aml_package(4); 1656ebc3028fSIgor Mammedov aml_append(pkg, aml_int(1)); /* PM1a_CNT.SLP_TYP */ 1657ebc3028fSIgor Mammedov aml_append(pkg, aml_int(1)); /* PM1b_CNT.SLP_TYP, FIXME: not impl. */ 1658ebc3028fSIgor Mammedov aml_append(pkg, aml_int(0)); /* reserved */ 1659ebc3028fSIgor Mammedov aml_append(pkg, aml_int(0)); /* reserved */ 1660ebc3028fSIgor Mammedov aml_append(scope, aml_name_decl("_S3", pkg)); 1661ebc3028fSIgor Mammedov } 1662ebc3028fSIgor Mammedov 1663ebc3028fSIgor Mammedov if (!pm->s4_disabled) { 1664ebc3028fSIgor Mammedov pkg = aml_package(4); 1665ebc3028fSIgor Mammedov aml_append(pkg, aml_int(pm->s4_val)); /* PM1a_CNT.SLP_TYP */ 1666ebc3028fSIgor Mammedov /* PM1b_CNT.SLP_TYP, FIXME: not impl. */ 1667ebc3028fSIgor Mammedov aml_append(pkg, aml_int(pm->s4_val)); 1668ebc3028fSIgor Mammedov aml_append(pkg, aml_int(0)); /* reserved */ 1669ebc3028fSIgor Mammedov aml_append(pkg, aml_int(0)); /* reserved */ 1670ebc3028fSIgor Mammedov aml_append(scope, aml_name_decl("_S4", pkg)); 1671ebc3028fSIgor Mammedov } 1672ebc3028fSIgor Mammedov 1673ebc3028fSIgor Mammedov pkg = aml_package(4); 1674ebc3028fSIgor Mammedov aml_append(pkg, aml_int(0)); /* PM1a_CNT.SLP_TYP */ 1675ebc3028fSIgor Mammedov aml_append(pkg, aml_int(0)); /* PM1b_CNT.SLP_TYP not impl. */ 1676ebc3028fSIgor Mammedov aml_append(pkg, aml_int(0)); /* reserved */ 1677ebc3028fSIgor Mammedov aml_append(pkg, aml_int(0)); /* reserved */ 1678ebc3028fSIgor Mammedov aml_append(scope, aml_name_decl("_S5", pkg)); 167941fa5c04SIgor Mammedov aml_append(dsdt, scope); 1680ebc3028fSIgor Mammedov 1681e2ec7568SGabriel L. Somlo /* create fw_cfg node, unconditionally */ 1682e2ec7568SGabriel L. Somlo { 1683e2ec7568SGabriel L. Somlo scope = aml_scope("\\_SB.PCI0"); 16840575c2fdSGerd Hoffmann fw_cfg_add_acpi_dsdt(scope, x86ms->fw_cfg); 1685e2ec7568SGabriel L. Somlo aml_append(dsdt, scope); 1686e2ec7568SGabriel L. Somlo } 1687e2ec7568SGabriel L. Somlo 16888ac6f7a6SIgor Mammedov if (misc->applesmc_io_base) { 16898ac6f7a6SIgor Mammedov scope = aml_scope("\\_SB.PCI0.ISA"); 16908ac6f7a6SIgor Mammedov dev = aml_device("SMC"); 16918ac6f7a6SIgor Mammedov 16928ac6f7a6SIgor Mammedov aml_append(dev, aml_name_decl("_HID", aml_eisaid("APP0001"))); 16938ac6f7a6SIgor Mammedov /* device present, functioning, decoding, not shown in UI */ 16948ac6f7a6SIgor Mammedov aml_append(dev, aml_name_decl("_STA", aml_int(0xB))); 16958ac6f7a6SIgor Mammedov 16968ac6f7a6SIgor Mammedov crs = aml_resource_template(); 16978ac6f7a6SIgor Mammedov aml_append(crs, 1698ff80dc7fSShannon Zhao aml_io(AML_DECODE16, misc->applesmc_io_base, misc->applesmc_io_base, 16998ac6f7a6SIgor Mammedov 0x01, APPLESMC_MAX_DATA_LENGTH) 17008ac6f7a6SIgor Mammedov ); 17018ac6f7a6SIgor Mammedov aml_append(crs, aml_irq_no_flags(6)); 17028ac6f7a6SIgor Mammedov aml_append(dev, aml_name_decl("_CRS", crs)); 17038ac6f7a6SIgor Mammedov 17048ac6f7a6SIgor Mammedov aml_append(scope, dev); 170541fa5c04SIgor Mammedov aml_append(dsdt, scope); 17068ac6f7a6SIgor Mammedov } 17078ac6f7a6SIgor Mammedov 1708cd61cb2eSIgor Mammedov if (misc->pvpanic_port) { 1709cd61cb2eSIgor Mammedov scope = aml_scope("\\_SB.PCI0.ISA"); 1710cd61cb2eSIgor Mammedov 17112332333cSRadim Krčmář dev = aml_device("PEVT"); 1712e65bef69SIgor Mammedov aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0001"))); 1713cd61cb2eSIgor Mammedov 1714cd61cb2eSIgor Mammedov crs = aml_resource_template(); 1715cd61cb2eSIgor Mammedov aml_append(crs, 1716ff80dc7fSShannon Zhao aml_io(AML_DECODE16, misc->pvpanic_port, misc->pvpanic_port, 1, 1) 1717cd61cb2eSIgor Mammedov ); 1718cd61cb2eSIgor Mammedov aml_append(dev, aml_name_decl("_CRS", crs)); 1719cd61cb2eSIgor Mammedov 1720ff80dc7fSShannon Zhao aml_append(dev, aml_operation_region("PEOR", AML_SYSTEM_IO, 17213f3009c0SXiao Guangrong aml_int(misc->pvpanic_port), 1)); 172236de884aSIgor Mammedov field = aml_field("PEOR", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE); 1723cd61cb2eSIgor Mammedov aml_append(field, aml_named_field("PEPT", 8)); 1724cd61cb2eSIgor Mammedov aml_append(dev, field); 1725cd61cb2eSIgor Mammedov 17268ef3ea25SGal Hammer /* device present, functioning, decoding, shown in UI */ 17278ef3ea25SGal Hammer aml_append(dev, aml_name_decl("_STA", aml_int(0xF))); 17282332333cSRadim Krčmář 17294dbfc881SXiao Guangrong method = aml_method("RDPT", 0, AML_NOTSERIALIZED); 1730cd61cb2eSIgor Mammedov aml_append(method, aml_store(aml_name("PEPT"), aml_local(0))); 1731cd61cb2eSIgor Mammedov aml_append(method, aml_return(aml_local(0))); 1732cd61cb2eSIgor Mammedov aml_append(dev, method); 1733cd61cb2eSIgor Mammedov 17344dbfc881SXiao Guangrong method = aml_method("WRPT", 1, AML_NOTSERIALIZED); 1735cd61cb2eSIgor Mammedov aml_append(method, aml_store(aml_arg(0), aml_name("PEPT"))); 1736cd61cb2eSIgor Mammedov aml_append(dev, method); 1737cd61cb2eSIgor Mammedov 1738cd61cb2eSIgor Mammedov aml_append(scope, dev); 173941fa5c04SIgor Mammedov aml_append(dsdt, scope); 1740cd61cb2eSIgor Mammedov } 1741cd61cb2eSIgor Mammedov 17427824df38SGal Hammer sb_scope = aml_scope("\\_SB"); 174372c194f7SMichael S. Tsirkin { 17448dcf525aSMichael S. Tsirkin Object *pci_host; 17458dcf525aSMichael S. Tsirkin PCIBus *bus = NULL; 17468dcf525aSMichael S. Tsirkin 1747ca6c1855SMarcel Apfelbaum pci_host = acpi_get_i386_pci_host(); 1748ca6c1855SMarcel Apfelbaum if (pci_host) { 17498dcf525aSMichael S. Tsirkin bus = PCI_HOST_BRIDGE(pci_host)->bus; 17508dcf525aSMichael S. Tsirkin } 175172c194f7SMichael S. Tsirkin 175299fd437dSMichael S. Tsirkin if (bus) { 175362b52c26SIgor Mammedov Aml *scope = aml_scope("PCI0"); 175499fd437dSMichael S. Tsirkin /* Scan all PCI buses. Generate tables to support hotplug. */ 175562b52c26SIgor Mammedov build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en); 175672d97b3aSIgor Mammedov 175743bc7f84SEric Auger if (TPM_IS_TIS_ISA(tpm)) { 175824cf5413SStefan Berger if (misc->tpm_version == TPM_VERSION_2_0) { 175924cf5413SStefan Berger dev = aml_device("TPM"); 176024cf5413SStefan Berger aml_append(dev, aml_name_decl("_HID", 176124cf5413SStefan Berger aml_string("MSFT0101"))); 176224cf5413SStefan Berger } else { 176372d97b3aSIgor Mammedov dev = aml_device("ISA.TPM"); 176424cf5413SStefan Berger aml_append(dev, aml_name_decl("_HID", 176524cf5413SStefan Berger aml_eisaid("PNP0C31"))); 176624cf5413SStefan Berger } 176724cf5413SStefan Berger 176872d97b3aSIgor Mammedov aml_append(dev, aml_name_decl("_STA", aml_int(0xF))); 176972d97b3aSIgor Mammedov crs = aml_resource_template(); 177072d97b3aSIgor Mammedov aml_append(crs, aml_memory32_fixed(TPM_TIS_ADDR_BASE, 177172d97b3aSIgor Mammedov TPM_TIS_ADDR_SIZE, AML_READ_WRITE)); 177252e38eb0SIgor Mammedov /* 177352e38eb0SIgor Mammedov FIXME: TPM_TIS_IRQ=5 conflicts with PNP0C0F irqs, 177452e38eb0SIgor Mammedov Rewrite to take IRQ from TPM device model and 177552e38eb0SIgor Mammedov fix default IRQ value there to use some unused IRQ 177652e38eb0SIgor Mammedov */ 177752e38eb0SIgor Mammedov /* aml_append(crs, aml_irq_no_flags(TPM_TIS_IRQ)); */ 177872d97b3aSIgor Mammedov aml_append(dev, aml_name_decl("_CRS", crs)); 1779ac6dd31eSStefan Berger 1780ac6dd31eSStefan Berger tpm_build_ppi_acpi(tpm, dev); 1781ac6dd31eSStefan Berger 178272d97b3aSIgor Mammedov aml_append(scope, dev); 178372d97b3aSIgor Mammedov } 178472d97b3aSIgor Mammedov 178562b52c26SIgor Mammedov aml_append(sb_scope, scope); 178672c194f7SMichael S. Tsirkin } 178772c194f7SMichael S. Tsirkin } 17884ab6cb4cSMarc-André Lureau 1789ac6dd31eSStefan Berger if (TPM_IS_CRB(tpm)) { 17904ab6cb4cSMarc-André Lureau dev = aml_device("TPM"); 17914ab6cb4cSMarc-André Lureau aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101"))); 17924ab6cb4cSMarc-André Lureau crs = aml_resource_template(); 17934ab6cb4cSMarc-André Lureau aml_append(crs, aml_memory32_fixed(TPM_CRB_ADDR_BASE, 17944ab6cb4cSMarc-André Lureau TPM_CRB_ADDR_SIZE, AML_READ_WRITE)); 17954ab6cb4cSMarc-André Lureau aml_append(dev, aml_name_decl("_CRS", crs)); 17964ab6cb4cSMarc-André Lureau 179788b3648fSGerd Hoffmann aml_append(dev, aml_name_decl("_STA", aml_int(0xf))); 17984ab6cb4cSMarc-André Lureau 1799ac6dd31eSStefan Berger tpm_build_ppi_acpi(tpm, dev); 1800ac6dd31eSStefan Berger 18014ab6cb4cSMarc-André Lureau aml_append(sb_scope, dev); 18024ab6cb4cSMarc-André Lureau } 18034ab6cb4cSMarc-André Lureau 180441fa5c04SIgor Mammedov aml_append(dsdt, sb_scope); 180572c194f7SMichael S. Tsirkin 1806011bb749SIgor Mammedov /* copy AML table into ACPI tables blob and patch header there */ 180741fa5c04SIgor Mammedov g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len); 180872c194f7SMichael S. Tsirkin build_header(linker, table_data, 180941fa5c04SIgor Mammedov (void *)(table_data->data + table_data->len - dsdt->buf->len), 1810602b4582SMarian Postevca "DSDT", dsdt->buf->len, 1, pcms->oem_id, pcms->oem_table_id); 1811011bb749SIgor Mammedov free_aml_allocator(); 181272c194f7SMichael S. Tsirkin } 181372c194f7SMichael S. Tsirkin 181472c194f7SMichael S. Tsirkin static void 1815602b4582SMarian Postevca build_hpet(GArray *table_data, BIOSLinker *linker, const char *oem_id, 1816602b4582SMarian Postevca const char *oem_table_id) 181772c194f7SMichael S. Tsirkin { 181872c194f7SMichael S. Tsirkin Acpi20Hpet *hpet; 181972c194f7SMichael S. Tsirkin 182072c194f7SMichael S. Tsirkin hpet = acpi_data_push(table_data, sizeof(*hpet)); 182172c194f7SMichael S. Tsirkin /* Note timer_block_id value must be kept in sync with value advertised by 182272c194f7SMichael S. Tsirkin * emulated hpet 182372c194f7SMichael S. Tsirkin */ 182472c194f7SMichael S. Tsirkin hpet->timer_block_id = cpu_to_le32(0x8086a201); 182572c194f7SMichael S. Tsirkin hpet->addr.address = cpu_to_le64(HPET_BASE); 182672c194f7SMichael S. Tsirkin build_header(linker, table_data, 1827602b4582SMarian Postevca (void *)hpet, "HPET", sizeof(*hpet), 1, oem_id, oem_table_id); 182872c194f7SMichael S. Tsirkin } 182972c194f7SMichael S. Tsirkin 1830711b20b4SStefan Berger static void 1831602b4582SMarian Postevca build_tpm_tcpa(GArray *table_data, BIOSLinker *linker, GArray *tcpalog, 1832602b4582SMarian Postevca const char *oem_id, const char *oem_table_id) 1833711b20b4SStefan Berger { 1834711b20b4SStefan Berger Acpi20Tcpa *tcpa = acpi_data_push(table_data, sizeof *tcpa); 18354678124bSIgor Mammedov unsigned log_addr_size = sizeof(tcpa->log_area_start_address); 18364678124bSIgor Mammedov unsigned log_addr_offset = 18374678124bSIgor Mammedov (char *)&tcpa->log_area_start_address - table_data->data; 1838711b20b4SStefan Berger 1839711b20b4SStefan Berger tcpa->platform_class = cpu_to_le16(TPM_TCPA_ACPI_CLASS_CLIENT); 1840711b20b4SStefan Berger tcpa->log_area_minimum_length = cpu_to_le32(TPM_LOG_AREA_MINIMUM_SIZE); 18419774ccf7SIgor Mammedov acpi_data_push(tcpalog, le32_to_cpu(tcpa->log_area_minimum_length)); 1842711b20b4SStefan Berger 1843ad9671b8SIgor Mammedov bios_linker_loader_alloc(linker, ACPI_BUILD_TPMLOG_FILE, tcpalog, 1, 184442a5b308SStefan Berger false /* high memory */); 184542a5b308SStefan Berger 1846711b20b4SStefan Berger /* log area start address to be filled by Guest linker */ 18474678124bSIgor Mammedov bios_linker_loader_add_pointer(linker, 18484678124bSIgor Mammedov ACPI_BUILD_TABLE_FILE, log_addr_offset, log_addr_size, 18494678124bSIgor Mammedov ACPI_BUILD_TPMLOG_FILE, 0); 1850711b20b4SStefan Berger 1851711b20b4SStefan Berger build_header(linker, table_data, 1852602b4582SMarian Postevca (void *)tcpa, "TCPA", sizeof(*tcpa), 2, oem_id, oem_table_id); 1853711b20b4SStefan Berger } 1854711b20b4SStefan Berger 1855d471bf3eSPaolo Bonzini #define HOLE_640K_START (640 * KiB) 1856d471bf3eSPaolo Bonzini #define HOLE_640K_END (1 * MiB) 18574926403cSEduardo Habkost 185872c194f7SMichael S. Tsirkin static void 18590e9b9edaSIgor Mammedov build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) 186072c194f7SMichael S. Tsirkin { 186172c194f7SMichael S. Tsirkin AcpiSystemResourceAffinityTable *srat; 186272c194f7SMichael S. Tsirkin AcpiSratMemoryAffinity *numamem; 186372c194f7SMichael S. Tsirkin 186472c194f7SMichael S. Tsirkin int i; 186572c194f7SMichael S. Tsirkin int srat_start, numa_start, slots; 186672c194f7SMichael S. Tsirkin uint64_t mem_len, mem_base, next_base; 18675803fce3SIgor Mammedov MachineClass *mc = MACHINE_GET_CLASS(machine); 1868f0bb276bSPaolo Bonzini X86MachineState *x86ms = X86_MACHINE(machine); 186980e5db30SIgor Mammedov const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(machine); 18703d3ebcadSIgor Mammedov PCMachineState *pcms = PC_MACHINE(machine); 1871cec65193SIgor Mammedov ram_addr_t hotplugabble_address_space_size = 1872f2ffbe2bSDavid Hildenbrand object_property_get_int(OBJECT(pcms), PC_MACHINE_DEVMEM_REGION_SIZE, 1873cec65193SIgor Mammedov NULL); 187472c194f7SMichael S. Tsirkin 187572c194f7SMichael S. Tsirkin srat_start = table_data->len; 187672c194f7SMichael S. Tsirkin 187772c194f7SMichael S. Tsirkin srat = acpi_data_push(table_data, sizeof *srat); 187872c194f7SMichael S. Tsirkin srat->reserved1 = cpu_to_le32(1); 187972c194f7SMichael S. Tsirkin 18805803fce3SIgor Mammedov for (i = 0; i < apic_ids->len; i++) { 1881d41f3e75SIgor Mammedov int node_id = apic_ids->cpus[i].props.node_id; 18825eff33a2SIgor Mammedov uint32_t apic_id = apic_ids->cpus[i].arch_id; 18835eff33a2SIgor Mammedov 18845eff33a2SIgor Mammedov if (apic_id < 255) { 18855eff33a2SIgor Mammedov AcpiSratProcessorAffinity *core; 18865803fce3SIgor Mammedov 188772c194f7SMichael S. Tsirkin core = acpi_data_push(table_data, sizeof *core); 1888e6e400d5SShannon Zhao core->type = ACPI_SRAT_PROCESSOR_APIC; 188972c194f7SMichael S. Tsirkin core->length = sizeof(*core); 18905803fce3SIgor Mammedov core->local_apic_id = apic_id; 1891ea265072SIgor Mammedov core->proximity_lo = node_id; 189272c194f7SMichael S. Tsirkin memset(core->proximity_hi, 0, 3); 189372c194f7SMichael S. Tsirkin core->local_sapic_eid = 0; 189472c194f7SMichael S. Tsirkin core->flags = cpu_to_le32(1); 18955eff33a2SIgor Mammedov } else { 18965eff33a2SIgor Mammedov AcpiSratProcessorX2ApicAffinity *core; 18975eff33a2SIgor Mammedov 18985eff33a2SIgor Mammedov core = acpi_data_push(table_data, sizeof *core); 18995eff33a2SIgor Mammedov core->type = ACPI_SRAT_PROCESSOR_x2APIC; 19005eff33a2SIgor Mammedov core->length = sizeof(*core); 19015eff33a2SIgor Mammedov core->x2apic_id = cpu_to_le32(apic_id); 1902ea265072SIgor Mammedov core->proximity_domain = cpu_to_le32(node_id); 19035eff33a2SIgor Mammedov core->flags = cpu_to_le32(1); 19045eff33a2SIgor Mammedov } 190572c194f7SMichael S. Tsirkin } 190672c194f7SMichael S. Tsirkin 190772c194f7SMichael S. Tsirkin 190872c194f7SMichael S. Tsirkin /* the memory map is a bit tricky, it contains at least one hole 190972c194f7SMichael S. Tsirkin * from 640k-1M and possibly another one from 3.5G-4G. 191072c194f7SMichael S. Tsirkin */ 191172c194f7SMichael S. Tsirkin next_base = 0; 191272c194f7SMichael S. Tsirkin numa_start = table_data->len; 191372c194f7SMichael S. Tsirkin 1914dd4c2f01SEduardo Habkost for (i = 1; i < pcms->numa_nodes + 1; ++i) { 191572c194f7SMichael S. Tsirkin mem_base = next_base; 1916dd4c2f01SEduardo Habkost mem_len = pcms->node_mem[i - 1]; 191772c194f7SMichael S. Tsirkin next_base = mem_base + mem_len; 191872c194f7SMichael S. Tsirkin 19194926403cSEduardo Habkost /* Cut out the 640K hole */ 19204926403cSEduardo Habkost if (mem_base <= HOLE_640K_START && 19214926403cSEduardo Habkost next_base > HOLE_640K_START) { 19224926403cSEduardo Habkost mem_len -= next_base - HOLE_640K_START; 19234926403cSEduardo Habkost if (mem_len > 0) { 19244926403cSEduardo Habkost numamem = acpi_data_push(table_data, sizeof *numamem); 19254926403cSEduardo Habkost build_srat_memory(numamem, mem_base, mem_len, i - 1, 19264926403cSEduardo Habkost MEM_AFFINITY_ENABLED); 19274926403cSEduardo Habkost } 19284926403cSEduardo Habkost 19294926403cSEduardo Habkost /* Check for the rare case: 640K < RAM < 1M */ 19304926403cSEduardo Habkost if (next_base <= HOLE_640K_END) { 19314926403cSEduardo Habkost next_base = HOLE_640K_END; 19324926403cSEduardo Habkost continue; 19334926403cSEduardo Habkost } 19344926403cSEduardo Habkost mem_base = HOLE_640K_END; 19354926403cSEduardo Habkost mem_len = next_base - HOLE_640K_END; 19364926403cSEduardo Habkost } 19374926403cSEduardo Habkost 193872c194f7SMichael S. Tsirkin /* Cut out the ACPI_PCI hole */ 1939f0bb276bSPaolo Bonzini if (mem_base <= x86ms->below_4g_mem_size && 1940f0bb276bSPaolo Bonzini next_base > x86ms->below_4g_mem_size) { 1941f0bb276bSPaolo Bonzini mem_len -= next_base - x86ms->below_4g_mem_size; 194272c194f7SMichael S. Tsirkin if (mem_len > 0) { 194372c194f7SMichael S. Tsirkin numamem = acpi_data_push(table_data, sizeof *numamem); 194464b83136SShannon Zhao build_srat_memory(numamem, mem_base, mem_len, i - 1, 194504ed3ea8SIgor Mammedov MEM_AFFINITY_ENABLED); 194672c194f7SMichael S. Tsirkin } 194772c194f7SMichael S. Tsirkin mem_base = 1ULL << 32; 1948f0bb276bSPaolo Bonzini mem_len = next_base - x86ms->below_4g_mem_size; 19496cf6fe39SDou Liyang next_base = mem_base + mem_len; 195072c194f7SMichael S. Tsirkin } 195116b42263SDou Liyang 195216b42263SDou Liyang if (mem_len > 0) { 195372c194f7SMichael S. Tsirkin numamem = acpi_data_push(table_data, sizeof *numamem); 195464b83136SShannon Zhao build_srat_memory(numamem, mem_base, mem_len, i - 1, 195504ed3ea8SIgor Mammedov MEM_AFFINITY_ENABLED); 195672c194f7SMichael S. Tsirkin } 195716b42263SDou Liyang } 1958c3b0cf6eSVishal Verma 1959c3b0cf6eSVishal Verma if (machine->nvdimms_state->is_enabled) { 1960c3b0cf6eSVishal Verma nvdimm_build_srat(table_data); 1961c3b0cf6eSVishal Verma } 1962c3b0cf6eSVishal Verma 196372c194f7SMichael S. Tsirkin slots = (table_data->len - numa_start) / sizeof *numamem; 1964dd4c2f01SEduardo Habkost for (; slots < pcms->numa_nodes + 2; slots++) { 196572c194f7SMichael S. Tsirkin numamem = acpi_data_push(table_data, sizeof *numamem); 196664b83136SShannon Zhao build_srat_memory(numamem, 0, 0, 0, MEM_AFFINITY_NOFLAGS); 196772c194f7SMichael S. Tsirkin } 196872c194f7SMichael S. Tsirkin 1969dbb6da8bSIgor Mammedov /* 1970dbb6da8bSIgor Mammedov * Entry is required for Windows to enable memory hotplug in OS 1971dbb6da8bSIgor Mammedov * and for Linux to enable SWIOTLB when booted with less than 1972dbb6da8bSIgor Mammedov * 4G of RAM. Windows works better if the entry sets proximity 1973dbb6da8bSIgor Mammedov * to the highest NUMA node in the machine. 1974dbb6da8bSIgor Mammedov * Memory devices may override proximity set by this entry, 1975dbb6da8bSIgor Mammedov * providing _PXM method if necessary. 1976dbb6da8bSIgor Mammedov */ 1977cec65193SIgor Mammedov if (hotplugabble_address_space_size) { 1978dbb6da8bSIgor Mammedov numamem = acpi_data_push(table_data, sizeof *numamem); 1979dbb6da8bSIgor Mammedov build_srat_memory(numamem, machine->device_memory->base, 1980dbb6da8bSIgor Mammedov hotplugabble_address_space_size, pcms->numa_nodes - 1, 1981dbb6da8bSIgor Mammedov MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED); 1982cec65193SIgor Mammedov } 1983cec65193SIgor Mammedov 198472c194f7SMichael S. Tsirkin build_header(linker, table_data, 198572c194f7SMichael S. Tsirkin (void *)(table_data->data + srat_start), 1986821e3227SMichael S. Tsirkin "SRAT", 1987602b4582SMarian Postevca table_data->len - srat_start, 1, pcms->oem_id, 1988602b4582SMarian Postevca pcms->oem_table_id); 198972c194f7SMichael S. Tsirkin } 199072c194f7SMichael S. Tsirkin 1991d46114f9SPeter Xu /* 1992d46114f9SPeter Xu * VT-d spec 8.1 DMA Remapping Reporting Structure 1993d46114f9SPeter Xu * (version Oct. 2014 or later) 1994d46114f9SPeter Xu */ 199572c194f7SMichael S. Tsirkin static void 1996602b4582SMarian Postevca build_dmar_q35(GArray *table_data, BIOSLinker *linker, const char *oem_id, 1997602b4582SMarian Postevca const char *oem_table_id) 1998d4eb9119SLe Tan { 1999d4eb9119SLe Tan int dmar_start = table_data->len; 2000d4eb9119SLe Tan 2001d4eb9119SLe Tan AcpiTableDmar *dmar; 2002d4eb9119SLe Tan AcpiDmarHardwareUnit *drhd; 2003bd2baaccSJason Wang AcpiDmarRootPortATS *atsr; 2004d46114f9SPeter Xu uint8_t dmar_flags = 0; 2005d46114f9SPeter Xu X86IOMMUState *iommu = x86_iommu_get_default(); 2006cfc13df4SPeter Xu AcpiDmarDeviceScope *scope = NULL; 2007cfc13df4SPeter Xu /* Root complex IOAPIC use one path[0] only */ 2008cfc13df4SPeter Xu size_t ioapic_scope_size = sizeof(*scope) + sizeof(scope->path[0]); 200937f51384SPrasad Singamsetty IntelIOMMUState *intel_iommu = INTEL_IOMMU_DEVICE(iommu); 2010d46114f9SPeter Xu 2011d46114f9SPeter Xu assert(iommu); 2012a924b3d8SPeter Xu if (x86_iommu_ir_supported(iommu)) { 2013d46114f9SPeter Xu dmar_flags |= 0x1; /* Flags: 0x1: INT_REMAP */ 2014d46114f9SPeter Xu } 2015d4eb9119SLe Tan 2016d4eb9119SLe Tan dmar = acpi_data_push(table_data, sizeof(*dmar)); 201737f51384SPrasad Singamsetty dmar->host_address_width = intel_iommu->aw_bits - 1; 2018d46114f9SPeter Xu dmar->flags = dmar_flags; 2019d4eb9119SLe Tan 2020d4eb9119SLe Tan /* DMAR Remapping Hardware Unit Definition structure */ 2021cfc13df4SPeter Xu drhd = acpi_data_push(table_data, sizeof(*drhd) + ioapic_scope_size); 2022d4eb9119SLe Tan drhd->type = cpu_to_le16(ACPI_DMAR_TYPE_HARDWARE_UNIT); 2023cfc13df4SPeter Xu drhd->length = cpu_to_le16(sizeof(*drhd) + ioapic_scope_size); 2024d4eb9119SLe Tan drhd->flags = ACPI_DMAR_INCLUDE_PCI_ALL; 2025d4eb9119SLe Tan drhd->pci_segment = cpu_to_le16(0); 2026d4eb9119SLe Tan drhd->address = cpu_to_le64(Q35_HOST_BRIDGE_IOMMU_ADDR); 2027d4eb9119SLe Tan 2028cfc13df4SPeter Xu /* Scope definition for the root-complex IOAPIC. See VT-d spec 2029cfc13df4SPeter Xu * 8.3.1 (version Oct. 2014 or later). */ 2030cfc13df4SPeter Xu scope = &drhd->scope[0]; 2031cfc13df4SPeter Xu scope->entry_type = 0x03; /* Type: 0x03 for IOAPIC */ 2032cfc13df4SPeter Xu scope->length = ioapic_scope_size; 2033cfc13df4SPeter Xu scope->enumeration_id = ACPI_BUILD_IOAPIC_ID; 2034cfc13df4SPeter Xu scope->bus = Q35_PSEUDO_BUS_PLATFORM; 20351b39bc1cSPeter Xu scope->path[0].device = PCI_SLOT(Q35_PSEUDO_DEVFN_IOAPIC); 20361b39bc1cSPeter Xu scope->path[0].function = PCI_FUNC(Q35_PSEUDO_DEVFN_IOAPIC); 2037cfc13df4SPeter Xu 2038bd2baaccSJason Wang if (iommu->dt_supported) { 2039bd2baaccSJason Wang atsr = acpi_data_push(table_data, sizeof(*atsr)); 2040bd2baaccSJason Wang atsr->type = cpu_to_le16(ACPI_DMAR_TYPE_ATSR); 2041bd2baaccSJason Wang atsr->length = cpu_to_le16(sizeof(*atsr)); 2042bd2baaccSJason Wang atsr->flags = ACPI_DMAR_ATSR_ALL_PORTS; 2043bd2baaccSJason Wang atsr->pci_segment = cpu_to_le16(0); 2044bd2baaccSJason Wang } 2045bd2baaccSJason Wang 2046d4eb9119SLe Tan build_header(linker, table_data, (void *)(table_data->data + dmar_start), 2047602b4582SMarian Postevca "DMAR", table_data->len - dmar_start, 1, oem_id, oem_table_id); 2048d4eb9119SLe Tan } 204914cda350SLiran Alon 205014cda350SLiran Alon /* 205114cda350SLiran Alon * Windows ACPI Emulated Devices Table 205214cda350SLiran Alon * (Version 1.0 - April 6, 2009) 205314cda350SLiran Alon * Spec: http://download.microsoft.com/download/7/E/7/7E7662CF-CBEA-470B-A97E-CE7CE0D98DC2/WAET.docx 205414cda350SLiran Alon * 205514cda350SLiran Alon * Helpful to speedup Windows guests and ignored by others. 205614cda350SLiran Alon */ 205714cda350SLiran Alon static void 2058602b4582SMarian Postevca build_waet(GArray *table_data, BIOSLinker *linker, const char *oem_id, 2059602b4582SMarian Postevca const char *oem_table_id) 206014cda350SLiran Alon { 206114cda350SLiran Alon int waet_start = table_data->len; 206214cda350SLiran Alon 206314cda350SLiran Alon /* WAET header */ 206414cda350SLiran Alon acpi_data_push(table_data, sizeof(AcpiTableHeader)); 206514cda350SLiran Alon /* 206614cda350SLiran Alon * Set "ACPI PM timer good" flag. 206714cda350SLiran Alon * 206814cda350SLiran Alon * Tells Windows guests that our ACPI PM timer is reliable in the 206914cda350SLiran Alon * sense that guest can read it only once to obtain a reliable value. 207014cda350SLiran Alon * Which avoids costly VMExits caused by guest re-reading it unnecessarily. 207114cda350SLiran Alon */ 207214cda350SLiran Alon build_append_int_noprefix(table_data, 1 << 1 /* ACPI PM timer good */, 4); 207314cda350SLiran Alon 207414cda350SLiran Alon build_header(linker, table_data, (void *)(table_data->data + waet_start), 2075602b4582SMarian Postevca "WAET", table_data->len - waet_start, 1, oem_id, oem_table_id); 207614cda350SLiran Alon } 207714cda350SLiran Alon 2078fb9f5926SDavid Kiarie /* 2079fb9f5926SDavid Kiarie * IVRS table as specified in AMD IOMMU Specification v2.62, Section 5.2 2080fb9f5926SDavid Kiarie * accessible here http://support.amd.com/TechDocs/48882_IOMMU.pdf 2081fb9f5926SDavid Kiarie */ 2082c028818dSSingh, Brijesh #define IOAPIC_SB_DEVID (uint64_t)PCI_BUILD_BDF(0, PCI_DEVFN(0x14, 0)) 2083c028818dSSingh, Brijesh 2084977aff10SAlex Williamson /* 2085977aff10SAlex Williamson * Insert IVHD entry for device and recurse, insert alias, or insert range as 2086977aff10SAlex Williamson * necessary for the PCI topology. 2087977aff10SAlex Williamson */ 2088977aff10SAlex Williamson static void 2089977aff10SAlex Williamson insert_ivhd(PCIBus *bus, PCIDevice *dev, void *opaque) 2090977aff10SAlex Williamson { 2091977aff10SAlex Williamson GArray *table_data = opaque; 2092977aff10SAlex Williamson uint32_t entry; 2093977aff10SAlex Williamson 2094977aff10SAlex Williamson /* "Select" IVHD entry, type 0x2 */ 2095977aff10SAlex Williamson entry = PCI_BUILD_BDF(pci_bus_num(bus), dev->devfn) << 8 | 0x2; 2096977aff10SAlex Williamson build_append_int_noprefix(table_data, entry, 4); 2097977aff10SAlex Williamson 2098977aff10SAlex Williamson if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) { 2099977aff10SAlex Williamson PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(dev)); 2100977aff10SAlex Williamson uint8_t sec = pci_bus_num(sec_bus); 2101977aff10SAlex Williamson uint8_t sub = dev->config[PCI_SUBORDINATE_BUS]; 2102977aff10SAlex Williamson 2103977aff10SAlex Williamson if (pci_bus_is_express(sec_bus)) { 2104977aff10SAlex Williamson /* 2105977aff10SAlex Williamson * Walk the bus if there are subordinates, otherwise use a range 2106977aff10SAlex Williamson * to cover an entire leaf bus. We could potentially also use a 2107977aff10SAlex Williamson * range for traversed buses, but we'd need to take care not to 2108977aff10SAlex Williamson * create both Select and Range entries covering the same device. 2109977aff10SAlex Williamson * This is easier and potentially more compact. 2110977aff10SAlex Williamson * 2111977aff10SAlex Williamson * An example bare metal system seems to use Select entries for 2112977aff10SAlex Williamson * root ports without a slot (ie. built-ins) and Range entries 2113977aff10SAlex Williamson * when there is a slot. The same system also only hard-codes 2114977aff10SAlex Williamson * the alias range for an onboard PCIe-to-PCI bridge, apparently 2115977aff10SAlex Williamson * making no effort to support nested bridges. We attempt to 2116977aff10SAlex Williamson * be more thorough here. 2117977aff10SAlex Williamson */ 2118977aff10SAlex Williamson if (sec == sub) { /* leaf bus */ 2119977aff10SAlex Williamson /* "Start of Range" IVHD entry, type 0x3 */ 2120977aff10SAlex Williamson entry = PCI_BUILD_BDF(sec, PCI_DEVFN(0, 0)) << 8 | 0x3; 2121977aff10SAlex Williamson build_append_int_noprefix(table_data, entry, 4); 2122977aff10SAlex Williamson /* "End of Range" IVHD entry, type 0x4 */ 2123977aff10SAlex Williamson entry = PCI_BUILD_BDF(sub, PCI_DEVFN(31, 7)) << 8 | 0x4; 2124977aff10SAlex Williamson build_append_int_noprefix(table_data, entry, 4); 2125977aff10SAlex Williamson } else { 2126977aff10SAlex Williamson pci_for_each_device(sec_bus, sec, insert_ivhd, table_data); 2127977aff10SAlex Williamson } 2128977aff10SAlex Williamson } else { 2129977aff10SAlex Williamson /* 2130977aff10SAlex Williamson * If the secondary bus is conventional, then we need to create an 2131977aff10SAlex Williamson * Alias range for everything downstream. The range covers the 2132977aff10SAlex Williamson * first devfn on the secondary bus to the last devfn on the 2133977aff10SAlex Williamson * subordinate bus. The alias target depends on legacy versus 2134977aff10SAlex Williamson * express bridges, just as in pci_device_iommu_address_space(). 2135977aff10SAlex Williamson * DeviceIDa vs DeviceIDb as per the AMD IOMMU spec. 2136977aff10SAlex Williamson */ 2137977aff10SAlex Williamson uint16_t dev_id_a, dev_id_b; 2138977aff10SAlex Williamson 2139977aff10SAlex Williamson dev_id_a = PCI_BUILD_BDF(sec, PCI_DEVFN(0, 0)); 2140977aff10SAlex Williamson 2141977aff10SAlex Williamson if (pci_is_express(dev) && 2142977aff10SAlex Williamson pcie_cap_get_type(dev) == PCI_EXP_TYPE_PCI_BRIDGE) { 2143977aff10SAlex Williamson dev_id_b = dev_id_a; 2144977aff10SAlex Williamson } else { 2145977aff10SAlex Williamson dev_id_b = PCI_BUILD_BDF(pci_bus_num(bus), dev->devfn); 2146977aff10SAlex Williamson } 2147977aff10SAlex Williamson 2148977aff10SAlex Williamson /* "Alias Start of Range" IVHD entry, type 0x43, 8 bytes */ 2149977aff10SAlex Williamson build_append_int_noprefix(table_data, dev_id_a << 8 | 0x43, 4); 2150977aff10SAlex Williamson build_append_int_noprefix(table_data, dev_id_b << 8 | 0x0, 4); 2151977aff10SAlex Williamson 2152977aff10SAlex Williamson /* "End of Range" IVHD entry, type 0x4 */ 2153977aff10SAlex Williamson entry = PCI_BUILD_BDF(sub, PCI_DEVFN(31, 7)) << 8 | 0x4; 2154977aff10SAlex Williamson build_append_int_noprefix(table_data, entry, 4); 2155977aff10SAlex Williamson } 2156977aff10SAlex Williamson } 2157977aff10SAlex Williamson } 2158977aff10SAlex Williamson 2159977aff10SAlex Williamson /* For all PCI host bridges, walk and insert IVHD entries */ 2160977aff10SAlex Williamson static int 2161977aff10SAlex Williamson ivrs_host_bridges(Object *obj, void *opaque) 2162977aff10SAlex Williamson { 2163977aff10SAlex Williamson GArray *ivhd_blob = opaque; 2164977aff10SAlex Williamson 2165977aff10SAlex Williamson if (object_dynamic_cast(obj, TYPE_PCI_HOST_BRIDGE)) { 2166977aff10SAlex Williamson PCIBus *bus = PCI_HOST_BRIDGE(obj)->bus; 2167977aff10SAlex Williamson 2168977aff10SAlex Williamson if (bus) { 2169977aff10SAlex Williamson pci_for_each_device(bus, pci_bus_num(bus), insert_ivhd, ivhd_blob); 2170977aff10SAlex Williamson } 2171977aff10SAlex Williamson } 2172977aff10SAlex Williamson 2173977aff10SAlex Williamson return 0; 2174977aff10SAlex Williamson } 2175977aff10SAlex Williamson 2176fb9f5926SDavid Kiarie static void 2177602b4582SMarian Postevca build_amd_iommu(GArray *table_data, BIOSLinker *linker, const char *oem_id, 2178602b4582SMarian Postevca const char *oem_table_id) 2179fb9f5926SDavid Kiarie { 2180977aff10SAlex Williamson int ivhd_table_len = 24; 2181fb9f5926SDavid Kiarie int iommu_start = table_data->len; 2182fb9f5926SDavid Kiarie AMDVIState *s = AMD_IOMMU_DEVICE(x86_iommu_get_default()); 2183977aff10SAlex Williamson GArray *ivhd_blob = g_array_new(false, true, 1); 2184fb9f5926SDavid Kiarie 2185fb9f5926SDavid Kiarie /* IVRS header */ 2186fb9f5926SDavid Kiarie acpi_data_push(table_data, sizeof(AcpiTableHeader)); 2187fb9f5926SDavid Kiarie /* IVinfo - IO virtualization information common to all 2188fb9f5926SDavid Kiarie * IOMMU units in a system 2189fb9f5926SDavid Kiarie */ 2190fb9f5926SDavid Kiarie build_append_int_noprefix(table_data, 40UL << 8/* PASize */, 4); 2191fb9f5926SDavid Kiarie /* reserved */ 2192fb9f5926SDavid Kiarie build_append_int_noprefix(table_data, 0, 8); 2193fb9f5926SDavid Kiarie 2194fb9f5926SDavid Kiarie /* IVHD definition - type 10h */ 2195fb9f5926SDavid Kiarie build_append_int_noprefix(table_data, 0x10, 1); 2196fb9f5926SDavid Kiarie /* virtualization flags */ 2197fb9f5926SDavid Kiarie build_append_int_noprefix(table_data, 2198fb9f5926SDavid Kiarie (1UL << 0) | /* HtTunEn */ 2199fb9f5926SDavid Kiarie (1UL << 4) | /* iotblSup */ 2200fb9f5926SDavid Kiarie (1UL << 6) | /* PrefSup */ 2201fb9f5926SDavid Kiarie (1UL << 7), /* PPRSup */ 2202fb9f5926SDavid Kiarie 1); 2203c028818dSSingh, Brijesh 2204c028818dSSingh, Brijesh /* 2205977aff10SAlex Williamson * A PCI bus walk, for each PCI host bridge, is necessary to create a 2206977aff10SAlex Williamson * complete set of IVHD entries. Do this into a separate blob so that we 2207977aff10SAlex Williamson * can calculate the total IVRS table length here and then append the new 2208977aff10SAlex Williamson * blob further below. Fall back to an entry covering all devices, which 2209977aff10SAlex Williamson * is sufficient when no aliases are present. 2210977aff10SAlex Williamson */ 2211977aff10SAlex Williamson object_child_foreach_recursive(object_get_root(), 2212977aff10SAlex Williamson ivrs_host_bridges, ivhd_blob); 2213977aff10SAlex Williamson 2214977aff10SAlex Williamson if (!ivhd_blob->len) { 2215977aff10SAlex Williamson /* 2216977aff10SAlex Williamson * Type 1 device entry reporting all devices 2217977aff10SAlex Williamson * These are 4-byte device entries currently reporting the range of 2218977aff10SAlex Williamson * Refer to Spec - Table 95:IVHD Device Entry Type Codes(4-byte) 2219977aff10SAlex Williamson */ 2220977aff10SAlex Williamson build_append_int_noprefix(ivhd_blob, 0x0000001, 4); 2221977aff10SAlex Williamson } 2222977aff10SAlex Williamson 2223977aff10SAlex Williamson ivhd_table_len += ivhd_blob->len; 2224977aff10SAlex Williamson 2225977aff10SAlex Williamson /* 2226c028818dSSingh, Brijesh * When interrupt remapping is supported, we add a special IVHD device 2227c028818dSSingh, Brijesh * for type IO-APIC. 2228c028818dSSingh, Brijesh */ 2229a924b3d8SPeter Xu if (x86_iommu_ir_supported(x86_iommu_get_default())) { 2230c028818dSSingh, Brijesh ivhd_table_len += 8; 2231c028818dSSingh, Brijesh } 2232977aff10SAlex Williamson 2233fb9f5926SDavid Kiarie /* IVHD length */ 2234c028818dSSingh, Brijesh build_append_int_noprefix(table_data, ivhd_table_len, 2); 2235fb9f5926SDavid Kiarie /* DeviceID */ 2236fb9f5926SDavid Kiarie build_append_int_noprefix(table_data, s->devid, 2); 2237fb9f5926SDavid Kiarie /* Capability offset */ 2238fb9f5926SDavid Kiarie build_append_int_noprefix(table_data, s->capab_offset, 2); 2239fb9f5926SDavid Kiarie /* IOMMU base address */ 2240fb9f5926SDavid Kiarie build_append_int_noprefix(table_data, s->mmio.addr, 8); 2241fb9f5926SDavid Kiarie /* PCI Segment Group */ 2242fb9f5926SDavid Kiarie build_append_int_noprefix(table_data, 0, 2); 2243fb9f5926SDavid Kiarie /* IOMMU info */ 2244fb9f5926SDavid Kiarie build_append_int_noprefix(table_data, 0, 2); 2245fb9f5926SDavid Kiarie /* IOMMU Feature Reporting */ 2246fb9f5926SDavid Kiarie build_append_int_noprefix(table_data, 2247fb9f5926SDavid Kiarie (48UL << 30) | /* HATS */ 2248fb9f5926SDavid Kiarie (48UL << 28) | /* GATS */ 224912499b23SSingh, Brijesh (1UL << 2) | /* GTSup */ 225012499b23SSingh, Brijesh (1UL << 6), /* GASup */ 2251fb9f5926SDavid Kiarie 4); 2252977aff10SAlex Williamson 2253977aff10SAlex Williamson /* IVHD entries as found above */ 2254977aff10SAlex Williamson g_array_append_vals(table_data, ivhd_blob->data, ivhd_blob->len); 2255977aff10SAlex Williamson g_array_free(ivhd_blob, TRUE); 2256fb9f5926SDavid Kiarie 2257c028818dSSingh, Brijesh /* 2258c028818dSSingh, Brijesh * Add a special IVHD device type. 2259c028818dSSingh, Brijesh * Refer to spec - Table 95: IVHD device entry type codes 2260c028818dSSingh, Brijesh * 2261c028818dSSingh, Brijesh * Linux IOMMU driver checks for the special IVHD device (type IO-APIC). 2262c028818dSSingh, Brijesh * See Linux kernel commit 'c2ff5cf5294bcbd7fa50f7d860e90a66db7e5059' 2263c028818dSSingh, Brijesh */ 2264a924b3d8SPeter Xu if (x86_iommu_ir_supported(x86_iommu_get_default())) { 2265c028818dSSingh, Brijesh build_append_int_noprefix(table_data, 2266c028818dSSingh, Brijesh (0x1ull << 56) | /* type IOAPIC */ 2267c028818dSSingh, Brijesh (IOAPIC_SB_DEVID << 40) | /* IOAPIC devid */ 2268c028818dSSingh, Brijesh 0x48, /* special device */ 2269c028818dSSingh, Brijesh 8); 2270c028818dSSingh, Brijesh } 2271c028818dSSingh, Brijesh 2272fb9f5926SDavid Kiarie build_header(linker, table_data, (void *)(table_data->data + iommu_start), 2273602b4582SMarian Postevca "IVRS", table_data->len - iommu_start, 1, oem_id, 2274602b4582SMarian Postevca oem_table_id); 2275fb9f5926SDavid Kiarie } 2276d4eb9119SLe Tan 227772c194f7SMichael S. Tsirkin typedef 227872c194f7SMichael S. Tsirkin struct AcpiBuildState { 227972c194f7SMichael S. Tsirkin /* Copy of table in RAM (for patching). */ 2280339240b5SPaolo Bonzini MemoryRegion *table_mr; 228172c194f7SMichael S. Tsirkin /* Is table patched? */ 228272c194f7SMichael S. Tsirkin uint8_t patched; 2283d70414a5SMichael S. Tsirkin void *rsdp; 2284339240b5SPaolo Bonzini MemoryRegion *rsdp_mr; 2285339240b5SPaolo Bonzini MemoryRegion *linker_mr; 228672c194f7SMichael S. Tsirkin } AcpiBuildState; 228772c194f7SMichael S. Tsirkin 228872c194f7SMichael S. Tsirkin static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg) 228972c194f7SMichael S. Tsirkin { 229072c194f7SMichael S. Tsirkin Object *pci_host; 229172c194f7SMichael S. Tsirkin QObject *o; 229272c194f7SMichael S. Tsirkin 2293ca6c1855SMarcel Apfelbaum pci_host = acpi_get_i386_pci_host(); 229472c194f7SMichael S. Tsirkin g_assert(pci_host); 229572c194f7SMichael S. Tsirkin 229672c194f7SMichael S. Tsirkin o = object_property_get_qobject(pci_host, PCIE_HOST_MCFG_BASE, NULL); 229772c194f7SMichael S. Tsirkin if (!o) { 229872c194f7SMichael S. Tsirkin return false; 229972c194f7SMichael S. Tsirkin } 2300c309434eSWei Yang mcfg->base = qnum_get_uint(qobject_to(QNum, o)); 2301cb3e7f08SMarc-André Lureau qobject_unref(o); 2302c309434eSWei Yang if (mcfg->base == PCIE_BASE_ADDR_UNMAPPED) { 2303fe4970adSIgor Mammedov return false; 2304fe4970adSIgor Mammedov } 230572c194f7SMichael S. Tsirkin 230672c194f7SMichael S. Tsirkin o = object_property_get_qobject(pci_host, PCIE_HOST_MCFG_SIZE, NULL); 230772c194f7SMichael S. Tsirkin assert(o); 2308c309434eSWei Yang mcfg->size = qnum_get_uint(qobject_to(QNum, o)); 2309cb3e7f08SMarc-André Lureau qobject_unref(o); 231072c194f7SMichael S. Tsirkin return true; 231172c194f7SMichael S. Tsirkin } 231272c194f7SMichael S. Tsirkin 231372c194f7SMichael S. Tsirkin static 23143d3ebcadSIgor Mammedov void acpi_build(AcpiBuildTables *tables, MachineState *machine) 231572c194f7SMichael S. Tsirkin { 23163d3ebcadSIgor Mammedov PCMachineState *pcms = PC_MACHINE(machine); 2317bb292f5aSEduardo Habkost PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); 2318f0bb276bSPaolo Bonzini X86MachineState *x86ms = X86_MACHINE(machine); 231972c194f7SMichael S. Tsirkin GArray *table_offsets; 232041fa5c04SIgor Mammedov unsigned facs, dsdt, rsdt, fadt; 232172c194f7SMichael S. Tsirkin AcpiPmInfo pm; 232272c194f7SMichael S. Tsirkin AcpiMiscInfo misc; 232372c194f7SMichael S. Tsirkin AcpiMcfgInfo mcfg; 232401c9742dSMarkus Armbruster Range pci_hole, pci_hole64; 232572c194f7SMichael S. Tsirkin uint8_t *u; 232607fb6176SPaolo Bonzini size_t aml_len = 0; 23277c2c1fa5SIgor Mammedov GArray *tables_blob = tables->table_data; 2328ae123749SLaszlo Ersek AcpiSlicOem slic_oem = { .id = NULL, .table_id = NULL }; 2329d03637bcSBen Warren Object *vmgenid_dev; 2330602b4582SMarian Postevca char *oem_id; 2331602b4582SMarian Postevca char *oem_table_id; 233272c194f7SMichael S. Tsirkin 23330e11fc69SLike Xu acpi_get_pm_info(machine, &pm); 233472c194f7SMichael S. Tsirkin acpi_get_misc_info(&misc); 233501c9742dSMarkus Armbruster acpi_get_pci_holes(&pci_hole, &pci_hole64); 2336ae123749SLaszlo Ersek acpi_get_slic_oem(&slic_oem); 233772c194f7SMichael S. Tsirkin 2338602b4582SMarian Postevca if (slic_oem.id) { 2339602b4582SMarian Postevca oem_id = slic_oem.id; 2340602b4582SMarian Postevca } else { 2341602b4582SMarian Postevca oem_id = pcms->oem_id; 2342602b4582SMarian Postevca } 2343602b4582SMarian Postevca 2344602b4582SMarian Postevca if (slic_oem.table_id) { 2345602b4582SMarian Postevca oem_table_id = slic_oem.table_id; 2346602b4582SMarian Postevca } else { 2347602b4582SMarian Postevca oem_table_id = pcms->oem_table_id; 2348602b4582SMarian Postevca } 2349602b4582SMarian Postevca 235072c194f7SMichael S. Tsirkin table_offsets = g_array_new(false, true /* clear */, 235172c194f7SMichael S. Tsirkin sizeof(uint32_t)); 23528b310fc4SGonglei ACPI_BUILD_DPRINTF("init ACPI tables\n"); 235372c194f7SMichael S. Tsirkin 2354ad9671b8SIgor Mammedov bios_linker_loader_alloc(tables->linker, 2355ad9671b8SIgor Mammedov ACPI_BUILD_TABLE_FILE, tables_blob, 235672c194f7SMichael S. Tsirkin 64 /* Ensure FACS is aligned */, 235772c194f7SMichael S. Tsirkin false /* high memory */); 235872c194f7SMichael S. Tsirkin 235972c194f7SMichael S. Tsirkin /* 236072c194f7SMichael S. Tsirkin * FACS is pointed to by FADT. 236172c194f7SMichael S. Tsirkin * We place it first since it's the only table that has alignment 236272c194f7SMichael S. Tsirkin * requirements. 236372c194f7SMichael S. Tsirkin */ 23647c2c1fa5SIgor Mammedov facs = tables_blob->len; 2365009180bdSWei Yang build_facs(tables_blob); 236672c194f7SMichael S. Tsirkin 236772c194f7SMichael S. Tsirkin /* DSDT is pointed to by FADT */ 23687c2c1fa5SIgor Mammedov dsdt = tables_blob->len; 236901c9742dSMarkus Armbruster build_dsdt(tables_blob, tables->linker, &pm, &misc, 237001c9742dSMarkus Armbruster &pci_hole, &pci_hole64, machine); 237172c194f7SMichael S. Tsirkin 237207fb6176SPaolo Bonzini /* Count the size of the DSDT and SSDT, we will need it for legacy 237307fb6176SPaolo Bonzini * sizing of ACPI tables. 237407fb6176SPaolo Bonzini */ 23757c2c1fa5SIgor Mammedov aml_len += tables_blob->len - dsdt; 237607fb6176SPaolo Bonzini 237772c194f7SMichael S. Tsirkin /* ACPI tables pointed to by RSDT */ 237841fa5c04SIgor Mammedov fadt = tables_blob->len; 23797c2c1fa5SIgor Mammedov acpi_add_table(table_offsets, tables_blob); 2380937d1b58SIgor Mammedov pm.fadt.facs_tbl_offset = &facs; 2381937d1b58SIgor Mammedov pm.fadt.dsdt_tbl_offset = &dsdt; 2382937d1b58SIgor Mammedov pm.fadt.xdsdt_tbl_offset = &dsdt; 2383602b4582SMarian Postevca build_fadt(tables_blob, tables->linker, &pm.fadt, oem_id, oem_table_id); 238441fa5c04SIgor Mammedov aml_len += tables_blob->len - fadt; 238572c194f7SMichael S. Tsirkin 23867c2c1fa5SIgor Mammedov acpi_add_table(table_offsets, tables_blob); 2387eb66ffabSGerd Hoffmann acpi_build_madt(tables_blob, tables->linker, x86ms, 2388602b4582SMarian Postevca ACPI_DEVICE_IF(x86ms->acpi_dev), pcms->oem_id, 2389602b4582SMarian Postevca pcms->oem_table_id); 23909ac1c4c0SMichael S. Tsirkin 2391d03637bcSBen Warren vmgenid_dev = find_vmgenid_dev(); 2392d03637bcSBen Warren if (vmgenid_dev) { 2393d03637bcSBen Warren acpi_add_table(table_offsets, tables_blob); 2394d03637bcSBen Warren vmgenid_build_acpi(VMGENID(vmgenid_dev), tables_blob, 2395602b4582SMarian Postevca tables->vmgenid, tables->linker, pcms->oem_id); 2396d03637bcSBen Warren } 2397d03637bcSBen Warren 239872c194f7SMichael S. Tsirkin if (misc.has_hpet) { 23997c2c1fa5SIgor Mammedov acpi_add_table(table_offsets, tables_blob); 2400602b4582SMarian Postevca build_hpet(tables_blob, tables->linker, pcms->oem_id, 2401602b4582SMarian Postevca pcms->oem_table_id); 240272c194f7SMichael S. Tsirkin } 24035cb18b3dSStefan Berger if (misc.tpm_version != TPM_VERSION_UNSPEC) { 24047e7c1b84SStefan Berger if (misc.tpm_version == TPM_VERSION_1_2) { 24057c2c1fa5SIgor Mammedov acpi_add_table(table_offsets, tables_blob); 2406602b4582SMarian Postevca build_tpm_tcpa(tables_blob, tables->linker, tables->tcpalog, 2407602b4582SMarian Postevca pcms->oem_id, pcms->oem_table_id); 24087e7c1b84SStefan Berger } else { /* TPM_VERSION_2_0 */ 24097c2c1fa5SIgor Mammedov acpi_add_table(table_offsets, tables_blob); 2410602b4582SMarian Postevca build_tpm2(tables_blob, tables->linker, tables->tcpalog, 2411602b4582SMarian Postevca pcms->oem_id, pcms->oem_table_id); 24125cb18b3dSStefan Berger } 2413711b20b4SStefan Berger } 2414dd4c2f01SEduardo Habkost if (pcms->numa_nodes) { 24157c2c1fa5SIgor Mammedov acpi_add_table(table_offsets, tables_blob); 24163d3ebcadSIgor Mammedov build_srat(tables_blob, tables->linker, machine); 2417118154b7STao Xu if (machine->numa_state->have_numa_distance) { 24180f203430SHe Chen acpi_add_table(table_offsets, tables_blob); 2419602b4582SMarian Postevca build_slit(tables_blob, tables->linker, machine, pcms->oem_id, 2420602b4582SMarian Postevca pcms->oem_table_id); 24210f203430SHe Chen } 2422e6f123c3SLiu Jingqi if (machine->numa_state->hmat_enabled) { 2423e6f123c3SLiu Jingqi acpi_add_table(table_offsets, tables_blob); 2424602b4582SMarian Postevca build_hmat(tables_blob, tables->linker, machine->numa_state, 2425602b4582SMarian Postevca pcms->oem_id, pcms->oem_table_id); 2426e6f123c3SLiu Jingqi } 242772c194f7SMichael S. Tsirkin } 242872c194f7SMichael S. Tsirkin if (acpi_get_mcfg(&mcfg)) { 24297c2c1fa5SIgor Mammedov acpi_add_table(table_offsets, tables_blob); 2430602b4582SMarian Postevca build_mcfg(tables_blob, tables->linker, &mcfg, pcms->oem_id, 2431602b4582SMarian Postevca pcms->oem_table_id); 243272c194f7SMichael S. Tsirkin } 2433fb9f5926SDavid Kiarie if (x86_iommu_get_default()) { 2434fb9f5926SDavid Kiarie IommuType IOMMUType = x86_iommu_get_type(); 2435fb9f5926SDavid Kiarie if (IOMMUType == TYPE_AMD) { 2436fb9f5926SDavid Kiarie acpi_add_table(table_offsets, tables_blob); 2437602b4582SMarian Postevca build_amd_iommu(tables_blob, tables->linker, pcms->oem_id, 2438602b4582SMarian Postevca pcms->oem_table_id); 2439fb9f5926SDavid Kiarie } else if (IOMMUType == TYPE_INTEL) { 24407c2c1fa5SIgor Mammedov acpi_add_table(table_offsets, tables_blob); 2441602b4582SMarian Postevca build_dmar_q35(tables_blob, tables->linker, pcms->oem_id, 2442602b4582SMarian Postevca pcms->oem_table_id); 2443d4eb9119SLe Tan } 2444fb9f5926SDavid Kiarie } 2445f6a0d06bSEric Auger if (machine->nvdimms_state->is_enabled) { 2446ad9671b8SIgor Mammedov nvdimm_build_acpi(table_offsets, tables_blob, tables->linker, 2447602b4582SMarian Postevca machine->nvdimms_state, machine->ram_slots, 2448602b4582SMarian Postevca pcms->oem_id, pcms->oem_table_id); 244987252e1bSXiao Guangrong } 245087252e1bSXiao Guangrong 245114cda350SLiran Alon acpi_add_table(table_offsets, tables_blob); 2452602b4582SMarian Postevca build_waet(tables_blob, tables->linker, pcms->oem_id, pcms->oem_table_id); 245314cda350SLiran Alon 245472c194f7SMichael S. Tsirkin /* Add tables supplied by user (if any) */ 245572c194f7SMichael S. Tsirkin for (u = acpi_table_first(); u; u = acpi_table_next(u)) { 245672c194f7SMichael S. Tsirkin unsigned len = acpi_table_len(u); 245772c194f7SMichael S. Tsirkin 24587c2c1fa5SIgor Mammedov acpi_add_table(table_offsets, tables_blob); 24597c2c1fa5SIgor Mammedov g_array_append_vals(tables_blob, u, len); 246072c194f7SMichael S. Tsirkin } 246172c194f7SMichael S. Tsirkin 246272c194f7SMichael S. Tsirkin /* RSDT is pointed to by RSDP */ 24637c2c1fa5SIgor Mammedov rsdt = tables_blob->len; 2464ae123749SLaszlo Ersek build_rsdt(tables_blob, tables->linker, table_offsets, 2465602b4582SMarian Postevca oem_id, oem_table_id); 246672c194f7SMichael S. Tsirkin 246772c194f7SMichael S. Tsirkin /* RSDP is in FSEG memory, so allocate it separately */ 2468a46ce1c2SSamuel Ortiz { 2469a46ce1c2SSamuel Ortiz AcpiRsdpData rsdp_data = { 2470a46ce1c2SSamuel Ortiz .revision = 0, 2471602b4582SMarian Postevca .oem_id = pcms->oem_id, 2472a46ce1c2SSamuel Ortiz .xsdt_tbl_offset = NULL, 2473a46ce1c2SSamuel Ortiz .rsdt_tbl_offset = &rsdt, 2474a46ce1c2SSamuel Ortiz }; 2475a46ce1c2SSamuel Ortiz build_rsdp(tables->rsdp, tables->linker, &rsdp_data); 2476a46ce1c2SSamuel Ortiz if (!pcmc->rsdp_in_ram) { 2477a46ce1c2SSamuel Ortiz /* We used to allocate some extra space for RSDP revision 2 but 2478a46ce1c2SSamuel Ortiz * only used the RSDP revision 0 space. The extra bytes were 2479a46ce1c2SSamuel Ortiz * zeroed out and not used. 2480a46ce1c2SSamuel Ortiz * Here we continue wasting those extra 16 bytes to make sure we 2481a46ce1c2SSamuel Ortiz * don't break migration for machine types 2.2 and older due to 2482a46ce1c2SSamuel Ortiz * RSDP blob size mismatch. 2483a46ce1c2SSamuel Ortiz */ 2484a46ce1c2SSamuel Ortiz build_append_int_noprefix(tables->rsdp, 0, 16); 2485a46ce1c2SSamuel Ortiz } 2486a46ce1c2SSamuel Ortiz } 248772c194f7SMichael S. Tsirkin 248807fb6176SPaolo Bonzini /* We'll expose it all to Guest so we want to reduce 248972c194f7SMichael S. Tsirkin * chance of size changes. 249007fb6176SPaolo Bonzini * 249107fb6176SPaolo Bonzini * We used to align the tables to 4k, but of course this would 249207fb6176SPaolo Bonzini * too simple to be enough. 4k turned out to be too small an 249307fb6176SPaolo Bonzini * alignment very soon, and in fact it is almost impossible to 249407fb6176SPaolo Bonzini * keep the table size stable for all (max_cpus, max_memory_slots) 249507fb6176SPaolo Bonzini * combinations. So the table size is always 64k for pc-i440fx-2.1 249607fb6176SPaolo Bonzini * and we give an error if the table grows beyond that limit. 249707fb6176SPaolo Bonzini * 249807fb6176SPaolo Bonzini * We still have the problem of migrating from "-M pc-i440fx-2.0". For 249907fb6176SPaolo Bonzini * that, we exploit the fact that QEMU 2.1 generates _smaller_ tables 250007fb6176SPaolo Bonzini * than 2.0 and we can always pad the smaller tables with zeros. We can 250107fb6176SPaolo Bonzini * then use the exact size of the 2.0 tables. 250207fb6176SPaolo Bonzini * 250307fb6176SPaolo Bonzini * All this is for PIIX4, since QEMU 2.0 didn't support Q35 migration. 250472c194f7SMichael S. Tsirkin */ 2505bb292f5aSEduardo Habkost if (pcmc->legacy_acpi_table_size) { 250607fb6176SPaolo Bonzini /* Subtracting aml_len gives the size of fixed tables. Then add the 250707fb6176SPaolo Bonzini * size of the PIIX4 DSDT/SSDT in QEMU 2.0. 250807fb6176SPaolo Bonzini */ 250907fb6176SPaolo Bonzini int legacy_aml_len = 2510bb292f5aSEduardo Habkost pcmc->legacy_acpi_table_size + 2511f0bb276bSPaolo Bonzini ACPI_BUILD_LEGACY_CPU_AML_SIZE * x86ms->apic_id_limit; 251207fb6176SPaolo Bonzini int legacy_table_size = 25137c2c1fa5SIgor Mammedov ROUND_UP(tables_blob->len - aml_len + legacy_aml_len, 251407fb6176SPaolo Bonzini ACPI_BUILD_ALIGN_SIZE); 25157c2c1fa5SIgor Mammedov if (tables_blob->len > legacy_table_size) { 251607fb6176SPaolo Bonzini /* Should happen only with PCI bridges and -M pc-i440fx-2.0. */ 25179e5d2c52SAlistair Francis warn_report("ACPI table size %u exceeds %d bytes," 25189e5d2c52SAlistair Francis " migration may not work", 25199e5d2c52SAlistair Francis tables_blob->len, legacy_table_size); 25209e5d2c52SAlistair Francis error_printf("Try removing CPUs, NUMA nodes, memory slots" 25219e5d2c52SAlistair Francis " or PCI bridges."); 252207fb6176SPaolo Bonzini } 25237c2c1fa5SIgor Mammedov g_array_set_size(tables_blob, legacy_table_size); 252407fb6176SPaolo Bonzini } else { 2525868270f2SMichael S. Tsirkin /* Make sure we have a buffer in case we need to resize the tables. */ 25267c2c1fa5SIgor Mammedov if (tables_blob->len > ACPI_BUILD_TABLE_SIZE / 2) { 252718045fb9SPaolo Bonzini /* As of QEMU 2.1, this fires with 160 VCPUs and 255 memory slots. */ 25289e5d2c52SAlistair Francis warn_report("ACPI table size %u exceeds %d bytes," 25299e5d2c52SAlistair Francis " migration may not work", 25309e5d2c52SAlistair Francis tables_blob->len, ACPI_BUILD_TABLE_SIZE / 2); 25319e5d2c52SAlistair Francis error_printf("Try removing CPUs, NUMA nodes, memory slots" 25329e5d2c52SAlistair Francis " or PCI bridges."); 253318045fb9SPaolo Bonzini } 25347c2c1fa5SIgor Mammedov acpi_align_size(tables_blob, ACPI_BUILD_TABLE_SIZE); 253507fb6176SPaolo Bonzini } 253672c194f7SMichael S. Tsirkin 25370e9b9edaSIgor Mammedov acpi_align_size(tables->linker->cmd_blob, ACPI_BUILD_ALIGN_SIZE); 253872c194f7SMichael S. Tsirkin 253972c194f7SMichael S. Tsirkin /* Cleanup memory that's no longer used. */ 254072c194f7SMichael S. Tsirkin g_array_free(table_offsets, true); 254172c194f7SMichael S. Tsirkin } 254272c194f7SMichael S. Tsirkin 2543339240b5SPaolo Bonzini static void acpi_ram_update(MemoryRegion *mr, GArray *data) 254442d85900SMichael S. Tsirkin { 254542d85900SMichael S. Tsirkin uint32_t size = acpi_data_len(data); 254642d85900SMichael S. Tsirkin 254742d85900SMichael S. Tsirkin /* Make sure RAM size is correct - in case it got changed e.g. by migration */ 2548339240b5SPaolo Bonzini memory_region_ram_resize(mr, size, &error_abort); 254942d85900SMichael S. Tsirkin 2550339240b5SPaolo Bonzini memcpy(memory_region_get_ram_ptr(mr), data->data, size); 2551339240b5SPaolo Bonzini memory_region_set_dirty(mr, 0, size); 255242d85900SMichael S. Tsirkin } 255342d85900SMichael S. Tsirkin 25543f8752b4SGabriel L. Somlo static void acpi_build_update(void *build_opaque) 255572c194f7SMichael S. Tsirkin { 255672c194f7SMichael S. Tsirkin AcpiBuildState *build_state = build_opaque; 255772c194f7SMichael S. Tsirkin AcpiBuildTables tables; 255872c194f7SMichael S. Tsirkin 255972c194f7SMichael S. Tsirkin /* No state to update or already patched? Nothing to do. */ 256072c194f7SMichael S. Tsirkin if (!build_state || build_state->patched) { 256172c194f7SMichael S. Tsirkin return; 256272c194f7SMichael S. Tsirkin } 256372c194f7SMichael S. Tsirkin build_state->patched = 1; 256472c194f7SMichael S. Tsirkin 256572c194f7SMichael S. Tsirkin acpi_build_tables_init(&tables); 256672c194f7SMichael S. Tsirkin 25673d3ebcadSIgor Mammedov acpi_build(&tables, MACHINE(qdev_get_machine())); 256872c194f7SMichael S. Tsirkin 2569339240b5SPaolo Bonzini acpi_ram_update(build_state->table_mr, tables.table_data); 2570a1666142SMichael S. Tsirkin 257142d85900SMichael S. Tsirkin if (build_state->rsdp) { 2572d70414a5SMichael S. Tsirkin memcpy(build_state->rsdp, tables.rsdp->data, acpi_data_len(tables.rsdp)); 257342d85900SMichael S. Tsirkin } else { 2574339240b5SPaolo Bonzini acpi_ram_update(build_state->rsdp_mr, tables.rsdp); 257542d85900SMichael S. Tsirkin } 2576ad5b88b1SMichael S. Tsirkin 25770e9b9edaSIgor Mammedov acpi_ram_update(build_state->linker_mr, tables.linker->cmd_blob); 257872c194f7SMichael S. Tsirkin acpi_build_tables_cleanup(&tables, true); 257972c194f7SMichael S. Tsirkin } 258072c194f7SMichael S. Tsirkin 258172c194f7SMichael S. Tsirkin static void acpi_build_reset(void *build_opaque) 258272c194f7SMichael S. Tsirkin { 258372c194f7SMichael S. Tsirkin AcpiBuildState *build_state = build_opaque; 258472c194f7SMichael S. Tsirkin build_state->patched = 0; 258572c194f7SMichael S. Tsirkin } 258672c194f7SMichael S. Tsirkin 258772c194f7SMichael S. Tsirkin static const VMStateDescription vmstate_acpi_build = { 258872c194f7SMichael S. Tsirkin .name = "acpi_build", 258972c194f7SMichael S. Tsirkin .version_id = 1, 259072c194f7SMichael S. Tsirkin .minimum_version_id = 1, 259172c194f7SMichael S. Tsirkin .fields = (VMStateField[]) { 259272c194f7SMichael S. Tsirkin VMSTATE_UINT8(patched, AcpiBuildState), 259372c194f7SMichael S. Tsirkin VMSTATE_END_OF_LIST() 259472c194f7SMichael S. Tsirkin }, 259572c194f7SMichael S. Tsirkin }; 259672c194f7SMichael S. Tsirkin 2597fb306ffeSEduardo Habkost void acpi_setup(void) 259872c194f7SMichael S. Tsirkin { 2599fb306ffeSEduardo Habkost PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); 2600bb292f5aSEduardo Habkost PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); 2601f0bb276bSPaolo Bonzini X86MachineState *x86ms = X86_MACHINE(pcms); 260272c194f7SMichael S. Tsirkin AcpiBuildTables tables; 260372c194f7SMichael S. Tsirkin AcpiBuildState *build_state; 2604d03637bcSBen Warren Object *vmgenid_dev; 26050fe24669SStefan Berger TPMIf *tpm; 26060fe24669SStefan Berger static FwCfgTPMConfig tpm_config; 260772c194f7SMichael S. Tsirkin 2608f0bb276bSPaolo Bonzini if (!x86ms->fw_cfg) { 26098b310fc4SGonglei ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n"); 261072c194f7SMichael S. Tsirkin return; 261172c194f7SMichael S. Tsirkin } 261272c194f7SMichael S. Tsirkin 2613021746c1SWei Liu if (!pcms->acpi_build_enabled) { 26148b310fc4SGonglei ACPI_BUILD_DPRINTF("ACPI build disabled. Bailing out.\n"); 261572c194f7SMichael S. Tsirkin return; 261672c194f7SMichael S. Tsirkin } 261772c194f7SMichael S. Tsirkin 261817e89077SGerd Hoffmann if (!x86_machine_is_acpi_enabled(X86_MACHINE(pcms))) { 26198b310fc4SGonglei ACPI_BUILD_DPRINTF("ACPI disabled. Bailing out.\n"); 262081adc513SMichael S. Tsirkin return; 262181adc513SMichael S. Tsirkin } 262281adc513SMichael S. Tsirkin 262372c194f7SMichael S. Tsirkin build_state = g_malloc0(sizeof *build_state); 262472c194f7SMichael S. Tsirkin 262572c194f7SMichael S. Tsirkin acpi_build_tables_init(&tables); 26263d3ebcadSIgor Mammedov acpi_build(&tables, MACHINE(pcms)); 262772c194f7SMichael S. Tsirkin 262872c194f7SMichael S. Tsirkin /* Now expose it all to Guest */ 262982f76c67SWei Yang build_state->table_mr = acpi_add_rom_blob(acpi_build_update, 263082f76c67SWei Yang build_state, tables.table_data, 2631a1666142SMichael S. Tsirkin ACPI_BUILD_TABLE_FILE, 2632a1666142SMichael S. Tsirkin ACPI_BUILD_TABLE_MAX_SIZE); 2633339240b5SPaolo Bonzini assert(build_state->table_mr != NULL); 263472c194f7SMichael S. Tsirkin 2635339240b5SPaolo Bonzini build_state->linker_mr = 263682f76c67SWei Yang acpi_add_rom_blob(acpi_build_update, build_state, 2637bac78f9cSShameer Kolothum tables.linker->cmd_blob, ACPI_BUILD_LOADER_FILE, 0); 263872c194f7SMichael S. Tsirkin 2639f0bb276bSPaolo Bonzini fw_cfg_add_file(x86ms->fw_cfg, ACPI_BUILD_TPMLOG_FILE, 264042a5b308SStefan Berger tables.tcpalog->data, acpi_data_len(tables.tcpalog)); 264142a5b308SStefan Berger 26420fe24669SStefan Berger tpm = tpm_find(); 26430fe24669SStefan Berger if (tpm && object_property_get_bool(OBJECT(tpm), "ppi", &error_abort)) { 26440fe24669SStefan Berger tpm_config = (FwCfgTPMConfig) { 26450fe24669SStefan Berger .tpmppi_address = cpu_to_le32(TPM_PPI_ADDR_BASE), 26460fe24669SStefan Berger .tpm_version = tpm_get_version(tpm), 2647ac6dd31eSStefan Berger .tpmppi_version = TPM_PPI_VERSION_1_30 26480fe24669SStefan Berger }; 2649f0bb276bSPaolo Bonzini fw_cfg_add_file(x86ms->fw_cfg, "etc/tpm/config", 26500fe24669SStefan Berger &tpm_config, sizeof tpm_config); 26510fe24669SStefan Berger } 26520fe24669SStefan Berger 2653d03637bcSBen Warren vmgenid_dev = find_vmgenid_dev(); 2654d03637bcSBen Warren if (vmgenid_dev) { 2655f0bb276bSPaolo Bonzini vmgenid_add_fw_cfg(VMGENID(vmgenid_dev), x86ms->fw_cfg, 2656d03637bcSBen Warren tables.vmgenid); 2657d03637bcSBen Warren } 2658d03637bcSBen Warren 2659bb292f5aSEduardo Habkost if (!pcmc->rsdp_in_ram) { 266072c194f7SMichael S. Tsirkin /* 2661358774d7SIgor Mammedov * Keep for compatibility with old machine types. 2662d70414a5SMichael S. Tsirkin * Though RSDP is small, its contents isn't immutable, so 2663afaa2e4bSMichael S. Tsirkin * we'll update it along with the rest of tables on guest access. 266472c194f7SMichael S. Tsirkin */ 2665afaa2e4bSMichael S. Tsirkin uint32_t rsdp_size = acpi_data_len(tables.rsdp); 2666afaa2e4bSMichael S. Tsirkin 2667afaa2e4bSMichael S. Tsirkin build_state->rsdp = g_memdup(tables.rsdp->data, rsdp_size); 2668f0bb276bSPaolo Bonzini fw_cfg_add_file_callback(x86ms->fw_cfg, ACPI_BUILD_RSDP_FILE, 26695f9252f7SMarc-André Lureau acpi_build_update, NULL, build_state, 2670baf2d5bfSMichael S. Tsirkin build_state->rsdp, rsdp_size, true); 2671339240b5SPaolo Bonzini build_state->rsdp_mr = NULL; 2672358774d7SIgor Mammedov } else { 267342d85900SMichael S. Tsirkin build_state->rsdp = NULL; 267482f76c67SWei Yang build_state->rsdp_mr = acpi_add_rom_blob(acpi_build_update, 267582f76c67SWei Yang build_state, tables.rsdp, 267642d85900SMichael S. Tsirkin ACPI_BUILD_RSDP_FILE, 0); 2677358774d7SIgor Mammedov } 2678d70414a5SMichael S. Tsirkin 267972c194f7SMichael S. Tsirkin qemu_register_reset(acpi_build_reset, build_state); 268072c194f7SMichael S. Tsirkin acpi_build_reset(build_state); 268172c194f7SMichael S. Tsirkin vmstate_register(NULL, 0, &vmstate_acpi_build, build_state); 268272c194f7SMichael S. Tsirkin 268372c194f7SMichael S. Tsirkin /* Cleanup tables but don't free the memory: we track it 268472c194f7SMichael S. Tsirkin * in build_state. 268572c194f7SMichael S. Tsirkin */ 268672c194f7SMichael S. Tsirkin acpi_build_tables_cleanup(&tables, false); 268772c194f7SMichael S. Tsirkin } 2688