diff options
Diffstat (limited to 'hw/i386/acpi-build.c')
-rw-r--r-- | hw/i386/acpi-build.c | 181 |
1 files changed, 110 insertions, 71 deletions
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index fa866f6378..4cc1440f77 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -39,6 +39,7 @@ #include "hw/loader.h" #include "hw/isa/isa.h" #include "hw/acpi/memory_hotplug.h" +#include "hw/mem/nvdimm.h" #include "sysemu/tpm.h" #include "hw/acpi/tpm.h" #include "sysemu/tpm_backend.h" @@ -361,7 +362,7 @@ build_fadt(GArray *table_data, GArray *linker, AcpiPmInfo *pm, fadt_setup(fadt, pm); build_header(linker, table_data, - (void *)fadt, "FACP", sizeof(*fadt), 1); + (void *)fadt, "FACP", sizeof(*fadt), 1, NULL); } static void @@ -431,7 +432,7 @@ build_madt(GArray *table_data, GArray *linker, AcpiCpuInfo *cpu, build_header(linker, table_data, (void *)(table_data->data + madt_start), "APIC", - table_data->len - madt_start, 1); + table_data->len - madt_start, 1, NULL); } /* Assign BSEL property to all buses. In the future, this can be changed @@ -469,7 +470,7 @@ static void build_append_pcihp_notify_entry(Aml *method, int slot) Aml *if_ctx; int32_t devfn = PCI_DEVFN(slot, 0); - if_ctx = aml_if(aml_and(aml_arg(0), aml_int(0x1U << slot))); + if_ctx = aml_if(aml_and(aml_arg(0), aml_int(0x1U << slot), NULL)); aml_append(if_ctx, aml_notify(aml_name("S%.02X", devfn), aml_arg(1))); aml_append(method, if_ctx); } @@ -666,10 +667,11 @@ static Aml *build_prt(void) /* slot = pin >> 2 */ aml_append(while_ctx, - aml_store(aml_shiftright(pin, aml_int(2)), slot)); + aml_store(aml_shiftright(pin, aml_int(2), NULL), slot)); /* lnk_idx = (slot + pin) & 3 */ aml_append(while_ctx, - aml_store(aml_and(aml_add(pin, slot), aml_int(3)), lnk_idx)); + aml_store(aml_and(aml_add(pin, slot, NULL), aml_int(3), NULL), + lnk_idx)); /* route[2] = "LNK[D|A|B|C]", selection based on pin % 3 */ aml_append(while_ctx, initialize_route(route, "LNKD", lnk_idx, 0)); @@ -679,11 +681,13 @@ static Aml *build_prt(void) /* route[0] = 0x[slot]FFFF */ aml_append(while_ctx, - aml_store(aml_or(aml_shiftleft(slot, aml_int(16)), aml_int(0xFFFF)), + aml_store(aml_or(aml_shiftleft(slot, aml_int(16)), aml_int(0xFFFF), + NULL), aml_index(route, aml_int(0)))); /* route[1] = pin & 3 */ aml_append(while_ctx, - aml_store(aml_and(pin, aml_int(3)), aml_index(route, aml_int(1)))); + aml_store(aml_and(pin, aml_int(3), NULL), + aml_index(route, aml_int(1)))); /* res[pin] = route */ aml_append(while_ctx, aml_store(route, aml_index(res, pin))); /* pin++ */ @@ -762,16 +766,59 @@ static void crs_replace_with_free_ranges(GPtrArray *ranges, g_ptr_array_free(free_ranges, false); } +/* + * crs_range_merge - merges adjacent ranges in the given array. + * Array elements are deleted and replaced with the merged ranges. + */ +static void crs_range_merge(GPtrArray *range) +{ + GPtrArray *tmp = g_ptr_array_new_with_free_func(crs_range_free); + CrsRangeEntry *entry; + uint64_t range_base, range_limit; + int i; + + if (!range->len) { + return; + } + + g_ptr_array_sort(range, crs_range_compare); + + entry = g_ptr_array_index(range, 0); + range_base = entry->base; + range_limit = entry->limit; + for (i = 1; i < range->len; i++) { + entry = g_ptr_array_index(range, i); + if (entry->base - 1 == range_limit) { + range_limit = entry->limit; + } else { + crs_range_insert(tmp, range_base, range_limit); + range_base = entry->base; + range_limit = entry->limit; + } + } + crs_range_insert(tmp, range_base, range_limit); + + g_ptr_array_set_size(range, 0); + for (i = 0; i < tmp->len; i++) { + entry = g_ptr_array_index(tmp, i); + crs_range_insert(range, entry->base, entry->limit); + } + g_ptr_array_free(tmp, true); +} + static Aml *build_crs(PCIHostState *host, GPtrArray *io_ranges, GPtrArray *mem_ranges) { Aml *crs = aml_resource_template(); + GPtrArray *host_io_ranges = g_ptr_array_new_with_free_func(crs_range_free); + GPtrArray *host_mem_ranges = g_ptr_array_new_with_free_func(crs_range_free); + CrsRangeEntry *entry; uint8_t max_bus = pci_bus_num(host->bus); uint8_t type; int devfn; + int i; for (devfn = 0; devfn < ARRAY_SIZE(host->bus->devices); devfn++) { - int i; uint64_t range_base, range_limit; PCIDevice *dev = host->bus->devices[devfn]; @@ -794,26 +841,9 @@ static Aml *build_crs(PCIHostState *host, } if (r->type & PCI_BASE_ADDRESS_SPACE_IO) { - aml_append(crs, - aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED, - AML_POS_DECODE, AML_ENTIRE_RANGE, - 0, - range_base, - range_limit, - 0, - range_limit - range_base + 1)); - crs_range_insert(io_ranges, range_base, range_limit); + crs_range_insert(host_io_ranges, range_base, range_limit); } else { /* "memory" */ - aml_append(crs, - aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, - AML_MAX_FIXED, AML_NON_CACHEABLE, - AML_READ_WRITE, - 0, - range_base, - range_limit, - 0, - range_limit - range_base + 1)); - crs_range_insert(mem_ranges, range_base, range_limit); + crs_range_insert(host_mem_ranges, range_base, range_limit); } } @@ -832,15 +862,7 @@ static Aml *build_crs(PCIHostState *host, * that do not support multiple root buses */ if (range_base && range_base <= range_limit) { - aml_append(crs, - aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED, - AML_POS_DECODE, AML_ENTIRE_RANGE, - 0, - range_base, - range_limit, - 0, - range_limit - range_base + 1)); - crs_range_insert(io_ranges, range_base, range_limit); + crs_range_insert(host_io_ranges, range_base, range_limit); } range_base = @@ -853,16 +875,7 @@ static Aml *build_crs(PCIHostState *host, * that do not support multiple root buses */ if (range_base && range_base <= range_limit) { - aml_append(crs, - aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, - AML_MAX_FIXED, AML_NON_CACHEABLE, - AML_READ_WRITE, - 0, - range_base, - range_limit, - 0, - range_limit - range_base + 1)); - crs_range_insert(mem_ranges, range_base, range_limit); + crs_range_insert(host_mem_ranges, range_base, range_limit); } range_base = @@ -875,20 +888,36 @@ static Aml *build_crs(PCIHostState *host, * that do not support multiple root buses */ if (range_base && range_base <= range_limit) { - aml_append(crs, - aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, - AML_MAX_FIXED, AML_NON_CACHEABLE, - AML_READ_WRITE, - 0, - range_base, - range_limit, - 0, - range_limit - range_base + 1)); - crs_range_insert(mem_ranges, range_base, range_limit); + crs_range_insert(host_mem_ranges, range_base, range_limit); } } } + crs_range_merge(host_io_ranges); + for (i = 0; i < host_io_ranges->len; i++) { + entry = g_ptr_array_index(host_io_ranges, i); + aml_append(crs, + aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED, + AML_POS_DECODE, AML_ENTIRE_RANGE, + 0, entry->base, entry->limit, 0, + entry->limit - entry->base + 1)); + crs_range_insert(io_ranges, entry->base, entry->limit); + } + g_ptr_array_free(host_io_ranges, true); + + crs_range_merge(host_mem_ranges); + for (i = 0; i < host_mem_ranges->len; i++) { + entry = g_ptr_array_index(host_mem_ranges, i); + aml_append(crs, + aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, + AML_MAX_FIXED, AML_NON_CACHEABLE, + AML_READ_WRITE, + 0, entry->base, entry->limit, 0, + entry->limit - entry->base + 1)); + crs_range_insert(mem_ranges, entry->base, entry->limit); + } + g_ptr_array_free(host_mem_ranges, true); + aml_append(crs, aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE, 0, @@ -925,8 +954,7 @@ build_ssdt(GArray *table_data, GArray *linker, /* Reserve space for header */ acpi_data_push(ssdt->buf, sizeof(AcpiTableHeader)); - /* Extra PCI root buses are implemented only for i440fx */ - bus = find_i440fx(); + bus = PC_MACHINE(machine)->bus; if (bus) { QLIST_FOREACH(bus, &bus->child, sibling) { uint8_t bus_num = pci_bus_num(bus); @@ -1105,7 +1133,7 @@ build_ssdt(GArray *table_data, GArray *linker, aml_append(dev, aml_operation_region("PEOR", AML_SYSTEM_IO, misc->pvpanic_port, 1)); - field = aml_field("PEOR", AML_BYTE_ACC, AML_PRESERVE); + field = aml_field("PEOR", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE); aml_append(field, aml_named_field("PEPT", 8)); aml_append(dev, field); @@ -1145,7 +1173,7 @@ build_ssdt(GArray *table_data, GArray *linker, /* declare CPU hotplug MMIO region and PRS field to access it */ aml_append(sb_scope, aml_operation_region( "PRST", AML_SYSTEM_IO, pm->cpu_hp_io_base, pm->cpu_hp_io_len)); - field = aml_field("PRST", AML_BYTE_ACC, AML_PRESERVE); + field = aml_field("PRST", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE); aml_append(field, aml_named_field("PRS", 256)); aml_append(sb_scope, field); @@ -1220,7 +1248,7 @@ build_ssdt(GArray *table_data, GArray *linker, ); field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_DWORD_ACC, - AML_PRESERVE); + AML_NOLOCK, AML_PRESERVE); aml_append(field, /* read only */ aml_named_field(stringify(MEMORY_SLOT_ADDR_LOW), 32)); aml_append(field, /* read only */ @@ -1234,7 +1262,7 @@ build_ssdt(GArray *table_data, GArray *linker, aml_append(scope, field); field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_BYTE_ACC, - AML_WRITE_AS_ZEROS); + AML_NOLOCK, AML_WRITE_AS_ZEROS); aml_append(field, aml_reserved_field(160 /* bits, Offset(20) */)); aml_append(field, /* 1 if enabled, read only */ aml_named_field(stringify(MEMORY_SLOT_ENABLED), 1)); @@ -1250,7 +1278,7 @@ build_ssdt(GArray *table_data, GArray *linker, aml_append(scope, field); field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_DWORD_ACC, - AML_PRESERVE); + AML_NOLOCK, AML_PRESERVE); aml_append(field, /* DIMM selector, write only */ aml_named_field(stringify(MEMORY_SLOT_SLECTOR), 32)); aml_append(field, /* _OST event code, write only */ @@ -1350,7 +1378,7 @@ build_ssdt(GArray *table_data, GArray *linker, g_array_append_vals(table_data, ssdt->buf->data, ssdt->buf->len); build_header(linker, table_data, (void *)(table_data->data + table_data->len - ssdt->buf->len), - "SSDT", ssdt->buf->len, 1); + "SSDT", ssdt->buf->len, 1, NULL); free_aml_allocator(); } @@ -1366,7 +1394,7 @@ build_hpet(GArray *table_data, GArray *linker) hpet->timer_block_id = cpu_to_le32(0x8086a201); hpet->addr.address = cpu_to_le64(HPET_BASE); build_header(linker, table_data, - (void *)hpet, "HPET", sizeof(*hpet), 1); + (void *)hpet, "HPET", sizeof(*hpet), 1, NULL); } static void @@ -1389,7 +1417,7 @@ build_tpm_tcpa(GArray *table_data, GArray *linker, GArray *tcpalog) sizeof(tcpa->log_area_start_address)); build_header(linker, table_data, - (void *)tcpa, "TCPA", sizeof(*tcpa), 2); + (void *)tcpa, "TCPA", sizeof(*tcpa), 2, NULL); acpi_data_push(tcpalog, TPM_LOG_AREA_MINIMUM_SIZE); } @@ -1406,7 +1434,7 @@ build_tpm2(GArray *table_data, GArray *linker) tpm2_ptr->start_method = cpu_to_le32(TPM2_START_METHOD_MMIO); build_header(linker, table_data, - (void *)tpm2_ptr, "TPM2", sizeof(*tpm2_ptr), 4); + (void *)tpm2_ptr, "TPM2", sizeof(*tpm2_ptr), 4, NULL); } typedef enum { @@ -1520,7 +1548,7 @@ build_srat(GArray *table_data, GArray *linker, PcGuestInfo *guest_info) build_header(linker, table_data, (void *)(table_data->data + srat_start), "SRAT", - table_data->len - srat_start, 1); + table_data->len - srat_start, 1, NULL); } static void @@ -1549,7 +1577,7 @@ build_mcfg_q35(GArray *table_data, GArray *linker, AcpiMcfgInfo *info) } else { sig = "MCFG"; } - build_header(linker, table_data, (void *)mcfg, sig, len, 1); + build_header(linker, table_data, (void *)mcfg, sig, len, 1, NULL); } static void @@ -1573,7 +1601,7 @@ build_dmar_q35(GArray *table_data, GArray *linker) drhd->address = cpu_to_le64(Q35_HOST_BRIDGE_IOMMU_ADDR); build_header(linker, table_data, (void *)(table_data->data + dmar_start), - "DMAR", table_data->len - dmar_start, 1); + "DMAR", table_data->len - dmar_start, 1, NULL); } static void @@ -1588,7 +1616,7 @@ build_dsdt(GArray *table_data, GArray *linker, AcpiMiscInfo *misc) memset(dsdt, 0, sizeof *dsdt); build_header(linker, table_data, dsdt, "DSDT", - misc->dsdt_size, 1); + misc->dsdt_size, 1, NULL); } static GArray * @@ -1659,6 +1687,13 @@ static bool acpi_has_iommu(void) return intel_iommu && !ambiguous; } +static bool acpi_has_nvdimm(void) +{ + PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); + + return pcms->nvdimm; +} + static void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) { @@ -1743,6 +1778,10 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) build_dmar_q35(tables_blob, tables->linker); } + if (acpi_has_nvdimm()) { + nvdimm_build_acpi(table_offsets, tables_blob, tables->linker); + } + /* Add tables supplied by user (if any) */ for (u = acpi_table_first(); u; u = acpi_table_next(u)) { unsigned len = acpi_table_len(u); |