aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2018-07-17 17:06:32 +0100
committerPeter Maydell <peter.maydell@linaro.org>2018-07-17 17:06:32 +0100
commit59b5552f020b739e273e969a0933c23d8f4e2284 (patch)
treeff90e006b6500ec58d0abb8d495a9a95151589f0
parentccf02d73d18930a15282556e577c0777fa09081b (diff)
parentdfaa7d50b0f72060764096ffcae4a0c06ce24f9b (diff)
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
Bug fixes. # gpg: Signature made Tue 17 Jul 2018 16:06:07 BST # gpg: using RSA key BFFBD25F78C7AE83 # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" # Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1 # Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83 * remotes/bonzini/tags/for-upstream: Document command line options with single dash opts: remove redundant check for NULL parameter i386: only parse the initrd_filename once for multiboot modules i386: fix regression parsing multiboot initrd modules virtio-scsi: fix hotplug ->reset() vs event race qdev: add HotplugHandler->post_plug() callback hw/char/serial: retry write if EAGAIN PC Chipset: Improve serial divisor calculation vhost-user-test: added proper TestServer *dest initialization in test_migrate() hyperv: ensure VP index equal to QEMU cpu_index hyperv: rename vcpu_id to vp_index accel: Fix typo and grammar in comment dump: add kernel_gs_base to QEMU CPU state Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--accel/tcg/translate-all.c2
-rw-r--r--hw/char/serial.c46
-rw-r--r--hw/core/hotplug.c10
-rw-r--r--hw/core/qdev.c4
-rw-r--r--hw/i386/multiboot.c35
-rw-r--r--hw/i386/pc.c5
-rw-r--r--hw/misc/hyperv_testdev.c16
-rw-r--r--hw/scsi/virtio-scsi.c11
-rw-r--r--include/hw/hotplug.h11
-rw-r--r--qemu-options.hx8
-rw-r--r--target/i386/arch_dump.c10
-rw-r--r--target/i386/hyperv.c16
-rw-r--r--target/i386/hyperv.h7
-rw-r--r--target/i386/kvm-stub.c5
-rw-r--r--target/i386/kvm.c47
-rw-r--r--target/i386/kvm_i386.h2
-rw-r--r--tests/vhost-user-test.c3
-rw-r--r--util/qemu-option.c8
18 files changed, 184 insertions, 62 deletions
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index 49d77fad44..1571987113 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -1795,7 +1795,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
tb->jmp_dest[0] = (uintptr_t)NULL;
tb->jmp_dest[1] = (uintptr_t)NULL;
- /* init original jump addresses wich has been set during tcg_gen_code() */
+ /* init original jump addresses which have been set during tcg_gen_code() */
if (tb->jmp_reset_offset[0] != TB_JMP_RESET_OFFSET_INVALID) {
tb_reset_jump(tb, 0);
}
diff --git a/hw/char/serial.c b/hw/char/serial.c
index cd7d747c68..251f40fdac 100644
--- a/hw/char/serial.c
+++ b/hw/char/serial.c
@@ -150,13 +150,10 @@ static void serial_update_irq(SerialState *s)
static void serial_update_parameters(SerialState *s)
{
- int speed, parity, data_bits, stop_bits, frame_size;
+ float speed;
+ int parity, data_bits, stop_bits, frame_size;
QEMUSerialSetParams ssp;
- if (s->divider == 0 || s->divider > s->baudbase) {
- return;
- }
-
/* Start bit. */
frame_size = 1;
if (s->lcr & 0x08) {
@@ -169,14 +166,16 @@ static void serial_update_parameters(SerialState *s)
} else {
parity = 'N';
}
- if (s->lcr & 0x04)
+ if (s->lcr & 0x04) {
stop_bits = 2;
- else
+ } else {
stop_bits = 1;
+ }
data_bits = (s->lcr & 0x03) + 5;
frame_size += data_bits + stop_bits;
- speed = s->baudbase / s->divider;
+ /* Zero divisor should give about 3500 baud */
+ speed = (s->divider == 0) ? 3500 : (float) s->baudbase / s->divider;
ssp.speed = speed;
ssp.parity = parity;
ssp.data_bits = data_bits;
@@ -184,7 +183,7 @@ static void serial_update_parameters(SerialState *s)
s->char_transmit_time = (NANOSECONDS_PER_SECOND / speed) * frame_size;
qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
- DPRINTF("speed=%d parity=%c data=%d stop=%d\n",
+ DPRINTF("speed=%.2f parity=%c data=%d stop=%d\n",
speed, parity, data_bits, stop_bits);
}
@@ -261,15 +260,20 @@ static void serial_xmit(SerialState *s)
if (s->mcr & UART_MCR_LOOP) {
/* in loopback mode, say that we just received a char */
serial_receive1(s, &s->tsr, 1);
- } else if (qemu_chr_fe_write(&s->chr, &s->tsr, 1) == 0 &&
- s->tsr_retry < MAX_XMIT_RETRY) {
- assert(s->watch_tag == 0);
- s->watch_tag =
- qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
- serial_watch_cb, s);
- if (s->watch_tag > 0) {
- s->tsr_retry++;
- return;
+ } else {
+ int rc = qemu_chr_fe_write(&s->chr, &s->tsr, 1);
+
+ if ((rc == 0 ||
+ (rc == -1 && errno == EAGAIN)) &&
+ s->tsr_retry < MAX_XMIT_RETRY) {
+ assert(s->watch_tag == 0);
+ s->watch_tag =
+ qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
+ serial_watch_cb, s);
+ if (s->watch_tag > 0) {
+ s->tsr_retry++;
+ return;
+ }
}
}
s->tsr_retry = 0;
@@ -341,7 +345,11 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
default:
case 0:
if (s->lcr & UART_LCR_DLAB) {
- s->divider = (s->divider & 0xff00) | val;
+ if (size == 2) {
+ s->divider = (s->divider & 0xff00) | val;
+ } else if (size == 4) {
+ s->divider = val;
+ }
serial_update_parameters(s);
} else {
s->thr = (uint8_t) val;
diff --git a/hw/core/hotplug.c b/hw/core/hotplug.c
index 17ac986685..2253072d0e 100644
--- a/hw/core/hotplug.c
+++ b/hw/core/hotplug.c
@@ -35,6 +35,16 @@ void hotplug_handler_plug(HotplugHandler *plug_handler,
}
}
+void hotplug_handler_post_plug(HotplugHandler *plug_handler,
+ DeviceState *plugged_dev)
+{
+ HotplugHandlerClass *hdc = HOTPLUG_HANDLER_GET_CLASS(plug_handler);
+
+ if (hdc->post_plug) {
+ hdc->post_plug(plug_handler, plugged_dev);
+ }
+}
+
void hotplug_handler_unplug_request(HotplugHandler *plug_handler,
DeviceState *plugged_dev,
Error **errp)
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index cf0db4b6da..529b82de18 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -867,6 +867,10 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
device_reset(dev);
}
dev->pending_deleted_event = false;
+
+ if (hotplug_ctrl) {
+ hotplug_handler_post_plug(hotplug_ctrl, dev);
+ }
} else if (!value && dev->realized) {
Error **local_errp = NULL;
QLIST_FOREACH(bus, &dev->child_bus, sibling) {
diff --git a/hw/i386/multiboot.c b/hw/i386/multiboot.c
index 7a2953e26f..d519e206c5 100644
--- a/hw/i386/multiboot.c
+++ b/hw/i386/multiboot.c
@@ -161,6 +161,7 @@ int load_multiboot(FWCfgState *fw_cfg,
uint8_t bootinfo[MBI_SIZE];
uint8_t *mb_bootinfo_data;
uint32_t cmdline_len;
+ GList *mods = NULL;
/* Ok, let's see if it is a multiboot image.
The header is 12x32bit long, so the latest entry may be 8192 - 48. */
@@ -291,16 +292,16 @@ int load_multiboot(FWCfgState *fw_cfg,
cmdline_len = strlen(kernel_filename) + 1;
cmdline_len += strlen(kernel_cmdline) + 1;
if (initrd_filename) {
- const char *r = get_opt_value(initrd_filename, NULL);
- cmdline_len += strlen(r) + 1;
- mbs.mb_mods_avail = 1;
- while (1) {
+ const char *r = initrd_filename;
+ cmdline_len += strlen(initrd_filename) + 1;
+ while (*r) {
+ char *value;
+ r = get_opt_value(r, &value);
mbs.mb_mods_avail++;
- r = get_opt_value(r, NULL);
- if (!*r) {
- break;
+ mods = g_list_append(mods, value);
+ if (*r) {
+ r++;
}
- r++;
}
}
@@ -315,20 +316,16 @@ int load_multiboot(FWCfgState *fw_cfg,
mbs.offset_cmdlines = mbs.offset_mbinfo + mbs.mb_mods_avail * MB_MOD_SIZE;
mbs.offset_bootloader = mbs.offset_cmdlines + cmdline_len;
- if (initrd_filename) {
- const char *next_initrd;
- char not_last;
- char *one_file = NULL;
-
+ if (mods) {
+ GList *tmpl = mods;
mbs.offset_mods = mbs.mb_buf_size;
- do {
+ while (tmpl) {
char *next_space;
int mb_mod_length;
uint32_t offs = mbs.mb_buf_size;
+ char *one_file = tmpl->data;
- next_initrd = get_opt_value(initrd_filename, &one_file);
- not_last = *next_initrd;
/* if a space comes after the module filename, treat everything
after that as parameters */
hwaddr c = mb_add_cmdline(&mbs, one_file);
@@ -353,10 +350,10 @@ int load_multiboot(FWCfgState *fw_cfg,
mb_debug("mod_start: %p\nmod_end: %p\n cmdline: "TARGET_FMT_plx,
(char *)mbs.mb_buf + offs,
(char *)mbs.mb_buf + offs + mb_mod_length, c);
- initrd_filename = next_initrd+1;
g_free(one_file);
- one_file = NULL;
- } while (not_last);
+ tmpl = tmpl->next;
+ }
+ g_list_free(mods);
}
/* Commandline support */
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 50d5553991..83a444472b 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1999,6 +1999,11 @@ static void pc_cpu_pre_plug(HotplugHandler *hotplug_dev,
}
cpu->thread_id = topo.smt_id;
+ if (cpu->hyperv_vpindex && !kvm_hv_vpindex_settable()) {
+ error_setg(errp, "kernel doesn't allow setting HyperV VP_INDEX");
+ return;
+ }
+
cs = CPU(cpu);
cs->cpu_index = idx;
diff --git a/hw/misc/hyperv_testdev.c b/hw/misc/hyperv_testdev.c
index dbd7cdda07..bf6bbfa8cf 100644
--- a/hw/misc/hyperv_testdev.c
+++ b/hw/misc/hyperv_testdev.c
@@ -57,7 +57,7 @@ static void free_sint_route_index(HypervTestDev *dev, int i)
dev->sint_route[i] = NULL;
}
-static int find_sint_route_index(HypervTestDev *dev, uint32_t vcpu_id,
+static int find_sint_route_index(HypervTestDev *dev, uint32_t vp_index,
uint32_t sint)
{
HvSintRoute *sint_route;
@@ -65,7 +65,7 @@ static int find_sint_route_index(HypervTestDev *dev, uint32_t vcpu_id,
for (i = 0; i < ARRAY_SIZE(dev->sint_route); i++) {
sint_route = dev->sint_route[i];
- if (sint_route && sint_route->vcpu_id == vcpu_id &&
+ if (sint_route && sint_route->vp_index == vp_index &&
sint_route->sint == sint) {
return i;
}
@@ -74,7 +74,7 @@ static int find_sint_route_index(HypervTestDev *dev, uint32_t vcpu_id,
}
static void hv_synic_test_dev_control(HypervTestDev *dev, uint32_t ctl,
- uint32_t vcpu_id, uint32_t sint)
+ uint32_t vp_index, uint32_t sint)
{
int i;
HvSintRoute *sint_route;
@@ -83,19 +83,19 @@ static void hv_synic_test_dev_control(HypervTestDev *dev, uint32_t ctl,
case HV_TEST_DEV_SINT_ROUTE_CREATE:
i = alloc_sint_route_index(dev);
assert(i >= 0);
- sint_route = kvm_hv_sint_route_create(vcpu_id, sint, NULL);
+ sint_route = kvm_hv_sint_route_create(vp_index, sint, NULL);
assert(sint_route);
dev->sint_route[i] = sint_route;
break;
case HV_TEST_DEV_SINT_ROUTE_DESTROY:
- i = find_sint_route_index(dev, vcpu_id, sint);
+ i = find_sint_route_index(dev, vp_index, sint);
assert(i >= 0);
sint_route = dev->sint_route[i];
kvm_hv_sint_route_destroy(sint_route);
free_sint_route_index(dev, i);
break;
case HV_TEST_DEV_SINT_ROUTE_SET_SINT:
- i = find_sint_route_index(dev, vcpu_id, sint);
+ i = find_sint_route_index(dev, vp_index, sint);
assert(i >= 0);
sint_route = dev->sint_route[i];
kvm_hv_sint_route_set_sint(sint_route);
@@ -117,8 +117,8 @@ static void hv_test_dev_control(void *opaque, hwaddr addr, uint64_t data,
case HV_TEST_DEV_SINT_ROUTE_DESTROY:
case HV_TEST_DEV_SINT_ROUTE_SET_SINT: {
uint8_t sint = data & 0xFF;
- uint8_t vcpu_id = (data >> 8ULL) & 0xFF;
- hv_synic_test_dev_control(dev, ctl, vcpu_id, sint);
+ uint8_t vp_index = (data >> 8ULL) & 0xFF;
+ hv_synic_test_dev_control(dev, ctl, vp_index, sint);
break;
}
default:
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index 3aa99717e2..5a3057d1f8 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -797,8 +797,16 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
virtio_scsi_acquire(s);
blk_set_aio_context(sd->conf.blk, s->ctx);
virtio_scsi_release(s);
-
}
+}
+
+/* Announce the new device after it has been plugged */
+static void virtio_scsi_post_hotplug(HotplugHandler *hotplug_dev,
+ DeviceState *dev)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(hotplug_dev);
+ VirtIOSCSI *s = VIRTIO_SCSI(vdev);
+ SCSIDevice *sd = SCSI_DEVICE(dev);
if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
virtio_scsi_acquire(s);
@@ -968,6 +976,7 @@ static void virtio_scsi_class_init(ObjectClass *klass, void *data)
vdc->start_ioeventfd = virtio_scsi_dataplane_start;
vdc->stop_ioeventfd = virtio_scsi_dataplane_stop;
hc->plug = virtio_scsi_hotplug;
+ hc->post_plug = virtio_scsi_post_hotplug;
hc->unplug = virtio_scsi_hotunplug;
}
diff --git a/include/hw/hotplug.h b/include/hw/hotplug.h
index 1a0516a479..51541d63e1 100644
--- a/include/hw/hotplug.h
+++ b/include/hw/hotplug.h
@@ -47,6 +47,8 @@ typedef void (*hotplug_fn)(HotplugHandler *plug_handler,
* @parent: Opaque parent interface.
* @pre_plug: pre plug callback called at start of device.realize(true)
* @plug: plug callback called at end of device.realize(true).
+ * @post_plug: post plug callback called after device.realize(true) and device
+ * reset
* @unplug_request: unplug request callback.
* Used as a means to initiate device unplug for devices that
* require asynchronous unplug handling.
@@ -61,6 +63,7 @@ typedef struct HotplugHandlerClass {
/* <public> */
hotplug_fn pre_plug;
hotplug_fn plug;
+ void (*post_plug)(HotplugHandler *plug_handler, DeviceState *plugged_dev);
hotplug_fn unplug_request;
hotplug_fn unplug;
} HotplugHandlerClass;
@@ -84,6 +87,14 @@ void hotplug_handler_pre_plug(HotplugHandler *plug_handler,
Error **errp);
/**
+ * hotplug_handler_post_plug:
+ *
+ * Call #HotplugHandlerClass.post_plug callback of @plug_handler.
+ */
+void hotplug_handler_post_plug(HotplugHandler *plug_handler,
+ DeviceState *plugged_dev);
+
+/**
* hotplug_handler_unplug_request:
*
* Calls #HotplugHandlerClass.unplug_request callback of @plug_handler.
diff --git a/qemu-options.hx b/qemu-options.hx
index 371c4271a4..b1bf0f485f 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -471,7 +471,7 @@ STEXI
@item -balloon virtio[,addr=@var{addr}]
@findex -balloon
Enable virtio balloon device, optionally with PCI address @var{addr}. This
-option is deprecated, use @option{--device virtio-balloon} instead.
+option is deprecated, use @option{-device virtio-balloon} instead.
ETEXI
DEF("device", HAS_ARG, QEMU_OPTION_device,
@@ -2005,7 +2005,7 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
"-netdev hubport,id=str,hubid=n[,netdev=nd]\n"
" configure a hub port on the hub with ID 'n'\n", QEMU_ARCH_ALL)
DEF("nic", HAS_ARG, QEMU_OPTION_nic,
- "--nic [tap|bridge|"
+ "-nic [tap|bridge|"
#ifdef CONFIG_SLIRP
"user|"
#endif
@@ -2024,7 +2024,7 @@ DEF("nic", HAS_ARG, QEMU_OPTION_nic,
"socket][,option][,...][mac=macaddr]\n"
" initialize an on-board / default host NIC (using MAC address\n"
" macaddr) and connect it to the given host network backend\n"
- "--nic none use it alone to have zero network devices (the default is to\n"
+ "-nic none use it alone to have zero network devices (the default is to\n"
" provided a 'user' network connection)\n",
QEMU_ARCH_ALL)
DEF("net", HAS_ARG, QEMU_OPTION_net,
@@ -3339,7 +3339,7 @@ mlocking qemu and guest memory can be enabled via @option{mlock=on}
ETEXI
DEF("overcommit", HAS_ARG, QEMU_OPTION_overcommit,
- "--overcommit [mem-lock=on|off][cpu-pm=on|off]\n"
+ "-overcommit [mem-lock=on|off][cpu-pm=on|off]\n"
" run qemu with overcommit hints\n"
" mem-lock=on|off controls memory lock support (default: off)\n"
" cpu-pm=on|off controls cpu power management (default: off)\n",
diff --git a/target/i386/arch_dump.c b/target/i386/arch_dump.c
index 35b55fc200..004141fc04 100644
--- a/target/i386/arch_dump.c
+++ b/target/i386/arch_dump.c
@@ -258,6 +258,12 @@ struct QEMUCPUState {
QEMUCPUSegment cs, ds, es, fs, gs, ss;
QEMUCPUSegment ldt, tr, gdt, idt;
uint64_t cr[5];
+ /*
+ * Fields below are optional and are being added at the end without
+ * changing the version. External tools may identify their presence
+ * by checking 'size' field.
+ */
+ uint64_t kernel_gs_base;
};
typedef struct QEMUCPUState QEMUCPUState;
@@ -315,6 +321,10 @@ static void qemu_get_cpustate(QEMUCPUState *s, CPUX86State *env)
s->cr[2] = env->cr[2];
s->cr[3] = env->cr[3];
s->cr[4] = env->cr[4];
+
+#ifdef TARGET_X86_64
+ s->kernel_gs_base = env->kernelgsbase;
+#endif
}
static inline int cpu_write_qemu_note(WriteCoreDumpFunction f,
diff --git a/target/i386/hyperv.c b/target/i386/hyperv.c
index a050c9d2d1..3065d765ed 100644
--- a/target/i386/hyperv.c
+++ b/target/i386/hyperv.c
@@ -16,6 +16,16 @@
#include "hyperv.h"
#include "hyperv-proto.h"
+uint32_t hyperv_vp_index(X86CPU *cpu)
+{
+ return CPU(cpu)->cpu_index;
+}
+
+X86CPU *hyperv_find_vcpu(uint32_t vp_index)
+{
+ return X86_CPU(qemu_get_cpu(vp_index));
+}
+
int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit)
{
CPUX86State *env = &cpu->env;
@@ -72,7 +82,7 @@ static void kvm_hv_sint_ack_handler(EventNotifier *notifier)
}
}
-HvSintRoute *kvm_hv_sint_route_create(uint32_t vcpu_id, uint32_t sint,
+HvSintRoute *kvm_hv_sint_route_create(uint32_t vp_index, uint32_t sint,
HvSintAckClb sint_ack_clb)
{
HvSintRoute *sint_route;
@@ -92,7 +102,7 @@ HvSintRoute *kvm_hv_sint_route_create(uint32_t vcpu_id, uint32_t sint,
event_notifier_set_handler(&sint_route->sint_ack_notifier,
kvm_hv_sint_ack_handler);
- gsi = kvm_irqchip_add_hv_sint_route(kvm_state, vcpu_id, sint);
+ gsi = kvm_irqchip_add_hv_sint_route(kvm_state, vp_index, sint);
if (gsi < 0) {
goto err_gsi;
}
@@ -105,7 +115,7 @@ HvSintRoute *kvm_hv_sint_route_create(uint32_t vcpu_id, uint32_t sint,
}
sint_route->gsi = gsi;
sint_route->sint_ack_clb = sint_ack_clb;
- sint_route->vcpu_id = vcpu_id;
+ sint_route->vp_index = vp_index;
sint_route->sint = sint;
return sint_route;
diff --git a/target/i386/hyperv.h b/target/i386/hyperv.h
index 0c3b562018..00c9b454bb 100644
--- a/target/i386/hyperv.h
+++ b/target/i386/hyperv.h
@@ -23,7 +23,7 @@ typedef void (*HvSintAckClb)(HvSintRoute *sint_route);
struct HvSintRoute {
uint32_t sint;
- uint32_t vcpu_id;
+ uint32_t vp_index;
int gsi;
EventNotifier sint_set_notifier;
EventNotifier sint_ack_notifier;
@@ -32,11 +32,14 @@ struct HvSintRoute {
int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit);
-HvSintRoute *kvm_hv_sint_route_create(uint32_t vcpu_id, uint32_t sint,
+HvSintRoute *kvm_hv_sint_route_create(uint32_t vp_index, uint32_t sint,
HvSintAckClb sint_ack_clb);
void kvm_hv_sint_route_destroy(HvSintRoute *sint_route);
int kvm_hv_sint_route_set_sint(HvSintRoute *sint_route);
+uint32_t hyperv_vp_index(X86CPU *cpu);
+X86CPU *hyperv_find_vcpu(uint32_t vp_index);
+
#endif
diff --git a/target/i386/kvm-stub.c b/target/i386/kvm-stub.c
index bda4dc2f0c..e7a673e5db 100644
--- a/target/i386/kvm-stub.c
+++ b/target/i386/kvm-stub.c
@@ -40,3 +40,8 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *env, uint32_t function,
abort();
}
#endif
+
+bool kvm_hv_vpindex_settable(void)
+{
+ return false;
+}
diff --git a/target/i386/kvm.c b/target/i386/kvm.c
index ebb2d23aa4..9313602d3d 100644
--- a/target/i386/kvm.c
+++ b/target/i386/kvm.c
@@ -85,6 +85,7 @@ static bool has_msr_hv_hypercall;
static bool has_msr_hv_crash;
static bool has_msr_hv_reset;
static bool has_msr_hv_vpindex;
+static bool hv_vpindex_settable;
static bool has_msr_hv_runtime;
static bool has_msr_hv_synic;
static bool has_msr_hv_stimer;
@@ -162,6 +163,11 @@ bool kvm_enable_x2apic(void)
has_x2apic_api);
}
+bool kvm_hv_vpindex_settable(void)
+{
+ return hv_vpindex_settable;
+}
+
static int kvm_get_tsc(CPUState *cs)
{
X86CPU *cpu = X86_CPU(cs);
@@ -745,6 +751,37 @@ static int hyperv_handle_properties(CPUState *cs)
return 0;
}
+static int hyperv_init_vcpu(X86CPU *cpu)
+{
+ if (cpu->hyperv_vpindex && !hv_vpindex_settable) {
+ /*
+ * the kernel doesn't support setting vp_index; assert that its value
+ * is in sync
+ */
+ int ret;
+ struct {
+ struct kvm_msrs info;
+ struct kvm_msr_entry entries[1];
+ } msr_data = {
+ .info.nmsrs = 1,
+ .entries[0].index = HV_X64_MSR_VP_INDEX,
+ };
+
+ ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, &msr_data);
+ if (ret < 0) {
+ return ret;
+ }
+ assert(ret == 1);
+
+ if (msr_data.entries[0].data != hyperv_vp_index(cpu)) {
+ error_report("kernel's vp_index != QEMU's vp_index");
+ return -ENXIO;
+ }
+ }
+
+ return 0;
+}
+
static Error *invtsc_mig_blocker;
#define KVM_MAX_CPUID_ENTRIES 100
@@ -1160,6 +1197,11 @@ int kvm_arch_init_vcpu(CPUState *cs)
has_msr_tsc_aux = false;
}
+ r = hyperv_init_vcpu(cpu);
+ if (r) {
+ goto fail;
+ }
+
return 0;
fail:
@@ -1351,6 +1393,8 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
has_pit_state2 = kvm_check_extension(s, KVM_CAP_PIT_STATE2);
#endif
+ hv_vpindex_settable = kvm_check_extension(s, KVM_CAP_HYPERV_VP_INDEX);
+
ret = kvm_get_supported_msrs(s);
if (ret < 0) {
return ret;
@@ -1900,6 +1944,9 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
if (has_msr_hv_runtime) {
kvm_msr_entry_add(cpu, HV_X64_MSR_VP_RUNTIME, env->msr_hv_runtime);
}
+ if (cpu->hyperv_vpindex && hv_vpindex_settable) {
+ kvm_msr_entry_add(cpu, HV_X64_MSR_VP_INDEX, hyperv_vp_index(cpu));
+ }
if (cpu->hyperv_synic) {
int j;
diff --git a/target/i386/kvm_i386.h b/target/i386/kvm_i386.h
index e5df24cad1..3057ba4f7d 100644
--- a/target/i386/kvm_i386.h
+++ b/target/i386/kvm_i386.h
@@ -63,4 +63,6 @@ void kvm_put_apicbase(X86CPU *cpu, uint64_t value);
bool kvm_enable_x2apic(void);
bool kvm_has_x2apic_api(void);
+
+bool kvm_hv_vpindex_settable(void);
#endif
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index 8ff2106d32..fecc832d99 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -537,6 +537,7 @@ static gboolean _test_server_free(TestServer *server)
g_free(server->mig_path);
g_free(server->chr_name);
+ g_assert(server->bus);
qpci_free_pc(server->bus);
g_free(server);
@@ -684,6 +685,7 @@ static void test_migrate(void)
g_free(cmd);
init_virtio_dev(s, 1u << VIRTIO_NET_F_MAC);
+ init_virtio_dev(dest, 1u << VIRTIO_NET_F_MAC);
wait_for_fds(s);
size = get_log_size(s);
g_assert_cmpint(size, ==, (2 * 1024 * 1024) / (VHOST_LOG_PAGE * 8));
@@ -739,6 +741,7 @@ static void test_migrate(void)
read_guest_mem_server(dest);
uninit_virtio_dev(s);
+ uninit_virtio_dev(dest);
g_source_destroy(source);
g_source_unref(source);
diff --git a/util/qemu-option.c b/util/qemu-option.c
index 19761e3eaf..01886efe90 100644
--- a/util/qemu-option.c
+++ b/util/qemu-option.c
@@ -82,11 +82,9 @@ const char *get_opt_value(const char *p, char **value)
if (*offset != '\0' && *(offset + 1) == ',') {
length++;
}
- if (value) {
- *value = g_renew(char, *value, capacity + length + 1);
- strncpy(*value + capacity, p, length);
- (*value)[capacity + length] = '\0';
- }
+ *value = g_renew(char, *value, capacity + length + 1);
+ strncpy(*value + capacity, p, length);
+ (*value)[capacity + length] = '\0';
capacity += length;
if (*offset == '\0' ||
*(offset + 1) != ',') {