summaryrefslogtreecommitdiffstats
path: root/hw/i386
diff options
context:
space:
mode:
authorPeter Maydell2020-12-09 21:08:54 +0100
committerPeter Maydell2020-12-09 21:08:54 +0100
commit5e7b204dbfae9a562fc73684986f936b97f63877 (patch)
tree6cbdd59e56f5b9342c8252deed085f21485ac0fb /hw/i386
parentMerge remote-tracking branch 'remotes/huth-gitlab/tags/pull-request-2020-12-0... (diff)
parenthw/virtio-pci Added AER capability. (diff)
downloadqemu-5e7b204dbfae9a562fc73684986f936b97f63877.tar.gz
qemu-5e7b204dbfae9a562fc73684986f936b97f63877.tar.xz
qemu-5e7b204dbfae9a562fc73684986f936b97f63877.zip
Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging
pc,pci,virtio: fixes, cleanups Lots of fixes, cleanups. CPU hot-unplug improvements. A new AER property for virtio devices, adding a dummy AER capability. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # gpg: Signature made Wed 09 Dec 2020 18:04:28 GMT # gpg: using RSA key 5D09FD0871C8F85B94CA8A0D281F0DB8D28D5469 # gpg: issuer "mst@redhat.com" # gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" [full] # gpg: aka "Michael S. Tsirkin <mst@redhat.com>" [full] # Primary key fingerprint: 0270 606B 6F3C DF3D 0B17 0970 C350 3912 AFBE 8E67 # Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA 8A0D 281F 0DB8 D28D 5469 * remotes/mst/tags/for_upstream: (65 commits) hw/virtio-pci Added AER capability. hw/virtio-pci Added counter for pcie capabilities offsets. pcie_aer: Fix help message of pcie_aer_inject_error command x86: ich9: let firmware negotiate 'CPU hot-unplug with SMI' feature x86: ich9: factor out "guest_cpu_hotplug_features" tests/acpi: update expected files x86: acpi: let the firmware handle pending "CPU remove" events in SMM tests/acpi: allow expected files change x86: acpi: introduce AcpiPmInfo::smi_on_cpu_unplug acpi: cpuhp: introduce 'firmware performs eject' status/control bits hw/i386/pc: add max combined fw size as machine configuration option block/export: avoid g_return_val_if() input validation contrib/vhost-user-input: avoid g_return_val_if() input validation contrib/vhost-user-gpu: avoid g_return_val_if() input validation contrib/vhost-user-blk: avoid g_return_val_if() input validation .gitlab-ci: add build-libvhost-user libvhost-user: add a simple link test without glib libvhost-user: make it a meson subproject libvhost-user: drop qemu/osdep.h dependency libvhost-user: remove qemu/compiler.h usage ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/i386')
-rw-r--r--hw/i386/acpi-build.c298
-rw-r--r--hw/i386/intel_iommu.c92
-rw-r--r--hw/i386/pc.c74
-rw-r--r--hw/i386/pc_piix.c14
-rw-r--r--hw/i386/pc_q35.c13
-rw-r--r--hw/i386/pc_sysfw.c15
6 files changed, 143 insertions, 363 deletions
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 1f5c211245..f18b71dea9 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -96,6 +96,7 @@ typedef struct AcpiPmInfo {
bool s4_disabled;
bool pcihp_bridge_en;
bool smi_on_cpuhp;
+ bool smi_on_cpu_unplug;
bool pcihp_root_en;
uint8_t s4_val;
AcpiFadtData fadt;
@@ -197,6 +198,7 @@ static void acpi_get_pm_info(MachineState *machine, AcpiPmInfo *pm)
pm->pcihp_io_base = 0;
pm->pcihp_io_len = 0;
pm->smi_on_cpuhp = false;
+ pm->smi_on_cpu_unplug = false;
assert(obj);
init_common_fadt_data(machine, obj, &pm->fadt);
@@ -220,6 +222,8 @@ static void acpi_get_pm_info(MachineState *machine, AcpiPmInfo *pm)
pm->cpu_hp_io_base = ICH9_CPU_HOTPLUG_IO_BASE;
pm->smi_on_cpuhp =
!!(smi_features & BIT_ULL(ICH9_LPC_SMI_F_CPU_HOTPLUG_BIT));
+ pm->smi_on_cpu_unplug =
+ !!(smi_features & BIT_ULL(ICH9_LPC_SMI_F_CPU_HOT_UNPLUG_BIT));
}
/* The above need not be conditional on machine type because the reset port
@@ -613,299 +617,6 @@ static Aml *build_prt(bool is_pci0_prt)
return method;
}
-typedef struct CrsRangeEntry {
- uint64_t base;
- uint64_t limit;
-} CrsRangeEntry;
-
-static void crs_range_insert(GPtrArray *ranges, uint64_t base, uint64_t limit)
-{
- CrsRangeEntry *entry;
-
- entry = g_malloc(sizeof(*entry));
- entry->base = base;
- entry->limit = limit;
-
- g_ptr_array_add(ranges, entry);
-}
-
-static void crs_range_free(gpointer data)
-{
- CrsRangeEntry *entry = (CrsRangeEntry *)data;
- g_free(entry);
-}
-
-typedef struct CrsRangeSet {
- GPtrArray *io_ranges;
- GPtrArray *mem_ranges;
- GPtrArray *mem_64bit_ranges;
- } CrsRangeSet;
-
-static void crs_range_set_init(CrsRangeSet *range_set)
-{
- range_set->io_ranges = g_ptr_array_new_with_free_func(crs_range_free);
- range_set->mem_ranges = g_ptr_array_new_with_free_func(crs_range_free);
- range_set->mem_64bit_ranges =
- g_ptr_array_new_with_free_func(crs_range_free);
-}
-
-static void crs_range_set_free(CrsRangeSet *range_set)
-{
- g_ptr_array_free(range_set->io_ranges, true);
- g_ptr_array_free(range_set->mem_ranges, true);
- g_ptr_array_free(range_set->mem_64bit_ranges, true);
-}
-
-static gint crs_range_compare(gconstpointer a, gconstpointer b)
-{
- CrsRangeEntry *entry_a = *(CrsRangeEntry **)a;
- CrsRangeEntry *entry_b = *(CrsRangeEntry **)b;
-
- if (entry_a->base < entry_b->base) {
- return -1;
- } else if (entry_a->base > entry_b->base) {
- return 1;
- } else {
- return 0;
- }
-}
-
-/*
- * crs_replace_with_free_ranges - given the 'used' ranges within [start - end]
- * interval, computes the 'free' ranges from the same interval.
- * Example: If the input array is { [a1 - a2],[b1 - b2] }, the function
- * will return { [base - a1], [a2 - b1], [b2 - limit] }.
- */
-static void crs_replace_with_free_ranges(GPtrArray *ranges,
- uint64_t start, uint64_t end)
-{
- GPtrArray *free_ranges = g_ptr_array_new();
- uint64_t free_base = start;
- int i;
-
- g_ptr_array_sort(ranges, crs_range_compare);
- for (i = 0; i < ranges->len; i++) {
- CrsRangeEntry *used = g_ptr_array_index(ranges, i);
-
- if (free_base < used->base) {
- crs_range_insert(free_ranges, free_base, used->base - 1);
- }
-
- free_base = used->limit + 1;
- }
-
- if (free_base < end) {
- crs_range_insert(free_ranges, free_base, end);
- }
-
- g_ptr_array_set_size(ranges, 0);
- for (i = 0; i < free_ranges->len; i++) {
- g_ptr_array_add(ranges, g_ptr_array_index(free_ranges, i));
- }
-
- g_ptr_array_free(free_ranges, true);
-}
-
-/*
- * 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, CrsRangeSet *range_set)
-{
- Aml *crs = aml_resource_template();
- CrsRangeSet temp_range_set;
- CrsRangeEntry *entry;
- uint8_t max_bus = pci_bus_num(host->bus);
- uint8_t type;
- int devfn;
- int i;
-
- crs_range_set_init(&temp_range_set);
- for (devfn = 0; devfn < ARRAY_SIZE(host->bus->devices); devfn++) {
- uint64_t range_base, range_limit;
- PCIDevice *dev = host->bus->devices[devfn];
-
- if (!dev) {
- continue;
- }
-
- for (i = 0; i < PCI_NUM_REGIONS; i++) {
- PCIIORegion *r = &dev->io_regions[i];
-
- range_base = r->addr;
- range_limit = r->addr + r->size - 1;
-
- /*
- * Work-around for old bioses
- * that do not support multiple root buses
- */
- if (!range_base || range_base > range_limit) {
- continue;
- }
-
- if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
- crs_range_insert(temp_range_set.io_ranges,
- range_base, range_limit);
- } else { /* "memory" */
- uint64_t length = range_limit - range_base + 1;
- if (range_limit <= UINT32_MAX && length <= UINT32_MAX) {
- crs_range_insert(temp_range_set.mem_ranges, range_base,
- range_limit);
- } else {
- crs_range_insert(temp_range_set.mem_64bit_ranges,
- range_base, range_limit);
- }
- }
- }
-
- type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
- if (type == PCI_HEADER_TYPE_BRIDGE) {
- uint8_t subordinate = dev->config[PCI_SUBORDINATE_BUS];
- if (subordinate > max_bus) {
- max_bus = subordinate;
- }
-
- range_base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO);
- range_limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO);
-
- /*
- * Work-around for old bioses
- * that do not support multiple root buses
- */
- if (range_base && range_base <= range_limit) {
- crs_range_insert(temp_range_set.io_ranges,
- range_base, range_limit);
- }
-
- range_base =
- pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
- range_limit =
- pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
-
- /*
- * Work-around for old bioses
- * that do not support multiple root buses
- */
- if (range_base && range_base <= range_limit) {
- uint64_t length = range_limit - range_base + 1;
- if (range_limit <= UINT32_MAX && length <= UINT32_MAX) {
- crs_range_insert(temp_range_set.mem_ranges,
- range_base, range_limit);
- } else {
- crs_range_insert(temp_range_set.mem_64bit_ranges,
- range_base, range_limit);
- }
- }
-
- range_base =
- pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
- range_limit =
- pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
-
- /*
- * Work-around for old bioses
- * that do not support multiple root buses
- */
- if (range_base && range_base <= range_limit) {
- uint64_t length = range_limit - range_base + 1;
- if (range_limit <= UINT32_MAX && length <= UINT32_MAX) {
- crs_range_insert(temp_range_set.mem_ranges,
- range_base, range_limit);
- } else {
- crs_range_insert(temp_range_set.mem_64bit_ranges,
- range_base, range_limit);
- }
- }
- }
- }
-
- crs_range_merge(temp_range_set.io_ranges);
- for (i = 0; i < temp_range_set.io_ranges->len; i++) {
- entry = g_ptr_array_index(temp_range_set.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(range_set->io_ranges, entry->base, entry->limit);
- }
-
- crs_range_merge(temp_range_set.mem_ranges);
- for (i = 0; i < temp_range_set.mem_ranges->len; i++) {
- entry = g_ptr_array_index(temp_range_set.mem_ranges, i);
- assert(entry->limit <= UINT32_MAX &&
- (entry->limit - entry->base + 1) <= UINT32_MAX);
- 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(range_set->mem_ranges, entry->base, entry->limit);
- }
-
- crs_range_merge(temp_range_set.mem_64bit_ranges);
- for (i = 0; i < temp_range_set.mem_64bit_ranges->len; i++) {
- entry = g_ptr_array_index(temp_range_set.mem_64bit_ranges, i);
- aml_append(crs,
- aml_qword_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(range_set->mem_64bit_ranges,
- entry->base, entry->limit);
- }
-
- crs_range_set_free(&temp_range_set);
-
- aml_append(crs,
- aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE,
- 0,
- pci_bus_num(host->bus),
- max_bus,
- 0,
- max_bus - pci_bus_num(host->bus) + 1));
-
- return crs;
-}
-
static void build_hpet_aml(Aml *table)
{
Aml *crs;
@@ -1582,6 +1293,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
CPUHotplugFeatures opts = {
.acpi_1_compatible = true, .has_legacy_cphp = true,
.smi_path = pm->smi_on_cpuhp ? "\\_SB.PCI0.SMI0.SMIC" : NULL,
+ .fw_unplugs_cpu = pm->smi_on_cpu_unplug,
};
build_cpus_aml(dsdt, machine, opts, pm->cpu_hp_io_base,
"\\_SB.PCI0", "\\_GPE._E02");
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index 70ac837733..0cc71e4057 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -1073,7 +1073,7 @@ static int vtd_iova_to_slpte(IntelIOMMUState *s, VTDContextEntry *ce,
}
}
-typedef int (*vtd_page_walk_hook)(IOMMUTLBEntry *entry, void *private);
+typedef int (*vtd_page_walk_hook)(IOMMUTLBEvent *event, void *private);
/**
* Constant information used during page walking
@@ -1094,11 +1094,12 @@ typedef struct {
uint16_t domain_id;
} vtd_page_walk_info;
-static int vtd_page_walk_one(IOMMUTLBEntry *entry, vtd_page_walk_info *info)
+static int vtd_page_walk_one(IOMMUTLBEvent *event, vtd_page_walk_info *info)
{
VTDAddressSpace *as = info->as;
vtd_page_walk_hook hook_fn = info->hook_fn;
void *private = info->private;
+ IOMMUTLBEntry *entry = &event->entry;
DMAMap target = {
.iova = entry->iova,
.size = entry->addr_mask,
@@ -1107,7 +1108,7 @@ static int vtd_page_walk_one(IOMMUTLBEntry *entry, vtd_page_walk_info *info)
};
DMAMap *mapped = iova_tree_find(as->iova_tree, &target);
- if (entry->perm == IOMMU_NONE && !info->notify_unmap) {
+ if (event->type == IOMMU_NOTIFIER_UNMAP && !info->notify_unmap) {
trace_vtd_page_walk_one_skip_unmap(entry->iova, entry->addr_mask);
return 0;
}
@@ -1115,7 +1116,7 @@ static int vtd_page_walk_one(IOMMUTLBEntry *entry, vtd_page_walk_info *info)
assert(hook_fn);
/* Update local IOVA mapped ranges */
- if (entry->perm) {
+ if (event->type == IOMMU_NOTIFIER_MAP) {
if (mapped) {
/* If it's exactly the same translation, skip */
if (!memcmp(mapped, &target, sizeof(target))) {
@@ -1141,19 +1142,21 @@ static int vtd_page_walk_one(IOMMUTLBEntry *entry, vtd_page_walk_info *info)
int ret;
/* Emulate an UNMAP */
+ event->type = IOMMU_NOTIFIER_UNMAP;
entry->perm = IOMMU_NONE;
trace_vtd_page_walk_one(info->domain_id,
entry->iova,
entry->translated_addr,
entry->addr_mask,
entry->perm);
- ret = hook_fn(entry, private);
+ ret = hook_fn(event, private);
if (ret) {
return ret;
}
/* Drop any existing mapping */
iova_tree_remove(as->iova_tree, &target);
- /* Recover the correct permission */
+ /* Recover the correct type */
+ event->type = IOMMU_NOTIFIER_MAP;
entry->perm = cache_perm;
}
}
@@ -1170,7 +1173,7 @@ static int vtd_page_walk_one(IOMMUTLBEntry *entry, vtd_page_walk_info *info)
trace_vtd_page_walk_one(info->domain_id, entry->iova,
entry->translated_addr, entry->addr_mask,
entry->perm);
- return hook_fn(entry, private);
+ return hook_fn(event, private);
}
/**
@@ -1191,7 +1194,7 @@ static int vtd_page_walk_level(dma_addr_t addr, uint64_t start,
uint32_t offset;
uint64_t slpte;
uint64_t subpage_size, subpage_mask;
- IOMMUTLBEntry entry;
+ IOMMUTLBEvent event;
uint64_t iova = start;
uint64_t iova_next;
int ret = 0;
@@ -1245,13 +1248,15 @@ static int vtd_page_walk_level(dma_addr_t addr, uint64_t start,
*
* In either case, we send an IOTLB notification down.
*/
- entry.target_as = &address_space_memory;
- entry.iova = iova & subpage_mask;
- entry.perm = IOMMU_ACCESS_FLAG(read_cur, write_cur);
- entry.addr_mask = ~subpage_mask;
+ event.entry.target_as = &address_space_memory;
+ event.entry.iova = iova & subpage_mask;
+ event.entry.perm = IOMMU_ACCESS_FLAG(read_cur, write_cur);
+ event.entry.addr_mask = ~subpage_mask;
/* NOTE: this is only meaningful if entry_valid == true */
- entry.translated_addr = vtd_get_slpte_addr(slpte, info->aw);
- ret = vtd_page_walk_one(&entry, info);
+ event.entry.translated_addr = vtd_get_slpte_addr(slpte, info->aw);
+ event.type = event.entry.perm ? IOMMU_NOTIFIER_MAP :
+ IOMMU_NOTIFIER_UNMAP;
+ ret = vtd_page_walk_one(&event, info);
}
if (ret < 0) {
@@ -1430,10 +1435,10 @@ static int vtd_dev_to_context_entry(IntelIOMMUState *s, uint8_t bus_num,
return 0;
}
-static int vtd_sync_shadow_page_hook(IOMMUTLBEntry *entry,
+static int vtd_sync_shadow_page_hook(IOMMUTLBEvent *event,
void *private)
{
- memory_region_notify_iommu((IOMMUMemoryRegion *)private, 0, *entry);
+ memory_region_notify_iommu(private, 0, *event);
return 0;
}
@@ -1473,6 +1478,10 @@ static int vtd_sync_shadow_page_table(VTDAddressSpace *vtd_as)
VTDContextEntry ce;
IOMMUNotifier *n;
+ if (!(vtd_as->iommu.iommu_notify_flags & IOMMU_NOTIFIER_IOTLB_EVENTS)) {
+ return 0;
+ }
+
ret = vtd_dev_to_context_entry(vtd_as->iommu_state,
pci_bus_num(vtd_as->bus),
vtd_as->devfn, &ce);
@@ -1993,14 +2002,17 @@ static void vtd_iotlb_page_invalidate_notify(IntelIOMMUState *s,
* page tables. We just deliver the PSI down to
* invalidate caches.
*/
- IOMMUTLBEntry entry = {
- .target_as = &address_space_memory,
- .iova = addr,
- .translated_addr = 0,
- .addr_mask = size - 1,
- .perm = IOMMU_NONE,
+ IOMMUTLBEvent event = {
+ .type = IOMMU_NOTIFIER_UNMAP,
+ .entry = {
+ .target_as = &address_space_memory,
+ .iova = addr,
+ .translated_addr = 0,
+ .addr_mask = size - 1,
+ .perm = IOMMU_NONE,
+ },
};
- memory_region_notify_iommu(&vtd_as->iommu, 0, entry);
+ memory_region_notify_iommu(&vtd_as->iommu, 0, event);
}
}
}
@@ -2412,7 +2424,7 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s,
VTDInvDesc *inv_desc)
{
VTDAddressSpace *vtd_dev_as;
- IOMMUTLBEntry entry;
+ IOMMUTLBEvent event;
struct VTDBus *vtd_bus;
hwaddr addr;
uint64_t sz;
@@ -2460,12 +2472,13 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s,
sz = VTD_PAGE_SIZE;
}
- entry.target_as = &vtd_dev_as->as;
- entry.addr_mask = sz - 1;
- entry.iova = addr;
- entry.perm = IOMMU_NONE;
- entry.translated_addr = 0;
- memory_region_notify_iommu(&vtd_dev_as->iommu, 0, entry);
+ event.type = IOMMU_NOTIFIER_DEVIOTLB_UNMAP;
+ event.entry.target_as = &vtd_dev_as->as;
+ event.entry.addr_mask = sz - 1;
+ event.entry.iova = addr;
+ event.entry.perm = IOMMU_NONE;
+ event.entry.translated_addr = 0;
+ memory_region_notify_iommu(&vtd_dev_as->iommu, 0, event);
done:
return true;
@@ -3485,19 +3498,20 @@ static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n)
size = remain = end - start + 1;
while (remain >= VTD_PAGE_SIZE) {
- IOMMUTLBEntry entry;
+ IOMMUTLBEvent event;
uint64_t mask = get_naturally_aligned_size(start, remain, s->aw_bits);
assert(mask);
- entry.iova = start;
- entry.addr_mask = mask - 1;
- entry.target_as = &address_space_memory;
- entry.perm = IOMMU_NONE;
+ event.type = IOMMU_NOTIFIER_UNMAP;
+ event.entry.iova = start;
+ event.entry.addr_mask = mask - 1;
+ event.entry.target_as = &address_space_memory;
+ event.entry.perm = IOMMU_NONE;
/* This field is meaningless for unmap */
- entry.translated_addr = 0;
+ event.entry.translated_addr = 0;
- memory_region_notify_one(n, &entry);
+ memory_region_notify_iommu_one(n, &event);
start += mask;
remain -= mask;
@@ -3533,9 +3547,9 @@ static void vtd_address_space_refresh_all(IntelIOMMUState *s)
vtd_switch_address_space_all(s);
}
-static int vtd_replay_hook(IOMMUTLBEntry *entry, void *private)
+static int vtd_replay_hook(IOMMUTLBEvent *event, void *private)
{
- memory_region_notify_one((IOMMUNotifier *)private, entry);
+ memory_region_notify_iommu_one(private, event);
return 0;
}
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 17b514d1da..9e29f3792b 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -97,6 +97,11 @@
#include "trace.h"
#include CONFIG_DEVICES
+GlobalProperty pc_compat_5_2[] = {
+ { "ICH9-LPC", "x-smi-cpu-hotunplug", "off" },
+};
+const size_t pc_compat_5_2_len = G_N_ELEMENTS(pc_compat_5_2);
+
GlobalProperty pc_compat_5_1[] = {
{ "ICH9-LPC", "x-smi-cpu-hotplug", "off" },
};
@@ -777,27 +782,11 @@ void pc_machine_done(Notifier *notifier, void *data)
PCMachineState *pcms = container_of(notifier,
PCMachineState, machine_done);
X86MachineState *x86ms = X86_MACHINE(pcms);
- PCIBus *bus = pcms->bus;
/* set the number of CPUs */
x86_rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus);
- if (bus) {
- int extra_hosts = 0;
-
- QLIST_FOREACH(bus, &bus->child, sibling) {
- /* look for expander root buses */
- if (pci_bus_is_root(bus)) {
- extra_hosts++;
- }
- }
- if (extra_hosts && x86ms->fw_cfg) {
- uint64_t *val = g_malloc(sizeof(*val));
- *val = cpu_to_le64(extra_hosts);
- fw_cfg_add_file(x86ms->fw_cfg,
- "etc/extra-pci-roots", val, sizeof(*val));
- }
- }
+ fw_cfg_add_extra_pci_roots(pcms->bus, x86ms->fw_cfg);
acpi_setup();
if (x86ms->fw_cfg) {
@@ -1582,6 +1571,50 @@ static void pc_machine_set_max_ram_below_4g(Object *obj, Visitor *v,
pcms->max_ram_below_4g = value;
}
+static void pc_machine_get_max_fw_size(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ PCMachineState *pcms = PC_MACHINE(obj);
+ uint64_t value = pcms->max_fw_size;
+
+ visit_type_size(v, name, &value, errp);
+}
+
+static void pc_machine_set_max_fw_size(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ PCMachineState *pcms = PC_MACHINE(obj);
+ Error *error = NULL;
+ uint64_t value;
+
+ visit_type_size(v, name, &value, &error);
+ if (error) {
+ error_propagate(errp, error);
+ return;
+ }
+
+ /*
+ * We don't have a theoretically justifiable exact lower bound on the base
+ * address of any flash mapping. In practice, the IO-APIC MMIO range is
+ * [0xFEE00000..0xFEE01000] -- see IO_APIC_DEFAULT_ADDRESS --, leaving free
+ * only 18MB-4KB below 4G. For now, restrict the cumulative mapping to 8MB in
+ * size.
+ */
+ if (value > 16 * MiB) {
+ error_setg(errp,
+ "User specified max allowed firmware size %" PRIu64 " is "
+ "greater than 16MiB. If combined firwmare size exceeds "
+ "16MiB the system may not boot, or experience intermittent"
+ "stability issues.",
+ value);
+ return;
+ }
+
+ pcms->max_fw_size = value;
+}
+
static void pc_machine_initfn(Object *obj)
{
PCMachineState *pcms = PC_MACHINE(obj);
@@ -1597,6 +1630,7 @@ static void pc_machine_initfn(Object *obj)
pcms->smbus_enabled = true;
pcms->sata_enabled = true;
pcms->pit_enabled = true;
+ pcms->max_fw_size = 8 * MiB;
#ifdef CONFIG_HPET
pcms->hpet_enabled = true;
#endif
@@ -1723,6 +1757,12 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
object_class_property_add_bool(oc, "hpet",
pc_machine_get_hpet, pc_machine_set_hpet);
+
+ object_class_property_add(oc, PC_MACHINE_MAX_FW_SIZE, "size",
+ pc_machine_get_max_fw_size, pc_machine_set_max_fw_size,
+ NULL, NULL);
+ object_class_property_set_description(oc, PC_MACHINE_MAX_FW_SIZE,
+ "Maximum combined firmware size");
}
static const TypeInfo pc_machine_info = {
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 13d1628f13..6188c3e97e 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -426,7 +426,7 @@ static void pc_i440fx_machine_options(MachineClass *m)
machine_class_allow_dynamic_sysbus_dev(m, TYPE_VMBUS_BRIDGE);
}
-static void pc_i440fx_5_2_machine_options(MachineClass *m)
+static void pc_i440fx_6_0_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pc_i440fx_machine_options(m);
@@ -435,6 +435,18 @@ static void pc_i440fx_5_2_machine_options(MachineClass *m)
pcmc->default_cpu_version = 1;
}
+DEFINE_I440FX_MACHINE(v6_0, "pc-i440fx-6.0", NULL,
+ pc_i440fx_6_0_machine_options);
+
+static void pc_i440fx_5_2_machine_options(MachineClass *m)
+{
+ pc_i440fx_6_0_machine_options(m);
+ m->alias = NULL;
+ m->is_default = false;
+ compat_props_add(m->compat_props, hw_compat_5_2, hw_compat_5_2_len);
+ compat_props_add(m->compat_props, pc_compat_5_2, pc_compat_5_2_len);
+}
+
DEFINE_I440FX_MACHINE(v5_2, "pc-i440fx-5.2", NULL,
pc_i440fx_5_2_machine_options);
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index a3f4959c43..0a212443aa 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -344,7 +344,7 @@ static void pc_q35_machine_options(MachineClass *m)
m->max_cpus = 288;
}
-static void pc_q35_5_2_machine_options(MachineClass *m)
+static void pc_q35_6_0_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pc_q35_machine_options(m);
@@ -352,6 +352,17 @@ static void pc_q35_5_2_machine_options(MachineClass *m)
pcmc->default_cpu_version = 1;
}
+DEFINE_Q35_MACHINE(v6_0, "pc-q35-6.0", NULL,
+ pc_q35_6_0_machine_options);
+
+static void pc_q35_5_2_machine_options(MachineClass *m)
+{
+ pc_q35_6_0_machine_options(m);
+ m->alias = NULL;
+ compat_props_add(m->compat_props, hw_compat_5_2, hw_compat_5_2_len);
+ compat_props_add(m->compat_props, pc_compat_5_2, pc_compat_5_2_len);
+}
+
DEFINE_Q35_MACHINE(v5_2, "pc-q35-5.2", NULL,
pc_q35_5_2_machine_options);
diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
index b6c0822fe3..f8bd3a8b85 100644
--- a/hw/i386/pc_sysfw.c
+++ b/hw/i386/pc_sysfw.c
@@ -39,15 +39,6 @@
#include "hw/block/flash.h"
#include "sysemu/kvm.h"
-/*
- * We don't have a theoretically justifiable exact lower bound on the base
- * address of any flash mapping. In practice, the IO-APIC MMIO range is
- * [0xFEE00000..0xFEE01000] -- see IO_APIC_DEFAULT_ADDRESS --, leaving free
- * only 18MB-4KB below 4G. For now, restrict the cumulative mapping to 8MB in
- * size.
- */
-#define FLASH_SIZE_LIMIT (8 * MiB)
-
#define FLASH_SECTOR_SIZE 4096
static void pc_isa_bios_init(MemoryRegion *rom_memory,
@@ -140,7 +131,7 @@ void pc_system_flash_cleanup_unused(PCMachineState *pcms)
* Stop at the first pcms->flash[0] lacking a block backend.
* Set each flash's size from its block backend. Fatal error if the
* size isn't a non-zero multiple of 4KiB, or the total size exceeds
- * FLASH_SIZE_LIMIT.
+ * pcms->max_fw_size.
*
* If pcms->flash[0] has a block backend, its memory is passed to
* pc_isa_bios_init(). Merging several flash devices for isa-bios is
@@ -182,10 +173,10 @@ static void pc_system_flash_map(PCMachineState *pcms,
}
if ((hwaddr)size != size
|| total_size > HWADDR_MAX - size
- || total_size + size > FLASH_SIZE_LIMIT) {
+ || total_size + size > pcms->max_fw_size) {
error_report("combined size of system firmware exceeds "
"%" PRIu64 " bytes",
- FLASH_SIZE_LIMIT);
+ pcms->max_fw_size);
exit(1);
}