[Spice-commits] 39 commits - Makefile.objs VERSION hw/core hw/i386 hw/ide hw/net hw/usb hw/virtio include/hw po/de_DE.po qapi-schema.json qdev-monitor.c qga/commands-posix.c qga/main.c target-i386/cpu-qom.h target-i386/cpu.c target-i386/cpu.h target-mips/dsp_helper.c target-mips/translate.c target-ppc/translate.c tests/Makefile tests/ide-test.c tests/libqos tests/qemu-iotests tests/tcg
Gerd Hoffmann
kraxel at kemper.freedesktop.org
Thu May 9 02:55:10 PDT 2013
Makefile.objs | 7
VERSION | 2
hw/core/qdev-properties.c | 51 ++--
hw/core/qdev.c | 7
hw/i386/pc_piix.c | 1
hw/i386/pc_q35.c | 1
hw/ide/ahci.c | 2
hw/ide/cmd646.c | 2
hw/ide/internal.h | 3
hw/ide/isa.c | 2
hw/ide/macio.c | 2
hw/ide/mmio.c | 2
hw/ide/pci.c | 1
hw/ide/piix.c | 2
hw/ide/qdev.c | 10
hw/ide/via.c | 2
hw/net/virtio-net.c | 4
hw/usb/hcd-uhci.c | 21 +
hw/usb/hcd-xhci.c | 5
hw/usb/host-libusb.c | 94 +++++++-
hw/virtio/virtio-pci.c | 5
hw/virtio/virtio.c | 30 +-
include/hw/i386/pc.h | 4
include/hw/qdev-properties.h | 7
po/de_DE.po | 4
qapi-schema.json | 32 ++
qdev-monitor.c | 6
qga/commands-posix.c | 123 ++++++++++
qga/main.c | 2
target-i386/cpu-qom.h | 3
target-i386/cpu.c | 150 ++++++++++---
target-i386/cpu.h | 4
target-mips/dsp_helper.c | 4
target-mips/translate.c | 1
target-ppc/translate.c | 34 +--
tests/Makefile | 2
tests/ide-test.c | 440 +++++++++++++++++++++++++++++++++++++++
tests/libqos/pci.c | 2
tests/qemu-iotests/017 | 4
tests/qemu-iotests/017.out | 2
tests/qemu-iotests/018 | 4
tests/qemu-iotests/018.out | 2
tests/qemu-iotests/042 | 2
tests/qemu-iotests/043 | 2
tests/tcg/mips/mips32-dsp/insv.c | 13 +
45 files changed, 970 insertions(+), 133 deletions(-)
New commits:
commit 47ec15cdd44877e553ed0bd0a16aea8a295dad62
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed May 8 15:54:47 2013 -0500
Update version for 1.5.0-rc1
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/VERSION b/VERSION
index 245205d..8d9b8b2 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.4.90
+1.4.91
commit cad2b59c198340a636c5e015fb90e0326a1d3dd7
Merge: 5f5a131 794d00f
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed May 8 15:54:36 2013 -0500
Merge remote-tracking branch 'kwolf/for-anthony' into staging
# By Kevin Wolf (7) and Fam Zheng (3)
# Via Kevin Wolf
* kwolf/for-anthony:
qemu-iotests: fix 017 018 for vmdk
qemu-iotests: exclude vmdk and qcow from 043
qemu-iotests: exclude vmdk for test 042
qtest/ide-test: Test short and long PRDTs
qtest/ide-test: Add simple DMA read/write test case
qtest: Add IDE test case
libqos/pci: Enable bus mastering
ide: Reset BMIDEA bit when the bus master is stopped
de_DE.po: Add missing leading spaces
ahci: Don't allow creating slave drives
Message-id: 1368023344-29731-1-git-send-email-kwolf at redhat.com
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
commit 5f5a1318653c08e435cfa52f60b6a712815b659d
Author: Jason Wang <jasowang at redhat.com>
Date: Tue May 7 13:42:49 2013 +0800
virtio: properly validate address before accessing config
There are several several issues in the current checking:
- The check was based on the minus of unsigned values which can overflow
- It was done after .{set|get}_config() which can lead crash when config_len
is zero since vdev->config is NULL
Fix this by:
- Validate the address in virtio_pci_config_{read|write}() before
.{set|get}_config
- Use addition instead minus to do the validation
Cc: Michael S. Tsirkin <mst at redhat.com>
Cc: Petr Matousek <pmatouse at redhat.com>
Signed-off-by: Jason Wang <jasowang at redhat.com>
Acked-by: Michael S. Tsirkin <mst at redhat.com>
Acked-by: Petr Matousek <pmatouse at redhat.com>
Message-id: 1367905369-10765-1-git-send-email-jasowang at redhat.com
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 53a0d90..8176c14 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -568,10 +568,11 @@ uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr)
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
uint8_t val;
- k->get_config(vdev, vdev->config);
-
- if (addr > (vdev->config_len - sizeof(val)))
+ if (addr + sizeof(val) > vdev->config_len) {
return (uint32_t)-1;
+ }
+
+ k->get_config(vdev, vdev->config);
val = ldub_p(vdev->config + addr);
return val;
@@ -582,10 +583,11 @@ uint32_t virtio_config_readw(VirtIODevice *vdev, uint32_t addr)
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
uint16_t val;
- k->get_config(vdev, vdev->config);
-
- if (addr > (vdev->config_len - sizeof(val)))
+ if (addr + sizeof(val) > vdev->config_len) {
return (uint32_t)-1;
+ }
+
+ k->get_config(vdev, vdev->config);
val = lduw_p(vdev->config + addr);
return val;
@@ -596,10 +598,11 @@ uint32_t virtio_config_readl(VirtIODevice *vdev, uint32_t addr)
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
uint32_t val;
- k->get_config(vdev, vdev->config);
-
- if (addr > (vdev->config_len - sizeof(val)))
+ if (addr + sizeof(val) > vdev->config_len) {
return (uint32_t)-1;
+ }
+
+ k->get_config(vdev, vdev->config);
val = ldl_p(vdev->config + addr);
return val;
@@ -610,8 +613,9 @@ void virtio_config_writeb(VirtIODevice *vdev, uint32_t addr, uint32_t data)
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
uint8_t val = data;
- if (addr > (vdev->config_len - sizeof(val)))
+ if (addr + sizeof(val) > vdev->config_len) {
return;
+ }
stb_p(vdev->config + addr, val);
@@ -625,8 +629,9 @@ void virtio_config_writew(VirtIODevice *vdev, uint32_t addr, uint32_t data)
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
uint16_t val = data;
- if (addr > (vdev->config_len - sizeof(val)))
+ if (addr + sizeof(val) > vdev->config_len) {
return;
+ }
stw_p(vdev->config + addr, val);
@@ -640,8 +645,9 @@ void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data)
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
uint32_t val = data;
- if (addr > (vdev->config_len - sizeof(val)))
+ if (addr + sizeof(val) > vdev->config_len) {
return;
+ }
stl_p(vdev->config + addr, val);
commit 62c96360ae7f2c7a8b029277fbb7cb082fdef7fd
Author: Michael S. Tsirkin <mst at redhat.com>
Date: Tue May 7 15:49:58 2013 +0300
virtio-pci: fix level interrupts
mask notifiers are never called without msix,
so devices with backend masking like vhost don't work.
Call mask notifiers explicitly at
startup/cleanup to make it work.
Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
Tested-by: Alexander Graf <agraf at suse.de>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index ec0066b..113fbd9 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -744,6 +744,7 @@ static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign,
bool with_irqfd)
{
VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
+ VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(proxy->vdev);
VirtQueue *vq = virtio_get_queue(proxy->vdev, n);
EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
@@ -758,6 +759,10 @@ static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign,
event_notifier_cleanup(notifier);
}
+ if (!msix_enabled(&proxy->pci_dev) && vdc->guest_notifier_mask) {
+ vdc->guest_notifier_mask(proxy->vdev, n, !assign);
+ }
+
return 0;
}
commit d551d220c9574b00a318297b8654344e13e0efde
Merge: 554ecc5 36f48d9
Author: Aurelien Jarno <aurelien at aurel32.net>
Date: Wed May 8 21:02:06 2013 +0200
Merge branch 'ppc-for-upstream' of git://github.com/agraf/qemu
* 'ppc-for-upstream' of git://github.com/agraf/qemu:
PPC: Depend behavior of cmp instructions only on instruction encoding
commit 554ecc5774badd181458fe3d6a1624c2ede9f04e
Author: Alexander Graf <agraf at suse.de>
Date: Mon May 6 19:49:43 2013 +0200
PPC: Fix rldcl
The implementation for rldcl tried to always fetch its
parameters from the opcode, even though the opcode was
already passed in in decoded and different forms.
Use the parameters instead, fixing rldcl.
Reported-by: Torbjorn Granlund <tg at gmplib.org>
Reviewed-by: Aurelien Jarno <aurelien at aurel32.net>
Signed-off-by: Alexander Graf <agraf at suse.de>
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 0886f4d..a018616 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -1733,8 +1733,6 @@ static inline void gen_rldnm(DisasContext *ctx, uint32_t mb, uint32_t me)
{
TCGv t0;
- mb = MB(ctx->opcode);
- me = ME(ctx->opcode);
t0 = tcg_temp_new();
tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x3f);
tcg_gen_rotl_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
commit 36f48d9c78c438170aa7259bdde67086c9b7e795
Author: Alexander Graf <agraf at suse.de>
Date: Wed May 8 15:19:14 2013 +0200
PPC: Depend behavior of cmp instructions only on instruction encoding
When running an L=1 cmp instruction on a 64bit PPC CPU with SF off, it
still behaves identical to what it does when SF is on. Remove the implicit
difference in the code.
Also, on most 32bit CPUs we should always treat the compare as 32bit
compare, as the CPU will ignore the L bit. This is not true for e500mc,
but that's up for a different patch.
Reported-by: Torbjorn Granlund <tg at gmplib.org>
Reviewed-by: Richard Henderson <rth at twiddle.net>
Signed-off-by: Alexander Graf <agraf at suse.de>
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index a018616..4590c6f 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -675,48 +675,48 @@ static inline void gen_set_Rc0(DisasContext *ctx, TCGv reg)
/* cmp */
static void gen_cmp(DisasContext *ctx)
{
- if (NARROW_MODE(ctx) || !(ctx->opcode & 0x00200000)) {
- gen_op_cmp32(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
- 1, crfD(ctx->opcode));
- } else {
+ if ((ctx->opcode & 0x00200000) && (ctx->insns_flags & PPC_64B)) {
gen_op_cmp(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
1, crfD(ctx->opcode));
+ } else {
+ gen_op_cmp32(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
+ 1, crfD(ctx->opcode));
}
}
/* cmpi */
static void gen_cmpi(DisasContext *ctx)
{
- if (NARROW_MODE(ctx) || !(ctx->opcode & 0x00200000)) {
- gen_op_cmpi32(cpu_gpr[rA(ctx->opcode)], SIMM(ctx->opcode),
- 1, crfD(ctx->opcode));
- } else {
+ if ((ctx->opcode & 0x00200000) && (ctx->insns_flags & PPC_64B)) {
gen_op_cmpi(cpu_gpr[rA(ctx->opcode)], SIMM(ctx->opcode),
1, crfD(ctx->opcode));
+ } else {
+ gen_op_cmpi32(cpu_gpr[rA(ctx->opcode)], SIMM(ctx->opcode),
+ 1, crfD(ctx->opcode));
}
}
/* cmpl */
static void gen_cmpl(DisasContext *ctx)
{
- if (NARROW_MODE(ctx) || !(ctx->opcode & 0x00200000)) {
- gen_op_cmp32(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
- 0, crfD(ctx->opcode));
- } else {
+ if ((ctx->opcode & 0x00200000) && (ctx->insns_flags & PPC_64B)) {
gen_op_cmp(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
0, crfD(ctx->opcode));
+ } else {
+ gen_op_cmp32(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
+ 0, crfD(ctx->opcode));
}
}
/* cmpli */
static void gen_cmpli(DisasContext *ctx)
{
- if (NARROW_MODE(ctx) || !(ctx->opcode & 0x00200000)) {
- gen_op_cmpi32(cpu_gpr[rA(ctx->opcode)], UIMM(ctx->opcode),
- 0, crfD(ctx->opcode));
- } else {
+ if ((ctx->opcode & 0x00200000) && (ctx->insns_flags & PPC_64B)) {
gen_op_cmpi(cpu_gpr[rA(ctx->opcode)], UIMM(ctx->opcode),
0, crfD(ctx->opcode));
+ } else {
+ gen_op_cmpi32(cpu_gpr[rA(ctx->opcode)], UIMM(ctx->opcode),
+ 0, crfD(ctx->opcode));
}
}
commit c0f5f9ce86ddca0a7d7ca60012059a5a18aa9c07
Author: Petar Jovanovic <petar.jovanovic at imgtec.com>
Date: Wed May 8 13:17:40 2013 +0200
target-mips: fix incorrect behaviour for INSV
Corner case for INSV instruction when size=32 has not been correctly
implemented. The mask for size should be one bit wider, and preparing the
filter variable should be aware of this case too.
The test for INSV has been extended to include the case that triggers the
bug.
Signed-off-by: Petar Jovanovic <petar.jovanovic at imgtec.com>
Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>
diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c
index 805247d..9212789 100644
--- a/target-mips/dsp_helper.c
+++ b/target-mips/dsp_helper.c
@@ -2921,7 +2921,7 @@ target_ulong helper_##name(CPUMIPSState *env, target_ulong rs, \
return rt; \
} \
\
- filter = ((int32_t)0x01 << size) - 1; \
+ filter = ((int64_t)0x01 << size) - 1; \
filter = filter << pos; \
temprs = (rs << pos) & filter; \
temprt = rt & ~filter; \
@@ -2930,7 +2930,7 @@ target_ulong helper_##name(CPUMIPSState *env, target_ulong rs, \
return (target_long)(ret_type)temp; \
}
-BIT_INSV(insv, 0x1F, 0x1F, int32_t);
+BIT_INSV(insv, 0x1F, 0x3F, int32_t);
#ifdef TARGET_MIPS64
BIT_INSV(dinsv, 0x7F, 0x3F, target_long);
#endif
diff --git a/tests/tcg/mips/mips32-dsp/insv.c b/tests/tcg/mips/mips32-dsp/insv.c
index 243b007..9d67469 100644
--- a/tests/tcg/mips/mips32-dsp/insv.c
+++ b/tests/tcg/mips/mips32-dsp/insv.c
@@ -19,5 +19,18 @@ int main()
);
assert(rt == result);
+ dsp = 0x1000;
+ rt = 0xF0F0F0F0;
+ rs = 0xA5A5A5A5;
+ result = 0xA5A5A5A5;
+
+ __asm
+ ("wrdsp %2\n\t"
+ "insv %0, %1\n\t"
+ : "+r"(rt)
+ : "r"(rs), "r"(dsp)
+ );
+ assert(rt == result);
+
return 0;
}
commit 639eadb9a32775e1c70bbf37d347972ca41128d1
Author: Petar Jovanovic <petar.jovanovic at imgtec.com>
Date: Wed May 8 16:09:04 2013 +0200
target-mips: add missing check_dspr2 for multiply instructions
The emulator needs to check in hflags if DSP unit has been turned off before
it generates code for MUL_PH, MUL_S_PH, MULQ_S_W, and MULQ_RS_W.
Signed-off-by: Petar Jovanovic <petar.jovanovic at imgtec.com>
Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>
diff --git a/target-mips/translate.c b/target-mips/translate.c
index b7f8203..0a53203 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -13400,6 +13400,7 @@ static void gen_mipsdsp_multiply(DisasContext *ctx, uint32_t op1, uint32_t op2,
/* OPC_MULT_G_2E, OPC_ADDUH_QB_DSP, OPC_MUL_PH_DSP have
* the same mask and op1. */
case OPC_MULT_G_2E:
+ check_dspr2(ctx);
switch (op2) {
case OPC_MUL_PH:
gen_helper_mul_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env);
commit 794d00f71d39e3d18eafade579b2ecb665d6d481
Author: Fam Zheng <famz at redhat.com>
Date: Tue May 7 19:13:05 2013 +0800
qemu-iotests: fix 017 018 for vmdk
017 and 018 use /bin/mv to move base img from t.IMGFMG to t.IMGFMT.base
after filling data, this is not enough for vmdk, when t.IMGFMT is only a
description text file who points to t-{flat,s001,f001,...}.IMGFMT as
data extent, so testing such subformats alway fails on them.
This patch use the trick of temprorily changing TEST_IMG to avoid using
/bin/mv.
Signed-off-by: Fam Zheng <famz at redhat.com>
Reviewed-by: Jeff Cody <jcody at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/tests/qemu-iotests/017 b/tests/qemu-iotests/017
index 66951eb..45f2c0b 100755
--- a/tests/qemu-iotests/017
+++ b/tests/qemu-iotests/017
@@ -46,6 +46,8 @@ _supported_os Linux
TEST_OFFSETS="0 4294967296"
+TEST_IMG_SAVE=$TEST_IMG
+TEST_IMG=$TEST_IMG.base
_make_test_img 6G
echo "Filling base image"
@@ -63,7 +65,7 @@ _check_test_img
echo "Creating test image with backing file"
echo
-mv $TEST_IMG $TEST_IMG.base
+TEST_IMG=$TEST_IMG_SAVE
_make_test_img -b $TEST_IMG.base 6G
echo "Filling test image"
diff --git a/tests/qemu-iotests/017.out b/tests/qemu-iotests/017.out
index a861e58..df34ee7 100644
--- a/tests/qemu-iotests/017.out
+++ b/tests/qemu-iotests/017.out
@@ -1,5 +1,5 @@
QA output created by 017
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=6442450944
Filling base image
=== IO: pattern 0
diff --git a/tests/qemu-iotests/018 b/tests/qemu-iotests/018
index bd2db78..453ce61 100755
--- a/tests/qemu-iotests/018
+++ b/tests/qemu-iotests/018
@@ -46,6 +46,8 @@ _supported_os Linux
TEST_OFFSETS="0 4294967296"
+TEST_IMG_SAVE=$TEST_IMG
+TEST_IMG=$TEST_IMG.base
_make_test_img 6G
echo "Filling base image"
@@ -63,7 +65,7 @@ _check_test_img
echo "Creating test image with backing file"
echo
-mv $TEST_IMG $TEST_IMG.base
+TEST_IMG=$TEST_IMG_SAVE
_make_test_img -b $TEST_IMG.base 6G
echo "Filling test image"
diff --git a/tests/qemu-iotests/018.out b/tests/qemu-iotests/018.out
index 6bbd815..3ddb8d8 100644
--- a/tests/qemu-iotests/018.out
+++ b/tests/qemu-iotests/018.out
@@ -1,5 +1,5 @@
QA output created by 018
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=6442450944
Filling base image
=== IO: pattern 0
commit dbcdd7cb04595cc0015f2dba6be751faa63fab00
Author: Fam Zheng <famz at redhat.com>
Date: Tue May 7 19:13:04 2013 +0800
qemu-iotests: exclude vmdk and qcow from 043
043 tests recursive backing file by changing backing file. VMDK has not
implemented this yet, and qcow1 probably never will.
Signed-off-by: Fam Zheng <famz at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/tests/qemu-iotests/043 b/tests/qemu-iotests/043
index 3ba08dc..478773d 100755
--- a/tests/qemu-iotests/043
+++ b/tests/qemu-iotests/043
@@ -40,7 +40,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
. ./common.filter
# Any format supporting backing files
-_supported_fmt qcow qcow2 vmdk qed
+_supported_fmt qcow2 qed
_supported_proto generic
_supported_os Linux
commit 1afe2726632a3344b92757bacdff57df49ef43e1
Author: Fam Zheng <famz at redhat.com>
Date: Tue May 7 19:13:03 2013 +0800
qemu-iotests: exclude vmdk for test 042
Zero sized disk is not supported by qemu vmdk driver, exclude vmdk from
the test script.
As tested on vmware-vdiskmanager and vmware workstation, zero sized disk
is not supported by vmware, either.
Signed-off-by: Fam Zheng <famz at redhat.com>
Reviewed-by: Jeff Cody <jcody at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/tests/qemu-iotests/042 b/tests/qemu-iotests/042
index c3c3ca8..16b2fdb 100755
--- a/tests/qemu-iotests/042
+++ b/tests/qemu-iotests/042
@@ -38,7 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
. ./common.rc
. ./common.filter
-_supported_fmt qcow2 qcow qed vmdk
+_supported_fmt qcow2 qcow qed
_supported_proto file
_supported_os Linux
commit 948eaed171e0dac541a59b42867f80881399bbd0
Author: Kevin Wolf <kwolf at redhat.com>
Date: Wed Mar 13 13:30:24 2013 +0100
qtest/ide-test: Test short and long PRDTs
This tests the behaviour of the DMA engine when the given PRDT contains
physical region descriptors for either more or less bytes than the
IDE request is for.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/tests/ide-test.c b/tests/ide-test.c
index 5fc496f..bdc1da7 100644
--- a/tests/ide-test.c
+++ b/tests/ide-test.c
@@ -77,6 +77,8 @@ enum {
CMD_READ_DMA = 0xc8,
CMD_WRITE_DMA = 0xca,
CMD_IDENTIFY = 0xec,
+
+ CMDF_ABORT = 0x100,
};
enum {
@@ -170,9 +172,13 @@ static int send_dma_request(int cmd, uint64_t sector, int nb_sectors,
size_t len;
bool from_dev;
uint8_t status;
+ int flags;
dev = get_pci_device(&bmdma_base);
+ flags = cmd & ~0xff;
+ cmd &= 0xff;
+
switch (cmd) {
case CMD_READ_DMA:
from_dev = true;
@@ -209,6 +215,10 @@ static int send_dma_request(int cmd, uint64_t sector, int nb_sectors,
/* Start DMA transfer */
outb(bmdma_base + bmreg_cmd, BM_CMD_START | (from_dev ? BM_CMD_WRITE : 0));
+ if (flags & CMDF_ABORT) {
+ outb(bmdma_base + bmreg_cmd, 0);
+ }
+
/* Wait for the DMA transfer to complete */
do {
status = inb(bmdma_base + bmreg_status);
@@ -289,6 +299,48 @@ static void test_bmdma_simple_rw(void)
g_free(cmpbuf);
}
+static void test_bmdma_short_prdt(void)
+{
+ uint8_t status;
+
+ PrdtEntry prdt[] = {
+ { .addr = 0, .size = 0x10 | PRDT_EOT },
+ };
+
+ /* Normal request */
+ status = send_dma_request(CMD_READ_DMA, 0, 1,
+ prdt, ARRAY_SIZE(prdt));
+ g_assert_cmphex(status, ==, 0);
+ assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR);
+
+ /* Abort the request before it completes */
+ status = send_dma_request(CMD_READ_DMA | CMDF_ABORT, 0, 1,
+ prdt, ARRAY_SIZE(prdt));
+ g_assert_cmphex(status, ==, 0);
+ assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR);
+}
+
+static void test_bmdma_long_prdt(void)
+{
+ uint8_t status;
+
+ PrdtEntry prdt[] = {
+ { .addr = 0, .size = 0x1000 | PRDT_EOT },
+ };
+
+ /* Normal request */
+ status = send_dma_request(CMD_READ_DMA, 0, 1,
+ prdt, ARRAY_SIZE(prdt));
+ g_assert_cmphex(status, ==, BM_STS_ACTIVE | BM_STS_INTR);
+ assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR);
+
+ /* Abort the request before it completes */
+ status = send_dma_request(CMD_READ_DMA | CMDF_ABORT, 0, 1,
+ prdt, ARRAY_SIZE(prdt));
+ g_assert_cmphex(status, ==, BM_STS_INTR);
+ assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR);
+}
+
static void test_bmdma_setup(void)
{
ide_test_start(
@@ -375,6 +427,8 @@ int main(int argc, char **argv)
qtest_add_func("/ide/bmdma/setup", test_bmdma_setup);
qtest_add_func("/ide/bmdma/simple_rw", test_bmdma_simple_rw);
+ qtest_add_func("/ide/bmdma/short_prdt", test_bmdma_short_prdt);
+ qtest_add_func("/ide/bmdma/long_prdt", test_bmdma_long_prdt);
qtest_add_func("/ide/bmdma/teardown", test_bmdma_teardown);
ret = g_test_run();
commit b95739dcf5ae1dfa8cd5b2a5be27d427835e693b
Author: Kevin Wolf <kwolf at redhat.com>
Date: Wed May 8 11:34:20 2013 +0200
qtest/ide-test: Add simple DMA read/write test case
This tests that single sectors can be successfully written and correctly
read back.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/tests/ide-test.c b/tests/ide-test.c
index 45036e3..5fc496f 100644
--- a/tests/ide-test.c
+++ b/tests/ide-test.c
@@ -29,8 +29,12 @@
#include <glib.h>
#include "libqtest.h"
+#include "libqos/pci-pc.h"
+#include "libqos/malloc-pc.h"
#include "qemu-common.h"
+#include "hw/pci/pci_ids.h"
+#include "hw/pci/pci_regs.h"
#define TEST_IMAGE_SIZE 64 * 1024 * 1024
@@ -60,12 +64,42 @@ enum {
};
enum {
+ LBA = 0x40,
+};
+
+enum {
+ bmreg_cmd = 0x0,
+ bmreg_status = 0x2,
+ bmreg_prdt = 0x4,
+};
+
+enum {
+ CMD_READ_DMA = 0xc8,
+ CMD_WRITE_DMA = 0xca,
CMD_IDENTIFY = 0xec,
};
+enum {
+ BM_CMD_START = 0x1,
+ BM_CMD_WRITE = 0x8, /* write = from device to memory */
+};
+
+enum {
+ BM_STS_ACTIVE = 0x1,
+ BM_STS_ERROR = 0x2,
+ BM_STS_INTR = 0x4,
+};
+
+enum {
+ PRDT_EOT = 0x80000000,
+};
+
#define assert_bit_set(data, mask) g_assert_cmphex((data) & (mask), ==, (mask))
#define assert_bit_clear(data, mask) g_assert_cmphex((data) & (mask), ==, 0)
+static QPCIBus *pcibus = NULL;
+static QGuestAllocator *guest_malloc;
+
static char tmp_path[] = "/tmp/qtest.XXXXXX";
static void ide_test_start(const char *cmdline_fmt, ...)
@@ -79,6 +113,7 @@ static void ide_test_start(const char *cmdline_fmt, ...)
qtest_start(cmdline);
qtest_irq_intercept_in(global_qtest, "ioapic");
+ guest_malloc = pc_alloc_init();
}
static void ide_test_quit(void)
@@ -86,6 +121,188 @@ static void ide_test_quit(void)
qtest_quit(global_qtest);
}
+static QPCIDevice *get_pci_device(uint16_t *bmdma_base)
+{
+ QPCIDevice *dev;
+ uint16_t vendor_id, device_id;
+
+ if (!pcibus) {
+ pcibus = qpci_init_pc();
+ }
+
+ /* Find PCI device and verify it's the right one */
+ dev = qpci_device_find(pcibus, QPCI_DEVFN(IDE_PCI_DEV, IDE_PCI_FUNC));
+ g_assert(dev != NULL);
+
+ vendor_id = qpci_config_readw(dev, PCI_VENDOR_ID);
+ device_id = qpci_config_readw(dev, PCI_DEVICE_ID);
+ g_assert(vendor_id == PCI_VENDOR_ID_INTEL);
+ g_assert(device_id == PCI_DEVICE_ID_INTEL_82371SB_1);
+
+ /* Map bmdma BAR */
+ *bmdma_base = (uint16_t)(uintptr_t) qpci_iomap(dev, 4);
+
+ qpci_device_enable(dev);
+
+ return dev;
+}
+
+static void free_pci_device(QPCIDevice *dev)
+{
+ /* libqos doesn't have a function for this, so free it manually */
+ g_free(dev);
+}
+
+typedef struct PrdtEntry {
+ uint32_t addr;
+ uint32_t size;
+} QEMU_PACKED PrdtEntry;
+
+#define assert_bit_set(data, mask) g_assert_cmphex((data) & (mask), ==, (mask))
+#define assert_bit_clear(data, mask) g_assert_cmphex((data) & (mask), ==, 0)
+
+static int send_dma_request(int cmd, uint64_t sector, int nb_sectors,
+ PrdtEntry *prdt, int prdt_entries)
+{
+ QPCIDevice *dev;
+ uint16_t bmdma_base;
+ uintptr_t guest_prdt;
+ size_t len;
+ bool from_dev;
+ uint8_t status;
+
+ dev = get_pci_device(&bmdma_base);
+
+ switch (cmd) {
+ case CMD_READ_DMA:
+ from_dev = true;
+ break;
+ case CMD_WRITE_DMA:
+ from_dev = false;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ /* Select device 0 */
+ outb(IDE_BASE + reg_device, 0 | LBA);
+
+ /* Stop any running transfer, clear any pending interrupt */
+ outb(bmdma_base + bmreg_cmd, 0);
+ outb(bmdma_base + bmreg_status, BM_STS_INTR);
+
+ /* Setup PRDT */
+ len = sizeof(*prdt) * prdt_entries;
+ guest_prdt = guest_alloc(guest_malloc, len);
+ memwrite(guest_prdt, prdt, len);
+ outl(bmdma_base + bmreg_prdt, guest_prdt);
+
+ /* ATA DMA command */
+ outb(IDE_BASE + reg_nsectors, nb_sectors);
+
+ outb(IDE_BASE + reg_lba_low, sector & 0xff);
+ outb(IDE_BASE + reg_lba_middle, (sector >> 8) & 0xff);
+ outb(IDE_BASE + reg_lba_high, (sector >> 16) & 0xff);
+
+ outb(IDE_BASE + reg_command, cmd);
+
+ /* Start DMA transfer */
+ outb(bmdma_base + bmreg_cmd, BM_CMD_START | (from_dev ? BM_CMD_WRITE : 0));
+
+ /* Wait for the DMA transfer to complete */
+ do {
+ status = inb(bmdma_base + bmreg_status);
+ } while ((status & (BM_STS_ACTIVE | BM_STS_INTR)) == BM_STS_ACTIVE);
+
+ g_assert_cmpint(get_irq(IDE_PRIMARY_IRQ), ==, !!(status & BM_STS_INTR));
+
+ /* Check IDE status code */
+ assert_bit_set(inb(IDE_BASE + reg_status), DRDY);
+ assert_bit_clear(inb(IDE_BASE + reg_status), BSY | DRQ);
+
+ /* Reading the status register clears the IRQ */
+ g_assert(!get_irq(IDE_PRIMARY_IRQ));
+
+ /* Stop DMA transfer if still active */
+ if (status & BM_STS_ACTIVE) {
+ outb(bmdma_base + bmreg_cmd, 0);
+ }
+
+ free_pci_device(dev);
+
+ return status;
+}
+
+static void test_bmdma_simple_rw(void)
+{
+ uint8_t status;
+ uint8_t *buf;
+ uint8_t *cmpbuf;
+ size_t len = 512;
+ uintptr_t guest_buf = guest_alloc(guest_malloc, len);
+
+ PrdtEntry prdt[] = {
+ { .addr = guest_buf, .size = len | PRDT_EOT },
+ };
+
+ buf = g_malloc(len);
+ cmpbuf = g_malloc(len);
+
+ /* Write 0x55 pattern to sector 0 */
+ memset(buf, 0x55, len);
+ memwrite(guest_buf, buf, len);
+
+ status = send_dma_request(CMD_WRITE_DMA, 0, 1, prdt, ARRAY_SIZE(prdt));
+ g_assert_cmphex(status, ==, BM_STS_INTR);
+ assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR);
+
+ /* Write 0xaa pattern to sector 1 */
+ memset(buf, 0xaa, len);
+ memwrite(guest_buf, buf, len);
+
+ status = send_dma_request(CMD_WRITE_DMA, 1, 1, prdt, ARRAY_SIZE(prdt));
+ g_assert_cmphex(status, ==, BM_STS_INTR);
+ assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR);
+
+ /* Read and verify 0x55 pattern in sector 0 */
+ memset(cmpbuf, 0x55, len);
+
+ status = send_dma_request(CMD_READ_DMA, 0, 1, prdt, ARRAY_SIZE(prdt));
+ g_assert_cmphex(status, ==, BM_STS_INTR);
+ assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR);
+
+ memread(guest_buf, buf, len);
+ g_assert(memcmp(buf, cmpbuf, len) == 0);
+
+ /* Read and verify 0xaa pattern in sector 1 */
+ memset(cmpbuf, 0xaa, len);
+
+ status = send_dma_request(CMD_READ_DMA, 1, 1, prdt, ARRAY_SIZE(prdt));
+ g_assert_cmphex(status, ==, BM_STS_INTR);
+ assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR);
+
+ memread(guest_buf, buf, len);
+ g_assert(memcmp(buf, cmpbuf, len) == 0);
+
+
+ g_free(buf);
+ g_free(cmpbuf);
+}
+
+static void test_bmdma_setup(void)
+{
+ ide_test_start(
+ "-vnc none "
+ "-drive file=%s,if=ide,serial=%s,cache=writeback "
+ "-global ide-hd.ver=%s",
+ tmp_path, "testdisk", "version");
+}
+
+static void test_bmdma_teardown(void)
+{
+ ide_test_quit();
+}
+
static void test_identify(void)
{
uint8_t data;
@@ -156,6 +373,10 @@ int main(int argc, char **argv)
qtest_add_func("/ide/identify", test_identify);
+ qtest_add_func("/ide/bmdma/setup", test_bmdma_setup);
+ qtest_add_func("/ide/bmdma/simple_rw", test_bmdma_simple_rw);
+ qtest_add_func("/ide/bmdma/teardown", test_bmdma_teardown);
+
ret = g_test_run();
/* Cleanup */
commit acbe48013bf1eb9c9a435e76959f409584b35509
Author: Kevin Wolf <kwolf at redhat.com>
Date: Wed May 8 11:18:41 2013 +0200
qtest: Add IDE test case
This adds a simple IDE test case and starts by verifying that IDENTIFY
can be successfully used and return the correct serial number, version
and the WCE flag is set for cache=writeback.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/tests/Makefile b/tests/Makefile
index bf41d10..a307d5a 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -51,6 +51,7 @@ check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
# really in libqtest, not in the testcases themselves.
check-qtest-i386-y = tests/fdc-test$(EXESUF)
gcov-files-i386-y = hw/fdc.c
+check-qtest-i386-y += tests/ide-test$(EXESUF)
check-qtest-i386-y += tests/hd-geo-test$(EXESUF)
gcov-files-i386-y += hw/hd-geometry.c
check-qtest-i386-y += tests/rtc-test$(EXESUF)
@@ -127,6 +128,7 @@ libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o
tests/rtc-test$(EXESUF): tests/rtc-test.o
tests/m48t59-test$(EXESUF): tests/m48t59-test.o
tests/fdc-test$(EXESUF): tests/fdc-test.o
+tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y)
tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o
tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
diff --git a/tests/ide-test.c b/tests/ide-test.c
new file mode 100644
index 0000000..45036e3
--- /dev/null
+++ b/tests/ide-test.c
@@ -0,0 +1,165 @@
+/*
+ * IDE test cases
+ *
+ * Copyright (c) 2013 Kevin Wolf <kwolf at redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <glib.h>
+
+#include "libqtest.h"
+
+#include "qemu-common.h"
+
+#define TEST_IMAGE_SIZE 64 * 1024 * 1024
+
+#define IDE_PCI_DEV 1
+#define IDE_PCI_FUNC 1
+
+#define IDE_BASE 0x1f0
+#define IDE_PRIMARY_IRQ 14
+
+enum {
+ reg_data = 0x0,
+ reg_nsectors = 0x2,
+ reg_lba_low = 0x3,
+ reg_lba_middle = 0x4,
+ reg_lba_high = 0x5,
+ reg_device = 0x6,
+ reg_status = 0x7,
+ reg_command = 0x7,
+};
+
+enum {
+ BSY = 0x80,
+ DRDY = 0x40,
+ DF = 0x20,
+ DRQ = 0x08,
+ ERR = 0x01,
+};
+
+enum {
+ CMD_IDENTIFY = 0xec,
+};
+
+#define assert_bit_set(data, mask) g_assert_cmphex((data) & (mask), ==, (mask))
+#define assert_bit_clear(data, mask) g_assert_cmphex((data) & (mask), ==, 0)
+
+static char tmp_path[] = "/tmp/qtest.XXXXXX";
+
+static void ide_test_start(const char *cmdline_fmt, ...)
+{
+ va_list ap;
+ char *cmdline;
+
+ va_start(ap, cmdline_fmt);
+ cmdline = g_strdup_vprintf(cmdline_fmt, ap);
+ va_end(ap);
+
+ qtest_start(cmdline);
+ qtest_irq_intercept_in(global_qtest, "ioapic");
+}
+
+static void ide_test_quit(void)
+{
+ qtest_quit(global_qtest);
+}
+
+static void test_identify(void)
+{
+ uint8_t data;
+ uint16_t buf[256];
+ int i;
+ int ret;
+
+ ide_test_start(
+ "-vnc none "
+ "-drive file=%s,if=ide,serial=%s,cache=writeback "
+ "-global ide-hd.ver=%s",
+ tmp_path, "testdisk", "version");
+
+ /* IDENTIFY command on device 0*/
+ outb(IDE_BASE + reg_device, 0);
+ outb(IDE_BASE + reg_command, CMD_IDENTIFY);
+
+ /* Read in the IDENTIFY buffer and check registers */
+ data = inb(IDE_BASE + reg_device);
+ g_assert_cmpint(data & 0x10, ==, 0);
+
+ for (i = 0; i < 256; i++) {
+ data = inb(IDE_BASE + reg_status);
+ assert_bit_set(data, DRDY | DRQ);
+ assert_bit_clear(data, BSY | DF | ERR);
+
+ ((uint16_t*) buf)[i] = inw(IDE_BASE + reg_data);
+ }
+
+ data = inb(IDE_BASE + reg_status);
+ assert_bit_set(data, DRDY);
+ assert_bit_clear(data, BSY | DF | ERR | DRQ);
+
+ /* Check serial number/version in the buffer */
+ ret = memcmp(&buf[10], "ettsidks ", 20);
+ g_assert(ret == 0);
+
+ ret = memcmp(&buf[23], "evsroi n", 8);
+ g_assert(ret == 0);
+
+ /* Write cache enabled bit */
+ assert_bit_set(buf[85], 0x20);
+
+ ide_test_quit();
+}
+
+int main(int argc, char **argv)
+{
+ const char *arch = qtest_get_arch();
+ int fd;
+ int ret;
+
+ /* Check architecture */
+ if (strcmp(arch, "i386") && strcmp(arch, "x86_64")) {
+ g_test_message("Skipping test for non-x86\n");
+ return 0;
+ }
+
+ /* Create a temporary raw image */
+ fd = mkstemp(tmp_path);
+ g_assert(fd >= 0);
+ ret = ftruncate(fd, TEST_IMAGE_SIZE);
+ g_assert(ret == 0);
+ close(fd);
+
+ /* Run the tests */
+ g_test_init(&argc, &argv, NULL);
+
+ qtest_add_func("/ide/identify", test_identify);
+
+ ret = g_test_run();
+
+ /* Cleanup */
+ unlink(tmp_path);
+
+ return ret;
+}
commit 9f0332b8cf27020d70be92f5e664466f0bcb84ec
Author: Kevin Wolf <kwolf at redhat.com>
Date: Wed Mar 13 17:00:40 2013 +0100
libqos/pci: Enable bus mastering
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/tests/libqos/pci.c b/tests/libqos/pci.c
index 95e287b..7e0907b 100644
--- a/tests/libqos/pci.c
+++ b/tests/libqos/pci.c
@@ -71,7 +71,7 @@ void qpci_device_enable(QPCIDevice *dev)
/* FIXME -- does this need to be a bus callout? */
cmd = qpci_config_readw(dev, PCI_COMMAND);
- cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+ cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
qpci_config_writew(dev, PCI_COMMAND, cmd);
}
commit b39f96126549e2834152211a99919917423d2212
Author: Kevin Wolf <kwolf at redhat.com>
Date: Wed Mar 13 16:53:06 2013 +0100
ide: Reset BMIDEA bit when the bus master is stopped
The device is supposed to reset the Bus Master IDE Active bit in the
status register when 0 is written to the Start/Stop Bus Master bit in
the command register.
In the common cases this happens automatically because bdrv_drain_all()
flushes the requests, but with a large PRDT it could remain set.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index a310975..635a364 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -312,6 +312,7 @@ void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val)
bdrv_drain_all();
assert(bm->bus->dma->aiocb == NULL);
}
+ bm->status &= ~BM_STATUS_DMAING;
} else {
bm->cur_addr = bm->addr;
if (!(bm->status & BM_STATUS_DMAING)) {
commit 3bac85d33716d9024afb8a262a39032bc0bba3ed
Author: Kevin Wolf <kwolf at redhat.com>
Date: Tue May 7 15:23:41 2013 +0200
de_DE.po: Add missing leading spaces
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/po/de_DE.po b/po/de_DE.po
index 92c5df5..e35aaf4 100644
--- a/po/de_DE.po
+++ b/po/de_DE.po
@@ -18,11 +18,11 @@ msgstr ""
#: ../ui/gtk.c:213
msgid " - Press Ctrl+Alt+G to release grab"
-msgstr "- Strg+Alt+G drücken, um Eingabegeräte freizugeben"
+msgstr " - Strg+Alt+G drücken, um Eingabegeräte freizugeben"
#: ../ui/gtk.c:217
msgid " [Paused]"
-msgstr "[Angehalten]"
+msgstr " [Angehalten]"
#: ../ui/gtk.c:1250
msgid "_Machine"
commit 0ee20e665840d8a887c145b368ee121cb86a028e
Author: Kevin Wolf <kwolf at redhat.com>
Date: Mon May 6 15:58:04 2013 +0200
ahci: Don't allow creating slave drives
An IDE bus provided by AHCI can only take a single IDE drive. If you add
a drive as slave, qemu used to accept the command line but the device
wouldn't be actually usable. Catch the situation instead and error out.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 3405583..eab6096 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -1163,7 +1163,7 @@ void ahci_init(AHCIState *s, DeviceState *qdev, DMAContext *dma, int ports)
for (i = 0; i < s->ports; i++) {
AHCIDevice *ad = &s->dev[i];
- ide_bus_new(&ad->port, qdev, i);
+ ide_bus_new(&ad->port, qdev, i, 1);
ide_init2(&ad->port, irqs[i]);
ad->hba = s;
diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index 541d4ef..a73eb9a 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -281,7 +281,7 @@ static int pci_cmd646_ide_initfn(PCIDevice *dev)
irq = qemu_allocate_irqs(cmd646_set_irq, d, 2);
for (i = 0; i < 2; i++) {
- ide_bus_new(&d->bus[i], &d->dev.qdev, i);
+ ide_bus_new(&d->bus[i], &d->dev.qdev, i, 2);
ide_init2(&d->bus[i], irq[i]);
bmdma_init(&d->bus[i], &d->bmdma[i], d);
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 0efb2da..03f1489 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -450,6 +450,7 @@ struct IDEBus {
IDEDevice *slave;
IDEState ifs[2];
int bus_id;
+ int max_units;
IDEDMA *dma;
uint8_t unit;
uint8_t cmd;
@@ -574,7 +575,7 @@ void ide_atapi_cmd(IDEState *s);
void ide_atapi_cmd_reply_end(IDEState *s);
/* hw/ide/qdev.c */
-void ide_bus_new(IDEBus *idebus, DeviceState *dev, int bus_id);
+void ide_bus_new(IDEBus *idebus, DeviceState *dev, int bus_id, int max_units);
IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive);
#endif /* HW_IDE_INTERNAL_H */
diff --git a/hw/ide/isa.c b/hw/ide/isa.c
index 5e7422f..369a7fa 100644
--- a/hw/ide/isa.c
+++ b/hw/ide/isa.c
@@ -69,7 +69,7 @@ static int isa_ide_initfn(ISADevice *dev)
{
ISAIDEState *s = ISA_IDE(dev);
- ide_bus_new(&s->bus, DEVICE(dev), 0);
+ ide_bus_new(&s->bus, DEVICE(dev), 0, 2);
ide_init_ioport(&s->bus, dev, s->iobase, s->iobase2);
isa_init_irq(dev, &s->irq, s->isairq);
ide_init2(&s->bus, s->irq);
diff --git a/hw/ide/macio.c b/hw/ide/macio.c
index 64b2406..bf12a10 100644
--- a/hw/ide/macio.c
+++ b/hw/ide/macio.c
@@ -334,7 +334,7 @@ static void macio_ide_initfn(Object *obj)
SysBusDevice *d = SYS_BUS_DEVICE(obj);
MACIOIDEState *s = MACIO_IDE(obj);
- ide_bus_new(&s->bus, DEVICE(obj), 0);
+ ide_bus_new(&s->bus, DEVICE(obj), 0, 2);
memory_region_init_io(&s->mem, &pmac_ide_ops, s, "pmac-ide", 0x1000);
sysbus_init_mmio(d, &s->mem);
sysbus_init_irq(d, &s->irq);
diff --git a/hw/ide/mmio.c b/hw/ide/mmio.c
index ce88c3a..e80e7e5 100644
--- a/hw/ide/mmio.c
+++ b/hw/ide/mmio.c
@@ -137,7 +137,7 @@ static void mmio_ide_initfn(Object *obj)
SysBusDevice *d = SYS_BUS_DEVICE(obj);
MMIOState *s = MMIO_IDE(obj);
- ide_bus_new(&s->bus, DEVICE(obj), 0);
+ ide_bus_new(&s->bus, DEVICE(obj), 0, 2);
sysbus_init_irq(d, &s->irq);
}
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index 1de284d..bf2856f 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -135,7 +135,7 @@ static void pci_piix_init_ports(PCIIDEState *d) {
int i;
for (i = 0; i < 2; i++) {
- ide_bus_new(&d->bus[i], &d->dev.qdev, i);
+ ide_bus_new(&d->bus[i], &d->dev.qdev, i, 2);
ide_init_ioport(&d->bus[i], NULL, port_info[i].iobase,
port_info[i].iobase2);
ide_init2(&d->bus[i], isa_get_irq(NULL, port_info[i].isairq));
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index 8a9a891..6a272b0 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -47,10 +47,11 @@ static const TypeInfo ide_bus_info = {
.class_init = ide_bus_class_init,
};
-void ide_bus_new(IDEBus *idebus, DeviceState *dev, int bus_id)
+void ide_bus_new(IDEBus *idebus, DeviceState *dev, int bus_id, int max_units)
{
qbus_create_inplace(&idebus->qbus, TYPE_IDE_BUS, dev, NULL);
idebus->bus_id = bus_id;
+ idebus->max_units = max_units;
}
static char *idebus_get_fw_dev_path(DeviceState *dev)
@@ -76,6 +77,13 @@ static int ide_qdev_init(DeviceState *qdev)
if (dev->unit == -1) {
dev->unit = bus->master ? 1 : 0;
}
+
+ if (dev->unit >= bus->max_units) {
+ error_report("Can't create IDE unit %d, bus supports only %d units",
+ dev->unit, bus->max_units);
+ goto err;
+ }
+
switch (dev->unit) {
case 0:
if (bus->master) {
diff --git a/hw/ide/via.c b/hw/ide/via.c
index 9d6a644..5fe053c 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -158,7 +158,7 @@ static void vt82c686b_init_ports(PCIIDEState *d) {
int i;
for (i = 0; i < 2; i++) {
- ide_bus_new(&d->bus[i], &d->dev.qdev, i);
+ ide_bus_new(&d->bus[i], &d->dev.qdev, i, 2);
ide_init_ioport(&d->bus[i], NULL, port_info[i].iobase,
port_info[i].iobase2);
ide_init2(&d->bus[i], isa_get_irq(NULL, port_info[i].isairq));
commit 15d23fb96656b1ae31bf4305b2108230c29298c6
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Tue May 7 06:50:19 2013 -0500
Update version for qemu-1.5.0-rc0
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/VERSION b/VERSION
index 8fe423b..245205d 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.4.50
+1.4.90
commit b174de51ae397549f58b1b76efa9026b213a1efd
Merge: c689b4f 4e906d5
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Tue May 7 06:48:31 2013 -0500
Merge remote-tracking branch 'kraxel/usb.82' into staging
# By Gerd Hoffmann (3) and Hans de Goede (1)
# Via Gerd Hoffmann
* kraxel/usb.82:
xhci: handle USB_RET_BABBLE
uhci: Use an intermediate buffer for usb packet data
usb-host: add usb_host_full_speed_compat
usb-host: live migration support for the libusb version
Message-id: 1367920207-1404-1-git-send-email-kraxel at redhat.com
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
commit c689b4f1bac352dcfd6ecb9a1d45337de0f1de67
Author: Laszlo Ersek <lersek at redhat.com>
Date: Wed Apr 24 13:13:18 2013 +0200
qga: set umask 0077 when daemonizing (CVE-2013-2007)
The qemu guest agent creates a bunch of files with insecure permissions
when started in daemon mode. For example:
-rw-rw-rw- 1 root root /var/log/qemu-ga.log
-rw-rw-rw- 1 root root /var/run/qga.state
-rw-rw-rw- 1 root root /var/log/qga-fsfreeze-hook.log
In addition, at least all files created with the "guest-file-open" QMP
command, and all files created with shell output redirection (or
otherwise) by utilities invoked by the fsfreeze hook script are affected.
For now mask all file mode bits for "group" and "others" in
become_daemon().
Temporarily, for compatibility reasons, stick with the 0666 file-mode in
case of files newly created by the "guest-file-open" QMP call. Do so
without changing the umask temporarily.
Signed-off-by: Laszlo Ersek <lersek at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 3b5c536..04c6951 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -18,6 +18,9 @@
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
#include <inttypes.h>
#include "qga/guest-agent-core.h"
#include "qga-qmp-commands.h"
@@ -237,9 +240,122 @@ static GuestFileHandle *guest_file_handle_find(int64_t id, Error **err)
return NULL;
}
+typedef const char * const ccpc;
+
+/* http://pubs.opengroup.org/onlinepubs/9699919799/functions/fopen.html */
+static const struct {
+ ccpc *forms;
+ int oflag_base;
+} guest_file_open_modes[] = {
+ { (ccpc[]){ "r", "rb", NULL }, O_RDONLY },
+ { (ccpc[]){ "w", "wb", NULL }, O_WRONLY | O_CREAT | O_TRUNC },
+ { (ccpc[]){ "a", "ab", NULL }, O_WRONLY | O_CREAT | O_APPEND },
+ { (ccpc[]){ "r+", "rb+", "r+b", NULL }, O_RDWR },
+ { (ccpc[]){ "w+", "wb+", "w+b", NULL }, O_RDWR | O_CREAT | O_TRUNC },
+ { (ccpc[]){ "a+", "ab+", "a+b", NULL }, O_RDWR | O_CREAT | O_APPEND }
+};
+
+static int
+find_open_flag(const char *mode_str, Error **err)
+{
+ unsigned mode;
+
+ for (mode = 0; mode < ARRAY_SIZE(guest_file_open_modes); ++mode) {
+ ccpc *form;
+
+ form = guest_file_open_modes[mode].forms;
+ while (*form != NULL && strcmp(*form, mode_str) != 0) {
+ ++form;
+ }
+ if (*form != NULL) {
+ break;
+ }
+ }
+
+ if (mode == ARRAY_SIZE(guest_file_open_modes)) {
+ error_setg(err, "invalid file open mode '%s'", mode_str);
+ return -1;
+ }
+ return guest_file_open_modes[mode].oflag_base | O_NOCTTY | O_NONBLOCK;
+}
+
+#define DEFAULT_NEW_FILE_MODE (S_IRUSR | S_IWUSR | \
+ S_IRGRP | S_IWGRP | \
+ S_IROTH | S_IWOTH)
+
+static FILE *
+safe_open_or_create(const char *path, const char *mode, Error **err)
+{
+ Error *local_err = NULL;
+ int oflag;
+
+ oflag = find_open_flag(mode, &local_err);
+ if (local_err == NULL) {
+ int fd;
+
+ /* If the caller wants / allows creation of a new file, we implement it
+ * with a two step process: open() + (open() / fchmod()).
+ *
+ * First we insist on creating the file exclusively as a new file. If
+ * that succeeds, we're free to set any file-mode bits on it. (The
+ * motivation is that we want to set those file-mode bits independently
+ * of the current umask.)
+ *
+ * If the exclusive creation fails because the file already exists
+ * (EEXIST is not possible for any other reason), we just attempt to
+ * open the file, but in this case we won't be allowed to change the
+ * file-mode bits on the preexistent file.
+ *
+ * The pathname should never disappear between the two open()s in
+ * practice. If it happens, then someone very likely tried to race us.
+ * In this case just go ahead and report the ENOENT from the second
+ * open() to the caller.
+ *
+ * If the caller wants to open a preexistent file, then the first
+ * open() is decisive and its third argument is ignored, and the second
+ * open() and the fchmod() are never called.
+ */
+ fd = open(path, oflag | ((oflag & O_CREAT) ? O_EXCL : 0), 0);
+ if (fd == -1 && errno == EEXIST) {
+ oflag &= ~(unsigned)O_CREAT;
+ fd = open(path, oflag);
+ }
+
+ if (fd == -1) {
+ error_setg_errno(&local_err, errno, "failed to open file '%s' "
+ "(mode: '%s')", path, mode);
+ } else {
+ qemu_set_cloexec(fd);
+
+ if ((oflag & O_CREAT) && fchmod(fd, DEFAULT_NEW_FILE_MODE) == -1) {
+ error_setg_errno(&local_err, errno, "failed to set permission "
+ "0%03o on new file '%s' (mode: '%s')",
+ (unsigned)DEFAULT_NEW_FILE_MODE, path, mode);
+ } else {
+ FILE *f;
+
+ f = fdopen(fd, mode);
+ if (f == NULL) {
+ error_setg_errno(&local_err, errno, "failed to associate "
+ "stdio stream with file descriptor %d, "
+ "file '%s' (mode: '%s')", fd, path, mode);
+ } else {
+ return f;
+ }
+ }
+
+ close(fd);
+ }
+ }
+
+ error_propagate(err, local_err);
+ return NULL;
+}
+
int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, Error **err)
{
FILE *fh;
+ Error *local_err = NULL;
int fd;
int64_t ret = -1, handle;
@@ -247,10 +363,9 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, E
mode = "r";
}
slog("guest-file-open called, filepath: %s, mode: %s", path, mode);
- fh = fopen(path, mode);
- if (!fh) {
- error_setg_errno(err, errno, "failed to open file '%s' (mode: '%s')",
- path, mode);
+ fh = safe_open_or_create(path, mode, &local_err);
+ if (local_err != NULL) {
+ error_propagate(err, local_err);
return -1;
}
diff --git a/qga/main.c b/qga/main.c
index 1841759..44a2836 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -478,7 +478,7 @@ static void become_daemon(const char *pidfile)
}
}
- umask(0);
+ umask(S_IRWXG | S_IRWXO);
sid = setsid();
if (sid < 0) {
goto fail;
commit d7108d90100d5bac5965abef5ed73f2602adae14
Author: Jason Wang <jasowang at redhat.com>
Date: Fri Apr 26 18:27:40 2013 +0800
virtio-net: properly check the vhost status during status set
Commit 32993698 (vhost: disable on tap link down) tries to disable the vhost
also when the peer's link is down. But the check was not done properly, the
vhost were only started when:
1) peer's link is not down
2) virtio-net has already been started.
Since == have a higher precedence than &&, place a brace to make sure both the
conditions were met then does the check. This fixes the crash when doing a savem
after set the link off which let qemu crash and complains:
virtio_net_save: Assertion `!n->vhost_started' failed.
Cc: Michael S. Tsirkin <mst at redhat.com>
Signed-off-by: Jason Wang <jasowang at redhat.com>
Message-id: 1366972060-21606-1-git-send-email-jasowang at redhat.com
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 908e7b8..9f18d6a 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -114,8 +114,8 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status)
return;
}
- if (!!n->vhost_started == virtio_net_started(n, status) &&
- !nc->peer->link_down) {
+ if (!!n->vhost_started ==
+ (virtio_net_started(n, status) && !nc->peer->link_down)) {
return;
}
if (!n->vhost_started) {
commit fd8192a5a868ddbb711abbf4a871b09bbb1dae04
Merge: b5803aa 4458c23
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Tue May 7 06:32:00 2013 -0500
Merge remote-tracking branch 'afaerber/qom-cpu' into staging
# By Eduardo Habkost (6) and others
# Via Andreas Färber
* afaerber/qom-cpu:
target-i386: n270 can MOVBE
target-i386: Introduce generic CPUID feature compat function
target-i386: Change CPUID model of 486 to 8
target-i386: Emulate X86CPU subclasses for global properties
qdev: Introduce qdev_prop_set_globals_for_type()
qdev: Let qdev_prop_parse() pass through Error
target-i386: Add "filtered-features" property to X86CPU
target-i386: Introduce X86CPU::filtered_features field
target-i386: Add "feature-words" property to X86CPU
target-i386: Use FeatureWord loop on filter_features_for_kvm()
target-i386: Add ECX information to FeatureWordInfo
commit 4e906d567a97ee45b4922001bf521dad0bde5268
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Mon May 6 12:33:56 2013 +0200
xhci: handle USB_RET_BABBLE
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 2c90e56..8813bdf 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -1716,6 +1716,11 @@ static int xhci_complete_packet(XHCITransfer *xfer)
xhci_xfer_report(xfer);
xhci_stall_ep(xfer);
break;
+ case USB_RET_BABBLE:
+ xfer->status = CC_BABBLE_DETECTED;
+ xhci_xfer_report(xfer);
+ xhci_stall_ep(xfer);
+ break;
default:
fprintf(stderr, "%s: FIXME: status = %d\n", __func__,
xfer->packet.status);
commit 9822261ce3bfbc7aec8b2a3e378892dc368910ed
Author: Hans de Goede <hdegoede at redhat.com>
Date: Mon May 6 10:48:57 2013 +0200
uhci: Use an intermediate buffer for usb packet data
Due to various unfortunate reasons we cannot reliable detect a guest
cancelling a packet as soon as it happens, instead we detect cancels
with some delay.
When packets are handled async, and we directly pass the guest memory for
the packet to the usb-device as iovec, this means that the usb-device can
write to guest-memory which the guest has already re-used for other purposes
-> not good!
This patch fixes this by adding an intermediate buffer and writing back not
only the result, but also the data, of async completed packets when scanning
the schedule.
Signed-off-by: Hans de Goede <hdegoede at redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index f8c4286..c85b203 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -119,7 +119,8 @@ struct UHCIPCIDeviceClass {
struct UHCIAsync {
USBPacket packet;
- QEMUSGList sgl;
+ uint8_t static_buf[64]; /* 64 bytes is enough, except for isoc packets */
+ uint8_t *buf;
UHCIQueue *queue;
QTAILQ_ENTRY(UHCIAsync) next;
uint32_t td_addr;
@@ -264,7 +265,6 @@ static UHCIAsync *uhci_async_alloc(UHCIQueue *queue, uint32_t td_addr)
async->queue = queue;
async->td_addr = td_addr;
usb_packet_init(&async->packet);
- pci_dma_sglist_init(&async->sgl, &queue->uhci->dev, 1);
trace_usb_uhci_packet_add(async->queue->token, async->td_addr);
return async;
@@ -274,7 +274,9 @@ static void uhci_async_free(UHCIAsync *async)
{
trace_usb_uhci_packet_del(async->queue->token, async->td_addr);
usb_packet_cleanup(&async->packet);
- qemu_sglist_destroy(&async->sgl);
+ if (async->buf != async->static_buf) {
+ g_free(async->buf);
+ }
g_free(async);
}
@@ -299,7 +301,6 @@ static void uhci_async_cancel(UHCIAsync *async)
async->done);
if (!async->done)
usb_cancel_packet(&async->packet);
- usb_packet_unmap(&async->packet, &async->sgl);
uhci_async_free(async);
}
@@ -774,6 +775,7 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
*int_mask |= 0x01;
if (pid == USB_TOKEN_IN) {
+ pci_dma_write(&s->dev, td->buffer, async->buf, len);
if ((td->ctrl & TD_CTRL_SPD) && len < max_len) {
*int_mask |= 0x02;
/* short packet: do not update QH */
@@ -881,12 +883,17 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
spd = (pid == USB_TOKEN_IN && (td->ctrl & TD_CTRL_SPD) != 0);
usb_packet_setup(&async->packet, pid, q->ep, 0, td_addr, spd,
(td->ctrl & TD_CTRL_IOC) != 0);
- qemu_sglist_add(&async->sgl, td->buffer, max_len);
- usb_packet_map(&async->packet, &async->sgl);
+ if (max_len <= sizeof(async->static_buf)) {
+ async->buf = async->static_buf;
+ } else {
+ async->buf = g_malloc(max_len);
+ }
+ usb_packet_addbuf(&async->packet, async->buf, max_len);
switch(pid) {
case USB_TOKEN_OUT:
case USB_TOKEN_SETUP:
+ pci_dma_read(&s->dev, td->buffer, async->buf, max_len);
usb_handle_packet(q->ep->dev, &async->packet);
if (async->packet.status == USB_RET_SUCCESS) {
async->packet.actual_length = max_len;
@@ -899,7 +906,6 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
default:
/* invalid pid : frame interrupted */
- usb_packet_unmap(&async->packet, &async->sgl);
uhci_async_free(async);
s->status |= UHCI_STS_HCPERR;
uhci_update_irq(s);
@@ -916,7 +922,6 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
done:
ret = uhci_complete_td(s, td, async, int_mask);
- usb_packet_unmap(&async->packet, &async->sgl);
uhci_async_free(async);
return ret;
}
commit c3268cc1135f41264cd26bcb269b3414d3c11453
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Mon May 6 13:12:16 2013 +0200
usb-host: add usb_host_full_speed_compat
Alloes to pass through usb2 devices on usb1 host controllers if possible.
Brings the libusb implementation to feature-parity with the linux usbfs
code, so the usb-host implementation in 1.5 (libusb) doesn't regress
compared to 1.4 (usbfs).
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c
index ee67c4c..f3de459 100644
--- a/hw/usb/host-libusb.c
+++ b/hw/usb/host-libusb.c
@@ -667,6 +667,42 @@ static void usb_host_iso_data_out(USBHostDevice *s, USBPacket *p)
/* ------------------------------------------------------------------------ */
+static bool usb_host_full_speed_compat(USBHostDevice *s)
+{
+ struct libusb_config_descriptor *conf;
+ const struct libusb_interface_descriptor *intf;
+ const struct libusb_endpoint_descriptor *endp;
+ uint8_t type;
+ int rc, c, i, a, e;
+
+ for (c = 0;; c++) {
+ rc = libusb_get_config_descriptor(s->dev, c, &conf);
+ if (rc != 0) {
+ break;
+ }
+ for (i = 0; i < conf->bNumInterfaces; i++) {
+ for (a = 0; a < conf->interface[i].num_altsetting; a++) {
+ intf = &conf->interface[i].altsetting[a];
+ for (e = 0; e < intf->bNumEndpoints; e++) {
+ endp = &intf->endpoint[e];
+ type = endp->bmAttributes & 0x3;
+ switch (type) {
+ case 0x01: /* ISO */
+ return false;
+ case 0x03: /* INTERRUPT */
+ if (endp->wMaxPacketSize > 64) {
+ return false;
+ }
+ break;
+ }
+ }
+ }
+ }
+ libusb_free_config_descriptor(conf);
+ }
+ return true;
+}
+
static void usb_host_ep_update(USBHostDevice *s)
{
static const char *tname[] = {
@@ -758,11 +794,9 @@ static int usb_host_open(USBHostDevice *s, libusb_device *dev)
udev->speed = speed_map[libusb_get_device_speed(dev)];
udev->speedmask = (1 << udev->speed);
-#if 0
- if (udev->speed == USB_SPEED_HIGH && usb_linux_full_speed_compat(dev)) {
+ if (udev->speed == USB_SPEED_HIGH && usb_host_full_speed_compat(s)) {
udev->speedmask |= USB_SPEED_MASK_FULL;
}
-#endif
if (s->ddesc.iProduct) {
libusb_get_string_descriptor_ascii(s->dh, s->ddesc.iProduct,
commit 95efb20c714800de7eaf991f19dab6e7a29d5364
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Wed Apr 24 14:29:08 2013 +0200
usb-host: live migration support for the libusb version
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c
index d1186b8..ee67c4c 100644
--- a/hw/usb/host-libusb.c
+++ b/hw/usb/host-libusb.c
@@ -94,7 +94,8 @@ struct USBHostDevice {
} ifs[USB_MAX_INTERFACES];
/* callbacks & friends */
- QEMUBH *bh;
+ QEMUBH *bh_nodev;
+ QEMUBH *bh_postld;
Notifier exit;
/* request queues */
@@ -835,10 +836,10 @@ static void usb_host_nodev_bh(void *opaque)
static void usb_host_nodev(USBHostDevice *s)
{
- if (!s->bh) {
- s->bh = qemu_bh_new(usb_host_nodev_bh, s);
+ if (!s->bh_nodev) {
+ s->bh_nodev = qemu_bh_new(usb_host_nodev_bh, s);
}
- qemu_bh_schedule(s->bh);
+ qemu_bh_schedule(s->bh_nodev);
}
static void usb_host_exit_notifier(struct Notifier *n, void *data)
@@ -1228,9 +1229,52 @@ static void usb_host_handle_reset(USBDevice *udev)
usb_host_ep_update(s);
}
+/*
+ * This is *NOT* about restoring state. We have absolutely no idea
+ * what state the host device is in at the moment and whenever it is
+ * still present in the first place. Attemping to contine where we
+ * left off is impossible.
+ *
+ * What we are going to to to here is emulate a surprise removal of
+ * the usb device passed through, then kick host scan so the device
+ * will get re-attached (and re-initialized by the guest) in case it
+ * is still present.
+ *
+ * As the device removal will change the state of other devices (usb
+ * host controller, most likely interrupt controller too) we have to
+ * wait with it until *all* vmstate is loaded. Thus post_load just
+ * kicks a bottom half which then does the actual work.
+ */
+static void usb_host_post_load_bh(void *opaque)
+{
+ USBHostDevice *dev = opaque;
+ USBDevice *udev = USB_DEVICE(dev);
+
+ if (dev->dh != NULL) {
+ usb_host_close(dev);
+ }
+ if (udev->attached) {
+ usb_device_detach(udev);
+ }
+ usb_host_auto_check(NULL);
+}
+
+static int usb_host_post_load(void *opaque, int version_id)
+{
+ USBHostDevice *dev = opaque;
+
+ if (!dev->bh_postld) {
+ dev->bh_postld = qemu_bh_new(usb_host_post_load_bh, dev);
+ }
+ qemu_bh_schedule(dev->bh_postld);
+ return 0;
+}
+
static const VMStateDescription vmstate_usb_host = {
.name = "usb-host",
- .unmigratable = 1,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .post_load = usb_host_post_load,
.fields = (VMStateField[]) {
VMSTATE_USB_DEVICE(parent_obj, USBHostDevice),
VMSTATE_END_OF_LIST()
commit 4458c23672904fa131e69897007eeb7c953be7e5
Author: Borislav Petkov <bp at suse.de>
Date: Thu Apr 25 15:43:04 2013 -0300
target-i386: n270 can MOVBE
The Atom core (cpu name "n270" in QEMU speak) supports MOVBE. This is
needed when booting 3.8 and later linux kernels built with the MATOM
target because we require MOVBE in order to boot properly now.
Signed-off-by: Borislav Petkov <bp at suse.de>
[ehabkost: added compat code to disable MOVBE on pc-*-1.4 and older]
Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index fe52e5f..f7c80ad 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -250,6 +250,7 @@ static void pc_init_pci_1_4(QEMUMachineInitArgs *args)
{
pc_sysfw_flash_vs_rom_bug_compatible = true;
has_pvpanic = false;
+ x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE);
pc_init_pci(args);
}
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 52511e2..4160e2b 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -212,6 +212,7 @@ static void pc_q35_init_1_4(QEMUMachineInitArgs *args)
{
pc_sysfw_flash_vs_rom_bug_compatible = true;
has_pvpanic = false;
+ x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE);
pc_q35_init(args);
}
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 8198a1b..1a501d9 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -657,7 +657,8 @@ static x86_def_t builtin_x86_defs[] = {
/* Some CPUs got no CPUID_SEP */
.features[FEAT_1_ECX] =
CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_SSSE3 |
- CPUID_EXT_DSCPL | CPUID_EXT_EST | CPUID_EXT_TM2 | CPUID_EXT_XTPR,
+ CPUID_EXT_DSCPL | CPUID_EXT_EST | CPUID_EXT_TM2 | CPUID_EXT_XTPR |
+ CPUID_EXT_MOVBE,
.features[FEAT_8000_0001_EDX] =
(PPRO_FEATURES & CPUID_EXT2_AMD_ALIASES) |
CPUID_EXT2_NX,
commit 0668af542f99b7bb1d95539829b27d5a1bcecde4
Author: Eduardo Habkost <ehabkost at redhat.com>
Date: Thu Apr 25 15:43:00 2013 -0300
target-i386: Introduce generic CPUID feature compat function
Introduce x86_cpu_compat_set_features(), that can be used to set/unset
feature bits on specific CPU models for machine-type compatibility.
Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 8e21c94..8198a1b 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -971,6 +971,32 @@ static x86_def_t builtin_x86_defs[] = {
},
};
+/**
+ * x86_cpu_compat_set_features:
+ * @cpu_model: CPU model name to be changed. If NULL, all CPU models are changed
+ * @w: Identifies the feature word to be changed.
+ * @feat_add: Feature bits to be added to feature word
+ * @feat_remove: Feature bits to be removed from feature word
+ *
+ * Change CPU model feature bits for compatibility.
+ *
+ * This function may be used by machine-type compatibility functions
+ * to enable or disable feature bits on specific CPU models.
+ */
+void x86_cpu_compat_set_features(const char *cpu_model, FeatureWord w,
+ uint32_t feat_add, uint32_t feat_remove)
+{
+ x86_def_t *def;
+ int i;
+ for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) {
+ def = &builtin_x86_defs[i];
+ if (!cpu_model || !strcmp(cpu_model, def->name)) {
+ def->features[w] |= feat_add;
+ def->features[w] &= ~feat_remove;
+ }
+ }
+}
+
#ifdef CONFIG_KVM
static int cpu_x86_fill_model_id(char *str)
{
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 3e2e9f6..058c57f 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -1255,6 +1255,10 @@ void cpu_report_tpr_access(CPUX86State *env, TPRAccess access);
void disable_kvm_pv_eoi(void);
+void x86_cpu_compat_set_features(const char *cpu_model, FeatureWord w,
+ uint32_t feat_add, uint32_t feat_remove);
+
+
/* Return name of 32-bit register, from a R_* constant */
const char *get_register_name_32(unsigned int reg);
commit b2a856d99281f2fee60a4313d204205bcd2c4269
Author: Andreas Färber <afaerber at suse.de>
Date: Wed May 1 17:30:51 2013 +0200
target-i386: Change CPUID model of 486 to 8
This changes the model number of 486 to 8 (DX4) which matches the
feature set presented, and actually has the CPUID instruction.
This adds a compatibility property, to keep model=0 on pc-*-1.4 and older.
Signed-off-by: H. Peter Anvin <hpa at zytor.com>
[AF: Add compat_props entry]
Tested-by: Eduardo Habkost <ehabkost at redhat.com>
Reviewed-by: Eduardo Habkost <ehabkost at redhat.com>
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 41869e5..417afe4 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -242,6 +242,10 @@ int e820_add_entry(uint64_t, uint64_t, uint32_t);
.driver = "pc-sysfw",\
.property = "rom_only",\
.value = stringify(0),\
+ },{\
+ .driver = "486-" TYPE_X86_CPU,\
+ .property = "model",\
+ .value = stringify(0),\
}
#endif
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index b438478..8e21c94 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -588,7 +588,7 @@ static x86_def_t builtin_x86_defs[] = {
.level = 1,
.vendor = CPUID_VENDOR_INTEL,
.family = 4,
- .model = 0,
+ .model = 8,
.stepping = 0,
.features[FEAT_1_EDX] =
I486_FEATURES,
commit ba2bc7a42e7c7b343f996967484ce3a1543cfebc
Author: Andreas Färber <afaerber at suse.de>
Date: Wed May 1 17:05:47 2013 +0200
target-i386: Emulate X86CPU subclasses for global properties
After initializing the object from its x86_def_t and before setting any
additional -cpu arguments, set any global properties for the designated
subclass <name>-{i386,x86_64}-cpu.
Reviewed-by: Eduardo Habkost <ehabkost at redhat.com>
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index eb1825b..b438478 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -1751,6 +1751,7 @@ X86CPU *cpu_x86_create(const char *cpu_model, DeviceState *icc_bridge,
CPUX86State *env;
gchar **model_pieces;
char *name, *features;
+ char *typename;
Error *error = NULL;
model_pieces = g_strsplit(cpu_model, ",", 2);
@@ -1778,6 +1779,14 @@ X86CPU *cpu_x86_create(const char *cpu_model, DeviceState *icc_bridge,
goto out;
}
+ /* Emulate per-model subclasses for global properties */
+ typename = g_strdup_printf("%s-" TYPE_X86_CPU, name);
+ qdev_prop_set_globals_for_type(DEVICE(cpu), typename, &error);
+ g_free(typename);
+ if (error) {
+ goto out;
+ }
+
cpu_x86_parse_featurestr(cpu, features, &error);
if (error) {
goto out;
commit 868d378bb087c6003bfa0e431aec0e5871a90ff4
Author: Andreas Färber <afaerber at suse.de>
Date: Wed May 1 16:03:19 2013 +0200
qdev: Introduce qdev_prop_set_globals_for_type()
Reuse it in qdev_prop_set_globals().
Reviewed-by: Eduardo Habkost <ehabkost at redhat.com>
[AF: Renamed from qdev_prop_set_custom_globals()]
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index 716ba19..3a324fb 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -1099,23 +1099,37 @@ void qdev_prop_register_global_list(GlobalProperty *props)
}
}
+void qdev_prop_set_globals_for_type(DeviceState *dev, const char *typename,
+ Error **errp)
+{
+ GlobalProperty *prop;
+
+ QTAILQ_FOREACH(prop, &global_props, next) {
+ Error *err = NULL;
+
+ if (strcmp(typename, prop->driver) != 0) {
+ continue;
+ }
+ qdev_prop_parse(dev, prop->property, prop->value, &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+ }
+}
+
void qdev_prop_set_globals(DeviceState *dev, Error **errp)
{
ObjectClass *class = object_get_class(OBJECT(dev));
do {
- GlobalProperty *prop;
- QTAILQ_FOREACH(prop, &global_props, next) {
- Error *err = NULL;
+ Error *err = NULL;
- if (strcmp(object_class_get_name(class), prop->driver) != 0) {
- continue;
- }
- qdev_prop_parse(dev, prop->property, prop->value, &err);
- if (err != NULL) {
- error_propagate(errp, err);
- return;
- }
+ qdev_prop_set_globals_for_type(dev, object_class_get_name(class),
+ &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
}
class = object_class_get_parent(class);
} while (class);
diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
index 38469d4..39448b7 100644
--- a/include/hw/qdev-properties.h
+++ b/include/hw/qdev-properties.h
@@ -169,6 +169,8 @@ void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value);
void qdev_prop_register_global(GlobalProperty *prop);
void qdev_prop_register_global_list(GlobalProperty *props);
void qdev_prop_set_globals(DeviceState *dev, Error **errp);
+void qdev_prop_set_globals_for_type(DeviceState *dev, const char *typename,
+ Error **errp);
void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
Property *prop, const char *value);
commit b1fe9bcbceb6fb9d800f735da37aa79ac4552c6e
Author: Andreas Färber <afaerber at suse.de>
Date: Wed May 1 16:10:24 2013 +0200
qdev: Let qdev_prop_parse() pass through Error
Move error reporting to callers.
Reviewed-by: Eduardo Habkost <ehabkost at redhat.com>
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index ca1739e..716ba19 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -986,25 +986,18 @@ void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
}
}
-int qdev_prop_parse(DeviceState *dev, const char *name, const char *value)
+void qdev_prop_parse(DeviceState *dev, const char *name, const char *value,
+ Error **errp)
{
char *legacy_name;
- Error *err = NULL;
legacy_name = g_strdup_printf("legacy-%s", name);
if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) {
- object_property_parse(OBJECT(dev), value, legacy_name, &err);
+ object_property_parse(OBJECT(dev), value, legacy_name, errp);
} else {
- object_property_parse(OBJECT(dev), value, name, &err);
+ object_property_parse(OBJECT(dev), value, name, errp);
}
g_free(legacy_name);
-
- if (err) {
- qerror_report_err(err);
- error_free(err);
- return -1;
- }
- return 0;
}
void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value)
@@ -1106,18 +1099,22 @@ void qdev_prop_register_global_list(GlobalProperty *props)
}
}
-void qdev_prop_set_globals(DeviceState *dev)
+void qdev_prop_set_globals(DeviceState *dev, Error **errp)
{
ObjectClass *class = object_get_class(OBJECT(dev));
do {
GlobalProperty *prop;
QTAILQ_FOREACH(prop, &global_props, next) {
+ Error *err = NULL;
+
if (strcmp(object_class_get_name(class), prop->driver) != 0) {
continue;
}
- if (qdev_prop_parse(dev, prop->property, prop->value) != 0) {
- exit(1);
+ qdev_prop_parse(dev, prop->property, prop->value, &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
}
}
class = object_class_get_parent(class);
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index 069ac90..6985ad8 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -752,7 +752,12 @@ static void device_initfn(Object *obj)
}
class = object_class_get_parent(class);
} while (class != object_class_by_name(TYPE_DEVICE));
- qdev_prop_set_globals(dev);
+ qdev_prop_set_globals(dev, &err);
+ if (err != NULL) {
+ qerror_report_err(err);
+ error_free(err);
+ exit(1);
+ }
object_property_add_link(OBJECT(dev), "parent_bus", TYPE_BUS,
(Object **)&dev->parent_bus, &err);
diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
index 25dd1bb..38469d4 100644
--- a/include/hw/qdev-properties.h
+++ b/include/hw/qdev-properties.h
@@ -148,7 +148,8 @@ extern PropertyInfo qdev_prop_arraylen;
/* Set properties between creation and init. */
void *qdev_get_prop_ptr(DeviceState *dev, Property *prop);
-int qdev_prop_parse(DeviceState *dev, const char *name, const char *value);
+void qdev_prop_parse(DeviceState *dev, const char *name, const char *value,
+ Error **errp);
void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value);
void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value);
void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value);
@@ -167,7 +168,7 @@ void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value);
void qdev_prop_register_global(GlobalProperty *prop);
void qdev_prop_register_global_list(GlobalProperty *props);
-void qdev_prop_set_globals(DeviceState *dev);
+void qdev_prop_set_globals(DeviceState *dev, Error **errp);
void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
Property *prop, const char *value);
diff --git a/qdev-monitor.c b/qdev-monitor.c
index 2cb5600..e54dbc2 100644
--- a/qdev-monitor.c
+++ b/qdev-monitor.c
@@ -105,13 +105,17 @@ static void qdev_print_devinfo(ObjectClass *klass, void *opaque)
static int set_property(const char *name, const char *value, void *opaque)
{
DeviceState *dev = opaque;
+ Error *err = NULL;
if (strcmp(name, "driver") == 0)
return 0;
if (strcmp(name, "bus") == 0)
return 0;
- if (qdev_prop_parse(dev, name, value) == -1) {
+ qdev_prop_parse(dev, name, value, &err);
+ if (err != NULL) {
+ qerror_report_err(err);
+ error_free(err);
return -1;
}
return 0;
commit 7e5292b553c9ec27e0816abdcb717f87aa6b6a8d
Author: Eduardo Habkost <ehabkost at redhat.com>
Date: Mon May 6 13:20:09 2013 -0300
target-i386: Add "filtered-features" property to X86CPU
This property will contain all the features that were removed from the
CPU because they are not supported by the host.
This way, libvirt or other management tools can emulate the
check/enforce behavior by checking if filtered-properties is all zeroes,
before starting the guest.
Example output where some features were missing:
$ qemu-system-x86_64 -enable-kvm -cpu Haswell,check -S \
-qmp unix:/tmp/m,server,nowait
warning: host doesn't support requested feature: CPUID.01H:ECX.fma [bit 12]
warning: host doesn't support requested feature: CPUID.01H:ECX.movbe [bit 22]
warning: host doesn't support requested feature: CPUID.01H:ECX.tsc-deadline [bit 24]
warning: host doesn't support requested feature: CPUID.01H:ECX.xsave [bit 26]
warning: host doesn't support requested feature: CPUID.01H:ECX.avx [bit 28]
warning: host doesn't support requested feature: CPUID.07H:EBX.fsgsbase [bit 0]
warning: host doesn't support requested feature: CPUID.07H:EBX.bmi1 [bit 3]
warning: host doesn't support requested feature: CPUID.07H:EBX.hle [bit 4]
warning: host doesn't support requested feature: CPUID.07H:EBX.avx2 [bit 5]
warning: host doesn't support requested feature: CPUID.07H:EBX.smep [bit 7]
warning: host doesn't support requested feature: CPUID.07H:EBX.bmi2 [bit 8]
warning: host doesn't support requested feature: CPUID.07H:EBX.erms [bit 9]
warning: host doesn't support requested feature: CPUID.07H:EBX.invpcid [bit 10]
warning: host doesn't support requested feature: CPUID.07H:EBX.rtm [bit 11]
[...]
$ ./QMP/qmp --path=/tmp/m \
qom-get --path=/machine/icc-bridge/icc/child[0] \
--property=filtered-features
item[0].cpuid-register: EDX
item[0].cpuid-input-eax: 2147483658
item[0].features: 0
item[1].cpuid-register: EAX
item[1].cpuid-input-eax: 1073741825
item[1].features: 0
item[2].cpuid-register: EDX
item[2].cpuid-input-eax: 3221225473
item[2].features: 0
item[3].cpuid-register: ECX
item[3].cpuid-input-eax: 2147483649
item[3].features: 0
item[4].cpuid-register: EDX
item[4].cpuid-input-eax: 2147483649
item[4].features: 0
item[5].cpuid-register: EBX
item[5].cpuid-input-eax: 7
item[5].features: 4025
item[5].cpuid-input-ecx: 0
item[6].cpuid-register: ECX
item[6].cpuid-input-eax: 1
item[6].features: 356519936
item[7].cpuid-register: EDX
item[7].cpuid-input-eax: 1
item[7].features: 0
Example output when no feature is missing:
$ qemu-system-x86_64 -enable-kvm -cpu Nehalem,enforce -S \
-qmp unix:/tmp/m,server,nowait
[...]
$ ./QMP/qmp --path=/tmp/m \
qom-get --path=/machine/icc-bridge/icc/child[0] \
--property=filtered-features
item[0].cpuid-register: EDX
item[0].cpuid-input-eax: 2147483658
item[0].features: 0
item[1].cpuid-register: EAX
item[1].cpuid-input-eax: 1073741825
item[1].features: 0
item[2].cpuid-register: EDX
item[2].cpuid-input-eax: 3221225473
item[2].features: 0
item[3].cpuid-register: ECX
item[3].cpuid-input-eax: 2147483649
item[3].features: 0
item[4].cpuid-register: EDX
item[4].cpuid-input-eax: 2147483649
item[4].features: 0
item[5].cpuid-register: EBX
item[5].cpuid-input-eax: 7
item[5].features: 0
item[5].cpuid-input-ecx: 0
item[6].cpuid-register: ECX
item[6].cpuid-input-eax: 1
item[6].features: 0
item[7].cpuid-register: EDX
item[7].cpuid-input-eax: 1
item[7].features: 0
Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
Reviewed-by: Eric Blake <eblake at redhat.com>
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 38793bc..eb1825b 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -1418,11 +1418,11 @@ static void x86_cpuid_set_apic_id(Object *obj, Visitor *v, void *opaque,
cpu->env.cpuid_apic_id = value;
}
+/* Generic getter for "feature-words" and "filtered-features" properties */
static void x86_cpu_get_feature_words(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
- X86CPU *cpu = X86_CPU(obj);
- CPUX86State *env = &cpu->env;
+ uint32_t *array = (uint32_t *)opaque;
FeatureWord w;
Error *err = NULL;
X86CPUFeatureWordInfo word_infos[FEATURE_WORDS] = { };
@@ -1436,7 +1436,7 @@ static void x86_cpu_get_feature_words(Object *obj, Visitor *v, void *opaque,
qwi->has_cpuid_input_ecx = wi->cpuid_needs_ecx;
qwi->cpuid_input_ecx = wi->cpuid_ecx;
qwi->cpuid_register = x86_reg_info_32[wi->cpuid_reg].qapi_enum;
- qwi->features = env->features[w];
+ qwi->features = array[w];
/* List will be in reverse order, but order shouldn't matter */
list_entries[w].next = list;
@@ -2444,7 +2444,10 @@ static void x86_cpu_initfn(Object *obj)
x86_cpuid_set_apic_id, NULL, NULL, NULL);
object_property_add(obj, "feature-words", "X86CPUFeatureWordInfo",
x86_cpu_get_feature_words,
- NULL, NULL, NULL, NULL);
+ NULL, NULL, (void *)env->features, NULL);
+ object_property_add(obj, "filtered-features", "X86CPUFeatureWordInfo",
+ x86_cpu_get_feature_words,
+ NULL, NULL, (void *)cpu->filtered_features, NULL);
env->cpuid_apic_id = x86_cpu_apic_id_from_index(cs->cpu_index);
commit 034acf4a581b03fc10cba772f731ae521e00fcd8
Author: Eduardo Habkost <ehabkost at redhat.com>
Date: Mon May 6 13:20:08 2013 -0300
target-i386: Introduce X86CPU::filtered_features field
This field will contain the feature bits that were filtered out because
of missing host support.
Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
Reviewed-by: Eric Blake <eblake at redhat.com>
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h
index f890f1c..849cedf 100644
--- a/target-i386/cpu-qom.h
+++ b/target-i386/cpu-qom.h
@@ -65,6 +65,9 @@ typedef struct X86CPU {
/*< public >*/
CPUX86State env;
+
+ /* Features that were filtered out because of missing host capabilities */
+ uint32_t filtered_features[FEATURE_WORDS];
} X86CPU;
static inline X86CPU *x86_env_get_cpu(CPUX86State *env)
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 3857514..38793bc 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -1698,9 +1698,12 @@ static void filter_features_for_kvm(X86CPU *cpu)
for (w = 0; w < FEATURE_WORDS; w++) {
FeatureWordInfo *wi = &feature_word_info[w];
- env->features[w] &= kvm_arch_get_supported_cpuid(s, wi->cpuid_eax,
- wi->cpuid_ecx,
- wi->cpuid_reg);
+ uint32_t host_feat = kvm_arch_get_supported_cpuid(s, wi->cpuid_eax,
+ wi->cpuid_ecx,
+ wi->cpuid_reg);
+ uint32_t requested_features = env->features[w];
+ env->features[w] &= host_feat;
+ cpu->filtered_features[w] = requested_features & ~env->features[w];
}
}
#endif
commit 8e8aba5054c043027445c880fcb9dbc8f6a217f3
Author: Eduardo Habkost <ehabkost at redhat.com>
Date: Mon May 6 13:20:07 2013 -0300
target-i386: Add "feature-words" property to X86CPU
This property will be useful for libvirt, as libvirt already has logic
based on low-level feature bits (not feature names), so it will be
really easy to convert the current libvirt logic to something using the
"feature-words" property.
The property will have two main use cases:
- Checking host capabilities, by checking the features of the "host"
CPU model
- Checking which features are enabled on each CPU model
Example output:
$ ./QMP/qmp --path=/tmp/m \
qom-get --path=/machine/icc-bridge/icc/child[0] \
--property=feature-words
item[0].cpuid-register: EDX
item[0].cpuid-input-eax: 2147483658
item[0].features: 0
item[1].cpuid-register: EAX
item[1].cpuid-input-eax: 1073741825
item[1].features: 0
item[2].cpuid-register: EDX
item[2].cpuid-input-eax: 3221225473
item[2].features: 0
item[3].cpuid-register: ECX
item[3].cpuid-input-eax: 2147483649
item[3].features: 101
item[4].cpuid-register: EDX
item[4].cpuid-input-eax: 2147483649
item[4].features: 563346425
item[5].cpuid-register: EBX
item[5].cpuid-input-eax: 7
item[5].features: 0
item[5].cpuid-input-ecx: 0
item[6].cpuid-register: ECX
item[6].cpuid-input-eax: 1
item[6].features: 2155880449
item[7].cpuid-register: EDX
item[7].cpuid-input-eax: 1
item[7].features: 126614521
Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
Reviewed-by: Eric Blake <eblake at redhat.com>
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/Makefile.objs b/Makefile.objs
index fcb303a..286ce06 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -79,10 +79,15 @@ common-obj-$(CONFIG_SMARTCARD_NSS) += $(libcacard-y)
######################################################################
# qapi
-common-obj-y += qmp-marshal.o qapi-visit.o qapi-types.o
+common-obj-y += qmp-marshal.o
common-obj-y += qmp.o hmp.o
endif
+######################################################################
+# some qapi visitors are used by both system and user emulation:
+
+common-obj-y += qapi-visit.o qapi-types.o
+
#######################################################################
# Target-independent parts used in system and user emulation
common-obj-y += qemu-log.o
diff --git a/qapi-schema.json b/qapi-schema.json
index 7797400..199744a 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3587,3 +3587,35 @@
##
{'command': 'query-command-line-options', 'data': { '*option': 'str' },
'returns': ['CommandLineOptionInfo'] }
+
+##
+# @X86CPURegister32
+#
+# A X86 32-bit register
+#
+# Since: 1.5
+##
+{ 'enum': 'X86CPURegister32',
+ 'data': [ 'EAX', 'EBX', 'ECX', 'EDX', 'ESP', 'EBP', 'ESI', 'EDI' ] }
+
+##
+# @X86CPUFeatureWordInfo
+#
+# Information about a X86 CPU feature word
+#
+# @cpuid-input-eax: Input EAX value for CPUID instruction for that feature word
+#
+# @cpuid-input-ecx: #optional Input ECX value for CPUID instruction for that
+# feature word
+#
+# @cpuid-register: Output register containing the feature bits
+#
+# @features: value of output register, containing the feature bits
+#
+# Since: 1.5
+##
+{ 'type': 'X86CPUFeatureWordInfo',
+ 'data': { 'cpuid-input-eax': 'int',
+ '*cpuid-input-ecx': 'int',
+ 'cpuid-register': 'X86CPURegister32',
+ 'features': 'int' } }
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index a39b364..3857514 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -30,6 +30,8 @@
#include "qemu/config-file.h"
#include "qapi/qmp/qerror.h"
+#include "qapi-types.h"
+#include "qapi-visit.h"
#include "qapi/visitor.h"
#include "sysemu/arch_init.h"
@@ -195,23 +197,34 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
},
};
+typedef struct X86RegisterInfo32 {
+ /* Name of register */
+ const char *name;
+ /* QAPI enum value register */
+ X86CPURegister32 qapi_enum;
+} X86RegisterInfo32;
+
+#define REGISTER(reg) \
+ [R_##reg] = { .name = #reg, .qapi_enum = X86_C_P_U_REGISTER32_##reg }
+X86RegisterInfo32 x86_reg_info_32[CPU_NB_REGS32] = {
+ REGISTER(EAX),
+ REGISTER(ECX),
+ REGISTER(EDX),
+ REGISTER(EBX),
+ REGISTER(ESP),
+ REGISTER(EBP),
+ REGISTER(ESI),
+ REGISTER(EDI),
+};
+#undef REGISTER
+
+
const char *get_register_name_32(unsigned int reg)
{
- static const char *reg_names[CPU_NB_REGS32] = {
- [R_EAX] = "EAX",
- [R_ECX] = "ECX",
- [R_EDX] = "EDX",
- [R_EBX] = "EBX",
- [R_ESP] = "ESP",
- [R_EBP] = "EBP",
- [R_ESI] = "ESI",
- [R_EDI] = "EDI",
- };
-
if (reg > CPU_NB_REGS32) {
return NULL;
}
- return reg_names[reg];
+ return x86_reg_info_32[reg].name;
}
/* collects per-function cpuid data
@@ -1405,6 +1418,36 @@ static void x86_cpuid_set_apic_id(Object *obj, Visitor *v, void *opaque,
cpu->env.cpuid_apic_id = value;
}
+static void x86_cpu_get_feature_words(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ X86CPU *cpu = X86_CPU(obj);
+ CPUX86State *env = &cpu->env;
+ FeatureWord w;
+ Error *err = NULL;
+ X86CPUFeatureWordInfo word_infos[FEATURE_WORDS] = { };
+ X86CPUFeatureWordInfoList list_entries[FEATURE_WORDS] = { };
+ X86CPUFeatureWordInfoList *list = NULL;
+
+ for (w = 0; w < FEATURE_WORDS; w++) {
+ FeatureWordInfo *wi = &feature_word_info[w];
+ X86CPUFeatureWordInfo *qwi = &word_infos[w];
+ qwi->cpuid_input_eax = wi->cpuid_eax;
+ qwi->has_cpuid_input_ecx = wi->cpuid_needs_ecx;
+ qwi->cpuid_input_ecx = wi->cpuid_ecx;
+ qwi->cpuid_register = x86_reg_info_32[wi->cpuid_reg].qapi_enum;
+ qwi->features = env->features[w];
+
+ /* List will be in reverse order, but order shouldn't matter */
+ list_entries[w].next = list;
+ list_entries[w].value = &word_infos[w];
+ list = &list_entries[w];
+ }
+
+ visit_type_X86CPUFeatureWordInfoList(v, &list, "feature-words", &err);
+ error_propagate(errp, err);
+}
+
static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *name)
{
x86_def_t *def;
@@ -2396,6 +2439,9 @@ static void x86_cpu_initfn(Object *obj)
object_property_add(obj, "apic-id", "int",
x86_cpuid_get_apic_id,
x86_cpuid_set_apic_id, NULL, NULL, NULL);
+ object_property_add(obj, "feature-words", "X86CPUFeatureWordInfo",
+ x86_cpu_get_feature_words,
+ NULL, NULL, NULL, NULL);
env->cpuid_apic_id = x86_cpu_apic_id_from_index(cs->cpu_index);
commit bd87d2a2c05569a28768648b069cbc24c40f4fb8
Author: Eduardo Habkost <ehabkost at redhat.com>
Date: Mon Apr 22 16:00:18 2013 -0300
target-i386: Use FeatureWord loop on filter_features_for_kvm()
Instead of open-coding the filtering code for each feature word, change
the existing code to use the feature_word_info array, that has exactly
the same CPUID eax/ecx/register values for each feature word.
Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
Reviewed-by: Eric Blake <eblake at redhat.com>
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 0f92469..a39b364 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -1651,24 +1651,14 @@ static void filter_features_for_kvm(X86CPU *cpu)
{
CPUX86State *env = &cpu->env;
KVMState *s = kvm_state;
+ FeatureWord w;
- env->features[FEAT_1_EDX] &=
- kvm_arch_get_supported_cpuid(s, 1, 0, R_EDX);
- env->features[FEAT_1_ECX] &=
- kvm_arch_get_supported_cpuid(s, 1, 0, R_ECX);
- env->features[FEAT_8000_0001_EDX] &=
- kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_EDX);
- env->features[FEAT_8000_0001_ECX] &=
- kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_ECX);
- env->features[FEAT_SVM] &=
- kvm_arch_get_supported_cpuid(s, 0x8000000A, 0, R_EDX);
- env->features[FEAT_7_0_EBX] &=
- kvm_arch_get_supported_cpuid(s, 7, 0, R_EBX);
- env->features[FEAT_KVM] &=
- kvm_arch_get_supported_cpuid(s, KVM_CPUID_FEATURES, 0, R_EAX);
- env->features[FEAT_C000_0001_EDX] &=
- kvm_arch_get_supported_cpuid(s, 0xC0000001, 0, R_EDX);
-
+ for (w = 0; w < FEATURE_WORDS; w++) {
+ FeatureWordInfo *wi = &feature_word_info[w];
+ env->features[w] &= kvm_arch_get_supported_cpuid(s, wi->cpuid_eax,
+ wi->cpuid_ecx,
+ wi->cpuid_reg);
+ }
}
#endif
commit 04d104b61198615c259d1851684b2713213dcf99
Author: Eduardo Habkost <ehabkost at redhat.com>
Date: Mon Apr 22 16:00:16 2013 -0300
target-i386: Add ECX information to FeatureWordInfo
FEAT_7_0_EBX uses ECX as input, so we have to take that into account
when reporting feature word values.
Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 9f2adad..0f92469 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -152,8 +152,10 @@ static const char *cpuid_7_0_ebx_feature_name[] = {
typedef struct FeatureWordInfo {
const char **feat_names;
- uint32_t cpuid_eax; /* Input EAX for CPUID */
- int cpuid_reg; /* R_* register constant */
+ uint32_t cpuid_eax; /* Input EAX for CPUID */
+ bool cpuid_needs_ecx; /* CPUID instruction uses ECX as input */
+ uint32_t cpuid_ecx; /* Input ECX value for CPUID */
+ int cpuid_reg; /* output register (R_* constant) */
} FeatureWordInfo;
static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
@@ -187,7 +189,9 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
},
[FEAT_7_0_EBX] = {
.feat_names = cpuid_7_0_ebx_feature_name,
- .cpuid_eax = 7, .cpuid_reg = R_EBX,
+ .cpuid_eax = 7,
+ .cpuid_needs_ecx = true, .cpuid_ecx = 0,
+ .cpuid_reg = R_EBX,
},
};
More information about the Spice-commits
mailing list