aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.target2
-rw-r--r--docs/specs/acpi_pci_hotplug.txt18
-rw-r--r--hw/acpi_piix4.c134
-rw-r--r--hw/ivshmem.c48
-rw-r--r--hw/pc.c8
-rw-r--r--hw/pc_piix.c320
-rw-r--r--hw/pci_host.c3
-rw-r--r--hw/piix_pci.c2
-rw-r--r--hw/vhost.c10
-rw-r--r--hw/virtio-pci.c8
-rw-r--r--hw/xen.h1
-rw-r--r--hw/xen_apic.c90
-rw-r--r--hw/xen_backend.c17
-rw-r--r--hw/xen_disk.c4
-rw-r--r--xen-all.c50
-rw-r--r--xen-mapcache.c15
-rw-r--r--xen-stub.c4
17 files changed, 392 insertions, 342 deletions
diff --git a/Makefile.target b/Makefile.target
index 61dfe3b..84951a0 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -239,7 +239,7 @@ QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
obj-$(CONFIG_XEN) += xen-all.o xen_machine_pv.o xen_domainbuild.o xen-mapcache.o
obj-$(CONFIG_NO_XEN) += xen-stub.o
-obj-i386-$(CONFIG_XEN) += xen_platform.o
+obj-i386-$(CONFIG_XEN) += xen_platform.o xen_apic.o
# Inter-VM PCI shared memory
CONFIG_IVSHMEM =
diff --git a/docs/specs/acpi_pci_hotplug.txt b/docs/specs/acpi_pci_hotplug.txt
index f0f74a7..a839434 100644
--- a/docs/specs/acpi_pci_hotplug.txt
+++ b/docs/specs/acpi_pci_hotplug.txt
@@ -15,23 +15,31 @@ PCI slot injection notification pending (IO port 0xae00-0xae03, 4-byte access):
Slot injection notification pending. One bit per slot.
Read by ACPI BIOS GPE.1 handler to notify OS of injection
-events.
+events. Read-only.
PCI slot removal notification (IO port 0xae04-0xae07, 4-byte access):
-----------------------------------------------------
Slot removal notification pending. One bit per slot.
Read by ACPI BIOS GPE.1 handler to notify OS of removal
-events.
+events. Read-only.
PCI device eject (IO port 0xae08-0xae0b, 4-byte access):
----------------------------------------
-Used by ACPI BIOS _EJ0 method to request device removal. One bit per slot.
-Reads return 0.
+Write: Used by ACPI BIOS _EJ0 method to request device removal.
+One bit per slot.
+
+Read: Hotplug features register. Used by platform to identify features
+available. Current base feature set (no bits set):
+ - Read-only "up" register @0xae00, 4-byte access, bit per slot
+ - Read-only "down" register @0xae04, 4-byte access, bit per slot
+ - Read/write "eject" register @0xae08, 4-byte access,
+ write: bit per slot eject, read: hotplug feature set
+ - Read-only hotplug capable register @0xae0c, 4-byte access, bit per slot
PCI removability status (IO port 0xae0c-0xae0f, 4-byte access):
-----------------------------------------------
Used by ACPI BIOS _RMV method to indicate removability status to OS. One
-bit per slot.
+bit per slot. Read-only
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index 797ed24..585da4e 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -40,14 +40,15 @@
#define GPE_BASE 0xafe0
#define GPE_LEN 4
-#define PCI_BASE 0xae00
+#define PCI_UP_BASE 0xae00
+#define PCI_DOWN_BASE 0xae04
#define PCI_EJ_BASE 0xae08
#define PCI_RMV_BASE 0xae0c
#define PIIX4_PCI_HOTPLUG_STATUS 2
struct pci_status {
- uint32_t up;
+ uint32_t up; /* deprecated, maintained for migration compatibility */
uint32_t down;
};
@@ -69,6 +70,7 @@ typedef struct PIIX4PMState {
/* for pci hotplug */
struct pci_status pci0_status;
uint32_t pci0_hotplug_enable;
+ uint32_t pci0_slot_device_present;
} PIIX4PMState;
static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s);
@@ -204,6 +206,17 @@ static void pm_write_config(PCIDevice *d,
pm_io_space_update((PIIX4PMState *)d);
}
+static void vmstate_pci_status_pre_save(void *opaque)
+{
+ struct pci_status *pci0_status = opaque;
+ PIIX4PMState *s = container_of(pci0_status, PIIX4PMState, pci0_status);
+
+ /* We no longer track up, so build a safe value for migrating
+ * to a version that still does... of course these might get lost
+ * by an old buggy implementation, but we try. */
+ pci0_status->up = s->pci0_slot_device_present & s->pci0_hotplug_enable;
+}
+
static int vmstate_acpi_post_load(void *opaque, int version_id)
{
PIIX4PMState *s = opaque;
@@ -240,6 +253,7 @@ static const VMStateDescription vmstate_pci_status = {
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
+ .pre_save = vmstate_pci_status_pre_save,
.fields = (VMStateField []) {
VMSTATE_UINT32(up, struct pci_status),
VMSTATE_UINT32(down, struct pci_status),
@@ -268,13 +282,45 @@ static const VMStateDescription vmstate_acpi = {
}
};
+static void acpi_piix_eject_slot(PIIX4PMState *s, unsigned slots)
+{
+ DeviceState *qdev, *next;
+ BusState *bus = qdev_get_parent_bus(&s->dev.qdev);
+ int slot = ffs(slots) - 1;
+ bool slot_free = true;
+
+ /* Mark request as complete */
+ s->pci0_status.down &= ~(1U << slot);
+
+ QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
+ PCIDevice *dev = PCI_DEVICE(qdev);
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
+ if (PCI_SLOT(dev->devfn) == slot) {
+ if (pc->no_hotplug) {
+ slot_free = false;
+ } else {
+ qdev_free(qdev);
+ }
+ }
+ }
+ if (slot_free) {
+ s->pci0_slot_device_present &= ~(1U << slot);
+ }
+}
+
static void piix4_update_hotplug(PIIX4PMState *s)
{
PCIDevice *dev = &s->dev;
BusState *bus = qdev_get_parent_bus(&dev->qdev);
DeviceState *qdev, *next;
+ /* Execute any pending removes during reset */
+ while (s->pci0_status.down) {
+ acpi_piix_eject_slot(s, s->pci0_status.down);
+ }
+
s->pci0_hotplug_enable = ~0;
+ s->pci0_slot_device_present = 0;
QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
PCIDevice *pdev = PCI_DEVICE(qdev);
@@ -282,8 +328,10 @@ static void piix4_update_hotplug(PIIX4PMState *s)
int slot = PCI_SLOT(pdev->devfn);
if (pc->no_hotplug) {
- s->pci0_hotplug_enable &= ~(1 << slot);
+ s->pci0_hotplug_enable &= ~(1U << slot);
}
+
+ s->pci0_slot_device_present |= (1U << slot);
}
}
@@ -448,60 +496,38 @@ static void gpe_writeb(void *opaque, uint32_t addr, uint32_t val)
PIIX4_DPRINTF("gpe write %x <== %d\n", addr, val);
}
-static uint32_t pcihotplug_read(void *opaque, uint32_t addr)
+static uint32_t pci_up_read(void *opaque, uint32_t addr)
{
- uint32_t val = 0;
- struct pci_status *g = opaque;
- switch (addr) {
- case PCI_BASE:
- val = g->up;
- break;
- case PCI_BASE + 4:
- val = g->down;
- break;
- default:
- break;
- }
+ PIIX4PMState *s = opaque;
+ uint32_t val;
- PIIX4_DPRINTF("pcihotplug read %x == %x\n", addr, val);
+ /* Manufacture an "up" value to cause a device check on any hotplug
+ * slot with a device. Extra device checks are harmless. */
+ val = s->pci0_slot_device_present & s->pci0_hotplug_enable;
+
+ PIIX4_DPRINTF("pci_up_read %x\n", val);
return val;
}
-static void pcihotplug_write(void *opaque, uint32_t addr, uint32_t val)
+static uint32_t pci_down_read(void *opaque, uint32_t addr)
{
- struct pci_status *g = opaque;
- switch (addr) {
- case PCI_BASE:
- g->up = val;
- break;
- case PCI_BASE + 4:
- g->down = val;
- break;
- }
-
- PIIX4_DPRINTF("pcihotplug write %x <== %d\n", addr, val);
+ PIIX4PMState *s = opaque;
+ uint32_t val = s->pci0_status.down;
+
+ PIIX4_DPRINTF("pci_down_read %x\n", val);
+ return val;
}
-static uint32_t pciej_read(void *opaque, uint32_t addr)
+static uint32_t pci_features_read(void *opaque, uint32_t addr)
{
- PIIX4_DPRINTF("pciej read %x\n", addr);
+ /* No feature defined yet */
+ PIIX4_DPRINTF("pci_features_read %x\n", 0);
return 0;
}
static void pciej_write(void *opaque, uint32_t addr, uint32_t val)
{
- BusState *bus = opaque;
- DeviceState *qdev, *next;
- int slot = ffs(val) - 1;
-
- QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
- PCIDevice *dev = PCI_DEVICE(qdev);
- PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
- if (PCI_SLOT(dev->devfn) == slot && !pc->no_hotplug) {
- qdev_free(qdev);
- }
- }
-
+ acpi_piix_eject_slot(opaque, val);
PIIX4_DPRINTF("pciej write %x <== %d\n", addr, val);
}
@@ -513,29 +539,22 @@ static uint32_t pcirmv_read(void *opaque, uint32_t addr)
return s->pci0_hotplug_enable;
}
-static void pcirmv_write(void *opaque, uint32_t addr, uint32_t val)
-{
- return;
-}
-
static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
PCIHotplugState state);
static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
{
- struct pci_status *pci0_status = &s->pci0_status;
register_ioport_write(GPE_BASE, GPE_LEN, 1, gpe_writeb, s);
register_ioport_read(GPE_BASE, GPE_LEN, 1, gpe_readb, s);
acpi_gpe_blk(&s->ar, GPE_BASE);
- register_ioport_write(PCI_BASE, 8, 4, pcihotplug_write, pci0_status);
- register_ioport_read(PCI_BASE, 8, 4, pcihotplug_read, pci0_status);
+ register_ioport_read(PCI_UP_BASE, 4, 4, pci_up_read, s);
+ register_ioport_read(PCI_DOWN_BASE, 4, 4, pci_down_read, s);
- register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, bus);
- register_ioport_read(PCI_EJ_BASE, 4, 4, pciej_read, bus);
+ register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, s);
+ register_ioport_read(PCI_EJ_BASE, 4, 4, pci_features_read, s);
- register_ioport_write(PCI_RMV_BASE, 4, 4, pcirmv_write, s);
register_ioport_read(PCI_RMV_BASE, 4, 4, pcirmv_read, s);
pci_bus_hotplug(bus, piix4_device_hotplug, &s->dev.qdev);
@@ -544,13 +563,13 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
static void enable_device(PIIX4PMState *s, int slot)
{
s->ar.gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;
- s->pci0_status.up |= (1 << slot);
+ s->pci0_slot_device_present |= (1U << slot);
}
static void disable_device(PIIX4PMState *s, int slot)
{
s->ar.gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;
- s->pci0_status.down |= (1 << slot);
+ s->pci0_status.down |= (1U << slot);
}
static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
@@ -564,11 +583,10 @@ static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
* it is present on boot, no hotplug event is necessary. We do send an
* event when the device is disabled later. */
if (state == PCI_COLDPLUG_ENABLED) {
+ s->pci0_slot_device_present |= (1U << slot);
return 0;
}
- s->pci0_status.up = 0;
- s->pci0_status.down = 0;
if (state == PCI_HOTPLUG_ENABLED) {
enable_device(s, slot);
} else {
diff --git a/hw/ivshmem.c b/hw/ivshmem.c
index df4f50a..d48e5f9 100644
--- a/hw/ivshmem.c
+++ b/hw/ivshmem.c
@@ -509,11 +509,29 @@ static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
return;
}
+/* Select the MSI-X vectors used by device.
+ * ivshmem maps events to vectors statically, so
+ * we just enable all vectors on init and after reset. */
+static void ivshmem_use_msix(IVShmemState * s)
+{
+ int i;
+
+ if (!msix_present(&s->dev)) {
+ return;
+ }
+
+ for (i = 0; i < s->vectors; i++) {
+ msix_vector_use(&s->dev, i);
+ }
+}
+
static void ivshmem_reset(DeviceState *d)
{
IVShmemState *s = DO_UPCAST(IVShmemState, dev.qdev, d);
s->intrstatus = 0;
+ msix_reset(&s->dev);
+ ivshmem_use_msix(s);
return;
}
@@ -544,12 +562,8 @@ static uint64_t ivshmem_get_size(IVShmemState * s) {
return value;
}
-static void ivshmem_setup_msi(IVShmemState * s) {
-
- int i;
-
- /* allocate the MSI-X vectors */
-
+static void ivshmem_setup_msi(IVShmemState * s)
+{
memory_region_init(&s->msix_bar, "ivshmem-msix", 4096);
if (!msix_init(&s->dev, s->vectors, &s->msix_bar, 1, 0)) {
pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY,
@@ -560,13 +574,10 @@ static void ivshmem_setup_msi(IVShmemState * s) {
exit(1);
}
- /* 'activate' the vectors */
- for (i = 0; i < s->vectors; i++) {
- msix_vector_use(&s->dev, i);
- }
-
/* allocate QEMU char devices for receiving interrupts */
s->eventfd_table = g_malloc0(s->vectors * sizeof(EventfdEntry));
+
+ ivshmem_use_msix(s);
}
static void ivshmem_save(QEMUFile* f, void *opaque)
@@ -590,7 +601,7 @@ static int ivshmem_load(QEMUFile* f, void *opaque, int version_id)
IVSHMEM_DPRINTF("ivshmem_load\n");
IVShmemState *proxy = opaque;
- int ret, i;
+ int ret;
if (version_id > 0) {
return -EINVAL;
@@ -608,9 +619,7 @@ static int ivshmem_load(QEMUFile* f, void *opaque, int version_id)
if (ivshmem_has_feature(proxy, IVSHMEM_MSI)) {
msix_load(&proxy->dev, f);
- for (i = 0; i < proxy->vectors; i++) {
- msix_vector_use(&proxy->dev, i);
- }
+ ivshmem_use_msix(proxy);
} else {
proxy->intrstatus = qemu_get_be32(f);
proxy->intrmask = qemu_get_be32(f);
@@ -619,6 +628,13 @@ static int ivshmem_load(QEMUFile* f, void *opaque, int version_id)
return 0;
}
+static void ivshmem_write_config(PCIDevice *pci_dev, uint32_t address,
+ uint32_t val, int len)
+{
+ pci_default_write_config(pci_dev, address, val, len);
+ msix_write_config(pci_dev, address, val, len);
+}
+
static int pci_ivshmem_init(PCIDevice *dev)
{
IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
@@ -744,6 +760,8 @@ static int pci_ivshmem_init(PCIDevice *dev)
}
+ s->dev.config_write = ivshmem_write_config;
+
return 0;
}
diff --git a/hw/pc.c b/hw/pc.c
index 67f0479..1f5aacb 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -42,6 +42,7 @@
#include "sysbus.h"
#include "sysemu.h"
#include "kvm.h"
+#include "xen.h"
#include "blockdev.h"
#include "ui/qemu-spice.h"
#include "memory.h"
@@ -891,9 +892,12 @@ static DeviceState *apic_init(void *env, uint8_t apic_id)
if (kvm_irqchip_in_kernel()) {
dev = qdev_create(NULL, "kvm-apic");
+ } else if (xen_enabled()) {
+ dev = qdev_create(NULL, "xen-apic");
} else {
dev = qdev_create(NULL, "apic");
}
+
qdev_prop_set_uint8(dev, "id", apic_id);
qdev_prop_set_ptr(dev, "cpu_env", env);
qdev_init_nofail(dev);
@@ -912,6 +916,10 @@ static DeviceState *apic_init(void *env, uint8_t apic_id)
msi_supported = true;
}
+ if (xen_enabled()) {
+ msi_supported = true;
+ }
+
return dev;
}
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 44995bf..907d723 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -28,6 +28,7 @@
#include "pc.h"
#include "apic.h"
#include "pci.h"
+#include "pci_ids.h"
#include "net.h"
#include "boards.h"
#include "ide.h"
@@ -359,58 +360,77 @@ static QEMUMachine pc_machine_v1_1 = {
.is_default = 1,
};
+#define PC_COMPAT_1_0 \
+ {\
+ .driver = "pc-sysfw",\
+ .property = "rom_only",\
+ .value = stringify(1),\
+ }, {\
+ .driver = "isa-fdc",\
+ .property = "check_media_rate",\
+ .value = "off",\
+ }, {\
+ .driver = "virtio-balloon-pci",\
+ .property = "class",\
+ .value = stringify(PCI_CLASS_MEMORY_RAM),\
+ },{\
+ .driver = "apic",\
+ .property = "vapic",\
+ .value = "off",\
+ }
+
static QEMUMachine pc_machine_v1_0 = {
.name = "pc-1.0",
.desc = "Standard PC",
.init = pc_init_pci,
.max_cpus = 255,
.compat_props = (GlobalProperty[]) {
- {
- .driver = "pc-sysfw",
- .property = "rom_only",
- .value = stringify(1),
- }, {
- .driver = "isa-fdc",
- .property = "check_media_rate",
- .value = "off",
- },{
- .driver = "apic",
- .property = "vapic",
- .value = "off",
- },
+ PC_COMPAT_1_0,
{ /* end of list */ }
},
};
+#define PC_COMPAT_0_15 \
+ PC_COMPAT_1_0
+
static QEMUMachine pc_machine_v0_15 = {
.name = "pc-0.15",
.desc = "Standard PC",
.init = pc_init_pci,
.max_cpus = 255,
.compat_props = (GlobalProperty[]) {
- {
- .driver = "pc-sysfw",
- .property = "rom_only",
- .value = stringify(1),
- }, {
- .driver = "isa-fdc",
- .property = "check_media_rate",
- .value = "off",
- },{
- .driver = "apic",
- .property = "vapic",
- .value = "off",
- },
+ PC_COMPAT_0_15,
{ /* end of list */ }
},
};
+#define PC_COMPAT_0_14 \
+ PC_COMPAT_0_15,\
+ {\
+ .driver = "virtio-blk-pci",\
+ .property = "event_idx",\
+ .value = "off",\
+ },{\
+ .driver = "virtio-serial-pci",\
+ .property = "event_idx",\
+ .value = "off",\
+ },{\
+ .driver = "virtio-net-pci",\
+ .property = "event_idx",\
+ .value = "off",\
+ },{\
+ .driver = "virtio-balloon-pci",\
+ .property = "event_idx",\
+ .value = "off",\
+ }
+
static QEMUMachine pc_machine_v0_14 = {
.name = "pc-0.14",
.desc = "Standard PC",
.init = pc_init_pci,
.max_cpus = 255,
.compat_props = (GlobalProperty[]) {
+ PC_COMPAT_0_14,
{
.driver = "qxl",
.property = "revision",
@@ -419,45 +439,30 @@ static QEMUMachine pc_machine_v0_14 = {
.driver = "qxl-vga",
.property = "revision",
.value = stringify(2),
- },{
- .driver = "virtio-blk-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-serial-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-net-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-balloon-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "isa-fdc",
- .property = "check_media_rate",
- .value = "off",
- },{
- .driver = "pc-sysfw",
- .property = "rom_only",
- .value = stringify(1),
- },{
- .driver = "apic",
- .property = "vapic",
- .value = "off",
},
{ /* end of list */ }
},
};
+#define PC_COMPAT_0_13 \
+ PC_COMPAT_0_14,\
+ {\
+ .driver = "PCI",\
+ .property = "command_serr_enable",\
+ .value = "off",\
+ },{\
+ .driver = "AC97",\
+ .property = "use_broken_id",\
+ .value = stringify(1),\
+ }
+
static QEMUMachine pc_machine_v0_13 = {
.name = "pc-0.13",
.desc = "Standard PC",
.init = pc_init_pci_no_kvmclock,
.max_cpus = 255,
.compat_props = (GlobalProperty[]) {
+ PC_COMPAT_0_13,
{
.driver = "virtio-9p-pci",
.property = "vectors",
@@ -470,62 +475,31 @@ static QEMUMachine pc_machine_v0_13 = {
.driver = "vmware-svga",
.property = "rombar",
.value = stringify(0),
- },{
- .driver = "PCI",
- .property = "command_serr_enable",
- .value = "off",
- },{
- .driver = "virtio-blk-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-serial-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-net-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-balloon-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "AC97",
- .property = "use_broken_id",
- .value = stringify(1),
- },{
- .driver = "isa-fdc",
- .property = "check_media_rate",
- .value = "off",
- },{
- .driver = "pc-sysfw",
- .property = "rom_only",
- .value = stringify(1),
- },{
- .driver = "apic",
- .property = "vapic",
- .value = "off",
},
{ /* end of list */ }
},
};
+#define PC_COMPAT_0_12 \
+ PC_COMPAT_0_13,\
+ {\
+ .driver = "virtio-serial-pci",\
+ .property = "max_ports",\
+ .value = stringify(1),\
+ },{\
+ .driver = "virtio-serial-pci",\
+ .property = "vectors",\
+ .value = stringify(0),\
+ }
+
static QEMUMachine pc_machine_v0_12 = {
.name = "pc-0.12",
.desc = "Standard PC",
.init = pc_init_pci_no_kvmclock,
.max_cpus = 255,
.compat_props = (GlobalProperty[]) {
+ PC_COMPAT_0_12,
{
- .driver = "virtio-serial-pci",
- .property = "max_ports",
- .value = stringify(1),
- },{
- .driver = "virtio-serial-pci",
- .property = "vectors",
- .value = stringify(0),
- },{
.driver = "VGA",
.property = "rombar",
.value = stringify(0),
@@ -533,66 +507,27 @@ static QEMUMachine pc_machine_v0_12 = {
.driver = "vmware-svga",
.property = "rombar",
.value = stringify(0),
- },{
- .driver = "PCI",
- .property = "command_serr_enable",
- .value = "off",
- },{
- .driver = "virtio-blk-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-serial-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-net-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-balloon-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "AC97",
- .property = "use_broken_id",
- .value = stringify(1),
- },{
- .driver = "isa-fdc",
- .property = "check_media_rate",
- .value = "off",
- },{
- .driver = "pc-sysfw",
- .property = "rom_only",
- .value = stringify(1),
- },{
- .driver = "apic",
- .property = "vapic",
- .value = "off",
},
{ /* end of list */ }
}
};
+#define PC_COMPAT_0_11 \
+ PC_COMPAT_0_12,\
+ {\
+ .driver = "virtio-blk-pci",\
+ .property = "vectors",\
+ .value = stringify(0),\
+ }
+
static QEMUMachine pc_machine_v0_11 = {
.name = "pc-0.11",
.desc = "Standard PC, qemu 0.11",
.init = pc_init_pci_no_kvmclock,
.max_cpus = 255,
.compat_props = (GlobalProperty[]) {
+ PC_COMPAT_0_11,
{
- .driver = "virtio-blk-pci",
- .property = "vectors",
- .value = stringify(0),
- },{
- .driver = "virtio-serial-pci",
- .property = "max_ports",
- .value = stringify(1),
- },{
- .driver = "virtio-serial-pci",
- .property = "vectors",
- .value = stringify(0),
- },{
.driver = "ide-drive",
.property = "ver",
.value = "0.11",
@@ -600,46 +535,6 @@ static QEMUMachine pc_machine_v0_11 = {
.driver = "scsi-disk",
.property = "ver",
.value = "0.11",
- },{
- .driver = "PCI",
- .property = "rombar",
- .value = stringify(0),
- },{
- .driver = "PCI",
- .property = "command_serr_enable",
- .value = "off",
- },{
- .driver = "virtio-blk-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-serial-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-net-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-balloon-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "AC97",
- .property = "use_broken_id",
- .value = stringify(1),
- },{
- .driver = "isa-fdc",
- .property = "check_media_rate",
- .value = "off",
- },{
- .driver = "pc-sysfw",
- .property = "rom_only",
- .value = stringify(1),
- },{
- .driver = "apic",
- .property = "vapic",
- .value = "off",
},
{ /* end of list */ }
}
@@ -651,6 +546,7 @@ static QEMUMachine pc_machine_v0_10 = {
.init = pc_init_pci_no_kvmclock,
.max_cpus = 255,
.compat_props = (GlobalProperty[]) {
+ PC_COMPAT_0_11,
{
.driver = "virtio-blk-pci",
.property = "class",
@@ -660,22 +556,10 @@ static QEMUMachine pc_machine_v0_10 = {
.property = "class",
.value = stringify(PCI_CLASS_DISPLAY_OTHER),
},{
- .driver = "virtio-serial-pci",
- .property = "max_ports",
- .value = stringify(1),
- },{
- .driver = "virtio-serial-pci",
- .property = "vectors",
- .value = stringify(0),
- },{
.driver = "virtio-net-pci",
.property = "vectors",
.value = stringify(0),
},{
- .driver = "virtio-blk-pci",
- .property = "vectors",
- .value = stringify(0),
- },{
.driver = "ide-drive",
.property = "ver",
.value = "0.10",
@@ -683,46 +567,6 @@ static QEMUMachine pc_machine_v0_10 = {
.driver = "scsi-disk",
.property = "ver",
.value = "0.10",
- },{
- .driver = "PCI",
- .property = "rombar",
- .value = stringify(0),
- },{
- .driver = "PCI",
- .property = "command_serr_enable",
- .value = "off",
- },{
- .driver = "virtio-blk-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-serial-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-net-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "virtio-balloon-pci",
- .property = "event_idx",
- .value = "off",
- },{
- .driver = "AC97",
- .property = "use_broken_id",
- .value = stringify(1),
- },{
- .driver = "isa-fdc",
- .property = "check_media_rate",
- .value = "off",
- },{
- .driver = "pc-sysfw",
- .property = "rom_only",
- .value = stringify(1),
- },{
- .driver = "apic",
- .property = "vapic",
- .value = "off",
},
{ /* end of list */ }
},
diff --git a/hw/pci_host.c b/hw/pci_host.c
index 44c6c20..8041778 100644
--- a/hw/pci_host.c
+++ b/hw/pci_host.c
@@ -101,6 +101,9 @@ static void pci_host_config_write(void *opaque, target_phys_addr_t addr,
PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx64"\n",
__func__, addr, len, val);
+ if (addr != 0 || len != 4) {
+ return;
+ }
s->config_reg = val;
}
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 179d9a6..09e84f5 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -349,7 +349,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn,
b = i440fx_common_init("i440FX", pi440fx_state, piix3_devfn, isa_bus, pic,
address_space_mem, address_space_io, ram_size,
pci_hole_start, pci_hole_size,
- pci_hole64_size, pci_hole64_size,
+ pci_hole64_start, pci_hole64_size,
pci_memory, ram_memory);
return b;
}
diff --git a/hw/vhost.c b/hw/vhost.c
index 8d3ba5b..43664e7 100644
--- a/hw/vhost.c
+++ b/hw/vhost.c
@@ -31,11 +31,12 @@ static void vhost_dev_sync_region(struct vhost_dev *dev,
vhost_log_chunk_t *to = dev->log + end / VHOST_LOG_CHUNK + 1;
uint64_t addr = (start / VHOST_LOG_CHUNK) * VHOST_LOG_CHUNK;
- assert(end / VHOST_LOG_CHUNK < dev->log_size);
- assert(start / VHOST_LOG_CHUNK < dev->log_size);
if (end < start) {
return;
}
+ assert(end / VHOST_LOG_CHUNK < dev->log_size);
+ assert(start / VHOST_LOG_CHUNK < dev->log_size);
+
for (;from < to; ++from) {
vhost_log_chunk_t log;
int bit;
@@ -277,8 +278,9 @@ static inline void vhost_dev_log_resize(struct vhost_dev* dev, uint64_t size)
r = ioctl(dev->control, VHOST_SET_LOG_BASE, &log_base);
assert(r >= 0);
for (i = 0; i < dev->n_mem_sections; ++i) {
- vhost_sync_dirty_bitmap(dev, &dev->mem_sections[i],
- 0, (target_phys_addr_t)~0x0ull);
+ /* Sync only the range covered by the old log */
+ vhost_sync_dirty_bitmap(dev, &dev->mem_sections[i], 0,
+ dev->log_size * VHOST_LOG_CHUNK - 1);
}
if (dev->log) {
g_free(dev->log);
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index a0fb7c1..4a4413d 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -790,6 +790,11 @@ static int virtio_balloon_init_pci(PCIDevice *pci_dev)
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
VirtIODevice *vdev;
+ if (proxy->class_code != PCI_CLASS_OTHERS &&
+ proxy->class_code != PCI_CLASS_MEMORY_RAM) { /* qemu < 1.1 */
+ proxy->class_code = PCI_CLASS_OTHERS;
+ }
+
vdev = virtio_balloon_init(&pci_dev->qdev);
if (!vdev) {
return -1;
@@ -906,6 +911,7 @@ static TypeInfo virtio_serial_info = {
static Property virtio_balloon_properties[] = {
DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+ DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
DEFINE_PROP_END_OF_LIST(),
};
@@ -919,7 +925,7 @@ static void virtio_balloon_class_init(ObjectClass *klass, void *data)
k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON;
k->revision = VIRTIO_PCI_ABI_VERSION;
- k->class_id = PCI_CLASS_MEMORY_RAM;
+ k->class_id = PCI_CLASS_OTHERS;
dc->reset = virtio_pci_reset;
dc->props = virtio_balloon_properties;
}
diff --git a/hw/xen.h b/hw/xen.h
index b46879c..e5926b7 100644
--- a/hw/xen.h
+++ b/hw/xen.h
@@ -34,6 +34,7 @@ static inline int xen_enabled(void)
int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num);
void xen_piix3_set_irq(void *opaque, int irq_num, int level);
void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len);
+void xen_hvm_inject_msi(uint64_t addr, uint32_t data);
void xen_cmos_set_s3_resume(void *opaque, int irq, int level);
qemu_irq *xen_interrupt_controller_init(void);
diff --git a/hw/xen_apic.c b/hw/xen_apic.c
new file mode 100644
index 0000000..1725ff6
--- /dev/null
+++ b/hw/xen_apic.c
@@ -0,0 +1,90 @@
+/*
+ * Xen basic APIC support
+ *
+ * Copyright (c) 2012 Citrix
+ *
+ * Authors:
+ * Wei Liu <wei.liu2@citrix.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2 or
+ * later. See the COPYING file in the top-level directory.
+ */
+#include "hw/apic_internal.h"
+#include "hw/msi.h"
+#include "xen.h"
+
+static uint64_t xen_apic_mem_read(void *opaque, target_phys_addr_t addr,
+ unsigned size)
+{
+ return ~(uint64_t)0;
+}
+
+static void xen_apic_mem_write(void *opaque, target_phys_addr_t addr,
+ uint64_t data, unsigned size)
+{
+ if (size != sizeof(uint32_t)) {
+ fprintf(stderr, "Xen: APIC write data size = %d, invalid\n", size);
+ return;
+ }
+
+ xen_hvm_inject_msi(addr, data);
+}
+
+static const MemoryRegionOps xen_apic_io_ops = {
+ .read = xen_apic_mem_read,
+ .write = xen_apic_mem_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void xen_apic_init(APICCommonState *s)
+{
+ memory_region_init_io(&s->io_memory, &xen_apic_io_ops, s, "xen-apic-msi",
+ MSI_SPACE_SIZE);
+}
+
+static void xen_apic_set_base(APICCommonState *s, uint64_t val)
+{
+}
+
+static void xen_apic_set_tpr(APICCommonState *s, uint8_t val)
+{
+}
+
+static uint8_t xen_apic_get_tpr(APICCommonState *s)
+{
+ return 0;
+}
+
+static void xen_apic_vapic_base_update(APICCommonState *s)
+{
+}
+
+static void xen_apic_external_nmi(APICCommonState *s)
+{
+}
+
+static void xen_apic_class_init(ObjectClass *klass, void *data)
+{
+ APICCommonClass *k = APIC_COMMON_CLASS(klass);
+
+ k->init = xen_apic_init;
+ k->set_base = xen_apic_set_base;
+ k->set_tpr = xen_apic_set_tpr;
+ k->get_tpr = xen_apic_get_tpr;
+ k->vapic_base_update = xen_apic_vapic_base_update;
+ k->external_nmi = xen_apic_external_nmi;
+}
+
+static TypeInfo xen_apic_info = {
+ .name = "xen-apic",
+ .parent = TYPE_APIC_COMMON,
+ .instance_size = sizeof(APICCommonState),
+ .class_init = xen_apic_class_init,
+};
+
+static void xen_apic_register_types(void)
+{
+ type_register_static(&xen_apic_info);
+}
+
+type_init(xen_apic_register_types)
diff --git a/hw/xen_backend.c b/hw/xen_backend.c
index 2673ace..66cb144 100644
--- a/hw/xen_backend.c
+++ b/hw/xen_backend.c
@@ -592,7 +592,7 @@ static void xenstore_update_be(char *watch, char *type, int dom,
struct XenDevOps *ops)
{
struct XenDevice *xendev;
- char path[XEN_BUFSIZE], *dom0;
+ char path[XEN_BUFSIZE], *dom0, *bepath;
unsigned int len, dev;
dom0 = xs_get_domain_path(xenstore, 0);
@@ -611,15 +611,16 @@ static void xenstore_update_be(char *watch, char *type, int dom,
return;
}
- if (0) {
- /* FIXME: detect devices being deleted from xenstore ... */
- xen_be_del_xendev(dom, dev);
- }
-
xendev = xen_be_get_xendev(type, dom, dev, ops);
if (xendev != NULL) {
- xen_be_backend_changed(xendev, path);
- xen_be_check_state(xendev);
+ bepath = xs_read(xenstore, 0, xendev->be, &len);
+ if (bepath == NULL) {
+ xen_be_del_xendev(dom, dev);
+ } else {
+ free(bepath);
+ xen_be_backend_changed(xendev, path);
+ xen_be_check_state(xendev);
+ }
}
}
diff --git a/hw/xen_disk.c b/hw/xen_disk.c
index 9719395..22dbd10 100644
--- a/hw/xen_disk.c
+++ b/hw/xen_disk.c
@@ -745,6 +745,10 @@ static int blk_free(struct XenDevice *xendev)
struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
struct ioreq *ioreq;
+ if (blkdev->bs || blkdev->sring) {
+ blk_disconnect(xendev);
+ }
+
while (!QLIST_EMPTY(&blkdev->freelist)) {
ioreq = QLIST_FIRST(&blkdev->freelist);
QLIST_REMOVE(ioreq, list);
diff --git a/xen-all.c b/xen-all.c
index 3e6de41..a08eec0 100644
--- a/xen-all.c
+++ b/xen-all.c
@@ -59,6 +59,9 @@ static inline ioreq_t *xen_vcpu_ioreq(shared_iopage_t *shared_page, int vcpu)
}
# define FMT_ioreq_size "u"
#endif
+#ifndef HVM_PARAM_BUFIOREQ_EVTCHN
+#define HVM_PARAM_BUFIOREQ_EVTCHN 26
+#endif
#define BUFFER_IO_MAX_DELAY 100
@@ -77,6 +80,8 @@ typedef struct XenIOState {
QEMUTimer *buffered_io_timer;
/* the evtchn port for polling the notification, */
evtchn_port_t *ioreq_local_port;
+ /* evtchn local port for buffered io */
+ evtchn_port_t bufioreq_local_port;
/* the evtchn fd for polling */
XenEvtchn xce_handle;
/* which vcpu we are serving */
@@ -122,6 +127,11 @@ void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len)
}
}
+void xen_hvm_inject_msi(uint64_t addr, uint32_t data)
+{
+ xc_hvm_inject_msi(xen_xc, xen_domid, addr, data);
+}
+
static void xen_suspend_notifier(Notifier *notifier, void *data)
{
xc_set_hvm_param(xen_xc, xen_domid, HVM_PARAM_ACPI_S_STATE, 3);
@@ -624,6 +634,12 @@ static ioreq_t *cpu_get_ioreq(XenIOState *state)
evtchn_port_t port;
port = xc_evtchn_pending(state->xce_handle);
+ if (port == state->bufioreq_local_port) {
+ qemu_mod_timer(state->buffered_io_timer,
+ BUFFER_IO_MAX_DELAY + qemu_get_clock_ms(rt_clock));
+ return NULL;
+ }
+
if (port != -1) {
for (i = 0; i < smp_cpus; i++) {
if (state->ioreq_local_port[i] == port) {
@@ -772,16 +788,18 @@ static void handle_ioreq(ioreq_t *req)
}
}
-static void handle_buffered_iopage(XenIOState *state)
+static int handle_buffered_iopage(XenIOState *state)
{
buf_ioreq_t *buf_req = NULL;
ioreq_t req;
int qw;
if (!state->buffered_io_page) {
- return;
+ return 0;
}
+ memset(&req, 0x00, sizeof(req));
+
while (state->buffered_io_page->read_pointer != state->buffered_io_page->write_pointer) {
buf_req = &state->buffered_io_page->buf_ioreq[
state->buffered_io_page->read_pointer % IOREQ_BUFFER_SLOT_NUM];
@@ -806,15 +824,21 @@ static void handle_buffered_iopage(XenIOState *state)
xen_mb();
state->buffered_io_page->read_pointer += qw ? 2 : 1;
}
+
+ return req.count;
}
static void handle_buffered_io(void *opaque)
{
XenIOState *state = opaque;
- handle_buffered_iopage(state);
- qemu_mod_timer(state->buffered_io_timer,
- BUFFER_IO_MAX_DELAY + qemu_get_clock_ms(rt_clock));
+ if (handle_buffered_iopage(state)) {
+ qemu_mod_timer(state->buffered_io_timer,
+ BUFFER_IO_MAX_DELAY + qemu_get_clock_ms(rt_clock));
+ } else {
+ qemu_del_timer(state->buffered_io_timer);
+ xc_evtchn_unmask(state->xce_handle, state->bufioreq_local_port);
+ }
}
static void cpu_handle_ioreq(void *opaque)
@@ -944,7 +968,6 @@ static void xen_main_loop_prepare(XenIOState *state)
state->buffered_io_timer = qemu_new_timer_ms(rt_clock, handle_buffered_io,
state);
- qemu_mod_timer(state->buffered_io_timer, qemu_get_clock_ms(rt_clock));
if (evtchn_fd != -1) {
qemu_set_fd_handler(evtchn_fd, cpu_handle_ioreq, NULL, state);
@@ -1045,6 +1068,7 @@ int xen_hvm_init(void)
{
int i, rc;
unsigned long ioreq_pfn;
+ unsigned long bufioreq_evtchn;
XenIOState *state;
state = g_malloc0(sizeof (XenIOState));
@@ -1097,6 +1121,20 @@ int xen_hvm_init(void)
state->ioreq_local_port[i] = rc;
}
+ rc = xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_BUFIOREQ_EVTCHN,
+ &bufioreq_evtchn);
+ if (rc < 0) {
+ fprintf(stderr, "failed to get HVM_PARAM_BUFIOREQ_EVTCHN\n");
+ return -1;
+ }
+ rc = xc_evtchn_bind_interdomain(state->xce_handle, xen_domid,
+ (uint32_t)bufioreq_evtchn);
+ if (rc == -1) {
+ fprintf(stderr, "bind interdomain ioctl error %d\n", errno);
+ return -1;
+ }
+ state->bufioreq_local_port = rc;
+
/* Init RAM management */
xen_map_cache_init(xen_phys_offset_to_gaddr, state);
xen_ram_init(ram_size);
diff --git a/xen-mapcache.c b/xen-mapcache.c
index a456479..59ba085 100644
--- a/xen-mapcache.c
+++ b/xen-mapcache.c
@@ -216,12 +216,14 @@ tryagain:
}
/* size is always a multiple of MCACHE_BUCKET_SIZE */
- if ((address_offset + (__size % MCACHE_BUCKET_SIZE)) > MCACHE_BUCKET_SIZE)
- __size += MCACHE_BUCKET_SIZE;
- if (__size % MCACHE_BUCKET_SIZE)
- __size += MCACHE_BUCKET_SIZE - (__size % MCACHE_BUCKET_SIZE);
- if (!__size)
+ if (size) {
+ __size = size + address_offset;
+ if (__size % MCACHE_BUCKET_SIZE) {
+ __size += MCACHE_BUCKET_SIZE - (__size % MCACHE_BUCKET_SIZE);
+ }
+ } else {
__size = MCACHE_BUCKET_SIZE;
+ }
entry = &mapcache->entry[address_index % mapcache->nr_buckets];
@@ -385,6 +387,9 @@ void xen_invalidate_map_cache(void)
if (entry->vaddr_base == NULL) {
continue;
}
+ if (entry->lock > 0) {
+ continue;
+ }
if (munmap(entry->vaddr_base, entry->size) != 0) {
perror("unmap fails");
diff --git a/xen-stub.c b/xen-stub.c
index 9ea02d4..8ff2b79 100644
--- a/xen-stub.c
+++ b/xen-stub.c
@@ -29,6 +29,10 @@ void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len)
{
}
+void xen_hvm_inject_msi(uint64_t addr, uint32_t data)
+{
+}
+
void xen_cmos_set_s3_resume(void *opaque, int irq, int level)
{
}