aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch_init.c13
-rw-r--r--backends/Makefile.objs2
-rw-r--r--backends/rng-egd.c6
-rw-r--r--backends/tpm.c154
-rw-r--r--block.c49
-rw-r--r--block/nbd.c2
-rw-r--r--block/qcow2-refcount.c25
-rw-r--r--block/sheepdog.c2
-rw-r--r--blockdev.c1
-rwxr-xr-xconfigure2
-rw-r--r--docs/usb2.txt20
-rw-r--r--gdbstub.c1
-rw-r--r--hw/acpi.c359
-rw-r--r--hw/acpi.h2
-rw-r--r--hw/acpi_ich9.c2
-rw-r--r--hw/acpi_piix4.c2
-rw-r--r--hw/apic_common.c2
-rw-r--r--hw/arm/nseries.c18
-rw-r--r--hw/arm/pxa2xx.c4
-rw-r--r--hw/arm/xilinx_zynq.c3
-rw-r--r--hw/arm_gic_common.c112
-rw-r--r--hw/arm_gic_internal.h42
-rw-r--r--hw/arm_mptimer.c5
-rw-r--r--hw/armv7m_nvic.c4
-rw-r--r--hw/bt-hci-csr.c1
-rw-r--r--hw/cadence_uart.c1
-rw-r--r--hw/i386/kvmvapic.c2
-rw-r--r--hw/i386/pc.c32
-rw-r--r--hw/ipoctal232.c42
-rw-r--r--hw/ivshmem.c1
-rw-r--r--hw/mcf_uart.c1
-rw-r--r--hw/microblaze/petalogix_ml605_mmu.c3
-rw-r--r--hw/nand.c1
-rw-r--r--hw/onenand.c3
-rw-r--r--hw/pc.h4
-rw-r--r--hw/pci/pci-hotplug.c2
-rw-r--r--hw/pflash_cfi01.c30
-rw-r--r--hw/pl050.c5
-rw-r--r--hw/pl330.c3
-rw-r--r--hw/qdev-properties-system.c5
-rw-r--r--hw/qdev.c23
-rw-r--r--hw/scsi-bus.c8
-rw-r--r--hw/scsi.h3
-rw-r--r--hw/sd.c2
-rw-r--r--hw/sh_serial.c4
-rw-r--r--hw/usb.h1
-rw-r--r--hw/usb/bus.c2
-rw-r--r--hw/usb/dev-hid.c2
-rw-r--r--hw/usb/dev-hub.c12
-rw-r--r--hw/usb/dev-storage.c2
-rw-r--r--hw/usb/hcd-xhci.c28
-rw-r--r--hw/usb/redirect.c37
-rw-r--r--hw/vfio_pci.c1174
-rw-r--r--hw/vmxnet3.c2
-rw-r--r--hw/vt82c686.c2
-rw-r--r--hw/xen_backend.c15
-rw-r--r--hw/xen_backend.h2
-rw-r--r--hw/xen_console.c18
-rw-r--r--hw/xen_disk.c76
-rw-r--r--hw/xilinx_axienet.c2
-rw-r--r--include/backends/tpm.h170
-rw-r--r--include/block/block_int.h3
-rw-r--r--include/char/char.h29
-rw-r--r--include/migration/vmstate.h36
-rw-r--r--include/qapi/qmp/qstring.h1
-rw-r--r--include/qemu/sockets.h4
-rw-r--r--include/qemu/timer.h3
-rw-r--r--include/sysemu/arch_init.h3
-rw-r--r--include/tpm/tpm.h4
-rw-r--r--linux-headers/linux/vfio.h9
-rw-r--r--linux-user/strace.c2
-rw-r--r--main-loop.c25
-rw-r--r--migration.c2
-rw-r--r--monitor.c60
-rw-r--r--nbd.c8
-rw-r--r--net/slirp.c1
-rw-r--r--net/socket.c13
-rw-r--r--po/Makefile16
-rw-r--r--po/de_DE.po41
-rw-r--r--po/fr_FR.po62
-rw-r--r--po/it.po41
-rw-r--r--po/messages.po36
-rw-r--r--qapi-schema.json60
-rw-r--r--qemu-char.c206
-rw-r--r--qemu-options.hx3
-rw-r--r--qobject/qstring.c8
-rw-r--r--savevm.c2
-rw-r--r--slirp/misc.c2
-rw-r--r--slirp/tcp_subr.c4
-rw-r--r--target-i386/cpu.c10
-rw-r--r--target-i386/cpu.h4
-rw-r--r--target-s390x/translate.c1
-rw-r--r--tests/test-visitor-serialization.c12
-rw-r--r--tpm/tpm.c11
-rw-r--r--tpm/tpm_int.h25
-rw-r--r--tpm/tpm_passthrough.c94
-rw-r--r--tpm/tpm_tis.c21
-rw-r--r--tpm/tpm_tis.h4
-rw-r--r--trace-events1
-rw-r--r--ui/gtk.c17
-rw-r--r--ui/vnc.c2
-rw-r--r--util/oslib-posix.c4
-rw-r--r--util/oslib-win32.c4
-rw-r--r--util/qemu-sockets.c5
-rw-r--r--util/qemu-timer-common.c4
-rw-r--r--vl.c19
-rw-r--r--xen-mapcache.c58
107 files changed, 2694 insertions, 839 deletions
diff --git a/arch_init.c b/arch_init.c
index 4ef5a15a6e..c2cbc71c31 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -142,7 +142,7 @@ int qemu_read_default_config_files(bool userconfig)
return ret;
}
}
-
+
return 0;
}
@@ -1103,11 +1103,16 @@ int qemu_uuid_parse(const char *str, uint8_t *uuid)
return 0;
}
-void do_acpitable_option(const char *optarg)
+void do_acpitable_option(const QemuOpts *opts)
{
#ifdef TARGET_I386
- if (acpi_table_add(optarg) < 0) {
- fprintf(stderr, "Wrong acpi table provided\n");
+ Error *err = NULL;
+
+ acpi_table_add(opts, &err);
+ if (err) {
+ fprintf(stderr, "Wrong acpi table provided: %s\n",
+ error_get_pretty(err));
+ error_free(err);
exit(1);
}
#endif
diff --git a/backends/Makefile.objs b/backends/Makefile.objs
index 464bc3e220..42557d54ea 100644
--- a/backends/Makefile.objs
+++ b/backends/Makefile.objs
@@ -4,3 +4,5 @@ common-obj-$(CONFIG_POSIX) += rng-random.o
common-obj-y += msmouse.o
common-obj-$(CONFIG_BRLAPI) += baum.o
$(obj)/baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
+
+common-obj-$(CONFIG_TPM) += tpm.o
diff --git a/backends/rng-egd.c b/backends/rng-egd.c
index 5e012e9e30..cc6f5ee28e 100644
--- a/backends/rng-egd.c
+++ b/backends/rng-egd.c
@@ -149,6 +149,11 @@ static void rng_egd_opened(RngBackend *b, Error **errp)
return;
}
+ if (qemu_chr_fe_claim(s->chr) != 0) {
+ error_set(errp, QERR_DEVICE_IN_USE, s->chr_name);
+ return;
+ }
+
/* FIXME we should resubmit pending requests when the CDS reconnects. */
qemu_chr_add_handlers(s->chr, rng_egd_chr_can_read, rng_egd_chr_read,
NULL, s);
@@ -191,6 +196,7 @@ static void rng_egd_finalize(Object *obj)
if (s->chr) {
qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL);
+ qemu_chr_fe_release(s->chr);
}
g_free(s->chr_name);
diff --git a/backends/tpm.c b/backends/tpm.c
new file mode 100644
index 0000000000..28148c23cf
--- /dev/null
+++ b/backends/tpm.c
@@ -0,0 +1,154 @@
+/*
+ * QEMU TPM Backend
+ *
+ * Copyright IBM, Corp. 2013
+ *
+ * Authors:
+ * Stefan Berger <stefanb@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * Based on backends/rng.c by Anthony Liguori
+ */
+
+#include "backends/tpm.h"
+#include "tpm/tpm_int.h"
+#include "qapi/qmp/qerror.h"
+
+enum TpmType tpm_backend_get_type(TPMBackend *s)
+{
+ TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+ return k->ops->type;
+}
+
+const char *tpm_backend_get_desc(TPMBackend *s)
+{
+ TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+ return k->ops->desc();
+}
+
+void tpm_backend_destroy(TPMBackend *s)
+{
+ TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+ return k->ops->destroy(s);
+}
+
+int tpm_backend_init(TPMBackend *s, TPMState *state,
+ TPMRecvDataCB *datacb)
+{
+ TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+ return k->ops->init(s, state, datacb);
+}
+
+int tpm_backend_startup_tpm(TPMBackend *s)
+{
+ TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+ return k->ops->startup_tpm(s);
+}
+
+bool tpm_backend_had_startup_error(TPMBackend *s)
+{
+ TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+ return k->ops->had_startup_error(s);
+}
+
+size_t tpm_backend_realloc_buffer(TPMBackend *s, TPMSizedBuffer *sb)
+{
+ TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+ return k->ops->realloc_buffer(sb);
+}
+
+void tpm_backend_deliver_request(TPMBackend *s)
+{
+ TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+ k->ops->deliver_request(s);
+}
+
+void tpm_backend_reset(TPMBackend *s)
+{
+ TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+ k->ops->reset(s);
+}
+
+void tpm_backend_cancel_cmd(TPMBackend *s)
+{
+ TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+ k->ops->cancel_cmd(s);
+}
+
+bool tpm_backend_get_tpm_established_flag(TPMBackend *s)
+{
+ TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+ return k->ops->get_tpm_established_flag(s);
+}
+
+static bool tpm_backend_prop_get_opened(Object *obj, Error **errp)
+{
+ TPMBackend *s = TPM_BACKEND(obj);
+
+ return s->opened;
+}
+
+void tpm_backend_open(TPMBackend *s, Error **errp)
+{
+ object_property_set_bool(OBJECT(s), true, "opened", errp);
+}
+
+static void tpm_backend_prop_set_opened(Object *obj, bool value, Error **errp)
+{
+ TPMBackend *s = TPM_BACKEND(obj);
+ TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+ if (value == s->opened) {
+ return;
+ }
+
+ if (!value && s->opened) {
+ error_set(errp, QERR_PERMISSION_DENIED);
+ return;
+ }
+
+ if (k->opened) {
+ k->opened(s, errp);
+ }
+
+ if (!error_is_set(errp)) {
+ s->opened = value;
+ }
+}
+
+static void tpm_backend_instance_init(Object *obj)
+{
+ object_property_add_bool(obj, "opened",
+ tpm_backend_prop_get_opened,
+ tpm_backend_prop_set_opened,
+ NULL);
+}
+
+static const TypeInfo tpm_backend_info = {
+ .name = TYPE_TPM_BACKEND,
+ .parent = TYPE_OBJECT,
+ .instance_size = sizeof(TPMBackend),
+ .instance_init = tpm_backend_instance_init,
+ .class_size = sizeof(TPMBackendClass),
+ .abstract = true,
+};
+
+static void register_types(void)
+{
+ type_register_static(&tpm_backend_info);
+}
+
+type_init(register_types);
diff --git a/block.c b/block.c
index 0ae2e93982..602d8a443e 100644
--- a/block.c
+++ b/block.c
@@ -140,8 +140,6 @@ void bdrv_io_limits_disable(BlockDriverState *bs)
bs->slice_start = 0;
bs->slice_end = 0;
- bs->slice_time = 0;
- memset(&bs->io_base, 0, sizeof(bs->io_base));
}
static void bdrv_block_timer(void *opaque)
@@ -1433,11 +1431,10 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
bs_dest->enable_write_cache = bs_src->enable_write_cache;
/* i/o timing parameters */
- bs_dest->slice_time = bs_src->slice_time;
bs_dest->slice_start = bs_src->slice_start;
bs_dest->slice_end = bs_src->slice_end;
+ bs_dest->slice_submitted = bs_src->slice_submitted;
bs_dest->io_limits = bs_src->io_limits;
- bs_dest->io_base = bs_src->io_base;
bs_dest->throttled_reqs = bs_src->throttled_reqs;
bs_dest->block_timer = bs_src->block_timer;
bs_dest->io_limits_enabled = bs_src->io_limits_enabled;
@@ -3750,6 +3747,7 @@ static bool bdrv_exceed_bps_limits(BlockDriverState *bs, int nb_sectors,
bool is_write, double elapsed_time, uint64_t *wait)
{
uint64_t bps_limit = 0;
+ uint64_t extension;
double bytes_limit, bytes_base, bytes_res;
double slice_time, wait_time;
@@ -3768,9 +3766,9 @@ static bool bdrv_exceed_bps_limits(BlockDriverState *bs, int nb_sectors,
slice_time = bs->slice_end - bs->slice_start;
slice_time /= (NANOSECONDS_PER_SECOND);
bytes_limit = bps_limit * slice_time;
- bytes_base = bs->nr_bytes[is_write] - bs->io_base.bytes[is_write];
+ bytes_base = bs->slice_submitted.bytes[is_write];
if (bs->io_limits.bps[BLOCK_IO_LIMIT_TOTAL]) {
- bytes_base += bs->nr_bytes[!is_write] - bs->io_base.bytes[!is_write];
+ bytes_base += bs->slice_submitted.bytes[!is_write];
}
/* bytes_base: the bytes of data which have been read/written; and
@@ -3797,10 +3795,12 @@ static bool bdrv_exceed_bps_limits(BlockDriverState *bs, int nb_sectors,
* info can be kept until the timer fire, so it is increased and tuned
* based on the result of experiment.
*/
- bs->slice_time = wait_time * BLOCK_IO_SLICE_TIME * 10;
- bs->slice_end += bs->slice_time - 3 * BLOCK_IO_SLICE_TIME;
+ extension = wait_time * NANOSECONDS_PER_SECOND;
+ extension = DIV_ROUND_UP(extension, BLOCK_IO_SLICE_TIME) *
+ BLOCK_IO_SLICE_TIME;
+ bs->slice_end += extension;
if (wait) {
- *wait = wait_time * BLOCK_IO_SLICE_TIME * 10;
+ *wait = wait_time * NANOSECONDS_PER_SECOND;
}
return true;
@@ -3828,9 +3828,9 @@ static bool bdrv_exceed_iops_limits(BlockDriverState *bs, bool is_write,
slice_time = bs->slice_end - bs->slice_start;
slice_time /= (NANOSECONDS_PER_SECOND);
ios_limit = iops_limit * slice_time;
- ios_base = bs->nr_ops[is_write] - bs->io_base.ios[is_write];
+ ios_base = bs->slice_submitted.ios[is_write];
if (bs->io_limits.iops[BLOCK_IO_LIMIT_TOTAL]) {
- ios_base += bs->nr_ops[!is_write] - bs->io_base.ios[!is_write];
+ ios_base += bs->slice_submitted.ios[!is_write];
}
if (ios_base + 1 <= ios_limit) {
@@ -3841,7 +3841,7 @@ static bool bdrv_exceed_iops_limits(BlockDriverState *bs, bool is_write,
return false;
}
- /* Calc approx time to dispatch */
+ /* Calc approx time to dispatch, in seconds */
wait_time = (ios_base + 1) / iops_limit;
if (wait_time > elapsed_time) {
wait_time = wait_time - elapsed_time;
@@ -3849,10 +3849,10 @@ static bool bdrv_exceed_iops_limits(BlockDriverState *bs, bool is_write,
wait_time = 0;
}
- bs->slice_time = wait_time * BLOCK_IO_SLICE_TIME * 10;
- bs->slice_end += bs->slice_time - 3 * BLOCK_IO_SLICE_TIME;
+ /* Exceeded current slice, extend it by another slice time */
+ bs->slice_end += BLOCK_IO_SLICE_TIME;
if (wait) {
- *wait = wait_time * BLOCK_IO_SLICE_TIME * 10;
+ *wait = wait_time * NANOSECONDS_PER_SECOND;
}
return true;
@@ -3867,19 +3867,10 @@ static bool bdrv_exceed_io_limits(BlockDriverState *bs, int nb_sectors,
int bps_ret, iops_ret;
now = qemu_get_clock_ns(vm_clock);
- if ((bs->slice_start < now)
- && (bs->slice_end > now)) {
- bs->slice_end = now + bs->slice_time;
- } else {
- bs->slice_time = 5 * BLOCK_IO_SLICE_TIME;
+ if (now > bs->slice_end) {
bs->slice_start = now;
- bs->slice_end = now + bs->slice_time;
-
- bs->io_base.bytes[is_write] = bs->nr_bytes[is_write];
- bs->io_base.bytes[!is_write] = bs->nr_bytes[!is_write];
-
- bs->io_base.ios[is_write] = bs->nr_ops[is_write];
- bs->io_base.ios[!is_write] = bs->nr_ops[!is_write];
+ bs->slice_end = now + BLOCK_IO_SLICE_TIME;
+ memset(&bs->slice_submitted, 0, sizeof(bs->slice_submitted));
}
elapsed_time = now - bs->slice_start;
@@ -3907,6 +3898,10 @@ static bool bdrv_exceed_io_limits(BlockDriverState *bs, int nb_sectors,
*wait = 0;
}
+ bs->slice_submitted.bytes[is_write] += (int64_t)nb_sectors *
+ BDRV_SECTOR_SIZE;
+ bs->slice_submitted.ios[is_write]++;
+
return false;
}
diff --git a/block/nbd.c b/block/nbd.c
index 3d711b2735..eff683c8df 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -415,7 +415,7 @@ static int nbd_establish_connection(BlockDriverState *bs)
/* Now that we're connected, set the socket to be non-blocking and
* kick the reply mechanism. */
- socket_set_nonblock(sock);
+ qemu_set_nonblock(sock);
qemu_aio_set_fd_handler(sock, nbd_reply_ready, NULL,
nbd_have_request, s);
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index c38e970bf2..b32738f8d9 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -747,10 +747,9 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
if (l1_table_offset != s->l1_table_offset) {
l1_table = g_malloc0(align_offset(l1_size2, 512));
l1_allocated = 1;
- if (bdrv_pread(bs->file, l1_table_offset,
- l1_table, l1_size2) != l1_size2)
- {
- ret = -EIO;
+
+ ret = bdrv_pread(bs->file, l1_table_offset, l1_table, l1_size2);
+ if (ret < 0) {
goto fail;
}
@@ -802,7 +801,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
}
if (refcount < 0) {
- ret = -EIO;
+ ret = refcount;
goto fail;
}
}
@@ -833,7 +832,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
refcount = get_refcount(bs, l2_offset >> s->cluster_bits);
}
if (refcount < 0) {
- ret = -EIO;
+ ret = refcount;
goto fail;
} else if (refcount == 1) {
l2_offset |= QCOW_OFLAG_COPIED;
@@ -852,14 +851,16 @@ fail:
}
/* Update L1 only if it isn't deleted anyway (addend = -1) */
- if (addend >= 0 && l1_modified) {
- for(i = 0; i < l1_size; i++)
+ if (ret == 0 && addend >= 0 && l1_modified) {
+ for (i = 0; i < l1_size; i++) {
cpu_to_be64s(&l1_table[i]);
- if (bdrv_pwrite_sync(bs->file, l1_table_offset, l1_table,
- l1_size2) < 0)
- goto fail;
- for(i = 0; i < l1_size; i++)
+ }
+
+ ret = bdrv_pwrite_sync(bs->file, l1_table_offset, l1_table, l1_size2);
+
+ for (i = 0; i < l1_size; i++) {
be64_to_cpus(&l1_table[i]);
+ }
}
if (l1_allocated)
g_free(l1_table);
diff --git a/block/sheepdog.c b/block/sheepdog.c
index bb67c4c071..987018e20c 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -471,7 +471,7 @@ static int connect_to_sdog(BDRVSheepdogState *s)
qerror_report_err(err);
error_free(err);
} else {
- socket_set_nonblock(fd);
+ qemu_set_nonblock(fd);
}
return fd;
diff --git a/blockdev.c b/blockdev.c
index 8cdc9ce16a..6dc999d802 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1069,7 +1069,6 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
}
bs->io_limits = io_limits;
- bs->slice_time = BLOCK_IO_SLICE_TIME;
if (!bs->io_limits_enabled && bdrv_io_limits_enabled(bs)) {
bdrv_io_limits_enable(bs);
diff --git a/configure b/configure
index fbea75e877..d685275c61 100755
--- a/configure
+++ b/configure
@@ -3899,8 +3899,6 @@ else
echo "AUTOCONF_HOST := " >> $config_host_mak
fi
echo "LDFLAGS=$LDFLAGS" >> $config_host_mak
-echo "ARLIBS_BEGIN=$arlibs_begin" >> $config_host_mak
-echo "ARLIBS_END=$arlibs_end" >> $config_host_mak
echo "LIBS+=$LIBS" >> $config_host_mak
echo "LIBS_TOOLS+=$libs_tools" >> $config_host_mak
echo "EXESUF=$EXESUF" >> $config_host_mak
diff --git a/docs/usb2.txt b/docs/usb2.txt
index 43dacdec28..c7a445afcd 100644
--- a/docs/usb2.txt
+++ b/docs/usb2.txt
@@ -11,7 +11,7 @@ one USB 2.0 bus driven by the EHCI controller. Devices must be
attached to the correct controller manually.
The '-usb' switch will make qemu create the UHCI controller as part of
-the PIIX3 chipset. The USB 1.1 bus will carry the name "usb.0".
+the PIIX3 chipset. The USB 1.1 bus will carry the name "usb-bus.0".
You can use the standard -device switch to add a EHCI controller to
your virtual machine. It is strongly recommended to specify an ID for
@@ -27,7 +27,7 @@ a complete example:
-drive if=none,id=usbstick,file=/path/to/image \
-usb \
-device usb-ehci,id=ehci \
- -device usb-tablet,bus=usb.0 \
+ -device usb-tablet,bus=usb-bus.0 \
-device usb-storage,bus=ehci.0,drive=usbstick
This attaches a usb tablet to the UHCI adapter and a usb mass storage
@@ -88,22 +88,22 @@ ports (1-4), the emulated (1.1) USB hub has eight ports.
Plugging a tablet into UHCI port 1 works like this:
- -device usb-tablet,bus=usb.0,port=1
+ -device usb-tablet,bus=usb-bus.0,port=1
Plugging a hub into UHCI port 2 works like this:
- -device usb-hub,bus=usb.0,port=2
+ -device usb-hub,bus=usb-bus.0,port=2
Plugging a virtual usb stick into port 4 of the hub just plugged works
this way:
- -device usb-storage,bus=usb.0,port=2.4,drive=...
+ -device usb-storage,bus=usb-bus.0,port=2.4,drive=...
You can do basically the same in the monitor using the device_add
command. If you want to unplug devices too you should specify some
unique id which you can use to refer to the device ...
- (qemu) device_add usb-tablet,bus=usb.0,port=1,id=my-tablet
+ (qemu) device_add usb-tablet,bus=usb-bus.0,port=1,id=my-tablet
(qemu) device_del my-tablet
... when unplugging it with device_del.
@@ -148,10 +148,10 @@ using for testing is bus 1 + port 1 for 2.0 devices and bus 3 + port 1
for 1.1 devices. Passing through any device plugged into that port
and also assign them to the correct bus can be done this way:
- qemu -M pc ${otheroptions} \
- -usb \
- -device usb-ehci,id=ehci \
- -device usb-host,bus=usb.0,hostbus=3,hostport=1 \
+ qemu -M pc ${otheroptions} \
+ -usb \
+ -device usb-ehci,id=ehci \
+ -device usb-host,bus=usb-bus.0,hostbus=3,hostport=1 \
-device usb-host,bus=ehci.0,hostbus=1,hostport=1
enjoy,
diff --git a/gdbstub.c b/gdbstub.c
index a666cb5bb0..a0288a77fb 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -3025,6 +3025,7 @@ int gdbserver_start(const char *device)
if (!chr)
return -1;
+ qemu_chr_fe_claim_no_fail(chr);
qemu_chr_add_handlers(chr, gdb_chr_can_receive, gdb_chr_receive,
gdb_chr_event, NULL);
}
diff --git a/hw/acpi.c b/hw/acpi.c
index 53e47d5857..856da81f0c 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -23,10 +23,14 @@
#include "hw/pc.h"
#include "hw/acpi.h"
#include "monitor/monitor.h"
+#include "qemu/config-file.h"
+#include "qapi/opts-visitor.h"
+#include "qapi/dealloc-visitor.h"
+#include "qapi-visit.h"
struct acpi_table_header {
uint16_t _length; /* our length, not actual part of the hdr */
- /* XXX why we have 2 length fields here? */
+ /* allows easier parsing for fw_cfg clients */
char sig[4]; /* ACPI signature (4 ASCII characters) */
uint32_t length; /* Length of table, in bytes, including header */
uint8_t revision; /* ACPI Specification minor version # */
@@ -41,16 +45,29 @@ struct acpi_table_header {
#define ACPI_TABLE_HDR_SIZE sizeof(struct acpi_table_header)
#define ACPI_TABLE_PFX_SIZE sizeof(uint16_t) /* size of the extra prefix */
-static const char dfl_hdr[ACPI_TABLE_HDR_SIZE] =
- "\0\0" /* fake _length (2) */
+static const char unsigned dfl_hdr[ACPI_TABLE_HDR_SIZE - ACPI_TABLE_PFX_SIZE] =
"QEMU\0\0\0\0\1\0" /* sig (4), len(4), revno (1), csum (1) */
"QEMUQEQEMUQEMU\1\0\0\0" /* OEM id (6), table (8), revno (4) */
"QEMU\1\0\0\0" /* ASL compiler ID (4), version (4) */
;
-char *acpi_tables;
+char unsigned *acpi_tables;
size_t acpi_tables_len;
+static QemuOptsList qemu_acpi_opts = {
+ .name = "acpi",
+ .implied_opt_name = "data",
+ .head = QTAILQ_HEAD_INITIALIZER(qemu_acpi_opts.head),
+ .desc = { { 0 } } /* validated with OptsVisitor */
+};
+
+static void acpi_register_config(void)
+{
+ qemu_add_opts(&qemu_acpi_opts);
+}
+
+machine_init(acpi_register_config);
+
static int acpi_checksum(const uint8_t *data, int len)
{
int sum, i;
@@ -61,184 +78,235 @@ static int acpi_checksum(const uint8_t *data, int len)
return (-sum) & 0xff;
}
-/* XXX fixme: this function uses obsolete argument parsing interface */
-int acpi_table_add(const char *t)
-{
- char buf[1024], *p, *f;
- unsigned long val;
- size_t len, start, allen;
- bool has_header;
- int changed;
- int r;
- struct acpi_table_header hdr;
-
- r = 0;
- r |= get_param_value(buf, sizeof(buf), "data", t) ? 1 : 0;
- r |= get_param_value(buf, sizeof(buf), "file", t) ? 2 : 0;
- switch (r) {
- case 0:
- buf[0] = '\0';
- /* fallthrough for default behavior */
- case 1:
- has_header = false;
- break;
- case 2:
- has_header = true;
- break;
- default:
- fprintf(stderr, "acpitable: both data and file are specified\n");
- return -1;
- }
- if (!acpi_tables) {
- allen = sizeof(uint16_t);
- acpi_tables = g_malloc0(allen);
+/* Install a copy of the ACPI table specified in @blob.
+ *
+ * If @has_header is set, @blob starts with the System Description Table Header
+ * structure. Otherwise, "dfl_hdr" is prepended. In any case, each header field
+ * is optionally overwritten from @hdrs.
+ *
+ * It is valid to call this function with
+ * (@blob == NULL && bloblen == 0 && !has_header).
+ *
+ * @hdrs->file and @hdrs->data are ignored.
+ *
+ * SIZE_MAX is considered "infinity" in this function.
+ *
+ * The number of tables that can be installed is not limited, but the 16-bit
+ * counter at the beginning of "acpi_tables" wraps around after UINT16_MAX.
+ */
+static void acpi_table_install(const char unsigned *blob, size_t bloblen,
+ bool has_header,
+ const struct AcpiTableOptions *hdrs,
+ Error **errp)
+{
+ size_t body_start;
+ const char unsigned *hdr_src;
+ size_t body_size, acpi_payload_size;
+ struct acpi_table_header *ext_hdr;
+ unsigned changed_fields;
+
+ /* Calculate where the ACPI table body starts within the blob, plus where
+ * to copy the ACPI table header from.
+ */
+ if (has_header) {
+ /* _length | ACPI header in blob | blob body
+ * ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^
+ * ACPI_TABLE_PFX_SIZE sizeof dfl_hdr body_size
+ * == body_start
+ *
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * acpi_payload_size == bloblen
+ */
+ body_start = sizeof dfl_hdr;
+
+ if (bloblen < body_start) {
+ error_setg(errp, "ACPI table claiming to have header is too "
+ "short, available: %zu, expected: %zu", bloblen,
+ body_start);
+ return;
+ }
+ hdr_src = blob;
} else {
- allen = acpi_tables_len;
+ /* _length | ACPI header in template | blob body
+ * ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^
+ * ACPI_TABLE_PFX_SIZE sizeof dfl_hdr body_size
+ * == bloblen
+ *
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * acpi_payload_size
+ */
+ body_start = 0;
+ hdr_src = dfl_hdr;
}
+ body_size = bloblen - body_start;
+ acpi_payload_size = sizeof dfl_hdr + body_size;
- start = allen;
- acpi_tables = g_realloc(acpi_tables, start + ACPI_TABLE_HDR_SIZE);
- allen += has_header ? ACPI_TABLE_PFX_SIZE : ACPI_TABLE_HDR_SIZE;
+ if (acpi_payload_size > UINT16_MAX) {
+ error_setg(errp, "ACPI table too big, requested: %zu, max: %u",
+ acpi_payload_size, (unsigned)UINT16_MAX);
+ return;
+ }
- /* now read in the data files, reallocating buffer as needed */
+ /* We won't fail from here on. Initialize / extend the globals. */
+ if (acpi_tables == NULL) {
+ acpi_tables_len = sizeof(uint16_t);
+ acpi_tables = g_malloc0(acpi_tables_len);
+ }
- for (f = strtok(buf, ":"); f; f = strtok(NULL, ":")) {
- int fd = open(f, O_RDONLY | O_BINARY);
+ acpi_tables = g_realloc(acpi_tables, acpi_tables_len +
+ ACPI_TABLE_PFX_SIZE +
+ sizeof dfl_hdr + body_size);
- if (fd < 0) {
- fprintf(stderr, "can't open file %s: %s\n", f, strerror(errno));
- return -1;
- }
+ ext_hdr = (struct acpi_table_header *)(acpi_tables + acpi_tables_len);
+ acpi_tables_len += ACPI_TABLE_PFX_SIZE;
- for (;;) {
- char data[8192];
- r = read(fd, data, sizeof(data));
- if (r == 0) {
- break;
- } else if (r > 0) {
- acpi_tables = g_realloc(acpi_tables, allen + r);
- memcpy(acpi_tables + allen, data, r);
- allen += r;
- } else if (errno != EINTR) {
- fprintf(stderr, "can't read file %s: %s\n",
- f, strerror(errno));
- close(fd);
- return -1;
- }
- }
+ memcpy(acpi_tables + acpi_tables_len, hdr_src, sizeof dfl_hdr);
+ acpi_tables_len += sizeof dfl_hdr;
- close(fd);
+ if (blob != NULL) {
+ memcpy(acpi_tables + acpi_tables_len, blob + body_start, body_size);
+ acpi_tables_len += body_size;
}
- /* now fill in the header fields */
+ /* increase number of tables */
+ cpu_to_le16wu((uint16_t *)acpi_tables,
+ le16_to_cpupu((uint16_t *)acpi_tables) + 1u);
- f = acpi_tables + start; /* start of the table */
- changed = 0;
+ /* Update the header fields. The strings need not be NUL-terminated. */
+ changed_fields = 0;
+ ext_hdr->_length = cpu_to_le16(acpi_payload_size);
- /* copy the header to temp place to align the fields */
- memcpy(&hdr, has_header ? f : dfl_hdr, ACPI_TABLE_HDR_SIZE);
+ if (hdrs->has_sig) {
+ strncpy(ext_hdr->sig, hdrs->sig, sizeof ext_hdr->sig);
+ ++changed_fields;
+ }
- /* length of the table minus our prefix */
- len = allen - start - ACPI_TABLE_PFX_SIZE;
+ if (has_header && le32_to_cpu(ext_hdr->length) != acpi_payload_size) {
+ fprintf(stderr,
+ "warning: ACPI table has wrong length, header says "
+ "%" PRIu32 ", actual size %zu bytes\n",
+ le32_to_cpu(ext_hdr->length), acpi_payload_size);
+ }
+ ext_hdr->length = cpu_to_le32(acpi_payload_size);
- hdr._length = cpu_to_le16(len);
+ if (hdrs->has_rev) {
+ ext_hdr->revision = hdrs->rev;
+ ++changed_fields;
+ }
- if (get_param_value(buf, sizeof(buf), "sig", t)) {
- /* strncpy is justified: the field need not be NUL-terminated. */
- strncpy(hdr.sig, buf, sizeof(hdr.sig));
- ++changed;
+ ext_hdr->checksum = 0;
+
+ if (hdrs->has_oem_id) {
+ strncpy(ext_hdr->oem_id, hdrs->oem_id, sizeof ext_hdr->oem_id);
+ ++changed_fields;
+ }
+ if (hdrs->has_oem_table_id) {
+ strncpy(ext_hdr->oem_table_id, hdrs->oem_table_id,
+ sizeof ext_hdr->oem_table_id);
+ ++changed_fields;
+ }
+ if (hdrs->has_oem_rev) {
+ ext_hdr->oem_revision = cpu_to_le32(hdrs->oem_rev);
+ ++changed_fields;
+ }
+ if (hdrs->has_asl_compiler_id) {
+ strncpy(ext_hdr->asl_compiler_id, hdrs->asl_compiler_id,
+ sizeof ext_hdr->asl_compiler_id);
+ ++changed_fields;
+ }
+ if (hdrs->has_asl_compiler_rev) {
+ ext_hdr->asl_compiler_revision = cpu_to_le32(hdrs->asl_compiler_rev);
+ ++changed_fields;
}
- /* length of the table including header, in bytes */
- if (has_header) {
- /* check if actual length is correct */
- val = le32_to_cpu(hdr.length);
- if (val != len) {
- fprintf(stderr,
- "warning: acpitable has wrong length,"
- " header says %lu, actual size %zu bytes\n",
- val, len);
- ++changed;
- }
+ if (!has_header && changed_fields == 0) {
+ fprintf(stderr, "warning: ACPI table: no headers are specified\n");
}
- /* we may avoid putting length here if has_header is true */
- hdr.length = cpu_to_le32(len);
- if (get_param_value(buf, sizeof(buf), "rev", t)) {
- val = strtoul(buf, &p, 0);
- if (val > 255 || *p) {
- fprintf(stderr, "acpitable: \"rev=%s\" is invalid\n", buf);
- return -1;
- }
- hdr.revision = (uint8_t)val;
- ++changed;
+ /* recalculate checksum */
+ ext_hdr->checksum = acpi_checksum((const char unsigned *)ext_hdr +
+ ACPI_TABLE_PFX_SIZE, acpi_payload_size);
+}
+
+void acpi_table_add(const QemuOpts *opts, Error **errp)
+{
+ AcpiTableOptions *hdrs = NULL;
+ Error *err = NULL;
+ char **pathnames = NULL;
+ char **cur;
+ size_t bloblen = 0;
+ char unsigned *blob = NULL;
+
+ {
+ OptsVisitor *ov;
+
+ ov = opts_visitor_new(opts);
+ visit_type_AcpiTableOptions(opts_get_visitor(ov), &hdrs, NULL, &err);
+ opts_visitor_cleanup(ov);
}
- if (get_param_value(buf, sizeof(buf), "oem_id", t)) {
- /* strncpy is justified: the field need not be NUL-terminated. */
- strncpy(hdr.oem_id, buf, sizeof(hdr.oem_id));
- ++changed;
+ if (err) {
+ goto out;
+ }
+ if (hdrs->has_file == hdrs->has_data) {
+ error_setg(&err, "'-acpitable' requires one of 'data' or 'file'");
+ goto out;
}
- if (get_param_value(buf, sizeof(buf), "oem_table_id", t)) {
- /* strncpy is justified: the field need not be NUL-terminated. */
- strncpy(hdr.oem_table_id, buf, sizeof(hdr.oem_table_id));
- ++changed;
+ pathnames = g_strsplit(hdrs->has_file ? hdrs->file : hdrs->data, ":", 0);
+ if (pathnames == NULL || pathnames[0] == NULL) {
+ error_setg(&err, "'-acpitable' requires at least one pathname");
+ goto out;
}
- if (get_param_value(buf, sizeof(buf), "oem_rev", t)) {
- val = strtol(buf, &p, 0);
- if (*p) {
- fprintf(stderr, "acpitable: \"oem_rev=%s\" is invalid\n", buf);
- return -1;
+ /* now read in the data files, reallocating buffer as needed */
+ for (cur = pathnames; *cur; ++cur) {
+ int fd = open(*cur, O_RDONLY | O_BINARY);
+
+ if (fd < 0) {
+ error_setg(&err, "can't open file %s: %s", *cur, strerror(errno));
+ goto out;
}
- hdr.oem_revision = cpu_to_le32(val);
- ++changed;
- }
- if (get_param_value(buf, sizeof(buf), "asl_compiler_id", t)) {
- /* strncpy is justified: the field need not be NUL-terminated. */
- strncpy(hdr.asl_compiler_id, buf, sizeof(hdr.asl_compiler_id));
- ++changed;
- }
+ for (;;) {
+ char unsigned data[8192];
+ ssize_t r;
- if (get_param_value(buf, sizeof(buf), "asl_compiler_rev", t)) {
- val = strtol(buf, &p, 0);
- if (*p) {
- fprintf(stderr, "acpitable: \"%s=%s\" is invalid\n",
- "asl_compiler_rev", buf);
- return -1;
+ r = read(fd, data, sizeof data);
+ if (r == 0) {
+ break;
+ } else if (r > 0) {
+ blob = g_realloc(blob, bloblen + r);
+ memcpy(blob + bloblen, data, r);
+ bloblen += r;
+ } else if (errno != EINTR) {
+ error_setg(&err, "can't read file %s: %s",
+ *cur, strerror(errno));
+ close(fd);
+ goto out;
+ }
}
- hdr.asl_compiler_revision = cpu_to_le32(val);
- ++changed;
- }
- if (!has_header && !changed) {
- fprintf(stderr, "warning: acpitable: no table headers are specified\n");
+ close(fd);
}
+ acpi_table_install(blob, bloblen, hdrs->has_file, hdrs, &err);
- /* now calculate checksum of the table, complete with the header */
- /* we may as well leave checksum intact if has_header is true */
- /* alternatively there may be a way to set cksum to a given value */
- hdr.checksum = 0; /* for checksum calculation */
+out:
+ g_free(blob);
+ g_strfreev(pathnames);
- /* put header back */
- memcpy(f, &hdr, sizeof(hdr));
+ if (hdrs != NULL) {
+ QapiDeallocVisitor *dv;
- if (changed || !has_header || 1) {
- ((struct acpi_table_header *)f)->checksum =
- acpi_checksum((uint8_t *)f + ACPI_TABLE_PFX_SIZE, len);
+ dv = qapi_dealloc_visitor_new();
+ visit_type_AcpiTableOptions(qapi_dealloc_get_visitor(dv), &hdrs, NULL,
+ NULL);
+ qapi_dealloc_visitor_cleanup(dv);
}
- /* increase number of tables */
- (*(uint16_t *)acpi_tables) =
- cpu_to_le32(le32_to_cpu(*(uint16_t *)acpi_tables) + 1);
-
- acpi_tables_len = allen;
- return 0;
-
+ error_propagate(errp, err);
}
static void acpi_notify_wakeup(Notifier *notifier, void *data)
@@ -472,8 +540,9 @@ static const MemoryRegionOps acpi_pm_cnt_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
-void acpi_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent)
+void acpi_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent, uint8_t s4_val)
{
+ ar->pm1.cnt.s4_val = s4_val;
ar->wakeup.notify = acpi_notify_wakeup;
qemu_register_wakeup_notifier(&ar->wakeup);
memory_region_init_io(&ar->pm1.cnt.io, &acpi_pm_cnt_ops, ar, "acpi-cnt", 2);
diff --git a/hw/acpi.h b/hw/acpi.h
index c3628d070d..e18ef28fd3 100644
--- a/hw/acpi.h
+++ b/hw/acpi.h
@@ -142,7 +142,7 @@ void acpi_pm1_evt_init(ACPIREGS *ar, acpi_update_sci_fn update_sci,
MemoryRegion *parent);
/* PM1a_CNT: piix and ich9 don't implement PM1b CNT. */
-void acpi_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent);
+void acpi_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent, uint8_t s4_val);
void acpi_pm1_cnt_update(ACPIREGS *ar,
bool sci_enable, bool sci_disable);
void acpi_pm1_cnt_reset(ACPIREGS *ar);
diff --git a/hw/acpi_ich9.c b/hw/acpi_ich9.c
index 29f84ffb45..7b34a03866 100644
--- a/hw/acpi_ich9.c
+++ b/hw/acpi_ich9.c
@@ -212,7 +212,7 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
acpi_pm_tmr_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io);
acpi_pm1_evt_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io);
- acpi_pm1_cnt_init(&pm->acpi_regs, &pm->io);
+ acpi_pm1_cnt_init(&pm->acpi_regs, &pm->io, 2);
acpi_gpe_init(&pm->acpi_regs, ICH9_PMIO_GPE0_LEN);
memory_region_init_io(&pm->io_gpe, &ich9_gpe_ops, pm, "apci-gpe0",
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index 7a4b712919..48a32b5aa0 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -418,7 +418,7 @@ static int piix4_pm_initfn(PCIDevice *dev)
acpi_pm_tmr_init(&s->ar, pm_tmr_timer, &s->io);
acpi_pm1_evt_init(&s->ar, pm_tmr_timer, &s->io);
- acpi_pm1_cnt_init(&s->ar, &s->io);
+ acpi_pm1_cnt_init(&s->ar, &s->io, s->s4_val);
acpi_gpe_init(&s->ar, GPE_LEN);
s->powerdown_notifier.notify = piix4_pm_powerdown_req;
diff --git a/hw/apic_common.c b/hw/apic_common.c
index d0c261602c..37985097ca 100644
--- a/hw/apic_common.c
+++ b/hw/apic_common.c
@@ -218,7 +218,7 @@ static void apic_reset_common(DeviceState *d)
bool bsp;
bsp = cpu_is_bsp(s->cpu);
- s->apicbase = 0xfee00000 |
+ s->apicbase = APIC_DEFAULT_ADDRESS |
(bsp ? MSR_IA32_APICBASE_BSP : 0) | MSR_IA32_APICBASE_ENABLE;
s->vapic_paddr = 0;
diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c
index 6747c1c547..b28e7d372f 100644
--- a/hw/arm/nseries.c
+++ b/hw/arm/nseries.c
@@ -129,8 +129,6 @@ static void n800_mmc_cs_cb(void *opaque, int line, int level)
/* TODO: this seems to actually be connected to the menelaus, to
* which also both MMC slots connect. */
omap_mmc_enable((struct omap_mmc_s *) opaque, !level);
-
- printf("%s: MMC slot %i active\n", __FUNCTION__, level + 1);
}
static void n8x0_gpio_setup(struct n800_s *s)
@@ -428,9 +426,6 @@ struct mipid_s {
static void mipid_reset(struct mipid_s *s)
{
- if (!s->sleep)
- fprintf(stderr, "%s: Display off\n", __FUNCTION__);
-
s->pm = 0;
s->cmd = 0;
@@ -578,11 +573,9 @@ static uint32_t mipid_txrx(void *opaque, uint32_t cmd, int len)
case 0x28: /* DISPOFF */
s->onoff = 0;
- fprintf(stderr, "%s: Display off\n", __FUNCTION__);
break;
case 0x29: /* DISPON */
s->onoff = 1;
- fprintf(stderr, "%s: Display on\n", __FUNCTION__);
break;
case 0x2a: /* CASET */
@@ -669,7 +662,8 @@ static uint32_t mipid_txrx(void *opaque, uint32_t cmd, int len)
default:
bad_cmd:
- fprintf(stderr, "%s: unknown command %02x\n", __FUNCTION__, s->cmd);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: unknown command %02x\n", __func__, s->cmd);
break;
}
@@ -1347,7 +1341,6 @@ static void n8x0_init(QEMUMachineInitArgs *args,
if (option_rom[0].name &&
(args->boot_device[0] == 'n' || !args->kernel_filename)) {
- int rom_size;
uint8_t nolo_tags[0x10000];
/* No, wait, better start at the ROM. */
s->mpu->cpu->env.regs[15] = OMAP2_Q2_BASE + 0x400000;
@@ -1361,10 +1354,9 @@ static void n8x0_init(QEMUMachineInitArgs *args,
*
* The code above is for loading the `zImage' file from Nokia
* images. */
- rom_size = load_image_targphys(option_rom[0].name,
- OMAP2_Q2_BASE + 0x400000,
- sdram_size - 0x400000);
- printf("%i bytes of image loaded\n", rom_size);
+ load_image_targphys(option_rom[0].name,
+ OMAP2_Q2_BASE + 0x400000,
+ sdram_size - 0x400000);
n800_setup_nolo_tags(nolo_tags);
cpu_physical_memory_write(OMAP2_SRAM_BASE, nolo_tags, 0x10000);
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
index 7467cca4f7..b7ca511d45 100644
--- a/hw/arm/pxa2xx.c
+++ b/hw/arm/pxa2xx.c
@@ -1981,9 +1981,11 @@ static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem,
memory_region_init_io(&s->iomem, &pxa2xx_fir_ops, s, "pxa2xx-fir", 0x1000);
memory_region_add_subregion(sysmem, base, &s->iomem);
- if (chr)
+ if (chr) {
+ qemu_chr_fe_claim_no_fail(chr);
qemu_chr_add_handlers(chr, pxa2xx_fir_is_empty,
pxa2xx_fir_rx, pxa2xx_fir_event, s);
+ }
register_savevm(NULL, "pxa2xx_fir", 0, 0, pxa2xx_fir_save,
pxa2xx_fir_load, s);
diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index 6f362865f9..5b9257a9de 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -86,8 +86,7 @@ static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq,
spi = (SSIBus *)qdev_get_child_bus(dev, bus_name);
for (j = 0; j < num_ss; ++j) {
- flash_dev = ssi_create_slave_no_init(spi, "n25q128");
- qdev_init_nofail(flash_dev);
+ flash_dev = ssi_create_slave(spi, "n25q128");
cs_line = qdev_get_gpio_in(flash_dev, 0);
sysbus_connect_irq(busdev, i * num_ss + j + 1, cs_line);
diff --git a/hw/arm_gic_common.c b/hw/arm_gic_common.c
index f2dc8bf555..71594f1f87 100644
--- a/hw/arm_gic_common.c
+++ b/hw/arm_gic_common.c
@@ -20,90 +20,65 @@
#include "hw/arm_gic_internal.h"
-static void gic_save(QEMUFile *f, void *opaque)
+static void gic_pre_save(void *opaque)
{
GICState *s = (GICState *)opaque;
ARMGICCommonClass *c = ARM_GIC_COMMON_GET_CLASS(s);
- int i;
- int j;
if (c->pre_save) {
c->pre_save(s);
}
-
- qemu_put_be32(f, s->enabled);
- for (i = 0; i < s->num_cpu; i++) {
- qemu_put_be32(f, s->cpu_enabled[i]);
- for (j = 0; j < GIC_INTERNAL; j++) {
- qemu_put_be32(f, s->priority1[j][i]);
- }
- for (j = 0; j < s->num_irq; j++) {
- qemu_put_be32(f, s->last_active[j][i]);
- }
- qemu_put_be32(f, s->priority_mask[i]);
- qemu_put_be32(f, s->running_irq[i]);
- qemu_put_be32(f, s->running_priority[i]);
- qemu_put_be32(f, s->current_pending[i]);
- }
- for (i = 0; i < s->num_irq - GIC_INTERNAL; i++) {
- qemu_put_be32(f, s->priority2[i]);
- }
- for (i = 0; i < s->num_irq; i++) {
- qemu_put_be32(f, s->irq_target[i]);
- qemu_put_byte(f, s->irq_state[i].enabled);
- qemu_put_byte(f, s->irq_state[i].pending);
- qemu_put_byte(f, s->irq_state[i].active);
- qemu_put_byte(f, s->irq_state[i].level);
- qemu_put_byte(f, s->irq_state[i].model);
- qemu_put_byte(f, s->irq_state[i].trigger);
- }
}
-static int gic_load(QEMUFile *f, void *opaque, int version_id)
+static int gic_post_load(void *opaque, int version_id)
{
GICState *s = (GICState *)opaque;
ARMGICCommonClass *c = ARM_GIC_COMMON_GET_CLASS(s);
- int i;
- int j;
-
- if (version_id != 3) {
- return -EINVAL;
- }
-
- s->enabled = qemu_get_be32(f);
- for (i = 0; i < s->num_cpu; i++) {
- s->cpu_enabled[i] = qemu_get_be32(f);
- for (j = 0; j < GIC_INTERNAL; j++) {
- s->priority1[j][i] = qemu_get_be32(f);
- }
- for (j = 0; j < s->num_irq; j++) {
- s->last_active[j][i] = qemu_get_be32(f);
- }
- s->priority_mask[i] = qemu_get_be32(f);
- s->running_irq[i] = qemu_get_be32(f);
- s->running_priority[i] = qemu_get_be32(f);
- s->current_pending[i] = qemu_get_be32(f);
- }
- for (i = 0; i < s->num_irq - GIC_INTERNAL; i++) {
- s->priority2[i] = qemu_get_be32(f);
- }
- for (i = 0; i < s->num_irq; i++) {
- s->irq_target[i] = qemu_get_be32(f);
- s->irq_state[i].enabled = qemu_get_byte(f);
- s->irq_state[i].pending = qemu_get_byte(f);
- s->irq_state[i].active = qemu_get_byte(f);
- s->irq_state[i].level = qemu_get_byte(f);
- s->irq_state[i].model = qemu_get_byte(f);
- s->irq_state[i].trigger = qemu_get_byte(f);
- }
if (c->post_load) {
c->post_load(s);
}
-
return 0;
}
+static const VMStateDescription vmstate_gic_irq_state = {
+ .name = "arm_gic_irq_state",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(enabled, gic_irq_state),
+ VMSTATE_UINT8(pending, gic_irq_state),
+ VMSTATE_UINT8(active, gic_irq_state),
+ VMSTATE_UINT8(level, gic_irq_state),
+ VMSTATE_BOOL(model, gic_irq_state),
+ VMSTATE_BOOL(trigger, gic_irq_state),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_gic = {
+ .name = "arm_gic",
+ .version_id = 4,
+ .minimum_version_id = 4,
+ .pre_save = gic_pre_save,
+ .post_load = gic_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_BOOL(enabled, GICState),
+ VMSTATE_BOOL_ARRAY(cpu_enabled, GICState, NCPU),
+ VMSTATE_STRUCT_ARRAY(irq_state, GICState, GIC_MAXIRQ, 1,
+ vmstate_gic_irq_state, gic_irq_state),
+ VMSTATE_UINT8_ARRAY(irq_target, GICState, GIC_MAXIRQ),
+ VMSTATE_UINT8_2DARRAY(priority1, GICState, GIC_INTERNAL, NCPU),
+ VMSTATE_UINT8_ARRAY(priority2, GICState, GIC_MAXIRQ - GIC_INTERNAL),
+ VMSTATE_UINT16_2DARRAY(last_active, GICState, GIC_MAXIRQ, NCPU),
+ VMSTATE_UINT16_ARRAY(priority_mask, GICState, NCPU),
+ VMSTATE_UINT16_ARRAY(running_irq, GICState, NCPU),
+ VMSTATE_UINT16_ARRAY(running_priority, GICState, NCPU),
+ VMSTATE_UINT16_ARRAY(current_pending, GICState, NCPU),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static void arm_gic_common_realize(DeviceState *dev, Error **errp)
{
GICState *s = ARM_GIC_COMMON(dev);
@@ -131,8 +106,6 @@ static void arm_gic_common_realize(DeviceState *dev, Error **errp)
num_irq);
return;
}
-
- register_savevm(NULL, "arm_gic", -1, 3, gic_save, gic_load, s);
}
static void arm_gic_common_reset(DeviceState *dev)
@@ -149,7 +122,7 @@ static void arm_gic_common_reset(DeviceState *dev)
s->current_pending[i] = 1023;
s->running_irq[i] = 1023;
s->running_priority[i] = 0x100;
- s->cpu_enabled[i] = 0;
+ s->cpu_enabled[i] = false;
}
for (i = 0; i < 16; i++) {
GIC_SET_ENABLED(i, ALL_CPU_MASK);
@@ -161,7 +134,7 @@ static void arm_gic_common_reset(DeviceState *dev)
s->irq_target[i] = 1;
}
}
- s->enabled = 0;
+ s->enabled = false;
}
static Property arm_gic_common_properties[] = {
@@ -182,6 +155,7 @@ static void arm_gic_common_class_init(ObjectClass *klass, void *data)
dc->reset = arm_gic_common_reset;
dc->realize = arm_gic_common_realize;
dc->props = arm_gic_common_properties;
+ dc->vmsd = &vmstate_gic;
dc->no_user = 1;
}
diff --git a/hw/arm_gic_internal.h b/hw/arm_gic_internal.h
index 3e1928b7eb..99a3bc362b 100644
--- a/hw/arm_gic_internal.h
+++ b/hw/arm_gic_internal.h
@@ -45,14 +45,14 @@
#define GIC_SET_ACTIVE(irq, cm) s->irq_state[irq].active |= (cm)
#define GIC_CLEAR_ACTIVE(irq, cm) s->irq_state[irq].active &= ~(cm)
#define GIC_TEST_ACTIVE(irq, cm) ((s->irq_state[irq].active & (cm)) != 0)
-#define GIC_SET_MODEL(irq) s->irq_state[irq].model = 1
-#define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = 0
+#define GIC_SET_MODEL(irq) s->irq_state[irq].model = true
+#define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = false
#define GIC_TEST_MODEL(irq) s->irq_state[irq].model
#define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level = (cm)
#define GIC_CLEAR_LEVEL(irq, cm) s->irq_state[irq].level &= ~(cm)
#define GIC_TEST_LEVEL(irq, cm) ((s->irq_state[irq].level & (cm)) != 0)
-#define GIC_SET_TRIGGER(irq) s->irq_state[irq].trigger = 1
-#define GIC_CLEAR_TRIGGER(irq) s->irq_state[irq].trigger = 0
+#define GIC_SET_TRIGGER(irq) s->irq_state[irq].trigger = true
+#define GIC_CLEAR_TRIGGER(irq) s->irq_state[irq].trigger = false
#define GIC_TEST_TRIGGER(irq) s->irq_state[irq].trigger
#define GIC_GET_PRIORITY(irq, cpu) (((irq) < GIC_INTERNAL) ? \
s->priority1[irq][cpu] : \
@@ -61,30 +61,30 @@
typedef struct gic_irq_state {
/* The enable bits are only banked for per-cpu interrupts. */
- unsigned enabled:NCPU;
- unsigned pending:NCPU;
- unsigned active:NCPU;
- unsigned level:NCPU;
- unsigned model:1; /* 0 = N:N, 1 = 1:N */
- unsigned trigger:1; /* nonzero = edge triggered. */
+ uint8_t enabled;
+ uint8_t pending;
+ uint8_t active;
+ uint8_t level;
+ bool model; /* 0 = N:N, 1 = 1:N */
+ bool trigger; /* nonzero = edge triggered. */
} gic_irq_state;
typedef struct GICState {
SysBusDevice busdev;
qemu_irq parent_irq[NCPU];
- int enabled;
- int cpu_enabled[NCPU];
+ bool enabled;
+ bool cpu_enabled[NCPU];
gic_irq_state irq_state[GIC_MAXIRQ];
- int irq_target[GIC_MAXIRQ];
- int priority1[GIC_INTERNAL][NCPU];
- int priority2[GIC_MAXIRQ - GIC_INTERNAL];
- int last_active[GIC_MAXIRQ][NCPU];
-
- int priority_mask[NCPU];
- int running_irq[NCPU];
- int running_priority[NCPU];
- int current_pending[NCPU];
+ uint8_t irq_target[GIC_MAXIRQ];
+ uint8_t priority1[GIC_INTERNAL][NCPU];
+ uint8_t priority2[GIC_MAXIRQ - GIC_INTERNAL];
+ uint16_t last_active[GIC_MAXIRQ][NCPU];
+
+ uint16_t priority_mask[NCPU];
+ uint16_t running_irq[NCPU];
+ uint16_t running_priority[NCPU];
+ uint16_t current_pending[NCPU];
uint32_t num_cpu;
diff --git a/hw/arm_mptimer.c b/hw/arm_mptimer.c
index f59a9f11f0..317f5e43ed 100644
--- a/hw/arm_mptimer.c
+++ b/hw/arm_mptimer.c
@@ -253,14 +253,15 @@ static int arm_mptimer_init(SysBusDevice *dev)
static const VMStateDescription vmstate_timerblock = {
.name = "arm_mptimer_timerblock",
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.fields = (VMStateField[]) {
VMSTATE_UINT32(count, TimerBlock),
VMSTATE_UINT32(load, TimerBlock),
VMSTATE_UINT32(control, TimerBlock),
VMSTATE_UINT32(status, TimerBlock),
VMSTATE_INT64(tick, TimerBlock),
+ VMSTATE_TIMER(timer, TimerBlock),
VMSTATE_END_OF_LIST()
}
};
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c
index d198cfd96e..235120024f 100644
--- a/hw/armv7m_nvic.c
+++ b/hw/armv7m_nvic.c
@@ -458,10 +458,10 @@ static void armv7m_nvic_reset(DeviceState *dev)
* as enabled by default, and with a priority mask which allows
* all interrupts through.
*/
- s->gic.cpu_enabled[0] = 1;
+ s->gic.cpu_enabled[0] = true;
s->gic.priority_mask[0] = 0x100;
/* The NVIC as a whole is always enabled. */
- s->gic.enabled = 1;
+ s->gic.enabled = true;
systick_reset(s);
}
diff --git a/hw/bt-hci-csr.c b/hw/bt-hci-csr.c
index e4ada3c731..55c819b085 100644
--- a/hw/bt-hci-csr.c
+++ b/hw/bt-hci-csr.c
@@ -439,6 +439,7 @@ CharDriverState *uart_hci_init(qemu_irq wakeup)
s->chr.opaque = s;
s->chr.chr_write = csrhci_write;
s->chr.chr_ioctl = csrhci_ioctl;
+ s->chr.avail_connections = 1;
s->hci = qemu_next_hci();
s->hci->opaque = s;
diff --git a/hw/cadence_uart.c b/hw/cadence_uart.c
index 5426f10018..421ec998d6 100644
--- a/hw/cadence_uart.c
+++ b/hw/cadence_uart.c
@@ -157,6 +157,7 @@ static void uart_rx_reset(UartState *s)
{
s->rx_wpos = 0;
s->rx_count = 0;
+ qemu_chr_accept_input(s->chr);
s->r[R_SR] |= UART_SR_INTR_REMPTY;
s->r[R_SR] &= ~UART_SR_INTR_RFUL;
diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c
index c151c95c3e..cc95e5c3f0 100644
--- a/hw/i386/kvmvapic.c
+++ b/hw/i386/kvmvapic.c
@@ -13,8 +13,6 @@
#include "sysemu/kvm.h"
#include "hw/apic_internal.h"
-#define APIC_DEFAULT_ADDRESS 0xfee00000
-
#define VAPIC_IO_PORT 0x7e
#define VAPIC_CPU_SHIFT 7
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index b1e06fa0e7..ebbf059225 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -51,6 +51,7 @@
#include "exec/address-spaces.h"
#include "sysemu/arch_init.h"
#include "qemu/bitmap.h"
+#include "qemu/config-file.h"
/* debug PC/ISA interrupts */
//#define DEBUG_IRQ
@@ -71,6 +72,8 @@
#define FW_CFG_E820_TABLE (FW_CFG_ARCH_LOCAL + 3)
#define FW_CFG_HPET (FW_CFG_ARCH_LOCAL + 4)
+#define IO_APIC_DEFAULT_ADDRESS 0xfec00000
+
#define E820_NR_ENTRIES 16
struct e820_entry {
@@ -888,7 +891,7 @@ void pc_cpus_init(const char *cpu_model)
void pc_acpi_init(const char *default_dsdt)
{
- char *filename = NULL, *arg = NULL;
+ char *filename;
if (acpi_tables != NULL) {
/* manually set via -acpitable, leave it alone */
@@ -898,15 +901,26 @@ void pc_acpi_init(const char *default_dsdt)
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, default_dsdt);
if (filename == NULL) {
fprintf(stderr, "WARNING: failed to find %s\n", default_dsdt);
- return;
- }
+ } else {
+ char *arg;
+ QemuOpts *opts;
+ Error *err = NULL;
- arg = g_strdup_printf("file=%s", filename);
- if (acpi_table_add(arg) != 0) {
- fprintf(stderr, "WARNING: failed to load %s\n", filename);
+ arg = g_strdup_printf("file=%s", filename);
+
+ /* creates a deep copy of "arg" */
+ opts = qemu_opts_parse(qemu_find_opts("acpi"), arg, 0);
+ g_assert(opts != NULL);
+
+ acpi_table_add(opts, &err);
+ if (err) {
+ fprintf(stderr, "WARNING: failed to load %s: %s\n", filename,
+ error_get_pretty(err));
+ error_free(err);
+ }
+ g_free(arg);
+ g_free(filename);
}
- g_free(arg);
- g_free(filename);
}
void *pc_memory_init(MemoryRegion *system_memory,
@@ -1158,7 +1172,7 @@ void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name)
}
qdev_init_nofail(dev);
d = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(d, 0, 0xfec00000);
+ sysbus_mmio_map(d, 0, IO_APIC_DEFAULT_ADDRESS);
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
gsi_state->ioapic_irq[i] = qdev_get_gpio_in(dev, i);
diff --git a/hw/ipoctal232.c b/hw/ipoctal232.c
index 1da6a99175..685fee2d2e 100644
--- a/hw/ipoctal232.c
+++ b/hw/ipoctal232.c
@@ -93,7 +93,6 @@ typedef struct SCC2698Block SCC2698Block;
struct SCC2698Channel {
IPOctalState *ipoctal;
CharDriverState *dev;
- char *devpath;
bool rx_enabled;
uint8_t mr[2];
uint8_t mr_idx;
@@ -545,25 +544,12 @@ static int ipoctal_init(IPackDevice *ip)
ch->ipoctal = s;
/* Redirect IP-Octal channels to host character devices */
- if (ch->devpath) {
- const char chr_name[] = "ipoctal";
- char label[ARRAY_SIZE(chr_name) + 2];
- static int index;
-
- snprintf(label, sizeof(label), "%s%d", chr_name, index);
-
- ch->dev = qemu_chr_new(label, ch->devpath, NULL);
-
- if (ch->dev) {
- index++;
- qemu_chr_add_handlers(ch->dev, hostdev_can_receive,
- hostdev_receive, hostdev_event, ch);
- DPRINTF("Redirecting channel %u to %s (%s)\n",
- i, ch->devpath, label);
- } else {
- DPRINTF("Could not redirect channel %u to %s\n",
- i, ch->devpath);
- }
+ if (ch->dev) {
+ qemu_chr_add_handlers(ch->dev, hostdev_can_receive,
+ hostdev_receive, hostdev_event, ch);
+ DPRINTF("Redirecting channel %u to %s\n", i, ch->dev->label);
+ } else {
+ DPRINTF("Could not redirect channel %u, no chardev set\n", i);
}
}
@@ -571,14 +557,14 @@ static int ipoctal_init(IPackDevice *ip)
}
static Property ipoctal_properties[] = {
- DEFINE_PROP_STRING("serial0", IPOctalState, ch[0].devpath),
- DEFINE_PROP_STRING("serial1", IPOctalState, ch[1].devpath),
- DEFINE_PROP_STRING("serial2", IPOctalState, ch[2].devpath),
- DEFINE_PROP_STRING("serial3", IPOctalState, ch[3].devpath),
- DEFINE_PROP_STRING("serial4", IPOctalState, ch[4].devpath),
- DEFINE_PROP_STRING("serial5", IPOctalState, ch[5].devpath),
- DEFINE_PROP_STRING("serial6", IPOctalState, ch[6].devpath),
- DEFINE_PROP_STRING("serial7", IPOctalState, ch[7].devpath),
+ DEFINE_PROP_CHR("chardev0", IPOctalState, ch[0].dev),
+ DEFINE_PROP_CHR("chardev1", IPOctalState, ch[1].dev),
+ DEFINE_PROP_CHR("chardev2", IPOctalState, ch[2].dev),
+ DEFINE_PROP_CHR("chardev3", IPOctalState, ch[3].dev),
+ DEFINE_PROP_CHR("chardev4", IPOctalState, ch[4].dev),
+ DEFINE_PROP_CHR("chardev5", IPOctalState, ch[5].dev),
+ DEFINE_PROP_CHR("chardev6", IPOctalState, ch[6].dev),
+ DEFINE_PROP_CHR("chardev7", IPOctalState, ch[7].dev),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/ivshmem.c b/hw/ivshmem.c
index 68a2cf2e69..af2789e9ac 100644
--- a/hw/ivshmem.c
+++ b/hw/ivshmem.c
@@ -292,6 +292,7 @@ static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier *
fprintf(stderr, "creating eventfd for eventfd %d failed\n", eventfd);
exit(-1);
}
+ qemu_chr_fe_claim_no_fail(chr);
/* if MSI is supported we need multiple interrupts */
if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
diff --git a/hw/mcf_uart.c b/hw/mcf_uart.c
index aacf0f05ed..e5de801671 100644
--- a/hw/mcf_uart.c
+++ b/hw/mcf_uart.c
@@ -280,6 +280,7 @@ void *mcf_uart_init(qemu_irq irq, CharDriverState *chr)
s->chr = chr;
s->irq = irq;
if (chr) {
+ qemu_chr_fe_claim_no_fail(chr);
qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive,
mcf_uart_event, s);
}
diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c
index cfc02207ab..07dc808405 100644
--- a/hw/microblaze/petalogix_ml605_mmu.c
+++ b/hw/microblaze/petalogix_ml605_mmu.c
@@ -158,8 +158,7 @@ petalogix_ml605_init(QEMUMachineInitArgs *args)
for (i = 0; i < NUM_SPI_FLASHES; i++) {
qemu_irq cs_line;
- dev = ssi_create_slave_no_init(spi, "n25q128");
- qdev_init_nofail(dev);
+ dev = ssi_create_slave(spi, "n25q128");
cs_line = qdev_get_gpio_in(dev, 0);
sysbus_connect_irq(busdev, i+1, cs_line);
}
diff --git a/hw/nand.c b/hw/nand.c
index de3e502596..63620938fb 100644
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -297,6 +297,7 @@ static void nand_command(NANDFlashState *s)
break;
case NAND_CMD_BLOCKERASE2:
+ s->addr &= (1ull << s->addrlen * 8) - 1;
if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
s->addr <<= 16;
else
diff --git a/hw/onenand.c b/hw/onenand.c
index ddba366ef5..57a346d7da 100644
--- a/hw/onenand.c
+++ b/hw/onenand.c
@@ -185,7 +185,8 @@ static const VMStateDescription vmstate_onenand = {
VMSTATE_UINT8(ecc.cp, OneNANDState),
VMSTATE_UINT16_ARRAY(ecc.lp, OneNANDState, 2),
VMSTATE_UINT16(ecc.count, OneNANDState),
- VMSTATE_BUFFER_UNSAFE(otp, OneNANDState, 0, ((64 + 2) << PAGE_SHIFT)),
+ VMSTATE_BUFFER_POINTER_UNSAFE(otp, OneNANDState, 0,
+ ((64 + 2) << PAGE_SHIFT)),
VMSTATE_END_OF_LIST()
}
};
diff --git a/hw/pc.h b/hw/pc.h
index 8e1dd4cad4..55964ced93 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -109,11 +109,11 @@ void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name);
/* acpi.c */
extern int acpi_enabled;
-extern char *acpi_tables;
+extern char unsigned *acpi_tables;
extern size_t acpi_tables_len;
void acpi_bios_init(void);
-int acpi_table_add(const char *table_desc);
+void acpi_table_add(const QemuOpts *opts, Error **errp);
/* acpi_piix.c */
diff --git a/hw/pci/pci-hotplug.c b/hw/pci/pci-hotplug.c
index f38df30540..180ee07fef 100644
--- a/hw/pci/pci-hotplug.c
+++ b/hw/pci/pci-hotplug.c
@@ -99,7 +99,7 @@ static int scsi_hot_add(Monitor *mon, DeviceState *adapter,
dinfo->unit = qemu_opt_get_number(dinfo->opts, "unit", -1);
dinfo->bus = scsibus->busnr;
scsidev = scsi_bus_legacy_add_drive(scsibus, dinfo->bdrv, dinfo->unit,
- false, -1);
+ false, -1, NULL);
if (!scsidev) {
return -1;
}
diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c
index 5d57babe07..646dc794bf 100644
--- a/hw/pflash_cfi01.c
+++ b/hw/pflash_cfi01.c
@@ -67,8 +67,7 @@ struct pflash_t {
uint64_t sector_len;
uint8_t width;
uint8_t be;
- int wcycle; /* if 0, the flash is read normally */
- int bypass;
+ uint8_t wcycle; /* if 0, the flash is read normally */
int ro;
uint8_t cmd;
uint8_t status;
@@ -78,7 +77,7 @@ struct pflash_t {
uint16_t ident3;
uint8_t cfi_len;
uint8_t cfi_table[0x52];
- hwaddr counter;
+ uint64_t counter;
unsigned int writeblock_size;
QEMUTimer *timer;
MemoryRegion mem;
@@ -86,6 +85,19 @@ struct pflash_t {
void *storage;
};
+static const VMStateDescription vmstate_pflash = {
+ .name = "pflash_cfi01",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(wcycle, pflash_t),
+ VMSTATE_UINT8(cmd, pflash_t),
+ VMSTATE_UINT8(status, pflash_t),
+ VMSTATE_UINT64(counter, pflash_t),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static void pflash_timer (void *opaque)
{
pflash_t *pfl = opaque;
@@ -93,12 +105,8 @@ static void pflash_timer (void *opaque)
DPRINTF("%s: command %02x done\n", __func__, pfl->cmd);
/* Reset flash */
pfl->status ^= 0x80;
- if (pfl->bypass) {
- pfl->wcycle = 2;
- } else {
- memory_region_rom_device_set_readable(&pfl->mem, true);
- pfl->wcycle = 0;
- }
+ memory_region_rom_device_set_readable(&pfl->mem, true);
+ pfl->wcycle = 0;
pfl->cmd = 0;
}
@@ -228,7 +236,7 @@ static inline void pflash_data_write(pflash_t *pfl, hwaddr offset,
uint8_t *p = pfl->storage;
DPRINTF("%s: block write offset " TARGET_FMT_plx
- " value %x counter " TARGET_FMT_plx "\n",
+ " value %x counter %016" PRIx64 "\n",
__func__, offset, value, pfl->counter);
switch (width) {
case 1:
@@ -452,7 +460,6 @@ static void pflash_write(pflash_t *pfl, hwaddr offset,
reset_flash:
memory_region_rom_device_set_readable(&pfl->mem, true);
- pfl->bypass = 0;
pfl->wcycle = 0;
pfl->cmd = 0;
}
@@ -707,6 +714,7 @@ static void pflash_cfi01_class_init(ObjectClass *klass, void *data)
k->init = pflash_cfi01_init;
dc->props = pflash_cfi01_properties;
+ dc->vmsd = &vmstate_pflash;
}
diff --git a/hw/pl050.c b/hw/pl050.c
index bc31ab6885..76735a0eda 100644
--- a/hw/pl050.c
+++ b/hw/pl050.c
@@ -24,14 +24,13 @@ typedef struct {
static const VMStateDescription vmstate_pl050 = {
.name = "pl050",
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.fields = (VMStateField[]) {
VMSTATE_UINT32(cr, pl050_state),
VMSTATE_UINT32(clk, pl050_state),
VMSTATE_UINT32(last, pl050_state),
VMSTATE_INT32(pending, pl050_state),
- VMSTATE_INT32(is_mouse, pl050_state),
VMSTATE_END_OF_LIST()
}
};
diff --git a/hw/pl330.c b/hw/pl330.c
index 1a04773a71..60aa4a8f9f 100644
--- a/hw/pl330.c
+++ b/hw/pl330.c
@@ -870,9 +870,8 @@ static void pl330_dmasev(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
ch->parent->int_status |= (1 << ev_id);
DB_PRINT("event interrupt raised %d\n", ev_id);
qemu_irq_raise(ch->parent->irq[ev_id]);
- } else {
- ch->parent->ev_status |= (1 << ev_id);
}
+ ch->parent->ev_status |= (1 << ev_id);
}
static void pl330_dmast(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
diff --git a/hw/qdev-properties-system.c b/hw/qdev-properties-system.c
index d9934b5b9c..a22b155b6f 100644
--- a/hw/qdev-properties-system.c
+++ b/hw/qdev-properties-system.c
@@ -123,11 +123,10 @@ static int parse_chr(DeviceState *dev, const char *str, void **ptr)
if (chr == NULL) {
return -ENOENT;
}
- if (chr->avail_connections < 1) {
+ if (qemu_chr_fe_claim(chr) != 0) {
return -EEXIST;
}
*ptr = chr;
- --chr->avail_connections;
return 0;
}
@@ -140,7 +139,7 @@ static void release_chr(Object *obj, const char *name, void *opaque)
if (chr) {
qemu_chr_add_handlers(chr, NULL, NULL, NULL, NULL);
- ++chr->avail_connections;
+ qemu_chr_fe_release(chr);
}
}
diff --git a/hw/qdev.c b/hw/qdev.c
index 9b0f65246a..e2bb37dc37 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -767,7 +767,7 @@ static void device_unparent(Object *obj)
DeviceClass *dc = DEVICE_GET_CLASS(dev);
BusState *bus;
QObject *event_data;
- gchar *path = object_get_canonical_path(obj);
+ bool have_realized = dev->realized;
while (dev->num_child_bus) {
bus = QLIST_FIRST(&dev->child_bus);
@@ -787,15 +787,20 @@ static void device_unparent(Object *obj)
dev->parent_bus = NULL;
}
- if (dev->id) {
- event_data = qobject_from_jsonf("{ 'device': %s, 'path': %s }",
- dev->id, path);
- } else {
- event_data = qobject_from_jsonf("{ 'path': %s }", path);
+ /* Only send event if the device had been completely realized */
+ if (have_realized) {
+ gchar *path = object_get_canonical_path(OBJECT(dev));
+
+ if (dev->id) {
+ event_data = qobject_from_jsonf("{ 'device': %s, 'path': %s }",
+ dev->id, path);
+ } else {
+ event_data = qobject_from_jsonf("{ 'path': %s }", path);
+ }
+ monitor_protocol_event(QEVENT_DEVICE_DELETED, event_data);
+ qobject_decref(event_data);
+ g_free(path);
}
- monitor_protocol_event(QEVENT_DEVICE_DELETED, event_data);
- qobject_decref(event_data);
- g_free(path);
}
static void device_class_init(ObjectClass *class, void *data)
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 08787c2a9b..ac2093a5ef 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -207,7 +207,8 @@ static int scsi_qdev_exit(DeviceState *qdev)
/* handle legacy '-drive if=scsi,...' cmd line args */
SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
- int unit, bool removable, int bootindex)
+ int unit, bool removable, int bootindex,
+ const char *serial)
{
const char *driver;
DeviceState *dev;
@@ -221,6 +222,9 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
if (object_property_find(OBJECT(dev), "removable", NULL)) {
qdev_prop_set_bit(dev, "removable", removable);
}
+ if (serial) {
+ qdev_prop_set_string(dev, "serial", serial);
+ }
if (qdev_prop_set_drive(dev, "drive", bdrv) < 0) {
qdev_free(dev);
return NULL;
@@ -243,7 +247,7 @@ int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
continue;
}
qemu_opts_loc_restore(dinfo->opts);
- if (!scsi_bus_legacy_add_drive(bus, dinfo->bdrv, unit, false, -1)) {
+ if (!scsi_bus_legacy_add_drive(bus, dinfo->bdrv, unit, false, -1, NULL)) {
res = -1;
break;
}
diff --git a/hw/scsi.h b/hw/scsi.h
index 33e2e0bdf1..02a1497d7a 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -160,7 +160,8 @@ static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d)
}
SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
- int unit, bool removable, int bootindex);
+ int unit, bool removable, int bootindex,
+ const char *serial);
int scsi_bus_legacy_handle_cmdline(SCSIBus *bus);
/*
diff --git a/hw/sd.c b/hw/sd.c
index a895123867..66c4014fbe 100644
--- a/hw/sd.c
+++ b/hw/sd.c
@@ -478,7 +478,7 @@ static const VMStateDescription sd_vmstate = {
VMSTATE_UINT64(data_start, SDState),
VMSTATE_UINT32(data_offset, SDState),
VMSTATE_UINT8_ARRAY(data, SDState, 512),
- VMSTATE_BUFFER_UNSAFE(buf, SDState, 1, 512),
+ VMSTATE_BUFFER_POINTER_UNSAFE(buf, SDState, 1, 512),
VMSTATE_BOOL(enable, SDState),
VMSTATE_END_OF_LIST()
}
diff --git a/hw/sh_serial.c b/hw/sh_serial.c
index 40e797c5a2..462969557c 100644
--- a/hw/sh_serial.c
+++ b/hw/sh_serial.c
@@ -396,9 +396,11 @@ void sh_serial_init(MemoryRegion *sysmem,
s->chr = chr;
- if (chr)
+ if (chr) {
+ qemu_chr_fe_claim_no_fail(chr);
qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1,
sh_serial_event, s);
+ }
s->eri = eri_source;
s->rxi = rxi_source;
diff --git a/hw/usb.h b/hw/usb.h
index 1b10684dde..4d9d05e9bc 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -337,6 +337,7 @@ typedef struct USBPortOps {
struct USBPort {
USBDevice *dev;
int speedmask;
+ int hubcount;
char path[16];
USBPortOps *ops;
void *opaque;
diff --git a/hw/usb/bus.c b/hw/usb/bus.c
index e58cd9ade2..b10c290cf4 100644
--- a/hw/usb/bus.c
+++ b/hw/usb/bus.c
@@ -341,8 +341,10 @@ void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr)
if (upstream) {
snprintf(downstream->path, sizeof(downstream->path), "%s.%d",
upstream->path, portnr);
+ downstream->hubcount = upstream->hubcount + 1;
} else {
snprintf(downstream->path, sizeof(downstream->path), "%d", portnr);
+ downstream->hubcount = 0;
}
}
diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c
index 9701048887..317b4740e2 100644
--- a/hw/usb/dev-hid.c
+++ b/hw/usb/dev-hid.c
@@ -236,7 +236,7 @@ static const USBDescDevice desc_device_tablet2 = {
.bNumInterfaces = 1,
.bConfigurationValue = 1,
.iConfiguration = STR_CONFIG_TABLET,
- .bmAttributes = 0xa0,
+ .bmAttributes = 0x80,
.bMaxPower = 50,
.nif = 1,
.ifs = &desc_iface_tablet2,
diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c
index 504c98c350..0b71abd028 100644
--- a/hw/usb/dev-hub.c
+++ b/hw/usb/dev-hub.c
@@ -25,6 +25,7 @@
#include "trace.h"
#include "hw/usb.h"
#include "hw/usb/desc.h"
+#include "qemu/error-report.h"
#define NUM_PORTS 8
@@ -32,6 +33,7 @@ typedef struct USBHubPort {
USBPort port;
uint16_t wPortStatus;
uint16_t wPortChange;
+ uint16_t wPortChange_reported;
} USBHubPort;
typedef struct USBHubState {
@@ -466,8 +468,11 @@ static void usb_hub_handle_data(USBDevice *dev, USBPacket *p)
status = 0;
for(i = 0; i < NUM_PORTS; i++) {
port = &s->ports[i];
- if (port->wPortChange)
+ if (port->wPortChange &&
+ port->wPortChange_reported != port->wPortChange) {
status |= (1 << (i + 1));
+ }
+ port->wPortChange_reported = port->wPortChange;
}
if (status != 0) {
for(i = 0; i < n; i++) {
@@ -514,6 +519,11 @@ static int usb_hub_initfn(USBDevice *dev)
USBHubPort *port;
int i;
+ if (dev->port->hubcount == 5) {
+ error_report("usb hub chain too deep");
+ return -1;
+ }
+
usb_desc_create_serial(dev);
usb_desc_init(dev);
s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
index d3f01aa2a7..21651b3637 100644
--- a/hw/usb/dev-storage.c
+++ b/hw/usb/dev-storage.c
@@ -625,7 +625,7 @@ static int usb_msd_initfn_storage(USBDevice *dev)
usb_desc_init(dev);
scsi_bus_new(&s->bus, &s->dev.qdev, &usb_msd_scsi_info_storage);
scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable,
- s->conf.bootindex);
+ s->conf.bootindex, s->serial);
if (!scsi_dev) {
return -1;
}
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 5aa342bda5..efd4b0dbde 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -452,7 +452,6 @@ struct XHCIState {
MemoryRegion mem_oper;
MemoryRegion mem_runtime;
MemoryRegion mem_doorbell;
- const char *name;
unsigned int devaddr;
/* properties */
@@ -1172,8 +1171,6 @@ static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx,
uint32_t ctx[5];
uint32_t ctx2[2];
- fprintf(stderr, "%s: epid %d, state %d\n",
- __func__, epctx->epid, state);
xhci_dma_read_u32s(xhci, epctx->pctx, ctx, sizeof(ctx));
ctx[0] &= ~EP_STATE_MASK;
ctx[0] |= state;
@@ -2568,7 +2565,7 @@ static void xhci_process_commands(XHCIState *xhci)
}
break;
default:
- fprintf(stderr, "xhci: unimplemented command %d\n", type);
+ trace_usb_xhci_unimplemented("command", type);
event.ccode = CC_TRB_ERROR;
break;
}
@@ -2767,7 +2764,7 @@ static uint64_t xhci_cap_read(void *ptr, hwaddr reg, unsigned size)
ret = 0x00000000; /* reserved */
break;
default:
- fprintf(stderr, "xhci_cap_read: reg %d unimplemented\n", (int)reg);
+ trace_usb_xhci_unimplemented("cap read", reg);
ret = 0;
}
@@ -2790,8 +2787,7 @@ static uint64_t xhci_port_read(void *ptr, hwaddr reg, unsigned size)
break;
case 0x0c: /* reserved */
default:
- fprintf(stderr, "xhci_port_read (port %d): reg 0x%x unimplemented\n",
- port->portnr, (uint32_t)reg);
+ trace_usb_xhci_unimplemented("port read", reg);
ret = 0;
}
@@ -2831,8 +2827,7 @@ static void xhci_port_write(void *ptr, hwaddr reg,
case 0x04: /* PORTPMSC */
case 0x08: /* PORTLI */
default:
- fprintf(stderr, "xhci_port_write (port %d): reg 0x%x unimplemented\n",
- port->portnr, (uint32_t)reg);
+ trace_usb_xhci_unimplemented("port write", reg);
}
}
@@ -2870,7 +2865,7 @@ static uint64_t xhci_oper_read(void *ptr, hwaddr reg, unsigned size)
ret = xhci->config;
break;
default:
- fprintf(stderr, "xhci_oper_read: reg 0x%x unimplemented\n", (int)reg);
+ trace_usb_xhci_unimplemented("oper read", reg);
ret = 0;
}
@@ -2935,7 +2930,7 @@ static void xhci_oper_write(void *ptr, hwaddr reg,
xhci->config = val & 0xff;
break;
default:
- fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", (int)reg);
+ trace_usb_xhci_unimplemented("oper write", reg);
}
}
@@ -2951,8 +2946,7 @@ static uint64_t xhci_runtime_read(void *ptr, hwaddr reg,
ret = xhci_mfindex_get(xhci) & 0x3fff;
break;
default:
- fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n",
- (int)reg);
+ trace_usb_xhci_unimplemented("runtime read", reg);
break;
}
} else {
@@ -2996,7 +2990,7 @@ static void xhci_runtime_write(void *ptr, hwaddr reg,
trace_usb_xhci_runtime_write(reg, val);
if (reg < 0x20) {
- fprintf(stderr, "%s: reg 0x%x unimplemented\n", __func__, (int)reg);
+ trace_usb_xhci_unimplemented("runtime write", reg);
return;
}
@@ -3038,8 +3032,7 @@ static void xhci_runtime_write(void *ptr, hwaddr reg,
xhci_events_update(xhci, v);
break;
default:
- fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n",
- (int)reg);
+ trace_usb_xhci_unimplemented("oper write", reg);
}
}
@@ -3290,6 +3283,9 @@ static int usb_xhci_initfn(struct PCIDevice *dev)
if (xhci->numintrs > MAXINTRS) {
xhci->numintrs = MAXINTRS;
}
+ while (xhci->numintrs & (xhci->numintrs - 1)) { /* ! power of 2 */
+ xhci->numintrs++;
+ }
if (xhci->numintrs < 1) {
xhci->numintrs = 1;
}
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index d02a7b94c4..0ddb0818d8 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -104,6 +104,8 @@ struct USBRedirDevice {
/* Data passed from chardev the fd_read cb to the usbredirparser read cb */
const uint8_t *read_buf;
int read_buf_size;
+ /* Active chardev-watch-tag */
+ guint watch;
/* For async handling of close */
QEMUBH *chardev_close_bh;
/* To delay the usb attach in case of quick chardev close + open */
@@ -254,9 +256,21 @@ static int usbredir_read(void *priv, uint8_t *data, int count)
return count;
}
+static gboolean usbredir_write_unblocked(GIOChannel *chan, GIOCondition cond,
+ void *opaque)
+{
+ USBRedirDevice *dev = opaque;
+
+ dev->watch = 0;
+ usbredirparser_do_write(dev->parser);
+
+ return FALSE;
+}
+
static int usbredir_write(void *priv, uint8_t *data, int count)
{
USBRedirDevice *dev = priv;
+ int r;
if (!dev->cs->be_open) {
return 0;
@@ -267,7 +281,17 @@ static int usbredir_write(void *priv, uint8_t *data, int count)
return 0;
}
- return qemu_chr_fe_write(dev->cs, data, count);
+ r = qemu_chr_fe_write(dev->cs, data, count);
+ if (r < count) {
+ if (!dev->watch) {
+ dev->watch = qemu_chr_fe_add_watch(dev->cs, G_IO_OUT,
+ usbredir_write_unblocked, dev);
+ }
+ if (r < 0) {
+ r = 0;
+ }
+ }
+ return r;
}
/*
@@ -1085,6 +1109,10 @@ static void usbredir_chardev_close_bh(void *opaque)
usbredirparser_destroy(dev->parser);
dev->parser = NULL;
}
+ if (dev->watch) {
+ g_source_remove(dev->watch);
+ dev->watch = 0;
+ }
}
static void usbredir_create_parser(USBRedirDevice *dev)
@@ -1317,6 +1345,9 @@ static void usbredir_handle_destroy(USBDevice *udev)
if (dev->parser) {
usbredirparser_destroy(dev->parser);
}
+ if (dev->watch) {
+ g_source_remove(dev->watch);
+ }
free(dev->filter_rules);
}
@@ -1973,6 +2004,10 @@ static int usbredir_post_load(void *priv, int version_id)
{
USBRedirDevice *dev = priv;
+ if (dev->parser == NULL) {
+ return 0;
+ }
+
switch (dev->device_info.speed) {
case usb_redir_speed_low:
dev->dev.speed = USB_SPEED_LOW;
diff --git a/hw/vfio_pci.c b/hw/vfio_pci.c
index 288361d0fb..693a9ffdda 100644
--- a/hw/vfio_pci.c
+++ b/hw/vfio_pci.c
@@ -19,25 +19,26 @@
*/
#include <dirent.h>
-#include <unistd.h>
+#include <linux/vfio.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <linux/vfio.h>
+#include <unistd.h>
#include "config.h"
-#include "qemu/event_notifier.h"
#include "exec/address-spaces.h"
-#include "sysemu/kvm.h"
#include "exec/memory.h"
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
#include "hw/pci/pci.h"
#include "qemu-common.h"
#include "qemu/error-report.h"
+#include "qemu/event_notifier.h"
#include "qemu/queue.h"
#include "qemu/range.h"
+#include "sysemu/kvm.h"
+#include "sysemu/sysemu.h"
/* #define DEBUG_VFIO */
#ifdef DEBUG_VFIO
@@ -48,6 +49,20 @@
do { } while (0)
#endif
+/* Extra debugging, trap acceleration paths for more logging */
+#define VFIO_ALLOW_MMAP 1
+#define VFIO_ALLOW_KVM_INTX 1
+
+struct VFIODevice;
+
+typedef struct VFIOQuirk {
+ MemoryRegion mem;
+ struct VFIODevice *vdev;
+ QLIST_ENTRY(VFIOQuirk) next;
+ uint32_t data;
+ uint32_t data2;
+} VFIOQuirk;
+
typedef struct VFIOBAR {
off_t fd_offset; /* offset of BAR within device fd */
int fd; /* device fd, allows us to pass VFIOBAR as opaque data */
@@ -57,8 +72,22 @@ typedef struct VFIOBAR {
size_t size;
uint32_t flags; /* VFIO region flags (rd/wr/mmap) */
uint8_t nr; /* cache the BAR number for debug */
+ QLIST_HEAD(, VFIOQuirk) quirks;
} VFIOBAR;
+typedef struct VFIOVGARegion {
+ MemoryRegion mem;
+ off_t offset;
+ int nr;
+ QLIST_HEAD(, VFIOQuirk) quirks;
+} VFIOVGARegion;
+
+typedef struct VFIOVGA {
+ off_t fd_offset;
+ int fd;
+ VFIOVGARegion region[QEMU_PCI_VGA_NUM_REGIONS];
+} VFIOVGA;
+
typedef struct VFIOINTx {
bool pending; /* interrupt pending */
bool kvm_accel; /* set when QEMU bypass through KVM enabled */
@@ -70,8 +99,6 @@ typedef struct VFIOINTx {
QEMUTimer *mmap_timer; /* enable mmaps after periods w/o interrupts */
} VFIOINTx;
-struct VFIODevice;
-
typedef struct VFIOMSIVector {
EventNotifier interrupt; /* eventfd triggered on interrupt */
struct VFIODevice *vdev; /* back pointer to device */
@@ -117,6 +144,7 @@ typedef struct VFIODevice {
int fd;
VFIOINTx intx;
unsigned int config_size;
+ uint8_t *emulated_config_bits; /* QEMU emulated bits, little-endian */
off_t config_offset; /* Offset of config space region within device fd */
unsigned int rom_size;
off_t rom_offset; /* Offset of ROM region within device fd */
@@ -126,10 +154,17 @@ typedef struct VFIODevice {
int nr_vectors; /* Number of MSI/MSIX vectors currently in use */
int interrupt; /* Current interrupt type */
VFIOBAR bars[PCI_NUM_REGIONS - 1]; /* No ROM */
+ VFIOVGA vga; /* 0xa0000, 0x3b0, 0x3c0 */
PCIHostDeviceAddress host;
QLIST_ENTRY(VFIODevice) next;
struct VFIOGroup *group;
+ uint32_t features;
+#define VFIO_FEATURE_ENABLE_VGA_BIT 0
+#define VFIO_FEATURE_ENABLE_VGA (1 << VFIO_FEATURE_ENABLE_VGA_BIT)
+ int32_t bootindex;
+ uint8_t pm_cap;
bool reset_works;
+ bool has_vga;
} VFIODevice;
typedef struct VFIOGroup {
@@ -151,6 +186,8 @@ static QLIST_HEAD(, VFIOGroup)
static void vfio_disable_interrupts(VFIODevice *vdev);
static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len);
+static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr,
+ uint32_t val, int len);
static void vfio_mmap_set_enabled(VFIODevice *vdev, bool enabled);
/*
@@ -275,7 +312,7 @@ static void vfio_enable_intx_kvm(VFIODevice *vdev)
int ret, argsz;
int32_t *pfd;
- if (!kvm_irqfds_enabled() ||
+ if (!VFIO_ALLOW_KVM_INTX || !kvm_irqfds_enabled() ||
vdev->intx.route.mode != PCI_INTX_ENABLED ||
!kvm_check_extension(kvm_state, KVM_CAP_IRQFD_RESAMPLE)) {
return;
@@ -895,8 +932,16 @@ static void vfio_bar_write(void *opaque, hwaddr addr,
__func__, addr, data, size);
}
- DPRINTF("%s(BAR%d+0x%"HWADDR_PRIx", 0x%"PRIx64", %d)\n",
- __func__, bar->nr, addr, data, size);
+#ifdef DEBUG_VFIO
+ {
+ VFIODevice *vdev = container_of(bar, VFIODevice, bars[bar->nr]);
+
+ DPRINTF("%s(%04x:%02x:%02x.%x:BAR%d+0x%"HWADDR_PRIx", 0x%"PRIx64
+ ", %d)\n", __func__, vdev->host.domain, vdev->host.bus,
+ vdev->host.slot, vdev->host.function, bar->nr, addr,
+ data, size);
+ }
+#endif
/*
* A read or write to a BAR always signals an INTx EOI. This will
@@ -942,8 +987,16 @@ static uint64_t vfio_bar_read(void *opaque,
break;
}
- DPRINTF("%s(BAR%d+0x%"HWADDR_PRIx", %d) = 0x%"PRIx64"\n",
- __func__, bar->nr, addr, size, data);
+#ifdef DEBUG_VFIO
+ {
+ VFIODevice *vdev = container_of(bar, VFIODevice, bars[bar->nr]);
+
+ DPRINTF("%s(%04x:%02x:%02x.%x:BAR%d+0x%"HWADDR_PRIx
+ ", %d) = 0x%"PRIx64"\n", __func__, vdev->host.domain,
+ vdev->host.bus, vdev->host.slot, vdev->host.function,
+ bar->nr, addr, size, data);
+ }
+#endif
/* Same as write above */
vfio_eoi(container_of(bar, VFIODevice, bars[bar->nr]));
@@ -957,51 +1010,813 @@ static const MemoryRegionOps vfio_bar_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
+static void vfio_vga_write(void *opaque, hwaddr addr,
+ uint64_t data, unsigned size)
+{
+ VFIOVGARegion *region = opaque;
+ VFIOVGA *vga = container_of(region, VFIOVGA, region[region->nr]);
+ union {
+ uint8_t byte;
+ uint16_t word;
+ uint32_t dword;
+ uint64_t qword;
+ } buf;
+ off_t offset = vga->fd_offset + region->offset + addr;
+
+ switch (size) {
+ case 1:
+ buf.byte = data;
+ break;
+ case 2:
+ buf.word = cpu_to_le16(data);
+ break;
+ case 4:
+ buf.dword = cpu_to_le32(data);
+ break;
+ default:
+ hw_error("vfio: unsupported write size, %d bytes\n", size);
+ break;
+ }
+
+ if (pwrite(vga->fd, &buf, size, offset) != size) {
+ error_report("%s(,0x%"HWADDR_PRIx", 0x%"PRIx64", %d) failed: %m",
+ __func__, region->offset + addr, data, size);
+ }
+
+ DPRINTF("%s(0x%"HWADDR_PRIx", 0x%"PRIx64", %d)\n",
+ __func__, region->offset + addr, data, size);
+}
+
+static uint64_t vfio_vga_read(void *opaque, hwaddr addr, unsigned size)
+{
+ VFIOVGARegion *region = opaque;
+ VFIOVGA *vga = container_of(region, VFIOVGA, region[region->nr]);
+ union {
+ uint8_t byte;
+ uint16_t word;
+ uint32_t dword;
+ uint64_t qword;
+ } buf;
+ uint64_t data = 0;
+ off_t offset = vga->fd_offset + region->offset + addr;
+
+ if (pread(vga->fd, &buf, size, offset) != size) {
+ error_report("%s(,0x%"HWADDR_PRIx", %d) failed: %m",
+ __func__, region->offset + addr, size);
+ return (uint64_t)-1;
+ }
+
+ switch (size) {
+ case 1:
+ data = buf.byte;
+ break;
+ case 2:
+ data = le16_to_cpu(buf.word);
+ break;
+ case 4:
+ data = le32_to_cpu(buf.dword);
+ break;
+ default:
+ hw_error("vfio: unsupported read size, %d bytes\n", size);
+ break;
+ }
+
+ DPRINTF("%s(0x%"HWADDR_PRIx", %d) = 0x%"PRIx64"\n",
+ __func__, region->offset + addr, size, data);
+
+ return data;
+}
+
+static const MemoryRegionOps vfio_vga_ops = {
+ .read = vfio_vga_read,
+ .write = vfio_vga_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
/*
- * PCI config space
+ * Device specific quirks
*/
-static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len)
+
+#define PCI_VENDOR_ID_ATI 0x1002
+
+/*
+ * Device 1002:68f9 (Advanced Micro Devices [AMD] nee ATI Cedar PRO [Radeon
+ * HD 5450/6350]) reports the upper byte of the physical address of the
+ * I/O port BAR4 through VGA register 0x3c3. The BAR is 256 bytes, so the
+ * lower byte is known to be zero. Probing for this quirk reads 0xff from
+ * port 0x3c3 on some devices so we store the physical address and replace
+ * reads with the virtual address any time it matches. XXX Research when
+ * to enable quirk.
+ */
+static uint64_t vfio_ati_3c3_quirk_read(void *opaque,
+ hwaddr addr, unsigned size)
{
- VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
- uint32_t val = 0;
+ VFIOQuirk *quirk = opaque;
+ VFIODevice *vdev = quirk->vdev;
+ PCIDevice *pdev = &vdev->pdev;
+ uint64_t data = vfio_vga_read(&vdev->vga.region[QEMU_PCI_VGA_IO_HI],
+ addr + 0x3, size);
+
+ if (data == quirk->data) {
+ data = pci_get_byte(pdev->config + PCI_BASE_ADDRESS_4 + 1);
+ DPRINTF("%s(0x3c3, 1) = 0x%"PRIx64"\n", __func__, data);
+ }
+
+ return data;
+}
+
+static const MemoryRegionOps vfio_ati_3c3_quirk = {
+ .read = vfio_ati_3c3_quirk_read,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void vfio_vga_probe_ati_3c3_quirk(VFIODevice *vdev)
+{
+ PCIDevice *pdev = &vdev->pdev;
+ off_t physoffset = vdev->config_offset + PCI_BASE_ADDRESS_4;
+ uint32_t physbar;
+ VFIOQuirk *quirk;
+
+ if (pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_ATI ||
+ vdev->bars[4].size < 256) {
+ return;
+ }
+
+ /* Get I/O port BAR physical address */
+ if (pread(vdev->fd, &physbar, 4, physoffset) != 4) {
+ error_report("vfio: probe failed for ATI/AMD 0x3c3 quirk on device "
+ "%04x:%02x:%02x.%x", vdev->host.domain,
+ vdev->host.bus, vdev->host.slot, vdev->host.function);
+ return;
+ }
+
+ quirk = g_malloc0(sizeof(*quirk));
+ quirk->vdev = vdev;
+ quirk->data = (physbar >> 8) & 0xff;
+
+ memory_region_init_io(&quirk->mem, &vfio_ati_3c3_quirk, quirk,
+ "vfio-ati-3c3-quirk", 1);
+ memory_region_add_subregion(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem, 3,
+ &quirk->mem);
+
+ QLIST_INSERT_HEAD(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks,
+ quirk, next);
+
+ DPRINTF("Enabled ATI/AMD quirk 0x3c3 for device %04x:%02x:%02x.%x\n",
+ vdev->host.domain, vdev->host.bus, vdev->host.slot,
+ vdev->host.function);
+}
+
+/*
+ * Device 1002:68f9 (Advanced Micro Devices [AMD] nee ATI Cedar PRO [Radeon
+ * HD 5450/6350]) reports the physical address of MMIO BAR0 through a
+ * write/read operation on I/O port BAR4. When uint32_t 0x4010 is written
+ * to offset 0x0, the subsequent read from offset 0x4 returns the contents
+ * of BAR0. Test for this quirk on all ATI/AMD devices. XXX - Note that
+ * 0x10 is the offset of BAR0 in config sapce, is this a window to all of
+ * config space?
+ */
+static uint64_t vfio_ati_4010_quirk_read(void *opaque,
+ hwaddr addr, unsigned size)
+{
+ VFIOQuirk *quirk = opaque;
+ VFIODevice *vdev = quirk->vdev;
+ PCIDevice *pdev = &vdev->pdev;
+ uint64_t data = vfio_bar_read(&vdev->bars[4], addr, size);
+
+ if (addr == 4 && size == 4 && quirk->data) {
+ data = pci_get_long(pdev->config + PCI_BASE_ADDRESS_0);
+ DPRINTF("%s(BAR4+0x4) = 0x%"PRIx64"\n", __func__, data);
+ }
+
+ quirk->data = 0;
+
+ return data;
+}
+
+static void vfio_ati_4010_quirk_write(void *opaque, hwaddr addr,
+ uint64_t data, unsigned size)
+{
+ VFIOQuirk *quirk = opaque;
+ VFIODevice *vdev = quirk->vdev;
+
+ vfio_bar_write(&vdev->bars[4], addr, data, size);
+
+ quirk->data = (addr == 0 && size == 4 && data == 0x4010) ? 1 : 0;
+}
+
+static const MemoryRegionOps vfio_ati_4010_quirk = {
+ .read = vfio_ati_4010_quirk_read,
+ .write = vfio_ati_4010_quirk_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void vfio_probe_ati_4010_quirk(VFIODevice *vdev, int nr)
+{
+ PCIDevice *pdev = &vdev->pdev;
+ off_t physoffset = vdev->config_offset + PCI_BASE_ADDRESS_0;
+ uint32_t physbar0;
+ uint64_t data;
+ VFIOQuirk *quirk;
+
+ if (!vdev->has_vga || nr != 4 || !vdev->bars[0].size ||
+ pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_ATI) {
+ return;
+ }
+
+ /* Get I/O port BAR physical address */
+ if (pread(vdev->fd, &physbar0, 4, physoffset) != 4) {
+ error_report("vfio: probe failed for ATI/AMD 0x4010 quirk on device "
+ "%04x:%02x:%02x.%x", vdev->host.domain,
+ vdev->host.bus, vdev->host.slot, vdev->host.function);
+ return;
+ }
+
+ /* Write 0x4010 to I/O port BAR offset 0 */
+ vfio_bar_write(&vdev->bars[4], 0, 0x4010, 4);
+ /* Read back result */
+ data = vfio_bar_read(&vdev->bars[4], 4, 4);
+
+ /* If the register matches the physical address of BAR0, we need a quirk */
+ if (data != physbar0) {
+ return;
+ }
+
+ quirk = g_malloc0(sizeof(*quirk));
+ quirk->vdev = vdev;
+
+ memory_region_init_io(&quirk->mem, &vfio_ati_4010_quirk, quirk,
+ "vfio-ati-4010-quirk", 8);
+ memory_region_add_subregion_overlap(&vdev->bars[nr].mem, 0, &quirk->mem, 1);
+
+ QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
+
+ DPRINTF("Enabled ATI/AMD quirk 0x4010 for device %04x:%02x:%02x.%x\n",
+ vdev->host.domain, vdev->host.bus, vdev->host.slot,
+ vdev->host.function);
+}
+
+/*
+ * Device 1002:5b63 (Advanced Micro Devices [AMD] nee ATI RV370 [Radeon X550])
+ * retrieves the upper half of the MMIO BAR0 physical address by writing
+ * 0xf10 to I/O port BAR1 offset 0 and reading the result from offset 6.
+ * XXX - 0x10 is the offset of BAR0 in PCI config space, this could provide
+ * full access to config space. Config space is little endian, so the data
+ * register probably starts at 0x4.
+ */
+static uint64_t vfio_ati_f10_quirk_read(void *opaque,
+ hwaddr addr, unsigned size)
+{
+ VFIOQuirk *quirk = opaque;
+ VFIODevice *vdev = quirk->vdev;
+ PCIDevice *pdev = &vdev->pdev;
+ uint64_t data = vfio_bar_read(&vdev->bars[1], addr, size);
+
+ if (addr == 6 && size == 2 && quirk->data) {
+ data = pci_get_word(pdev->config + PCI_BASE_ADDRESS_0 + 2);
+ DPRINTF("%s(BAR1+0x6) = 0x%"PRIx64"\n", __func__, data);
+ }
+
+ quirk->data = 0;
+
+ return data;
+}
+
+static void vfio_ati_f10_quirk_write(void *opaque, hwaddr addr,
+ uint64_t data, unsigned size)
+{
+ VFIOQuirk *quirk = opaque;
+ VFIODevice *vdev = quirk->vdev;
+
+ vfio_bar_write(&vdev->bars[1], addr, data, size);
+
+ quirk->data = (addr == 0 && size == 4 && data == 0xf10) ? 1 : 0;
+}
+
+static const MemoryRegionOps vfio_ati_f10_quirk = {
+ .read = vfio_ati_f10_quirk_read,
+ .write = vfio_ati_f10_quirk_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void vfio_probe_ati_f10_quirk(VFIODevice *vdev, int nr)
+{
+ PCIDevice *pdev = &vdev->pdev;
+ off_t physoffset = vdev->config_offset + PCI_BASE_ADDRESS_0;
+ uint32_t physbar0;
+ uint64_t data;
+ VFIOQuirk *quirk;
+
+ if (!vdev->has_vga || nr != 1 || !vdev->bars[0].size ||
+ pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_ATI) {
+ return;
+ }
+
+ /* Get I/O port BAR physical address */
+ if (pread(vdev->fd, &physbar0, 4, physoffset) != 4) {
+ error_report("vfio: probe failed for ATI/AMD 0xf10 quirk on device "
+ "%04x:%02x:%02x.%x", vdev->host.domain,
+ vdev->host.bus, vdev->host.slot, vdev->host.function);
+ return;
+ }
+
+ vfio_bar_write(&vdev->bars[1], 0, 0xf10, 4);
+ data = vfio_bar_read(&vdev->bars[1], 0x6, 2);
+
+ /* If the register matches the physical address of BAR0, we need a quirk */
+ if (data != (le32_to_cpu(physbar0) >> 16)) {
+ return;
+ }
+
+ quirk = g_malloc0(sizeof(*quirk));
+ quirk->vdev = vdev;
+
+ memory_region_init_io(&quirk->mem, &vfio_ati_f10_quirk, quirk,
+ "vfio-ati-f10-quirk", 8);
+ memory_region_add_subregion_overlap(&vdev->bars[nr].mem, 0, &quirk->mem, 1);
+
+ QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
+
+ DPRINTF("Enabled ATI/AMD quirk 0xf10 for device %04x:%02x:%02x.%x\n",
+ vdev->host.domain, vdev->host.bus, vdev->host.slot,
+ vdev->host.function);
+}
+
+#define PCI_VENDOR_ID_NVIDIA 0x10de
+
+/*
+ * Nvidia has several different methods to get to config space, the
+ * nouveu project has several of these documented here:
+ * https://github.com/pathscale/envytools/tree/master/hwdocs
+ *
+ * The first quirk is actually not documented in envytools and is found
+ * on 10de:01d1 (NVIDIA Corporation G72 [GeForce 7300 LE]). This is an
+ * NV46 chipset. The backdoor uses the legacy VGA I/O ports to access
+ * the mirror of PCI config space found at BAR0 offset 0x1800. The access
+ * sequence first writes 0x338 to I/O port 0x3d4. The target offset is
+ * then written to 0x3d0. Finally 0x538 is written for a read and 0x738
+ * is written for a write to 0x3d4. The BAR0 offset is then accessible
+ * through 0x3d0. This quirk doesn't seem to be necessary on newer cards
+ * that use the I/O port BAR5 window but it doesn't hurt to leave it.
+ */
+enum {
+ NV_3D0_NONE,
+ NV_3D0_SELECT,
+ NV_3D0_WINDOW,
+ NV_3D0_READ,
+ NV_3D0_WRITE,
+};
+
+static uint64_t vfio_nvidia_3d0_quirk_read(void *opaque,
+ hwaddr addr, unsigned size)
+{
+ VFIOQuirk *quirk = opaque;
+ VFIODevice *vdev = quirk->vdev;
+ PCIDevice *pdev = &vdev->pdev;
+ uint64_t data = vfio_vga_read(&vdev->vga.region[QEMU_PCI_VGA_IO_HI],
+ addr + 0x10, size);
+
+ if (quirk->data == NV_3D0_READ && addr == 0) {
+ data = vfio_pci_read_config(pdev, quirk->data2, size);
+ DPRINTF("%s(0x3d0, %d) = 0x%"PRIx64"\n", __func__, size, data);
+ }
+
+ quirk->data = NV_3D0_NONE;
+
+ return data;
+}
+
+static void vfio_nvidia_3d0_quirk_write(void *opaque, hwaddr addr,
+ uint64_t data, unsigned size)
+{
+ VFIOQuirk *quirk = opaque;
+ VFIODevice *vdev = quirk->vdev;
+ PCIDevice *pdev = &vdev->pdev;
+
+ switch (quirk->data) {
+ case NV_3D0_NONE:
+ if (addr == 4 && data == 0x338) {
+ quirk->data = NV_3D0_SELECT;
+ }
+ break;
+ case NV_3D0_SELECT:
+ quirk->data = NV_3D0_NONE;
+ if (addr == 0 && (data & ~0xff) == 0x1800) {
+ quirk->data = NV_3D0_WINDOW;
+ quirk->data2 = data & 0xff;
+ }
+ break;
+ case NV_3D0_WINDOW:
+ quirk->data = NV_3D0_NONE;
+ if (addr == 4) {
+ if (data == 0x538) {
+ quirk->data = NV_3D0_READ;
+ } else if (data == 0x738) {
+ quirk->data = NV_3D0_WRITE;
+ }
+ }
+ break;
+ case NV_3D0_WRITE:
+ quirk->data = NV_3D0_NONE;
+ if (addr == 0) {
+ vfio_pci_write_config(pdev, quirk->data2, data, size);
+ DPRINTF("%s(0x3d0, 0x%"PRIx64", %d)\n", __func__, data, size);
+ return;
+ }
+ break;
+ default:
+ quirk->data = NV_3D0_NONE;
+ }
+
+ vfio_vga_write(&vdev->vga.region[QEMU_PCI_VGA_IO_HI],
+ addr + 0x10, data, size);
+}
+
+static const MemoryRegionOps vfio_nvidia_3d0_quirk = {
+ .read = vfio_nvidia_3d0_quirk_read,
+ .write = vfio_nvidia_3d0_quirk_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void vfio_vga_probe_nvidia_3d0_quirk(VFIODevice *vdev)
+{
+ PCIDevice *pdev = &vdev->pdev;
+ VFIOQuirk *quirk;
+
+ if (pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA ||
+ !vdev->bars[1].size) {
+ return;
+ }
+
+ quirk = g_malloc0(sizeof(*quirk));
+ quirk->vdev = vdev;
+
+ memory_region_init_io(&quirk->mem, &vfio_nvidia_3d0_quirk, quirk,
+ "vfio-nvidia-3d0-quirk", 6);
+ memory_region_add_subregion(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem,
+ 0x10, &quirk->mem);
+
+ QLIST_INSERT_HEAD(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks,
+ quirk, next);
+
+ DPRINTF("Enabled NVIDIA VGA 0x3d0 quirk for device %04x:%02x:%02x.%x\n",
+ vdev->host.domain, vdev->host.bus, vdev->host.slot,
+ vdev->host.function);
+}
+
+/*
+ * The second quirk is documented in envytools. The I/O port BAR5 is just
+ * a set of address/data ports to the MMIO BARs. The BAR we care about is
+ * again BAR0. This backdoor is apparently a bit newer than the one above
+ * so we need to not only trap 256 bytes @0x1800, but all of PCI config
+ * space, including extended space is available at the 4k @0x88000.
+ */
+enum {
+ NV_BAR5_ADDRESS = 0x1,
+ NV_BAR5_ENABLE = 0x2,
+ NV_BAR5_MASTER = 0x4,
+ NV_BAR5_VALID = 0x7,
+};
+
+static uint64_t vfio_nvidia_bar5_window_quirk_read(void *opaque,
+ hwaddr addr, unsigned size)
+{
+ VFIOQuirk *quirk = opaque;
+ VFIODevice *vdev = quirk->vdev;
+ uint64_t data = vfio_bar_read(&vdev->bars[5], addr, size);
+
+ if (addr == 0xc && quirk->data == NV_BAR5_VALID) {
+ data = vfio_pci_read_config(&vdev->pdev, quirk->data2, size);
+ DPRINTF("%s(%04x:%02x:%02x.%x:BAR5+0x%"HWADDR_PRIx", %d) = 0x%"
+ PRIx64"\n", __func__, vdev->host.domain, vdev->host.bus,
+ vdev->host.slot, vdev->host.function, addr, size, data);
+ }
+
+ return data;
+}
+
+static void vfio_nvidia_bar5_window_quirk_write(void *opaque, hwaddr addr,
+ uint64_t data, unsigned size)
+{
+ VFIOQuirk *quirk = opaque;
+ VFIODevice *vdev = quirk->vdev;
/*
- * We only need QEMU PCI config support for the ROM BAR, the MSI and MSIX
- * capabilities, and the multifunction bit below. We let VFIO handle
- * virtualizing everything else. Performance is not a concern here.
+ * Use quirk->data to track enables and quirk->data2 for the offset
*/
- if (ranges_overlap(addr, len, PCI_ROM_ADDRESS, 4) ||
- (pdev->cap_present & QEMU_PCI_CAP_MSIX &&
- ranges_overlap(addr, len, pdev->msix_cap, MSIX_CAP_LENGTH)) ||
- (pdev->cap_present & QEMU_PCI_CAP_MSI &&
- ranges_overlap(addr, len, pdev->msi_cap, vdev->msi_cap_size))) {
+ switch (addr) {
+ case 0x0:
+ if (data & 0x1) {
+ quirk->data |= NV_BAR5_MASTER;
+ } else {
+ quirk->data &= ~NV_BAR5_MASTER;
+ }
+ break;
+ case 0x4:
+ if (data & 0x1) {
+ quirk->data |= NV_BAR5_ENABLE;
+ } else {
+ quirk->data &= ~NV_BAR5_ENABLE;
+ }
+ break;
+ case 0x8:
+ if (quirk->data & NV_BAR5_MASTER) {
+ if ((data & ~0xfff) == 0x88000) {
+ quirk->data |= NV_BAR5_ADDRESS;
+ quirk->data2 = data & 0xfff;
+ } else if ((data & ~0xff) == 0x1800) {
+ quirk->data |= NV_BAR5_ADDRESS;
+ quirk->data2 = data & 0xff;
+ } else {
+ quirk->data &= ~NV_BAR5_ADDRESS;
+ }
+ }
+ break;
+ case 0xc:
+ if (quirk->data == NV_BAR5_VALID) {
+ vfio_pci_write_config(&vdev->pdev, quirk->data2, data, size);
+ DPRINTF("%s(%04x:%02x:%02x.%x:BAR5+0x%"HWADDR_PRIx", 0x%"
+ PRIx64", %d)\n", __func__, vdev->host.domain,
+ vdev->host.bus, vdev->host.slot, vdev->host.function,
+ addr, data, size);
+ return;
+ }
+ }
+
+ vfio_bar_write(&vdev->bars[5], addr, data, size);
+}
+
+static const MemoryRegionOps vfio_nvidia_bar5_window_quirk = {
+ .read = vfio_nvidia_bar5_window_quirk_read,
+ .write = vfio_nvidia_bar5_window_quirk_write,
+ .valid.min_access_size = 4,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void vfio_probe_nvidia_bar5_window_quirk(VFIODevice *vdev, int nr)
+{
+ PCIDevice *pdev = &vdev->pdev;
+ VFIOQuirk *quirk;
+
+ if (!vdev->has_vga || nr != 5 ||
+ pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA) {
+ return;
+ }
+
+ quirk = g_malloc0(sizeof(*quirk));
+ quirk->vdev = vdev;
+
+ memory_region_init_io(&quirk->mem, &vfio_nvidia_bar5_window_quirk, quirk,
+ "vfio-nvidia-bar5-window-quirk", 16);
+ memory_region_add_subregion_overlap(&vdev->bars[nr].mem, 0, &quirk->mem, 1);
+
+ QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
+
+ DPRINTF("Enabled NVIDIA BAR5 window quirk for device %04x:%02x:%02x.%x\n",
+ vdev->host.domain, vdev->host.bus, vdev->host.slot,
+ vdev->host.function);
+}
+
+/*
+ * Finally, BAR0 itself. We want to redirect any accesses to either
+ * 0x1800 or 0x88000 through the PCI config space access functions.
+ *
+ * NB - quirk at a page granularity or else they don't seem to work when
+ * BARs are mmap'd
+ *
+ * Here's offset 0x88000...
+ */
+static uint64_t vfio_nvidia_bar0_88000_quirk_read(void *opaque,
+ hwaddr addr, unsigned size)
+{
+ VFIOQuirk *quirk = opaque;
+ VFIODevice *vdev = quirk->vdev;
+ hwaddr base = 0x88000 & TARGET_PAGE_MASK;
+ hwaddr offset = 0x88000 & ~TARGET_PAGE_MASK;
+ uint64_t data = vfio_bar_read(&vdev->bars[0], addr + base, size);
+
+ if (ranges_overlap(addr, size, offset, PCI_CONFIG_SPACE_SIZE)) {
+ data = vfio_pci_read_config(&vdev->pdev, addr - offset, size);
+
+ DPRINTF("%s(%04x:%02x:%02x.%x:BAR0+0x%"HWADDR_PRIx", %d) = 0x%"
+ PRIx64"\n", __func__, vdev->host.domain, vdev->host.bus,
+ vdev->host.slot, vdev->host.function, addr + base, size, data);
+ }
+
+ return data;
+}
+
+static void vfio_nvidia_bar0_88000_quirk_write(void *opaque, hwaddr addr,
+ uint64_t data, unsigned size)
+{
+ VFIOQuirk *quirk = opaque;
+ VFIODevice *vdev = quirk->vdev;
+ hwaddr base = 0x88000 & TARGET_PAGE_MASK;
+ hwaddr offset = 0x88000 & ~TARGET_PAGE_MASK;
+
+ if (ranges_overlap(addr, size, offset, PCI_CONFIG_SPACE_SIZE)) {
+ vfio_pci_write_config(&vdev->pdev, addr - offset, data, size);
- val = pci_default_read_config(pdev, addr, len);
+ DPRINTF("%s(%04x:%02x:%02x.%x:BAR0+0x%"HWADDR_PRIx", 0x%"
+ PRIx64", %d)\n", __func__, vdev->host.domain, vdev->host.bus,
+ vdev->host.slot, vdev->host.function, addr + base, data, size);
} else {
- if (pread(vdev->fd, &val, len, vdev->config_offset + addr) != len) {
- error_report("%s(%04x:%02x:%02x.%x, 0x%x, 0x%x) failed: %m",
- __func__, vdev->host.domain, vdev->host.bus,
- vdev->host.slot, vdev->host.function, addr, len);
- return -errno;
- }
- val = le32_to_cpu(val);
+ vfio_bar_write(&vdev->bars[0], addr + base, data, size);
}
+}
+
+static const MemoryRegionOps vfio_nvidia_bar0_88000_quirk = {
+ .read = vfio_nvidia_bar0_88000_quirk_read,
+ .write = vfio_nvidia_bar0_88000_quirk_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
- /* Multifunction bit is virualized in QEMU */
- if (unlikely(ranges_overlap(addr, len, PCI_HEADER_TYPE, 1))) {
- uint32_t mask = PCI_HEADER_TYPE_MULTI_FUNCTION;
+static void vfio_probe_nvidia_bar0_88000_quirk(VFIODevice *vdev, int nr)
+{
+ PCIDevice *pdev = &vdev->pdev;
+ VFIOQuirk *quirk;
- if (len == 4) {
- mask <<= 16;
+ if (!vdev->has_vga || nr != 0 ||
+ pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA) {
+ return;
+ }
+
+ quirk = g_malloc0(sizeof(*quirk));
+ quirk->vdev = vdev;
+
+ memory_region_init_io(&quirk->mem, &vfio_nvidia_bar0_88000_quirk, quirk,
+ "vfio-nvidia-bar0-88000-quirk",
+ TARGET_PAGE_ALIGN(PCIE_CONFIG_SPACE_SIZE));
+ memory_region_add_subregion_overlap(&vdev->bars[nr].mem,
+ 0x88000 & TARGET_PAGE_MASK,
+ &quirk->mem, 1);
+
+ QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
+
+ DPRINTF("Enabled NVIDIA BAR0 0x88000 quirk for device %04x:%02x:%02x.%x\n",
+ vdev->host.domain, vdev->host.bus, vdev->host.slot,
+ vdev->host.function);
+}
+
+/*
+ * And here's the same for BAR0 offset 0x1800...
+ */
+static uint64_t vfio_nvidia_bar0_1800_quirk_read(void *opaque,
+ hwaddr addr, unsigned size)
+{
+ VFIOQuirk *quirk = opaque;
+ VFIODevice *vdev = quirk->vdev;
+ hwaddr base = 0x1800 & TARGET_PAGE_MASK;
+ hwaddr offset = 0x1800 & ~TARGET_PAGE_MASK;
+ uint64_t data = vfio_bar_read(&vdev->bars[0], addr + base, size);
+
+ if (ranges_overlap(addr, size, offset, PCI_CONFIG_SPACE_SIZE)) {
+ data = vfio_pci_read_config(&vdev->pdev, addr - offset, size);
+
+ DPRINTF("%s(%04x:%02x:%02x.%x:BAR0+0x%"HWADDR_PRIx", %d) = 0x%"
+ PRIx64"\n", __func__, vdev->host.domain, vdev->host.bus,
+ vdev->host.slot, vdev->host.function, addr + base, size, data);
+ }
+
+ return data;
+}
+
+static void vfio_nvidia_bar0_1800_quirk_write(void *opaque, hwaddr addr,
+ uint64_t data, unsigned size)
+{
+ VFIOQuirk *quirk = opaque;
+ VFIODevice *vdev = quirk->vdev;
+ hwaddr base = 0x1800 & TARGET_PAGE_MASK;
+ hwaddr offset = 0x1800 & ~TARGET_PAGE_MASK;
+
+ if (ranges_overlap(addr, size, offset, PCI_CONFIG_SPACE_SIZE)) {
+ vfio_pci_write_config(&vdev->pdev, addr - offset, data, size);
+
+ DPRINTF("%s(%04x:%02x:%02x.%x:BAR0+0x%"HWADDR_PRIx", 0x%"
+ PRIx64", %d)\n", __func__, vdev->host.domain, vdev->host.bus,
+ vdev->host.slot, vdev->host.function, addr + base, data, size);
+ } else {
+ vfio_bar_write(&vdev->bars[0], addr + base, data, size);
+ }
+}
+
+static const MemoryRegionOps vfio_nvidia_bar0_1800_quirk = {
+ .read = vfio_nvidia_bar0_1800_quirk_read,
+ .write = vfio_nvidia_bar0_1800_quirk_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void vfio_probe_nvidia_bar0_1800_quirk(VFIODevice *vdev, int nr)
+{
+ PCIDevice *pdev = &vdev->pdev;
+ VFIOQuirk *quirk;
+
+ if (!vdev->has_vga || nr != 0 ||
+ pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA) {
+ return;
+ }
+
+ /* Log the chipset ID */
+ DPRINTF("Nvidia NV%02x\n",
+ (unsigned int)(vfio_bar_read(&vdev->bars[0], 0, 4) >> 20) & 0xff);
+
+ quirk = g_malloc0(sizeof(*quirk));
+ quirk->vdev = vdev;
+
+ memory_region_init_io(&quirk->mem, &vfio_nvidia_bar0_1800_quirk, quirk,
+ "vfio-nvidia-bar0-1800-quirk",
+ TARGET_PAGE_ALIGN(PCI_CONFIG_SPACE_SIZE));
+ memory_region_add_subregion_overlap(&vdev->bars[nr].mem,
+ 0x1800 & TARGET_PAGE_MASK,
+ &quirk->mem, 1);
+
+ QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
+
+ DPRINTF("Enabled NVIDIA BAR0 0x1800 quirk for device %04x:%02x:%02x.%x\n",
+ vdev->host.domain, vdev->host.bus, vdev->host.slot,
+ vdev->host.function);
+}
+
+/*
+ * TODO - Some Nvidia devices provide config access to their companion HDA
+ * device and even to their parent bridge via these config space mirrors.
+ * Add quirks for those regions.
+ */
+
+/*
+ * Common quirk probe entry points.
+ */
+static void vfio_vga_quirk_setup(VFIODevice *vdev)
+{
+ vfio_vga_probe_ati_3c3_quirk(vdev);
+ vfio_vga_probe_nvidia_3d0_quirk(vdev);
+}
+
+static void vfio_vga_quirk_teardown(VFIODevice *vdev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(vdev->vga.region); i++) {
+ while (!QLIST_EMPTY(&vdev->vga.region[i].quirks)) {
+ VFIOQuirk *quirk = QLIST_FIRST(&vdev->vga.region[i].quirks);
+ memory_region_del_subregion(&vdev->vga.region[i].mem, &quirk->mem);
+ QLIST_REMOVE(quirk, next);
+ g_free(quirk);
}
+ }
+}
- if (pdev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {
- val |= mask;
- } else {
- val &= ~mask;
+static void vfio_bar_quirk_setup(VFIODevice *vdev, int nr)
+{
+ vfio_probe_ati_4010_quirk(vdev, nr);
+ vfio_probe_ati_f10_quirk(vdev, nr);
+ vfio_probe_nvidia_bar5_window_quirk(vdev, nr);
+ vfio_probe_nvidia_bar0_88000_quirk(vdev, nr);
+ vfio_probe_nvidia_bar0_1800_quirk(vdev, nr);
+}
+
+static void vfio_bar_quirk_teardown(VFIODevice *vdev, int nr)
+{
+ VFIOBAR *bar = &vdev->bars[nr];
+
+ while (!QLIST_EMPTY(&bar->quirks)) {
+ VFIOQuirk *quirk = QLIST_FIRST(&bar->quirks);
+ memory_region_del_subregion(&bar->mem, &quirk->mem);
+ QLIST_REMOVE(quirk, next);
+ g_free(quirk);
+ }
+}
+
+/*
+ * PCI config space
+ */
+static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len)
+{
+ VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
+ uint32_t emu_bits = 0, emu_val = 0, phys_val = 0, val;
+
+ memcpy(&emu_bits, vdev->emulated_config_bits + addr, len);
+ emu_bits = le32_to_cpu(emu_bits);
+
+ if (emu_bits) {
+ emu_val = pci_default_read_config(pdev, addr, len);
+ }
+
+ if (~emu_bits & (0xffffffffU >> (32 - len * 8))) {
+ ssize_t ret;
+
+ ret = pread(vdev->fd, &phys_val, len, vdev->config_offset + addr);
+ if (ret != len) {
+ error_report("%s(%04x:%02x:%02x.%x, 0x%x, 0x%x) failed: %m",
+ __func__, vdev->host.domain, vdev->host.bus,
+ vdev->host.slot, vdev->host.function, addr, len);
+ return -errno;
}
+ phys_val = le32_to_cpu(phys_val);
}
+ val = (emu_val & emu_bits) | (phys_val & ~emu_bits);
+
DPRINTF("%s(%04x:%02x:%02x.%x, @0x%x, len=0x%x) %x\n", __func__,
vdev->host.domain, vdev->host.bus, vdev->host.slot,
vdev->host.function, addr, len, val);
@@ -1026,12 +1841,6 @@ static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr,
vdev->host.slot, vdev->host.function, addr, val, len);
}
- /* Write standard header bits to emulation */
- if (addr < PCI_CONFIG_HEADER_SIZE) {
- pci_default_write_config(pdev, addr, val, len);
- return;
- }
-
/* MSI/MSI-X Enabling/Disabling */
if (pdev->cap_present & QEMU_PCI_CAP_MSI &&
ranges_overlap(addr, len, pdev->msi_cap, vdev->msi_cap_size)) {
@@ -1046,9 +1855,7 @@ static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr,
} else if (was_enabled && !is_enabled) {
vfio_disable_msi(vdev);
}
- }
-
- if (pdev->cap_present & QEMU_PCI_CAP_MSIX &&
+ } else if (pdev->cap_present & QEMU_PCI_CAP_MSIX &&
ranges_overlap(addr, len, pdev->msix_cap, MSIX_CAP_LENGTH)) {
int is_enabled, was_enabled = msix_enabled(pdev);
@@ -1061,6 +1868,9 @@ static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr,
} else if (was_enabled && !is_enabled) {
vfio_disable_msix(vdev);
}
+ } else {
+ /* Write everything to QEMU to keep emulated bits correct */
+ pci_default_write_config(pdev, addr, val, len);
}
}
@@ -1130,7 +1940,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
int ret;
if (vfio_listener_skipped_section(section)) {
- DPRINTF("vfio: SKIPPING region_add %"HWADDR_PRIx" - %"PRIx64"\n",
+ DPRINTF("SKIPPING region_add %"HWADDR_PRIx" - %"PRIx64"\n",
section->offset_within_address_space,
section->offset_within_address_space + section->size - 1);
return;
@@ -1154,7 +1964,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
section->offset_within_region +
(iova - section->offset_within_address_space);
- DPRINTF("vfio: region_add %"HWADDR_PRIx" - %"HWADDR_PRIx" [%p]\n",
+ DPRINTF("region_add %"HWADDR_PRIx" - %"HWADDR_PRIx" [%p]\n",
iova, end - 1, vaddr);
ret = vfio_dma_map(container, iova, end - iova, vaddr, section->readonly);
@@ -1174,7 +1984,7 @@ static void vfio_listener_region_del(MemoryListener *listener,
int ret;
if (vfio_listener_skipped_section(section)) {
- DPRINTF("vfio: SKIPPING region_del %"HWADDR_PRIx" - %"PRIx64"\n",
+ DPRINTF("SKIPPING region_del %"HWADDR_PRIx" - %"PRIx64"\n",
section->offset_within_address_space,
section->offset_within_address_space + section->size - 1);
return;
@@ -1194,7 +2004,7 @@ static void vfio_listener_region_del(MemoryListener *listener,
return;
}
- DPRINTF("vfio: region_del %"HWADDR_PRIx" - %"HWADDR_PRIx"\n",
+ DPRINTF("region_del %"HWADDR_PRIx" - %"HWADDR_PRIx"\n",
iova, end - 1);
ret = vfio_dma_unmap(container, iova, end - iova);
@@ -1378,6 +2188,8 @@ static void vfio_unmap_bar(VFIODevice *vdev, int nr)
return;
}
+ vfio_bar_quirk_teardown(vdev, nr);
+
memory_region_del_subregion(&bar->mem, &bar->mmap_mem);
munmap(bar->mmap, memory_region_size(&bar->mmap_mem));
@@ -1395,7 +2207,7 @@ static int vfio_mmap_bar(VFIOBAR *bar, MemoryRegion *mem, MemoryRegion *submem,
{
int ret = 0;
- if (size && bar->flags & VFIO_REGION_INFO_FLAG_MMAP) {
+ if (VFIO_ALLOW_MMAP && size && bar->flags & VFIO_REGION_INFO_FLAG_MMAP) {
int prot = 0;
if (bar->flags & VFIO_REGION_INFO_FLAG_READ) {
@@ -1488,6 +2300,8 @@ static void vfio_map_bar(VFIODevice *vdev, int nr)
error_report("%s unsupported. Performance may be slow", name);
}
}
+
+ vfio_bar_quirk_setup(vdev, nr);
}
static void vfio_map_bars(VFIODevice *vdev)
@@ -1497,6 +2311,29 @@ static void vfio_map_bars(VFIODevice *vdev)
for (i = 0; i < PCI_ROM_SLOT; i++) {
vfio_map_bar(vdev, i);
}
+
+ if (vdev->has_vga) {
+ memory_region_init_io(&vdev->vga.region[QEMU_PCI_VGA_MEM].mem,
+ &vfio_vga_ops,
+ &vdev->vga.region[QEMU_PCI_VGA_MEM],
+ "vfio-vga-mmio@0xa0000",
+ QEMU_PCI_VGA_MEM_SIZE);
+ memory_region_init_io(&vdev->vga.region[QEMU_PCI_VGA_IO_LO].mem,
+ &vfio_vga_ops,
+ &vdev->vga.region[QEMU_PCI_VGA_IO_LO],
+ "vfio-vga-io@0x3b0",
+ QEMU_PCI_VGA_IO_LO_SIZE);
+ memory_region_init_io(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem,
+ &vfio_vga_ops,
+ &vdev->vga.region[QEMU_PCI_VGA_IO_HI],
+ "vfio-vga-io@0x3c0",
+ QEMU_PCI_VGA_IO_HI_SIZE);
+
+ pci_register_vga(&vdev->pdev, &vdev->vga.region[QEMU_PCI_VGA_MEM].mem,
+ &vdev->vga.region[QEMU_PCI_VGA_IO_LO].mem,
+ &vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem);
+ vfio_vga_quirk_setup(vdev);
+ }
}
static void vfio_unmap_bars(VFIODevice *vdev)
@@ -1506,6 +2343,14 @@ static void vfio_unmap_bars(VFIODevice *vdev)
for (i = 0; i < PCI_ROM_SLOT; i++) {
vfio_unmap_bar(vdev, i);
}
+
+ if (vdev->has_vga) {
+ vfio_vga_quirk_teardown(vdev);
+ pci_unregister_vga(&vdev->pdev);
+ memory_region_destroy(&vdev->vga.region[QEMU_PCI_VGA_MEM].mem);
+ memory_region_destroy(&vdev->vga.region[QEMU_PCI_VGA_IO_LO].mem);
+ memory_region_destroy(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem);
+ }
}
/*
@@ -1525,6 +2370,124 @@ static uint8_t vfio_std_cap_max_size(PCIDevice *pdev, uint8_t pos)
return next - pos;
}
+static void vfio_set_word_bits(uint8_t *buf, uint16_t val, uint16_t mask)
+{
+ pci_set_word(buf, (pci_get_word(buf) & ~mask) | val);
+}
+
+static void vfio_add_emulated_word(VFIODevice *vdev, int pos,
+ uint16_t val, uint16_t mask)
+{
+ vfio_set_word_bits(vdev->pdev.config + pos, val, mask);
+ vfio_set_word_bits(vdev->pdev.wmask + pos, ~mask, mask);
+ vfio_set_word_bits(vdev->emulated_config_bits + pos, mask, mask);
+}
+
+static void vfio_set_long_bits(uint8_t *buf, uint32_t val, uint32_t mask)
+{
+ pci_set_long(buf, (pci_get_long(buf) & ~mask) | val);
+}
+
+static void vfio_add_emulated_long(VFIODevice *vdev, int pos,
+ uint32_t val, uint32_t mask)
+{
+ vfio_set_long_bits(vdev->pdev.config + pos, val, mask);
+ vfio_set_long_bits(vdev->pdev.wmask + pos, ~mask, mask);
+ vfio_set_long_bits(vdev->emulated_config_bits + pos, mask, mask);
+}
+
+static int vfio_setup_pcie_cap(VFIODevice *vdev, int pos, uint8_t size)
+{
+ uint16_t flags;
+ uint8_t type;
+
+ flags = pci_get_word(vdev->pdev.config + pos + PCI_CAP_FLAGS);
+ type = (flags & PCI_EXP_FLAGS_TYPE) >> 4;
+
+ if (type != PCI_EXP_TYPE_ENDPOINT &&
+ type != PCI_EXP_TYPE_LEG_END &&
+ type != PCI_EXP_TYPE_RC_END) {
+
+ error_report("vfio: Assignment of PCIe type 0x%x "
+ "devices is not currently supported", type);
+ return -EINVAL;
+ }
+
+ if (!pci_bus_is_express(vdev->pdev.bus)) {
+ /*
+ * Use express capability as-is on PCI bus. It doesn't make much
+ * sense to even expose, but some drivers (ex. tg3) depend on it
+ * and guests don't seem to be particular about it. We'll need
+ * to revist this or force express devices to express buses if we
+ * ever expose an IOMMU to the guest.
+ */
+ } else if (pci_bus_is_root(vdev->pdev.bus)) {
+ /*
+ * On a Root Complex bus Endpoints become Root Complex Integrated
+ * Endpoints, which changes the type and clears the LNK & LNK2 fields.
+ */
+ if (type == PCI_EXP_TYPE_ENDPOINT) {
+ vfio_add_emulated_word(vdev, pos + PCI_CAP_FLAGS,
+ PCI_EXP_TYPE_RC_END << 4,
+ PCI_EXP_FLAGS_TYPE);
+
+ /* Link Capabilities, Status, and Control goes away */
+ if (size > PCI_EXP_LNKCTL) {
+ vfio_add_emulated_long(vdev, pos + PCI_EXP_LNKCAP, 0, ~0);
+ vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKCTL, 0, ~0);
+ vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKSTA, 0, ~0);
+
+#ifndef PCI_EXP_LNKCAP2
+#define PCI_EXP_LNKCAP2 44
+#endif
+#ifndef PCI_EXP_LNKSTA2
+#define PCI_EXP_LNKSTA2 50
+#endif
+ /* Link 2 Capabilities, Status, and Control goes away */
+ if (size > PCI_EXP_LNKCAP2) {
+ vfio_add_emulated_long(vdev, pos + PCI_EXP_LNKCAP2, 0, ~0);
+ vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKCTL2, 0, ~0);
+ vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKSTA2, 0, ~0);
+ }
+ }
+
+ } else if (type == PCI_EXP_TYPE_LEG_END) {
+ /*
+ * Legacy endpoints don't belong on the root complex. Windows
+ * seems to be happier with devices if we skip the capability.
+ */
+ return 0;
+ }
+
+ } else {
+ /*
+ * Convert Root Complex Integrated Endpoints to regular endpoints.
+ * These devices don't support LNK/LNK2 capabilities, so make them up.
+ */
+ if (type == PCI_EXP_TYPE_RC_END) {
+ vfio_add_emulated_word(vdev, pos + PCI_CAP_FLAGS,
+ PCI_EXP_TYPE_ENDPOINT << 4,
+ PCI_EXP_FLAGS_TYPE);
+ vfio_add_emulated_long(vdev, pos + PCI_EXP_LNKCAP,
+ PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25, ~0);
+ vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKCTL, 0, ~0);
+ }
+
+ /* Mark the Link Status bits as emulated to allow virtual negotiation */
+ vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKSTA,
+ pci_get_word(vdev->pdev.config + pos +
+ PCI_EXP_LNKSTA),
+ PCI_EXP_LNKCAP_MLW | PCI_EXP_LNKCAP_SLS);
+ }
+
+ pos = pci_add_capability(&vdev->pdev, PCI_CAP_ID_EXP, pos, size);
+ if (pos >= 0) {
+ vdev->pdev.exp.exp_cap = pos;
+ }
+
+ return pos;
+}
+
static int vfio_add_std_cap(VFIODevice *vdev, uint8_t pos)
{
PCIDevice *pdev = &vdev->pdev;
@@ -1555,16 +2518,27 @@ static int vfio_add_std_cap(VFIODevice *vdev, uint8_t pos)
return ret;
}
} else {
- pdev->config[PCI_CAPABILITY_LIST] = 0; /* Begin the rebuild */
+ /* Begin the rebuild, use QEMU emulated list bits */
+ pdev->config[PCI_CAPABILITY_LIST] = 0;
+ vdev->emulated_config_bits[PCI_CAPABILITY_LIST] = 0xff;
+ vdev->emulated_config_bits[PCI_STATUS] |= PCI_STATUS_CAP_LIST;
}
+ /* Use emulated next pointer to allow dropping caps */
+ pci_set_byte(vdev->emulated_config_bits + pos + 1, 0xff);
+
switch (cap_id) {
case PCI_CAP_ID_MSI:
ret = vfio_setup_msi(vdev, pos);
break;
+ case PCI_CAP_ID_EXP:
+ ret = vfio_setup_pcie_cap(vdev, pos, size);
+ break;
case PCI_CAP_ID_MSIX:
ret = vfio_setup_msix(vdev, pos);
break;
+ case PCI_CAP_ID_PM:
+ vdev->pm_cap = pos;
default:
ret = pci_add_capability(pdev, cap_id, pos, size);
break;
@@ -1867,6 +2841,7 @@ static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev)
vdev->bars[i].fd_offset = reg_info.offset;
vdev->bars[i].fd = vdev->fd;
vdev->bars[i].nr = i;
+ QLIST_INIT(&vdev->bars[i].quirks);
}
reg_info.index = VFIO_PCI_ROM_REGION_INDEX;
@@ -1904,6 +2879,47 @@ static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev)
}
vdev->config_offset = reg_info.offset;
+ if ((vdev->features & VFIO_FEATURE_ENABLE_VGA) &&
+ dev_info.num_regions > VFIO_PCI_VGA_REGION_INDEX) {
+ struct vfio_region_info vga_info = {
+ .argsz = sizeof(vga_info),
+ .index = VFIO_PCI_VGA_REGION_INDEX,
+ };
+
+ ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, &vga_info);
+ if (ret) {
+ error_report(
+ "vfio: Device does not support requested feature x-vga");
+ goto error;
+ }
+
+ if (!(vga_info.flags & VFIO_REGION_INFO_FLAG_READ) ||
+ !(vga_info.flags & VFIO_REGION_INFO_FLAG_WRITE) ||
+ vga_info.size < 0xbffff + 1) {
+ error_report("vfio: Unexpected VGA info, flags 0x%lx, size 0x%lx",
+ (unsigned long)vga_info.flags,
+ (unsigned long)vga_info.size);
+ goto error;
+ }
+
+ vdev->vga.fd_offset = vga_info.offset;
+ vdev->vga.fd = vdev->fd;
+
+ vdev->vga.region[QEMU_PCI_VGA_MEM].offset = QEMU_PCI_VGA_MEM_BASE;
+ vdev->vga.region[QEMU_PCI_VGA_MEM].nr = QEMU_PCI_VGA_MEM;
+ QLIST_INIT(&vdev->vga.region[QEMU_PCI_VGA_MEM].quirks);
+
+ vdev->vga.region[QEMU_PCI_VGA_IO_LO].offset = QEMU_PCI_VGA_IO_LO_BASE;
+ vdev->vga.region[QEMU_PCI_VGA_IO_LO].nr = QEMU_PCI_VGA_IO_LO;
+ QLIST_INIT(&vdev->vga.region[QEMU_PCI_VGA_IO_LO].quirks);
+
+ vdev->vga.region[QEMU_PCI_VGA_IO_HI].offset = QEMU_PCI_VGA_IO_HI_BASE;
+ vdev->vga.region[QEMU_PCI_VGA_IO_HI].nr = QEMU_PCI_VGA_IO_HI;
+ QLIST_INIT(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks);
+
+ vdev->has_vga = true;
+ }
+
error:
if (ret) {
QLIST_REMOVE(vdev, next);
@@ -2003,6 +3019,16 @@ static int vfio_initfn(PCIDevice *pdev)
goto out_put;
}
+ /* vfio emulates a lot for us, but some bits need extra love */
+ vdev->emulated_config_bits = g_malloc0(vdev->config_size);
+
+ /* QEMU can choose to expose the ROM or not */
+ memset(vdev->emulated_config_bits + PCI_ROM_ADDRESS, 0xff, 4);
+
+ /* QEMU can change multi-function devices to single function, or reverse */
+ vdev->emulated_config_bits[PCI_HEADER_TYPE] =
+ PCI_HEADER_TYPE_MULTI_FUNCTION;
+
/*
* Clear host resource mapping info. If we choose not to register a
* BAR, such as might be the case with the option ROM, we can get
@@ -2025,6 +3051,17 @@ static int vfio_initfn(PCIDevice *pdev)
goto out_teardown;
}
+ /* QEMU emulates all of MSI & MSIX */
+ if (pdev->cap_present & QEMU_PCI_CAP_MSIX) {
+ memset(vdev->emulated_config_bits + pdev->msix_cap, 0xff,
+ MSIX_CAP_LENGTH);
+ }
+
+ if (pdev->cap_present & QEMU_PCI_CAP_MSI) {
+ memset(vdev->emulated_config_bits + pdev->msi_cap, 0xff,
+ vdev->msi_cap_size);
+ }
+
if (vfio_pci_read_config(&vdev->pdev, PCI_INTERRUPT_PIN, 1)) {
vdev->intx.mmap_timer = qemu_new_timer_ms(vm_clock,
vfio_intx_mmap_enable, vdev);
@@ -2035,6 +3072,8 @@ static int vfio_initfn(PCIDevice *pdev)
}
}
+ add_boot_device_path(vdev->bootindex, &pdev->qdev, NULL);
+
return 0;
out_teardown:
@@ -2042,6 +3081,7 @@ out_teardown:
vfio_teardown_msi(vdev);
vfio_unmap_bars(vdev);
out_put:
+ g_free(vdev->emulated_config_bits);
vfio_put_device(vdev);
vfio_put_group(group);
return ret;
@@ -2059,6 +3099,7 @@ static void vfio_exitfn(PCIDevice *pdev)
}
vfio_teardown_msi(vdev);
vfio_unmap_bars(vdev);
+ g_free(vdev->emulated_config_bits);
vfio_put_device(vdev);
vfio_put_group(group);
}
@@ -2074,6 +3115,26 @@ static void vfio_pci_reset(DeviceState *dev)
vfio_disable_interrupts(vdev);
+ /* Make sure the device is in D0 */
+ if (vdev->pm_cap) {
+ uint16_t pmcsr;
+ uint8_t state;
+
+ pmcsr = vfio_pci_read_config(pdev, vdev->pm_cap + PCI_PM_CTRL, 2);
+ state = pmcsr & PCI_PM_CTRL_STATE_MASK;
+ if (state) {
+ pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+ vfio_pci_write_config(pdev, vdev->pm_cap + PCI_PM_CTRL, pmcsr, 2);
+ /* vfio handles the necessary delay here */
+ pmcsr = vfio_pci_read_config(pdev, vdev->pm_cap + PCI_PM_CTRL, 2);
+ state = pmcsr & PCI_PM_CTRL_STATE_MASK;
+ if (state) {
+ error_report("vfio: Unable to power on device, stuck in D%d\n",
+ state);
+ }
+ }
+ }
+
/*
* Stop any ongoing DMA by disconecting I/O, MMIO, and bus master.
* Also put INTx Disable in known state.
@@ -2098,6 +3159,9 @@ static Property vfio_pci_dev_properties[] = {
DEFINE_PROP_PCI_HOST_DEVADDR("host", VFIODevice, host),
DEFINE_PROP_UINT32("x-intx-mmap-timeout-ms", VFIODevice,
intx.mmap_timeout, 1100),
+ DEFINE_PROP_BIT("x-vga", VFIODevice, features,
+ VFIO_FEATURE_ENABLE_VGA_BIT, false),
+ DEFINE_PROP_INT32("bootindex", VFIODevice, bootindex, -1),
/*
* TODO - support passed fds... is this necessary?
* DEFINE_PROP_STRING("vfiofd", VFIODevice, vfiofd_name),
diff --git a/hw/vmxnet3.c b/hw/vmxnet3.c
index 925be8084a..bdd256e9d5 100644
--- a/hw/vmxnet3.c
+++ b/hw/vmxnet3.c
@@ -969,7 +969,7 @@ vmxnet3_indicate_packet(VMXNET3State *s)
struct Vmxnet3_RxDesc rxd;
bool is_head = true;
uint32_t rxd_idx;
- uint32_t rx_ridx;
+ uint32_t rx_ridx = 0;
struct Vmxnet3_RxCompDesc rxcd;
uint32_t new_rxcd_gen = VMXNET3_INIT_GEN;
diff --git a/hw/vt82c686.c b/hw/vt82c686.c
index 452950826c..9d9b64eedd 100644
--- a/hw/vt82c686.c
+++ b/hw/vt82c686.c
@@ -360,7 +360,7 @@ static int vt82c686b_pm_initfn(PCIDevice *dev)
acpi_pm_tmr_init(&s->ar, pm_tmr_timer, &s->io);
acpi_pm1_evt_init(&s->ar, pm_tmr_timer, &s->io);
- acpi_pm1_cnt_init(&s->ar, &s->io);
+ acpi_pm1_cnt_init(&s->ar, &s->io, 2);
return 0;
}
diff --git a/hw/xen_backend.c b/hw/xen_backend.c
index 24381b55e5..02693d7565 100644
--- a/hw/xen_backend.c
+++ b/hw/xen_backend.c
@@ -85,12 +85,20 @@ char *xenstore_read_str(const char *base, const char *node)
int xenstore_write_int(const char *base, const char *node, int ival)
{
- char val[32];
+ char val[12];
snprintf(val, sizeof(val), "%d", ival);
return xenstore_write_str(base, node, val);
}
+int xenstore_write_int64(const char *base, const char *node, int64_t ival)
+{
+ char val[21];
+
+ snprintf(val, sizeof(val), "%"PRId64, ival);
+ return xenstore_write_str(base, node, val);
+}
+
int xenstore_read_int(const char *base, const char *node, int *ival)
{
char *val;
@@ -114,6 +122,11 @@ int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival)
return xenstore_write_int(xendev->be, node, ival);
}
+int xenstore_write_be_int64(struct XenDevice *xendev, const char *node, int64_t ival)
+{
+ return xenstore_write_int64(xendev->be, node, ival);
+}
+
char *xenstore_read_be_str(struct XenDevice *xendev, const char *node)
{
return xenstore_read_str(xendev->be, node);
diff --git a/hw/xen_backend.h b/hw/xen_backend.h
index 6d5c699c51..d04b985d10 100644
--- a/hw/xen_backend.h
+++ b/hw/xen_backend.h
@@ -63,11 +63,13 @@ extern const char *xen_protocol;
/* xenstore helper functions */
int xenstore_write_str(const char *base, const char *node, const char *val);
int xenstore_write_int(const char *base, const char *node, int ival);
+int xenstore_write_int64(const char *base, const char *node, int64_t ival);
char *xenstore_read_str(const char *base, const char *node);
int xenstore_read_int(const char *base, const char *node, int *ival);
int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val);
int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival);
+int xenstore_write_be_int64(struct XenDevice *xendev, const char *node, int64_t ival);
char *xenstore_read_be_str(struct XenDevice *xendev, const char *node);
int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival);
char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node);
diff --git a/hw/xen_console.c b/hw/xen_console.c
index a8db6f8d8f..c56ef4737f 100644
--- a/hw/xen_console.c
+++ b/hw/xen_console.c
@@ -241,9 +241,17 @@ static int con_initialise(struct XenDevice *xendev)
return -1;
xen_be_bind_evtchn(&con->xendev);
- if (con->chr)
- qemu_chr_add_handlers(con->chr, xencons_can_receive, xencons_receive,
- NULL, con);
+ if (con->chr) {
+ if (qemu_chr_fe_claim(con->chr) == 0) {
+ qemu_chr_add_handlers(con->chr, xencons_can_receive,
+ xencons_receive, NULL, con);
+ } else {
+ xen_be_printf(xendev, 0,
+ "xen_console_init error chardev %s already used\n",
+ con->chr->label);
+ con->chr = NULL;
+ }
+ }
xen_be_printf(xendev, 1, "ring mfn %d, remote port %d, local port %d, limit %zd\n",
con->ring_ref,
@@ -260,8 +268,10 @@ static void con_disconnect(struct XenDevice *xendev)
if (!xendev->dev) {
return;
}
- if (con->chr)
+ if (con->chr) {
qemu_chr_add_handlers(con->chr, NULL, NULL, NULL, NULL);
+ qemu_chr_fe_release(con->chr);
+ }
xen_be_unbind_evtchn(&con->xendev);
if (con->sring) {
diff --git a/hw/xen_disk.c b/hw/xen_disk.c
index 83329e2e69..47a51cf014 100644
--- a/hw/xen_disk.c
+++ b/hw/xen_disk.c
@@ -700,7 +700,7 @@ static void blk_alloc(struct XenDevice *xendev)
static int blk_init(struct XenDevice *xendev)
{
struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
- int index, qflags, info = 0;
+ int info = 0;
/* read xenstore entries */
if (blkdev->params == NULL) {
@@ -743,10 +743,7 @@ static int blk_init(struct XenDevice *xendev)
}
/* read-only ? */
- qflags = BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NATIVE_AIO;
- if (strcmp(blkdev->mode, "w") == 0) {
- qflags |= BDRV_O_RDWR;
- } else {
+ if (strcmp(blkdev->mode, "w")) {
info |= VDISK_READONLY;
}
@@ -755,6 +752,41 @@ static int blk_init(struct XenDevice *xendev)
info |= VDISK_CDROM;
}
+ blkdev->file_blk = BLOCK_SIZE;
+
+ /* fill info
+ * blk_connect supplies sector-size and sectors
+ */
+ xenstore_write_be_int(&blkdev->xendev, "feature-flush-cache", 1);
+ xenstore_write_be_int(&blkdev->xendev, "feature-persistent", 1);
+ xenstore_write_be_int(&blkdev->xendev, "info", info);
+ return 0;
+
+out_error:
+ g_free(blkdev->params);
+ blkdev->params = NULL;
+ g_free(blkdev->mode);
+ blkdev->mode = NULL;
+ g_free(blkdev->type);
+ blkdev->type = NULL;
+ g_free(blkdev->dev);
+ blkdev->dev = NULL;
+ g_free(blkdev->devtype);
+ blkdev->devtype = NULL;
+ return -1;
+}
+
+static int blk_connect(struct XenDevice *xendev)
+{
+ struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+ int pers, index, qflags;
+
+ /* read-only ? */
+ qflags = BDRV_O_CACHE_WB | BDRV_O_NATIVE_AIO;
+ if (strcmp(blkdev->mode, "w") == 0) {
+ qflags |= BDRV_O_RDWR;
+ }
+
/* init qemu block driver */
index = (blkdev->xendev.dev - 202 * 256) / 16;
blkdev->dinfo = drive_get(IF_XEN, 0, index);
@@ -770,7 +802,7 @@ static int blk_init(struct XenDevice *xendev)
}
}
if (!blkdev->bs) {
- goto out_error;
+ return -1;
}
} else {
/* setup via qemu cmdline -> already setup for us */
@@ -778,7 +810,6 @@ static int blk_init(struct XenDevice *xendev)
blkdev->bs = blkdev->dinfo->bdrv;
}
bdrv_attach_dev_nofail(blkdev->bs, blkdev);
- blkdev->file_blk = BLOCK_SIZE;
blkdev->file_size = bdrv_getlength(blkdev->bs);
if (blkdev->file_size < 0) {
xen_be_printf(&blkdev->xendev, 1, "bdrv_getlength: %d (%s) | drv %s\n",
@@ -792,33 +823,10 @@ static int blk_init(struct XenDevice *xendev)
blkdev->type, blkdev->fileproto, blkdev->filename,
blkdev->file_size, blkdev->file_size >> 20);
- /* fill info */
- xenstore_write_be_int(&blkdev->xendev, "feature-flush-cache", 1);
- xenstore_write_be_int(&blkdev->xendev, "feature-persistent", 1);
- xenstore_write_be_int(&blkdev->xendev, "info", info);
- xenstore_write_be_int(&blkdev->xendev, "sector-size", blkdev->file_blk);
- xenstore_write_be_int(&blkdev->xendev, "sectors",
- blkdev->file_size / blkdev->file_blk);
- return 0;
-
-out_error:
- g_free(blkdev->params);
- blkdev->params = NULL;
- g_free(blkdev->mode);
- blkdev->mode = NULL;
- g_free(blkdev->type);
- blkdev->type = NULL;
- g_free(blkdev->dev);
- blkdev->dev = NULL;
- g_free(blkdev->devtype);
- blkdev->devtype = NULL;
- return -1;
-}
-
-static int blk_connect(struct XenDevice *xendev)
-{
- struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
- int pers;
+ /* Fill in number of sector size and number of sectors */
+ xenstore_write_be_int(&blkdev->xendev, "sector-size", blkdev->file_blk);
+ xenstore_write_be_int64(&blkdev->xendev, "sectors",
+ blkdev->file_size / blkdev->file_blk);
if (xenstore_read_fe_int(&blkdev->xendev, "ring-ref", &blkdev->ring_ref) == -1) {
return -1;
diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c
index 5785290224..07c4badd98 100644
--- a/hw/xilinx_axienet.c
+++ b/hw/xilinx_axienet.c
@@ -516,6 +516,8 @@ static void enet_write(void *opaque, hwaddr addr,
s->rcw[addr & 1] = value;
if ((addr & 1) && value & RCW1_RST) {
axienet_rx_reset(s);
+ } else {
+ qemu_flush_queued_packets(qemu_get_queue(s->nic));
}
break;
diff --git a/include/backends/tpm.h b/include/backends/tpm.h
new file mode 100644
index 0000000000..9e93cc5060
--- /dev/null
+++ b/include/backends/tpm.h
@@ -0,0 +1,170 @@
+/*
+ * QEMU TPM Backend
+ *
+ * Copyright IBM, Corp. 2013
+ *
+ * Authors:
+ * Stefan Berger <stefanb@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef _QEMU_TPM_H
+#define _QEMU_TPM_H
+
+#include "qom/object.h"
+#include "qemu-common.h"
+#include "qapi/error.h"
+#include "qapi-types.h"
+#include "qemu/option.h"
+#include "tpm/tpm.h"
+
+#define TYPE_TPM_BACKEND "tpm-backend"
+#define TPM_BACKEND(obj) \
+ OBJECT_CHECK(TPMBackend, (obj), TYPE_TPM_BACKEND)
+#define TPM_BACKEND_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(TPMBackendClass, (obj), TYPE_TPM_BACKEND)
+#define TPM_BACKEND_CLASS(klass) \
+ OBJECT_CLASS_CHECK(TPMBackendClass, (klass), TYPE_TPM_BACKEND)
+
+typedef struct TPMBackendClass TPMBackendClass;
+typedef struct TPMBackend TPMBackend;
+
+typedef struct TPMDriverOps TPMDriverOps;
+
+struct TPMBackendClass {
+ ObjectClass parent_class;
+
+ const TPMDriverOps *ops;
+
+ void (*opened)(TPMBackend *s, Error **errp);
+};
+
+struct TPMBackend {
+ Object parent;
+
+ /*< protected >*/
+ bool opened;
+
+ char *id;
+ enum TpmModel fe_model;
+ char *path;
+ char *cancel_path;
+ const TPMDriverOps *ops;
+
+ QLIST_ENTRY(TPMBackend) list;
+};
+
+
+/**
+ * tpm_backend_get_type:
+ * @s: the backend
+ *
+ * Returns the TpmType of the backend.
+ */
+enum TpmType tpm_backend_get_type(TPMBackend *s);
+
+/**
+ * tpm_backend_get_desc:
+ * @s: the backend
+ *
+ * Returns a human readable description of the backend.
+ */
+const char *tpm_backend_get_desc(TPMBackend *s);
+
+/**
+ * tpm_backend_destroy:
+ * @s: the backend to destroy
+ */
+void tpm_backend_destroy(TPMBackend *s);
+
+/**
+ * tpm_backend_init:
+ * @s: the backend to initialized
+ * @state: TPMState
+ * @datacb: callback for sending data to frontend
+ *
+ * Initialize the backend with the given variables.
+ *
+ * Returns 0 on success.
+ */
+int tpm_backend_init(TPMBackend *s, TPMState *state,
+ TPMRecvDataCB *datacb);
+
+/**
+ * tpm_backend_startup_tpm:
+ * @s: the backend whose TPM support is to be started
+ *
+ * Returns 0 on success.
+ */
+int tpm_backend_startup_tpm(TPMBackend *s);
+
+/**
+ * tpm_backend_had_startup_error:
+ * @s: the backend to query for a statup error
+ *
+ * Check whether the backend had an error during startup. Returns
+ * false if no error occurred and the backend can be used, true
+ * otherwise.
+ */
+bool tpm_backend_had_startup_error(TPMBackend *s);
+
+/**
+ * tpm_backend_realloc_buffer:
+ * @s: the backend
+ * @sb: the TPMSizedBuffer to re-allocated to the size suitable for the
+ * backend.
+ *
+ * This function returns the size of the allocated buffer
+ */
+size_t tpm_backend_realloc_buffer(TPMBackend *s, TPMSizedBuffer *sb);
+
+/**
+ * tpm_backend_deliver_request:
+ * @s: the backend to send the request to
+ *
+ * Send a request to the backend. The backend will then send the request
+ * to the TPM implementation.
+ */
+void tpm_backend_deliver_request(TPMBackend *s);
+
+/**
+ * tpm_backend_reset:
+ * @s: the backend to reset
+ *
+ * Reset the backend into a well defined state with all previous errors
+ * reset.
+ */
+void tpm_backend_reset(TPMBackend *s);
+
+/**
+ * tpm_backend_cancel_cmd:
+ * @s: the backend
+ *
+ * Cancel any ongoing command being processed by the TPM implementation
+ * on behalf of the QEMU guest.
+ */
+void tpm_backend_cancel_cmd(TPMBackend *s);
+
+/**
+ * tpm_backend_get_tpm_established_flag:
+ * @s: the backend
+ *
+ * Get the TPM establishment flag. This function may be called very
+ * frequently by the frontend since for example in the TIS implementation
+ * this flag is part of a register.
+ */
+bool tpm_backend_get_tpm_established_flag(TPMBackend *s);
+
+/**
+ * tpm_backend_open:
+ * @s: the backend to open
+ * @errp: a pointer to return the #Error object if an error occurs.
+ *
+ * This function will open the backend if it is not already open. Calling this
+ * function on an already opened backend will not result in an error.
+ */
+void tpm_backend_open(TPMBackend *s, Error **errp);
+
+#endif
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 0986a2d6ac..9aa98b5d12 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -252,11 +252,10 @@ struct BlockDriverState {
unsigned int copy_on_read_in_flight;
/* the time for latest disk I/O */
- int64_t slice_time;
int64_t slice_start;
int64_t slice_end;
BlockIOLimit io_limits;
- BlockIOBaseValue io_base;
+ BlockIOBaseValue slice_submitted;
CoQueue throttled_reqs;
QEMUTimer *block_timer;
bool io_limits_enabled;
diff --git a/include/char/char.h b/include/char/char.h
index 32c9999113..9d1ea46117 100644
--- a/include/char/char.h
+++ b/include/char/char.h
@@ -203,6 +203,35 @@ int qemu_chr_fe_ioctl(CharDriverState *s, int cmd, void *arg);
int qemu_chr_fe_get_msgfd(CharDriverState *s);
/**
+ * @qemu_chr_fe_claim:
+ *
+ * Claim a backend before using it, should be called before calling
+ * qemu_chr_add_handlers().
+ *
+ * Returns: -1 if the backend is already in use by another frontend, 0 on
+ * success.
+ */
+int qemu_chr_fe_claim(CharDriverState *s);
+
+/**
+ * @qemu_chr_fe_claim_no_fail:
+ *
+ * Like qemu_chr_fe_claim, but will exit qemu with an error when the
+ * backend is already in use.
+ */
+void qemu_chr_fe_claim_no_fail(CharDriverState *s);
+
+/**
+ * @qemu_chr_fe_claim:
+ *
+ * Release a backend for use by another frontend.
+ *
+ * Returns: -1 if the backend is already in use by another frontend, 0 on
+ * success.
+ */
+void qemu_chr_fe_release(CharDriverState *s);
+
+/**
* @qemu_chr_be_can_write:
*
* Determine how much data the front end can currently accept. This function
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 65918a9abe..ebc4d09141 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -164,6 +164,7 @@ extern const VMStateInfo vmstate_info_buffer;
extern const VMStateInfo vmstate_info_unused_buffer;
extern const VMStateInfo vmstate_info_bitmap;
+#define type_check_2darray(t1,t2,n,m) ((t1(*)[n][m])0 - (t2*)0)
#define type_check_array(t1,t2,n) ((t1(*)[n])0 - (t2*)0)
#define type_check_pointer(t1,t2) ((t1**)0 - (t2*)0)
@@ -179,6 +180,10 @@ extern const VMStateInfo vmstate_info_bitmap;
(offsetof(_state, _field) + \
type_check_array(_type, typeof_field(_state, _field), _num))
+#define vmstate_offset_2darray(_state, _field, _type, _n1, _n2) \
+ (offsetof(_state, _field) + \
+ type_check_2darray(_type, typeof_field(_state, _field), _n1, _n2))
+
#define vmstate_offset_sub_array(_state, _field, _type, _start) \
(offsetof(_state, _field[_start]))
@@ -224,6 +229,16 @@ extern const VMStateInfo vmstate_info_bitmap;
.offset = vmstate_offset_array(_state, _field, _type, _num), \
}
+#define VMSTATE_2DARRAY(_field, _state, _n1, _n2, _version, _info, _type) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .num = (_n1) * (_n2), \
+ .info = &(_info), \
+ .size = sizeof(_type), \
+ .flags = VMS_ARRAY, \
+ .offset = vmstate_offset_2darray(_state, _field, _type, _n1, _n2), \
+}
+
#define VMSTATE_ARRAY_TEST(_field, _state, _num, _test, _info, _type) {\
.name = (stringify(_field)), \
.field_exists = (_test), \
@@ -436,6 +451,15 @@ extern const VMStateInfo vmstate_info_bitmap;
.offset = offsetof(_state, _field), \
}
+#define VMSTATE_BUFFER_POINTER_UNSAFE(_field, _state, _version, _size) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .size = (_size), \
+ .info = &vmstate_info_buffer, \
+ .flags = VMS_BUFFER|VMS_POINTER, \
+ .offset = offsetof(_state, _field), \
+}
+
#define VMSTATE_UNUSED_BUFFER(_test, _version, _size) { \
.name = "unused", \
.field_exists = (_test), \
@@ -583,15 +607,27 @@ extern const VMStateInfo vmstate_info_bitmap;
#define VMSTATE_UINT16_ARRAY_V(_f, _s, _n, _v) \
VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint16, uint16_t)
+#define VMSTATE_UINT16_2DARRAY_V(_f, _s, _n1, _n2, _v) \
+ VMSTATE_2DARRAY(_f, _s, _n1, _n2, _v, vmstate_info_uint16, uint16_t)
+
#define VMSTATE_UINT16_ARRAY(_f, _s, _n) \
VMSTATE_UINT16_ARRAY_V(_f, _s, _n, 0)
+#define VMSTATE_UINT16_2DARRAY(_f, _s, _n1, _n2) \
+ VMSTATE_UINT16_2DARRAY_V(_f, _s, _n1, _n2, 0)
+
+#define VMSTATE_UINT8_2DARRAY_V(_f, _s, _n1, _n2, _v) \
+ VMSTATE_2DARRAY(_f, _s, _n1, _n2, _v, vmstate_info_uint8, uint8_t)
+
#define VMSTATE_UINT8_ARRAY_V(_f, _s, _n, _v) \
VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint8, uint8_t)
#define VMSTATE_UINT8_ARRAY(_f, _s, _n) \
VMSTATE_UINT8_ARRAY_V(_f, _s, _n, 0)
+#define VMSTATE_UINT8_2DARRAY(_f, _s, _n1, _n2) \
+ VMSTATE_UINT8_2DARRAY_V(_f, _s, _n1, _n2, 0)
+
#define VMSTATE_UINT32_ARRAY_V(_f, _s, _n, _v) \
VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint32, uint32_t)
diff --git a/include/qapi/qmp/qstring.h b/include/qapi/qmp/qstring.h
index 0e690f4849..1bc3666107 100644
--- a/include/qapi/qmp/qstring.h
+++ b/include/qapi/qmp/qstring.h
@@ -26,6 +26,7 @@ typedef struct QString {
QString *qstring_new(void);
QString *qstring_from_str(const char *str);
QString *qstring_from_substr(const char *str, int start, int end);
+size_t qstring_get_length(const QString *qstring);
const char *qstring_get_str(const QString *qstring);
void qstring_append_int(QString *qstring, int64_t value);
void qstring_append(QString *qstring, const char *str);
diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h
index d225f6dd74..c5174d76a7 100644
--- a/include/qemu/sockets.h
+++ b/include/qemu/sockets.h
@@ -37,8 +37,8 @@ int qemu_socket(int domain, int type, int protocol);
int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
int socket_set_cork(int fd, int v);
int socket_set_nodelay(int fd);
-void socket_set_block(int fd);
-void socket_set_nonblock(int fd);
+void qemu_set_block(int fd);
+void qemu_set_nonblock(int fd);
int send_all(int fd, const void *buf, int len1);
int recv_all(int fd, void *buf, int len1, bool single_read);
diff --git a/include/qemu/timer.h b/include/qemu/timer.h
index 1766b2d6c7..c363190fca 100644
--- a/include/qemu/timer.h
+++ b/include/qemu/timer.h
@@ -117,8 +117,7 @@ extern int use_rt_clock;
static inline int64_t get_clock(void)
{
-#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \
- || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
+#ifdef CLOCK_MONOTONIC
if (use_rt_clock) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h
index 8c8d78e76e..aed3d1d9a7 100644
--- a/include/sysemu/arch_init.h
+++ b/include/sysemu/arch_init.h
@@ -2,6 +2,7 @@
#define QEMU_ARCH_INIT_H
#include "qmp-commands.h"
+#include "qemu/option.h"
enum {
QEMU_ARCH_ALL = -1,
@@ -26,7 +27,7 @@ enum {
extern const uint32_t arch_type;
void select_soundhw(const char *optarg);
-void do_acpitable_option(const char *optarg);
+void do_acpitable_option(const QemuOpts *opts);
void do_smbios_option(const char *optarg);
void cpudef_init(void);
int audio_available(void);
diff --git a/include/tpm/tpm.h b/include/tpm/tpm.h
index cc8f20e69e..2d457c4439 100644
--- a/include/tpm/tpm.h
+++ b/include/tpm/tpm.h
@@ -14,6 +14,10 @@
#include "qemu/option.h"
+typedef struct TPMState TPMState;
+typedef struct TPMSizedBuffer TPMSizedBuffer;
+typedef void (TPMRecvDataCB)(TPMState *, uint8_t locty);
+
int tpm_config_parse(QemuOptsList *opts_list, const char *optarg);
int tpm_init(void);
void tpm_cleanup(void);
diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h
index f787b727a9..e094121ee7 100644
--- a/linux-headers/linux/vfio.h
+++ b/linux-headers/linux/vfio.h
@@ -303,6 +303,15 @@ enum {
VFIO_PCI_BAR5_REGION_INDEX,
VFIO_PCI_ROM_REGION_INDEX,
VFIO_PCI_CONFIG_REGION_INDEX,
+ /*
+ * Expose VGA regions defined for PCI base class 03, subclass 00.
+ * This includes I/O port ranges 0x3b0 to 0x3bb and 0x3c0 to 0x3df
+ * as well as the MMIO range 0xa0000 to 0xbffff. Each implemented
+ * range is found at it's identity mapped offset from the region
+ * offset, for example 0x3b0 is region_info.offset + 0x3b0. Areas
+ * between described ranges are unimplemented.
+ */
+ VFIO_PCI_VGA_REGION_INDEX,
VFIO_PCI_NUM_REGIONS
};
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 0fbae3c2f6..ea6c1d24e6 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -143,7 +143,7 @@ print_signal(abi_ulong arg, int last)
case TARGET_SIGTTOU: signal_name = "SIGTTOU"; break;
}
if (signal_name == NULL) {
- print_raw_param("%ld", arg, 1);
+ print_raw_param("%ld", arg, last);
return;
}
gemu_log("%s%s", signal_name, get_comma(last));
diff --git a/main-loop.c b/main-loop.c
index eb80ff369f..f46aece8b8 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -188,14 +188,39 @@ static void glib_pollfds_poll(void)
}
}
+#define MAX_MAIN_LOOP_SPIN (1000)
+
static int os_host_main_loop_wait(uint32_t timeout)
{
int ret;
+ static int spin_counter;
glib_pollfds_fill(&timeout);
+ /* If the I/O thread is very busy or we are incorrectly busy waiting in
+ * the I/O thread, this can lead to starvation of the BQL such that the
+ * VCPU threads never run. To make sure we can detect the later case,
+ * print a message to the screen. If we run into this condition, create
+ * a fake timeout in order to give the VCPU threads a chance to run.
+ */
+ if (spin_counter > MAX_MAIN_LOOP_SPIN) {
+ static bool notified;
+
+ if (!notified) {
+ fprintf(stderr,
+ "main-loop: WARNING: I/O thread spun for %d iterations\n",
+ MAX_MAIN_LOOP_SPIN);
+ notified = true;
+ }
+
+ timeout = 1;
+ }
+
if (timeout > 0) {
+ spin_counter = 0;
qemu_mutex_unlock_iothread();
+ } else {
+ spin_counter++;
}
ret = g_poll((GPollFD *)gpollfds->data, gpollfds->len, timeout);
diff --git a/migration.c b/migration.c
index 7fb2147391..3b4b467c32 100644
--- a/migration.c
+++ b/migration.c
@@ -121,7 +121,7 @@ void process_incoming_migration(QEMUFile *f)
int fd = qemu_get_fd(f);
assert(fd != -1);
- socket_set_nonblock(fd);
+ qemu_set_nonblock(fd);
qemu_coroutine_enter(co, f);
}
diff --git a/monitor.c b/monitor.c
index 4ec1db980c..b4bda7777e 100644
--- a/monitor.c
+++ b/monitor.c
@@ -188,8 +188,8 @@ struct Monitor {
int reset_seen;
int flags;
int suspend_cnt;
- uint8_t outbuf[1024];
- int outbuf_index;
+ bool skip_flush;
+ QString *outbuf;
ReadLineState *rs;
MonitorControl *mc;
CPUArchState *mon_cpu;
@@ -271,45 +271,56 @@ static gboolean monitor_unblocked(GIOChannel *chan, GIOCondition cond,
void monitor_flush(Monitor *mon)
{
int rc;
+ size_t len;
+ const char *buf;
+
+ if (mon->skip_flush) {
+ return;
+ }
- if (mon && mon->outbuf_index != 0 && !mon->mux_out) {
- rc = qemu_chr_fe_write(mon->chr, mon->outbuf, mon->outbuf_index);
- if (rc == mon->outbuf_index) {
+ buf = qstring_get_str(mon->outbuf);
+ len = qstring_get_length(mon->outbuf);
+
+ if (mon && len && !mon->mux_out) {
+ rc = qemu_chr_fe_write(mon->chr, (const uint8_t *) buf, len);
+ if (rc == len) {
/* all flushed */
- mon->outbuf_index = 0;
+ QDECREF(mon->outbuf);
+ mon->outbuf = qstring_new();
return;
}
if (rc > 0) {
/* partinal write */
- memmove(mon->outbuf, mon->outbuf + rc, mon->outbuf_index - rc);
- mon->outbuf_index -= rc;
+ QString *tmp = qstring_from_str(buf + rc);
+ QDECREF(mon->outbuf);
+ mon->outbuf = tmp;
}
qemu_chr_fe_add_watch(mon->chr, G_IO_OUT, monitor_unblocked, mon);
}
}
-/* flush at every end of line or if the buffer is full */
+/* flush at every end of line */
static void monitor_puts(Monitor *mon, const char *str)
{
char c;
for(;;) {
- assert(mon->outbuf_index < sizeof(mon->outbuf) - 1);
c = *str++;
if (c == '\0')
break;
- if (c == '\n')
- mon->outbuf[mon->outbuf_index++] = '\r';
- mon->outbuf[mon->outbuf_index++] = c;
- if (mon->outbuf_index >= (sizeof(mon->outbuf) - 1)
- || c == '\n')
+ if (c == '\n') {
+ qstring_append_chr(mon->outbuf, '\r');
+ }
+ qstring_append_chr(mon->outbuf, c);
+ if (c == '\n') {
monitor_flush(mon);
+ }
}
}
void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
{
- char buf[4096];
+ char *buf;
if (!mon)
return;
@@ -318,8 +329,9 @@ void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
return;
}
- vsnprintf(buf, sizeof(buf), fmt, ap);
+ buf = g_strdup_vprintf(fmt, ap);
monitor_puts(mon, buf);
+ g_free(buf);
}
void monitor_printf(Monitor *mon, const char *fmt, ...)
@@ -668,11 +680,10 @@ char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
{
char *output = NULL;
Monitor *old_mon, hmp;
- CharDriverState mchar;
memset(&hmp, 0, sizeof(hmp));
- qemu_chr_init_mem(&mchar);
- hmp.chr = &mchar;
+ hmp.outbuf = qstring_new();
+ hmp.skip_flush = true;
old_mon = cur_mon;
cur_mon = &hmp;
@@ -690,16 +701,14 @@ char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
handle_user_command(&hmp, command_line);
cur_mon = old_mon;
- if (qemu_chr_mem_osize(hmp.chr) > 0) {
- QString *str = qemu_chr_mem_to_qs(hmp.chr);
- output = g_strdup(qstring_get_str(str));
- QDECREF(str);
+ if (qstring_get_length(hmp.outbuf) > 0) {
+ output = g_strdup(qstring_get_str(hmp.outbuf));
} else {
output = g_strdup("");
}
out:
- qemu_chr_close_mem(hmp.chr);
+ QDECREF(hmp.outbuf);
return output;
}
@@ -4749,6 +4758,7 @@ void monitor_init(CharDriverState *chr, int flags)
}
mon = g_malloc0(sizeof(*mon));
+ mon->outbuf = qstring_new();
mon->chr = chr;
mon->flags = flags;
diff --git a/nbd.c b/nbd.c
index d1a67eeaf4..85187fff9f 100644
--- a/nbd.c
+++ b/nbd.c
@@ -386,7 +386,7 @@ static int nbd_send_negotiate(NBDClient *client)
[28 .. 151] reserved (0)
*/
- socket_set_block(csock);
+ qemu_set_block(csock);
rc = -EINVAL;
TRACE("Beginning negotiation.");
@@ -429,7 +429,7 @@ static int nbd_send_negotiate(NBDClient *client)
TRACE("Negotiation succeeded.");
rc = 0;
fail:
- socket_set_nonblock(csock);
+ qemu_set_nonblock(csock);
return rc;
}
@@ -443,7 +443,7 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
TRACE("Receiving negotiation.");
- socket_set_block(csock);
+ qemu_set_block(csock);
rc = -EINVAL;
if (read_sync(csock, buf, 8) != 8) {
@@ -558,7 +558,7 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
rc = 0;
fail:
- socket_set_nonblock(csock);
+ qemu_set_nonblock(csock);
return rc;
}
diff --git a/net/slirp.c b/net/slirp.c
index 4df550faf6..eabfee6d4f 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -660,6 +660,7 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str,
fwd->port = port;
fwd->slirp = s->slirp;
+ qemu_chr_fe_claim_no_fail(fwd->hd);
qemu_chr_add_handlers(fwd->hd, guestfwd_can_read, guestfwd_read,
NULL, fwd);
}
diff --git a/net/socket.c b/net/socket.c
index 6c3752b88a..87af1d3d39 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -308,7 +308,7 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr
}
}
- socket_set_nonblock(fd);
+ qemu_set_nonblock(fd);
return fd;
fail:
if (fd >= 0)
@@ -519,7 +519,7 @@ static int net_socket_listen_init(NetClientState *peer,
perror("socket");
return -1;
}
- socket_set_nonblock(fd);
+ qemu_set_nonblock(fd);
/* allow fast reuse */
val = 1;
@@ -565,7 +565,7 @@ static int net_socket_connect_init(NetClientState *peer,
perror("socket");
return -1;
}
- socket_set_nonblock(fd);
+ qemu_set_nonblock(fd);
connected = 0;
for(;;) {
@@ -674,6 +674,7 @@ static int net_socket_udp_init(NetClientState *peer,
closesocket(fd);
return -1;
}
+ qemu_set_nonblock(fd);
s = net_socket_fd_init(peer, model, name, fd, 0);
if (!s) {
@@ -712,7 +713,11 @@ int net_init_socket(const NetClientOptions *opts, const char *name,
int fd;
fd = monitor_handle_fd_param(cur_mon, sock->fd);
- if (fd == -1 || !net_socket_fd_init(peer, "socket", name, fd, 1)) {
+ if (fd == -1) {
+ return -1;
+ }
+ qemu_set_nonblock(fd);
+ if (!net_socket_fd_init(peer, "socket", name, fd, 1)) {
return -1;
}
return 0;
diff --git a/po/Makefile b/po/Makefile
index 2b4420f178..60ccd7d3bb 100644
--- a/po/Makefile
+++ b/po/Makefile
@@ -2,9 +2,8 @@
# process and also within the source tree to update the translation files.
VERSION=$(shell cat ../VERSION)
-TRANSLATIONS=de_DE it
-SRCS=$(addsuffix .po, $(TRANSLATIONS))
-OBJS=$(addsuffix .mo, $(TRANSLATIONS))
+SRCS=$(filter-out messages.po,$(wildcard *.po))
+OBJS=$(patsubst %.po,%.mo,$(SRCS))
SRC_PATH=..
@@ -31,16 +30,13 @@ install: $(OBJS)
$(INSTALL) -m644 $$obj $(DESTDIR)$(prefix)/share/locale/$$base/LC_MESSAGES/qemu.mo; \
done
-%.mo:
+%.mo: %.po
@msgfmt -o $@ $(SRC_PATH)/po/`basename $@ .mo`.po
messages.po: $(SRC_PATH)/ui/gtk.c
- @xgettext -o $@ --foreign-user --package-name=QEMU --package-version=1.0.50 --msgid-bugs-address=qemu-devel@nongnu.org -k_ -C $<
+ @xgettext -o $@ --foreign-user --package-name=QEMU --package-version=$(VERSION) --msgid-bugs-address=qemu-devel@nongnu.org -k_ -C $<
-de_DE.po: messages.po $(SRC_PATH)/ui/gtk.c
+%.po: messages.po
@msgmerge $@ $< > $@.bak && mv $@.bak $@
-it.po: messages.po $(SRC_PATH)/ui/gtk.c
- @msgmerge $@ $< > $@.bak && mv $@.bak $@
-
-.PHONY: $(SRCS) clean all
+.PHONY: clean all
diff --git a/po/de_DE.po b/po/de_DE.po
index 875578349d..92c5df5307 100644
--- a/po/de_DE.po
+++ b/po/de_DE.po
@@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: QEMU 1.4.50\n"
"Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n"
-"POT-Creation-Date: 2013-02-08 09:21-0600\n"
+"POT-Creation-Date: 2013-03-31 20:42+0200\n"
"PO-Revision-Date: 2012-02-28 16:00+0100\n"
"Last-Translator: Kevin Wolf <kwolf@redhat.com>\n"
"Language-Team: Deutsch <de@li.org>\n"
@@ -16,26 +16,49 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n!=1);\n"
-#: ../ui/gtk.c:990
-msgid "_File"
-msgstr "_Datei"
+#: ../ui/gtk.c:213
+msgid " - Press Ctrl+Alt+G to release grab"
+msgstr "- Strg+Alt+G drücken, um Eingabegeräte freizugeben"
-#: ../ui/gtk.c:1000
+#: ../ui/gtk.c:217
+msgid " [Paused]"
+msgstr "[Angehalten]"
+
+#: ../ui/gtk.c:1250
+msgid "_Machine"
+msgstr "_Maschine"
+
+#: ../ui/gtk.c:1252
+msgid "_Pause"
+msgstr "_Angehalten"
+
+#: ../ui/gtk.c:1258
+msgid "_Reset"
+msgstr "_Reset"
+
+#: ../ui/gtk.c:1261
+msgid "Power _Down"
+msgstr "_Herunterfahren"
+
+#: ../ui/gtk.c:1276
msgid "_View"
msgstr "_Ansicht"
-#: ../ui/gtk.c:1029
+#: ../ui/gtk.c:1306
msgid "Zoom To _Fit"
msgstr "Auf _Fenstergröße skalieren"
-#: ../ui/gtk.c:1035
+#: ../ui/gtk.c:1312
msgid "Grab On _Hover"
msgstr "Tastatur _automatisch einfangen"
-#: ../ui/gtk.c:1038
+#: ../ui/gtk.c:1315
msgid "_Grab Input"
msgstr "_Eingabegeräte einfangen"
-#: ../ui/gtk.c:1064
+#: ../ui/gtk.c:1341
msgid "Show _Tabs"
msgstr "_Tableiste anzeigen"
+
+#~ msgid "_File"
+#~ msgstr "_Datei"
diff --git a/po/fr_FR.po b/po/fr_FR.po
new file mode 100644
index 0000000000..27d86367c9
--- /dev/null
+++ b/po/fr_FR.po
@@ -0,0 +1,62 @@
+# French translation for QEMU.
+# This file is put in the public domain.
+#
+# Aurelien Jarno <aurelien@aurel32.net>, 2013.
+msgid ""
+msgstr ""
+"Project-Id-Version: QEMU 1.4.50\n"
+"Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n"
+"POT-Creation-Date: 2013-03-31 20:42+0200\n"
+"PO-Revision-Date: 2013-03-31 19:39+0200\n"
+"Last-Translator: Aurelien Jarno <aurelien@aurel32.net>\n"
+"Language-Team: French <FR@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Lokalize 1.4\n"
+
+#: ../ui/gtk.c:213
+msgid " - Press Ctrl+Alt+G to release grab"
+msgstr "- Appuyer sur Ctrl+Alt+G pour arrêter la capture"
+
+#: ../ui/gtk.c:217
+msgid " [Paused]"
+msgstr " [En pause]"
+
+#: ../ui/gtk.c:1250
+msgid "_Machine"
+msgstr "_Machine"
+
+#: ../ui/gtk.c:1252
+msgid "_Pause"
+msgstr "_Pause"
+
+#: ../ui/gtk.c:1258
+msgid "_Reset"
+msgstr "_Réinitialiser"
+
+#: ../ui/gtk.c:1261
+msgid "Power _Down"
+msgstr "_Éteindre"
+
+#: ../ui/gtk.c:1276
+msgid "_View"
+msgstr "_Vue"
+
+#: ../ui/gtk.c:1306
+msgid "Zoom To _Fit"
+msgstr "Zoomer pour _ajuster"
+
+#: ../ui/gtk.c:1312
+msgid "Grab On _Hover"
+msgstr "Capturer en _survolant"
+
+#: ../ui/gtk.c:1315
+msgid "_Grab Input"
+msgstr "_Capturer les entrées"
+
+#: ../ui/gtk.c:1341
+msgid "Show _Tabs"
+msgstr "Montrer les _onglets"
diff --git a/po/it.po b/po/it.po
index 7d77fff2d3..2ace3b0e2b 100644
--- a/po/it.po
+++ b/po/it.po
@@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: QEMU 1.4.50\n"
"Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n"
-"POT-Creation-Date: 2013-02-08 09:21-0600\n"
+"POT-Creation-Date: 2013-03-31 20:42+0200\n"
"PO-Revision-Date: 2012-02-27 08:23+0100\n"
"Last-Translator: Paolo Bonzini <pbonzini@redhat.com>\n"
"Language-Team: Italian <it@li.org>\n"
@@ -16,26 +16,49 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-#: ../ui/gtk.c:990
-msgid "_File"
-msgstr "_File"
+#: ../ui/gtk.c:213
+msgid " - Press Ctrl+Alt+G to release grab"
+msgstr ""
+
+#: ../ui/gtk.c:217
+msgid " [Paused]"
+msgstr ""
+
+#: ../ui/gtk.c:1250
+msgid "_Machine"
+msgstr ""
+
+#: ../ui/gtk.c:1252
+msgid "_Pause"
+msgstr ""
+
+#: ../ui/gtk.c:1258
+msgid "_Reset"
+msgstr ""
-#: ../ui/gtk.c:1000
+#: ../ui/gtk.c:1261
+msgid "Power _Down"
+msgstr ""
+
+#: ../ui/gtk.c:1276
msgid "_View"
msgstr "_Visualizza"
-#: ../ui/gtk.c:1029
+#: ../ui/gtk.c:1306
msgid "Zoom To _Fit"
msgstr "Adatta alla _finestra"
-#: ../ui/gtk.c:1035
+#: ../ui/gtk.c:1312
msgid "Grab On _Hover"
msgstr "Cattura _automatica input"
-#: ../ui/gtk.c:1038
+#: ../ui/gtk.c:1315
msgid "_Grab Input"
msgstr "_Cattura input"
-#: ../ui/gtk.c:1064
+#: ../ui/gtk.c:1341
msgid "Show _Tabs"
msgstr "Mostra _tab"
+
+#~ msgid "_File"
+#~ msgstr "_File"
diff --git a/po/messages.po b/po/messages.po
index 191e81cc7c..42a3eacbea 100644
--- a/po/messages.po
+++ b/po/messages.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: QEMU 1.4.50\n"
"Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n"
-"POT-Creation-Date: 2013-02-08 09:21-0600\n"
+"POT-Creation-Date: 2013-03-31 20:42+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -16,26 +16,46 @@ msgstr ""
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
-#: ../ui/gtk.c:990
-msgid "_File"
+#: ../ui/gtk.c:213
+msgid " - Press Ctrl+Alt+G to release grab"
msgstr ""
-#: ../ui/gtk.c:1000
+#: ../ui/gtk.c:217
+msgid " [Paused]"
+msgstr ""
+
+#: ../ui/gtk.c:1250
+msgid "_Machine"
+msgstr ""
+
+#: ../ui/gtk.c:1252
+msgid "_Pause"
+msgstr ""
+
+#: ../ui/gtk.c:1258
+msgid "_Reset"
+msgstr ""
+
+#: ../ui/gtk.c:1261
+msgid "Power _Down"
+msgstr ""
+
+#: ../ui/gtk.c:1276
msgid "_View"
msgstr ""
-#: ../ui/gtk.c:1029
+#: ../ui/gtk.c:1306
msgid "Zoom To _Fit"
msgstr ""
-#: ../ui/gtk.c:1035
+#: ../ui/gtk.c:1312
msgid "Grab On _Hover"
msgstr ""
-#: ../ui/gtk.c:1038
+#: ../ui/gtk.c:1315
msgid "_Grab Input"
msgstr ""
-#: ../ui/gtk.c:1064
+#: ../ui/gtk.c:1341
msgid "Show _Tabs"
msgstr ""
diff --git a/qapi-schema.json b/qapi-schema.json
index f629a249de..db542f6692 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2591,6 +2591,8 @@
#
# @vhostforce: #optional vhost on for non-MSIX virtio guests
#
+# @queues: #optional number of queues to be created for multiqueue capable tap
+#
# Since 1.2
##
{ 'type': 'NetdevTapOptions',
@@ -3453,3 +3455,61 @@
# Since: 1.5
##
{ 'command': 'query-tpm', 'returns': ['TPMInfo'] }
+
+##
+# @AcpiTableOptions
+#
+# Specify an ACPI table on the command line to load.
+#
+# At most one of @file and @data can be specified. The list of files specified
+# by any one of them is loaded and concatenated in order. If both are omitted,
+# @data is implied.
+#
+# Other fields / optargs can be used to override fields of the generic ACPI
+# table header; refer to the ACPI specification 5.0, section 5.2.6 System
+# Description Table Header. If a header field is not overridden, then the
+# corresponding value from the concatenated blob is used (in case of @file), or
+# it is filled in with a hard-coded value (in case of @data).
+#
+# String fields are copied into the matching ACPI member from lowest address
+# upwards, and silently truncated / NUL-padded to length.
+#
+# @sig: #optional table signature / identifier (4 bytes)
+#
+# @rev: #optional table revision number (dependent on signature, 1 byte)
+#
+# @oem_id: #optional OEM identifier (6 bytes)
+#
+# @oem_table_id: #optional OEM table identifier (8 bytes)
+#
+# @oem_rev: #optional OEM-supplied revision number (4 bytes)
+#
+# @asl_compiler_id: #optional identifier of the utility that created the table
+# (4 bytes)
+#
+# @asl_compiler_rev: #optional revision number of the utility that created the
+# table (4 bytes)
+#
+# @file: #optional colon (:) separated list of pathnames to load and
+# concatenate as table data. The resultant binary blob is expected to
+# have an ACPI table header. At least one file is required. This field
+# excludes @data.
+#
+# @data: #optional colon (:) separated list of pathnames to load and
+# concatenate as table data. The resultant binary blob must not have an
+# ACPI table header. At least one file is required. This field excludes
+# @file.
+#
+# Since 1.5
+##
+{ 'type': 'AcpiTableOptions',
+ 'data': {
+ '*sig': 'str',
+ '*rev': 'uint8',
+ '*oem_id': 'str',
+ '*oem_table_id': 'str',
+ '*oem_rev': 'uint32',
+ '*asl_compiler_id': 'str',
+ '*asl_compiler_rev': 'uint32',
+ '*file': 'str',
+ '*data': 'str' }}
diff --git a/qemu-char.c b/qemu-char.c
index dee623e592..dd410ce40f 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -594,65 +594,51 @@ int recv_all(int fd, void *_buf, int len1, bool single_read)
typedef struct IOWatchPoll
{
+ GSource parent;
+
GSource *src;
- int max_size;
IOCanReadHandler *fd_can_read;
void *opaque;
-
- QTAILQ_ENTRY(IOWatchPoll) node;
} IOWatchPoll;
-static QTAILQ_HEAD(, IOWatchPoll) io_watch_poll_list =
- QTAILQ_HEAD_INITIALIZER(io_watch_poll_list);
-
static IOWatchPoll *io_watch_poll_from_source(GSource *source)
{
- IOWatchPoll *i;
-
- QTAILQ_FOREACH(i, &io_watch_poll_list, node) {
- if (i->src == source) {
- return i;
- }
- }
-
- return NULL;
+ return container_of(source, IOWatchPoll, parent);
}
static gboolean io_watch_poll_prepare(GSource *source, gint *timeout_)
{
IOWatchPoll *iwp = io_watch_poll_from_source(source);
-
- iwp->max_size = iwp->fd_can_read(iwp->opaque);
- if (iwp->max_size == 0) {
+ bool now_active = iwp->fd_can_read(iwp->opaque) > 0;
+ bool was_active = g_source_get_context(iwp->src) != NULL;
+ if (was_active == now_active) {
return FALSE;
}
- return g_io_watch_funcs.prepare(source, timeout_);
+ if (now_active) {
+ g_source_attach(iwp->src, NULL);
+ } else {
+ g_source_remove(g_source_get_id(iwp->src));
+ }
+ return FALSE;
}
static gboolean io_watch_poll_check(GSource *source)
{
- IOWatchPoll *iwp = io_watch_poll_from_source(source);
-
- if (iwp->max_size == 0) {
- return FALSE;
- }
-
- return g_io_watch_funcs.check(source);
+ return FALSE;
}
static gboolean io_watch_poll_dispatch(GSource *source, GSourceFunc callback,
gpointer user_data)
{
- return g_io_watch_funcs.dispatch(source, callback, user_data);
+ abort();
}
static void io_watch_poll_finalize(GSource *source)
{
IOWatchPoll *iwp = io_watch_poll_from_source(source);
- QTAILQ_REMOVE(&io_watch_poll_list, iwp, node);
- g_io_watch_funcs.finalize(source);
+ g_source_unref(iwp->src);
}
static GSourceFuncs io_watch_poll_funcs = {
@@ -669,24 +655,14 @@ static guint io_add_watch_poll(GIOChannel *channel,
gpointer user_data)
{
IOWatchPoll *iwp;
- GSource *src;
- guint tag;
-
- src = g_io_create_watch(channel, G_IO_IN | G_IO_ERR | G_IO_HUP);
- g_source_set_funcs(src, &io_watch_poll_funcs);
- g_source_set_callback(src, (GSourceFunc)fd_read, user_data, NULL);
- tag = g_source_attach(src, NULL);
- g_source_unref(src);
- iwp = g_malloc0(sizeof(*iwp));
- iwp->src = src;
- iwp->max_size = 0;
+ iwp = (IOWatchPoll *) g_source_new(&io_watch_poll_funcs, sizeof(IOWatchPoll));
iwp->fd_can_read = fd_can_read;
iwp->opaque = user_data;
+ iwp->src = g_io_create_watch(channel, G_IO_IN | G_IO_ERR | G_IO_HUP);
+ g_source_set_callback(iwp->src, (GSourceFunc)fd_read, user_data, NULL);
- QTAILQ_INSERT_HEAD(&io_watch_poll_list, iwp, node);
-
- return tag;
+ return g_source_attach(&iwp->parent, NULL);
}
#ifndef _WIN32
@@ -727,33 +703,37 @@ static GIOChannel *io_channel_from_socket(int fd)
return chan;
}
-static int io_channel_send_all(GIOChannel *fd, const void *_buf, int len1)
+static int io_channel_send(GIOChannel *fd, const void *buf, size_t len)
{
GIOStatus status;
- gsize bytes_written;
- int len;
- const uint8_t *buf = _buf;
+ size_t offset;
- len = len1;
- while (len > 0) {
- status = g_io_channel_write_chars(fd, (const gchar *)buf, len,
+ offset = 0;
+ while (offset < len) {
+ gsize bytes_written;
+
+ status = g_io_channel_write_chars(fd, buf + offset, len - offset,
&bytes_written, NULL);
if (status != G_IO_STATUS_NORMAL) {
if (status == G_IO_STATUS_AGAIN) {
+ /* If we've written any data, return a partial write. */
+ if (offset) {
+ break;
+ }
errno = EAGAIN;
- return -1;
} else {
errno = EINVAL;
- return -1;
}
+
+ return -1;
} else if (status == G_IO_STATUS_EOF) {
break;
- } else {
- buf += bytes_written;
- len -= bytes_written;
}
+
+ offset += bytes_written;
}
- return len1 - len;
+
+ return offset;
}
#ifndef _WIN32
@@ -770,7 +750,7 @@ static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
{
FDCharDriver *s = chr->opaque;
- return io_channel_send_all(s->fd_out, buf, len);
+ return io_channel_send(s->fd_out, buf, len);
}
static gboolean fd_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque)
@@ -1088,7 +1068,7 @@ static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
pty_chr_update_read_handler(chr);
return 0;
}
- return io_channel_send_all(s->fd, buf, len);
+ return io_channel_send(s->fd, buf, len);
}
static GSource *pty_chr_add_watch(CharDriverState *chr, GIOCondition cond)
@@ -2347,7 +2327,7 @@ static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
{
TCPCharDriver *s = chr->opaque;
if (s->connected) {
- return io_channel_send_all(s->chan, buf, len);
+ return io_channel_send(s->chan, buf, len);
} else {
/* XXX: indicate an error ? */
return len;
@@ -2440,6 +2420,9 @@ static void unix_process_msgfd(CharDriverState *chr, struct msghdr *msg)
if (fd < 0)
continue;
+ /* O_NONBLOCK is preserved across SCM_RIGHTS so reset it */
+ qemu_set_block(fd);
+
#ifndef MSG_CMSG_CLOEXEC
qemu_set_cloexec(fd);
#endif
@@ -2570,7 +2553,7 @@ static int tcp_chr_add_client(CharDriverState *chr, int fd)
if (s->fd != -1)
return -1;
- socket_set_nonblock(fd);
+ qemu_set_nonblock(fd);
if (s->do_nodelay)
socket_set_nodelay(fd);
s->fd = fd;
@@ -2722,7 +2705,7 @@ static CharDriverState *qemu_chr_open_socket_fd(int fd, bool do_nodelay,
printf("QEMU waiting for connection on: %s\n",
chr->filename);
tcp_chr_accept(s->listen_chan, G_IO_IN, chr);
- socket_set_nonblock(s->listen_fd);
+ qemu_set_nonblock(s->listen_fd);
}
return chr;
}
@@ -2764,7 +2747,7 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
}
if (!is_waitconnect)
- socket_set_nonblock(fd);
+ qemu_set_nonblock(fd);
chr = qemu_chr_open_socket_fd(fd, do_nodelay, is_listen, is_telnet,
is_waitconnect, &local_err);
@@ -2789,70 +2772,6 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
return NULL;
}
-/***********************************************************/
-/* Memory chardev */
-typedef struct {
- size_t outbuf_size;
- size_t outbuf_capacity;
- uint8_t *outbuf;
-} MemoryDriver;
-
-static int mem_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
-{
- MemoryDriver *d = chr->opaque;
-
- /* TODO: the QString implementation has the same code, we should
- * introduce a generic way to do this in cutils.c */
- if (d->outbuf_capacity < d->outbuf_size + len) {
- /* grow outbuf */
- d->outbuf_capacity += len;
- d->outbuf_capacity *= 2;
- d->outbuf = g_realloc(d->outbuf, d->outbuf_capacity);
- }
-
- memcpy(d->outbuf + d->outbuf_size, buf, len);
- d->outbuf_size += len;
-
- return len;
-}
-
-void qemu_chr_init_mem(CharDriverState *chr)
-{
- MemoryDriver *d;
-
- d = g_malloc(sizeof(*d));
- d->outbuf_size = 0;
- d->outbuf_capacity = 4096;
- d->outbuf = g_malloc0(d->outbuf_capacity);
-
- memset(chr, 0, sizeof(*chr));
- chr->opaque = d;
- chr->chr_write = mem_chr_write;
-}
-
-QString *qemu_chr_mem_to_qs(CharDriverState *chr)
-{
- MemoryDriver *d = chr->opaque;
- return qstring_from_substr((char *) d->outbuf, 0, d->outbuf_size - 1);
-}
-
-/* NOTE: this driver can not be closed with qemu_chr_delete()! */
-void qemu_chr_close_mem(CharDriverState *chr)
-{
- MemoryDriver *d = chr->opaque;
-
- g_free(d->outbuf);
- g_free(chr->opaque);
- chr->opaque = NULL;
- chr->chr_write = NULL;
-}
-
-size_t qemu_chr_mem_osize(const CharDriverState *chr)
-{
- const MemoryDriver *d = chr->opaque;
- return d->outbuf_size;
-}
-
/*********************************************************/
/* Ring buffer chardev */
@@ -3404,6 +3323,7 @@ CharDriverState *qemu_chr_new(const char *label, const char *filename, void (*in
error_free(err);
}
if (chr && qemu_opt_get_bool(opts, "mux", 0)) {
+ qemu_chr_fe_claim_no_fail(chr);
monitor_init(chr, MONITOR_USE_READLINE);
}
return chr;
@@ -3445,6 +3365,29 @@ int qemu_chr_fe_add_watch(CharDriverState *s, GIOCondition cond,
return tag;
}
+int qemu_chr_fe_claim(CharDriverState *s)
+{
+ if (s->avail_connections < 1) {
+ return -1;
+ }
+ s->avail_connections--;
+ return 0;
+}
+
+void qemu_chr_fe_claim_no_fail(CharDriverState *s)
+{
+ if (qemu_chr_fe_claim(s) != 0) {
+ fprintf(stderr, "%s: error chardev \"%s\" already used\n",
+ __func__, s->label);
+ exit(1);
+ }
+}
+
+void qemu_chr_fe_release(CharDriverState *s)
+{
+ s->avail_connections++;
+}
+
void qemu_chr_delete(CharDriverState *chr)
{
QTAILQ_REMOVE(&chardevs, chr, next);
@@ -3493,9 +3436,16 @@ CharDriverState *qemu_chr_find(const char *name)
CharDriverState *qemu_char_get_next_serial(void)
{
static int next_serial;
+ CharDriverState *chr;
/* FIXME: This function needs to go away: use chardev properties! */
- return serial_hds[next_serial++];
+
+ while (next_serial < MAX_SERIAL_PORTS && serial_hds[next_serial]) {
+ chr = serial_hds[next_serial++];
+ qemu_chr_fe_claim_no_fail(chr);
+ return chr;
+ }
+ return NULL;
}
QemuOptsList qemu_chardev_opts = {
@@ -3653,7 +3603,7 @@ static CharDriverState *qmp_chardev_open_serial(ChardevHostdev *serial,
if (error_is_set(errp)) {
return NULL;
}
- socket_set_nonblock(fd);
+ qemu_set_nonblock(fd);
return qemu_chr_open_tty_fd(fd);
#else
error_setg(errp, "character device backend type 'serial' not supported");
diff --git a/qemu-options.hx b/qemu-options.hx
index c40ba554f9..7cd6002d95 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1360,7 +1360,7 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
"-net tap[,vlan=n][,name=str],ifname=name\n"
" connect the host TAP network interface to VLAN 'n'\n"
#else
- "-net tap[,vlan=n][,name=str][,fd=h][,fds=x:y:...:z][,ifname=name][,script=file][,downscript=dfile][,helper=helper][,sndbuf=nbytes][,vnet_hdr=on|off][,vhost=on|off][,vhostfd=h][,vhostfds=x:y:...:z][,vhostforce=on|off]\n"
+ "-net tap[,vlan=n][,name=str][,fd=h][,fds=x:y:...:z][,ifname=name][,script=file][,downscript=dfile][,helper=helper][,sndbuf=nbytes][,vnet_hdr=on|off][,vhost=on|off][,vhostfd=h][,vhostfds=x:y:...:z][,vhostforce=on|off][,queues=n]\n"
" connect the host TAP network interface to VLAN 'n'\n"
" use network scripts 'file' (default=" DEFAULT_NETWORK_SCRIPT ")\n"
" to configure it and 'dfile' (default=" DEFAULT_NETWORK_DOWN_SCRIPT ")\n"
@@ -1379,6 +1379,7 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
" use vhostforce=on to force vhost on for non-MSIX virtio guests\n"
" use 'vhostfd=h' to connect to an already opened vhost net device\n"
" use 'vhostfds=x:y:...:z to connect to multiple already opened vhost net devices\n"
+ " use 'queues=n' to specify the number of queues to be created for multiqueue TAP\n"
"-net bridge[,vlan=n][,name=str][,br=bridge][,helper=helper]\n"
" connects a host TAP network interface to a host bridge device 'br'\n"
" (default=" DEFAULT_BRIDGE_INTERFACE ") using the program 'helper'\n"
diff --git a/qobject/qstring.c b/qobject/qstring.c
index 5f7376c336..607b7a142c 100644
--- a/qobject/qstring.c
+++ b/qobject/qstring.c
@@ -32,6 +32,14 @@ QString *qstring_new(void)
}
/**
+ * qstring_get_length(): Get the length of a QString
+ */
+size_t qstring_get_length(const QString *qstring)
+{
+ return qstring->length;
+}
+
+/**
* qstring_from_substr(): Create a new QString from a C string substring
*
* Return string reference
diff --git a/savevm.c b/savevm.c
index 406caa90e5..b1d8988c78 100644
--- a/savevm.c
+++ b/savevm.c
@@ -422,7 +422,7 @@ QEMUFile *qemu_fopen_socket(int fd, const char *mode)
s->fd = fd;
if (mode[0] == 'w') {
- socket_set_block(s->fd);
+ qemu_set_block(s->fd);
s->file = qemu_fopen_ops(s, &socket_write_ops);
} else {
s->file = qemu_fopen_ops(s, &socket_read_ops);
diff --git a/slirp/misc.c b/slirp/misc.c
index 6b9c2c405b..8ecced547f 100644
--- a/slirp/misc.c
+++ b/slirp/misc.c
@@ -215,7 +215,7 @@ fork_exec(struct socket *so, const char *ex, int do_pty)
qemu_setsockopt(so->s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int));
opt = 1;
qemu_setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
- socket_set_nonblock(so->s);
+ qemu_set_nonblock(so->s);
/* Append the telnet options now */
if (so->so_m != NULL && do_pty == 1) {
diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c
index 84a6bb560b..e98ce1a50c 100644
--- a/slirp/tcp_subr.c
+++ b/slirp/tcp_subr.c
@@ -336,7 +336,7 @@ int tcp_fconnect(struct socket *so)
int opt, s=so->s;
struct sockaddr_in addr;
- socket_set_nonblock(s);
+ qemu_set_nonblock(s);
opt = 1;
qemu_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
opt = 1;
@@ -425,7 +425,7 @@ void tcp_connect(struct socket *inso)
tcp_close(sototcpcb(so)); /* This will sofree() as well */
return;
}
- socket_set_nonblock(s);
+ qemu_set_nonblock(s);
opt = 1;
qemu_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int));
opt = 1;
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 4b43759ec5..69c3570a15 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -2049,8 +2049,6 @@ static void mce_init(X86CPU *cpu)
}
}
-#define MSI_ADDR_BASE 0xfee00000
-
#ifndef CONFIG_USER_ONLY
static void x86_cpu_apic_init(X86CPU *cpu, Error **errp)
{
@@ -2090,7 +2088,7 @@ static void x86_cpu_apic_init(X86CPU *cpu, Error **errp)
on the global memory bus. */
/* XXX: what if the base changes? */
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(env->apic_state), 0,
- MSI_ADDR_BASE, 0x1000);
+ APIC_DEFAULT_ADDRESS, 0x1000);
apic_mapped = 1;
}
}
@@ -2131,14 +2129,14 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
env->cpuid_ext3_features &= TCG_EXT3_FEATURES;
env->cpuid_svm_features &= TCG_SVM_FEATURES;
} else {
-#ifdef CONFIG_KVM
- filter_features_for_kvm(cpu);
-#endif
if (check_cpuid && kvm_check_features_against_host(cpu)
&& enforce_cpuid) {
error_setg(errp, "Host's CPU doesn't support requested features");
return;
}
+#ifdef CONFIG_KVM
+ filter_features_for_kvm(cpu);
+#endif
}
#ifndef CONFIG_USER_ONLY
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 48f41ca3e3..069a2e2cf9 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -185,7 +185,7 @@
#define HF2_VINTR_SHIFT 3 /* value of V_INTR_MASKING bit */
#define HF2_GIF_MASK (1 << HF2_GIF_SHIFT)
-#define HF2_HIF_MASK (1 << HF2_HIF_SHIFT)
+#define HF2_HIF_MASK (1 << HF2_HIF_SHIFT)
#define HF2_NMI_MASK (1 << HF2_NMI_SHIFT)
#define HF2_VINTR_MASK (1 << HF2_VINTR_SHIFT)
@@ -1267,4 +1267,6 @@ const char *get_register_name_32(unsigned int reg);
uint32_t x86_cpu_apic_id_from_index(unsigned int cpu_index);
void enable_compat_apic_id_mode(void);
+#define APIC_DEFAULT_ADDRESS 0xfee00000
+
#endif /* CPU_I386_H */
diff --git a/target-s390x/translate.c b/target-s390x/translate.c
index a4f2194ec7..0c3cf68e1d 100644
--- a/target-s390x/translate.c
+++ b/target-s390x/translate.c
@@ -3088,6 +3088,7 @@ static ExitStatus op_srnm(DisasContext *s, DisasOps *o)
break;
case 0xb9: /* SRNMT */
pos = 4, len = 3;
+ break;
default:
tcg_abort();
}
diff --git a/tests/test-visitor-serialization.c b/tests/test-visitor-serialization.c
index 3c6b8df607..e84926f97c 100644
--- a/tests/test-visitor-serialization.c
+++ b/tests/test-visitor-serialization.c
@@ -258,6 +258,7 @@ static void test_primitives(gconstpointer opaque)
g_assert(pt_copy != NULL);
if (pt->type == PTYPE_STRING) {
g_assert_cmpstr(pt->value.string, ==, pt_copy->value.string);
+ g_free((char *)pt_copy->value.string);
} else if (pt->type == PTYPE_NUMBER) {
/* we serialize with %f for our reference visitors, so rather than fuzzy
* floating math to test "equality", just compare the formatted values
@@ -275,6 +276,7 @@ static void test_primitives(gconstpointer opaque)
ops->cleanup(serialize_data);
g_free(args);
+ g_free(pt_copy);
}
static void test_struct(gconstpointer opaque)
@@ -660,6 +662,7 @@ static void qmp_deserialize(void **native_out, void *datap,
QDECREF(output_json);
d->qiv = qmp_input_visitor_new(obj);
+ qobject_decref(obj);
visit(qmp_input_get_visitor(d->qiv), native_out, errp);
}
@@ -668,9 +671,12 @@ static void qmp_cleanup(void *datap)
QmpSerializeData *d = datap;
qmp_output_visitor_cleanup(d->qov);
qmp_input_visitor_cleanup(d->qiv);
+
+ g_free(d);
}
typedef struct StringSerializeData {
+ char *string;
StringOutputVisitor *sov;
StringInputVisitor *siv;
} StringSerializeData;
@@ -690,15 +696,19 @@ static void string_deserialize(void **native_out, void *datap,
{
StringSerializeData *d = datap;
- d->siv = string_input_visitor_new(string_output_get_string(d->sov));
+ d->string = string_output_get_string(d->sov);
+ d->siv = string_input_visitor_new(d->string);
visit(string_input_get_visitor(d->siv), native_out, errp);
}
static void string_cleanup(void *datap)
{
StringSerializeData *d = datap;
+
string_output_visitor_cleanup(d->sov);
string_input_visitor_cleanup(d->siv);
+ g_free(d->string);
+ g_free(d);
}
/* visitor registration, test harness */
diff --git a/tpm/tpm.c b/tpm/tpm.c
index ae00eae618..1f4ac8da00 100644
--- a/tpm/tpm.c
+++ b/tpm/tpm.c
@@ -15,6 +15,7 @@
#include "monitor/monitor.h"
#include "qapi/qmp/qerror.h"
+#include "backends/tpm.h"
#include "tpm_int.h"
#include "tpm/tpm.h"
#include "qemu/config-file.h"
@@ -145,6 +146,7 @@ static int configure_tpm(QemuOpts *opts)
const char *id;
const TPMDriverOps *be;
TPMBackend *drv;
+ Error *local_err = NULL;
if (!QLIST_EMPTY(&tpm_backends)) {
error_report("Only one TPM is allowed.\n");
@@ -177,6 +179,13 @@ static int configure_tpm(QemuOpts *opts)
return 1;
}
+ tpm_backend_open(drv, &local_err);
+ if (local_err) {
+ qerror_report_err(local_err);
+ error_free(local_err);
+ return 1;
+ }
+
QLIST_INSERT_HEAD(&tpm_backends, drv, list);
return 0;
@@ -197,7 +206,7 @@ void tpm_cleanup(void)
QLIST_FOREACH_SAFE(drv, &tpm_backends, list, next) {
QLIST_REMOVE(drv, list);
- drv->ops->destroy(drv);
+ tpm_backend_destroy(drv);
}
}
diff --git a/tpm/tpm_int.h b/tpm/tpm_int.h
index f7056436cc..340bfd52f1 100644
--- a/tpm/tpm_int.h
+++ b/tpm/tpm_int.h
@@ -15,27 +15,8 @@
#include "exec/memory.h"
#include "tpm/tpm_tis.h"
-struct TPMDriverOps;
-typedef struct TPMDriverOps TPMDriverOps;
-
-typedef struct TPMPassthruState TPMPassthruState;
-
-typedef struct TPMBackend {
- char *id;
- enum TpmModel fe_model;
- char *path;
- char *cancel_path;
- const TPMDriverOps *ops;
-
- union {
- TPMPassthruState *tpm_pt;
- } s;
-
- QLIST_ENTRY(TPMBackend) list;
-} TPMBackend;
-
/* overall state of the TPM interface */
-typedef struct TPMState {
+struct TPMState {
ISADevice busdev;
MemoryRegion mmio;
@@ -48,12 +29,10 @@ typedef struct TPMState {
char *backend;
TPMBackend *be_driver;
-} TPMState;
+};
#define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS)
-typedef void (TPMRecvDataCB)(TPMState *, uint8_t locty);
-
struct TPMDriverOps {
enum TpmType type;
/* get a descriptive text of the backend to display to the user */
diff --git a/tpm/tpm_passthrough.c b/tpm/tpm_passthrough.c
index 24aff4d69c..80a48d68cd 100644
--- a/tpm/tpm_passthrough.c
+++ b/tpm/tpm_passthrough.c
@@ -27,6 +27,7 @@
#include "qemu-common.h"
#include "qapi/error.h"
#include "qemu/sockets.h"
+#include "backends/tpm.h"
#include "tpm_int.h"
#include "hw/hw.h"
#include "hw/pc.h"
@@ -43,8 +44,11 @@
do { } while (0)
#endif
-/* data structures */
+#define TYPE_TPM_PASSTHROUGH "tpm-passthrough"
+#define TPM_PASSTHROUGH(obj) \
+ OBJECT_CHECK(TPMPassthruState, (obj), TYPE_TPM_PASSTHROUGH)
+/* data structures */
typedef struct TPMPassthruThreadParams {
TPMState *tpm_state;
@@ -53,6 +57,8 @@ typedef struct TPMPassthruThreadParams {
} TPMPassthruThreadParams;
struct TPMPassthruState {
+ TPMBackend parent;
+
TPMBackendThread tbt;
TPMPassthruThreadParams tpm_thread_params;
@@ -65,6 +71,8 @@ struct TPMPassthruState {
bool had_startup_error;
};
+typedef struct TPMPassthruState TPMPassthruState;
+
#define TPM_PASSTHROUGH_DEFAULT_DEVICE "/dev/tpm0"
/* functions */
@@ -149,7 +157,7 @@ static void tpm_passthrough_worker_thread(gpointer data,
gpointer user_data)
{
TPMPassthruThreadParams *thr_parms = user_data;
- TPMPassthruState *tpm_pt = thr_parms->tb->s.tpm_pt;
+ TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(thr_parms->tb);
TPMBackendCmd cmd = (TPMBackendCmd)data;
DPRINTF("tpm_passthrough: processing command type %d\n", cmd);
@@ -176,21 +184,21 @@ static void tpm_passthrough_worker_thread(gpointer data,
*/
static int tpm_passthrough_startup_tpm(TPMBackend *tb)
{
- TPMPassthruState *tpm_pt = tb->s.tpm_pt;
+ TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
/* terminate a running TPM */
tpm_backend_thread_end(&tpm_pt->tbt);
tpm_backend_thread_create(&tpm_pt->tbt,
tpm_passthrough_worker_thread,
- &tb->s.tpm_pt->tpm_thread_params);
+ &tpm_pt->tpm_thread_params);
return 0;
}
static void tpm_passthrough_reset(TPMBackend *tb)
{
- TPMPassthruState *tpm_pt = tb->s.tpm_pt;
+ TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
DPRINTF("tpm_passthrough: CALL TO TPM_RESET!\n");
@@ -204,7 +212,7 @@ static void tpm_passthrough_reset(TPMBackend *tb)
static int tpm_passthrough_init(TPMBackend *tb, TPMState *s,
TPMRecvDataCB *recv_data_cb)
{
- TPMPassthruState *tpm_pt = tb->s.tpm_pt;
+ TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
tpm_pt->tpm_thread_params.tpm_state = s;
tpm_pt->tpm_thread_params.recv_data_callback = recv_data_cb;
@@ -220,7 +228,7 @@ static bool tpm_passthrough_get_tpm_established_flag(TPMBackend *tb)
static bool tpm_passthrough_get_startup_error(TPMBackend *tb)
{
- TPMPassthruState *tpm_pt = tb->s.tpm_pt;
+ TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
return tpm_pt->had_startup_error;
}
@@ -238,14 +246,14 @@ static size_t tpm_passthrough_realloc_buffer(TPMSizedBuffer *sb)
static void tpm_passthrough_deliver_request(TPMBackend *tb)
{
- TPMPassthruState *tpm_pt = tb->s.tpm_pt;
+ TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
tpm_backend_thread_deliver_request(&tpm_pt->tbt);
}
static void tpm_passthrough_cancel_cmd(TPMBackend *tb)
{
- TPMPassthruState *tpm_pt = tb->s.tpm_pt;
+ TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
int n;
/*
@@ -412,6 +420,7 @@ static int tpm_passthrough_open_sysfs_cancel(TPMBackend *tb)
static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb)
{
+ TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
const char *value;
value = qemu_opt_get(opts, "cancel-path");
@@ -424,45 +433,45 @@ static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb)
value = TPM_PASSTHROUGH_DEFAULT_DEVICE;
}
- tb->s.tpm_pt->tpm_dev = g_strdup(value);
+ tpm_pt->tpm_dev = g_strdup(value);
- tb->path = g_strdup(tb->s.tpm_pt->tpm_dev);
+ tb->path = g_strdup(tpm_pt->tpm_dev);
- tb->s.tpm_pt->tpm_fd = qemu_open(tb->s.tpm_pt->tpm_dev, O_RDWR);
- if (tb->s.tpm_pt->tpm_fd < 0) {
+ tpm_pt->tpm_fd = qemu_open(tpm_pt->tpm_dev, O_RDWR);
+ if (tpm_pt->tpm_fd < 0) {
error_report("Cannot access TPM device using '%s': %s\n",
- tb->s.tpm_pt->tpm_dev, strerror(errno));
+ tpm_pt->tpm_dev, strerror(errno));
goto err_free_parameters;
}
- if (tpm_passthrough_test_tpmdev(tb->s.tpm_pt->tpm_fd)) {
+ if (tpm_passthrough_test_tpmdev(tpm_pt->tpm_fd)) {
error_report("'%s' is not a TPM device.\n",
- tb->s.tpm_pt->tpm_dev);
+ tpm_pt->tpm_dev);
goto err_close_tpmdev;
}
return 0;
err_close_tpmdev:
- qemu_close(tb->s.tpm_pt->tpm_fd);
- tb->s.tpm_pt->tpm_fd = -1;
+ qemu_close(tpm_pt->tpm_fd);
+ tpm_pt->tpm_fd = -1;
err_free_parameters:
g_free(tb->path);
tb->path = NULL;
- g_free(tb->s.tpm_pt->tpm_dev);
- tb->s.tpm_pt->tpm_dev = NULL;
+ g_free(tpm_pt->tpm_dev);
+ tpm_pt->tpm_dev = NULL;
return 1;
}
static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id)
{
- TPMBackend *tb;
+ Object *obj = object_new(TYPE_TPM_PASSTHROUGH);
+ TPMBackend *tb = TPM_BACKEND(obj);
+ TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
- tb = g_new0(TPMBackend, 1);
- tb->s.tpm_pt = g_new0(TPMPassthruState, 1);
tb->id = g_strdup(id);
/* let frontend set the fe_model to proper value */
tb->fe_model = -1;
@@ -473,8 +482,8 @@ static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id)
goto err_exit;
}
- tb->s.tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tb);
- if (tb->s.tpm_pt->cancel_fd < 0) {
+ tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tb);
+ if (tpm_pt->cancel_fd < 0) {
goto err_exit;
}
@@ -482,29 +491,25 @@ static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id)
err_exit:
g_free(tb->id);
- g_free(tb->s.tpm_pt);
- g_free(tb);
return NULL;
}
static void tpm_passthrough_destroy(TPMBackend *tb)
{
- TPMPassthruState *tpm_pt = tb->s.tpm_pt;
+ TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
tpm_passthrough_cancel_cmd(tb);
tpm_backend_thread_end(&tpm_pt->tbt);
qemu_close(tpm_pt->tpm_fd);
- qemu_close(tb->s.tpm_pt->cancel_fd);
+ qemu_close(tpm_pt->cancel_fd);
g_free(tb->id);
g_free(tb->path);
g_free(tb->cancel_path);
- g_free(tb->s.tpm_pt->tpm_dev);
- g_free(tb->s.tpm_pt);
- g_free(tb);
+ g_free(tpm_pt->tpm_dev);
}
const TPMDriverOps tpm_passthrough_driver = {
@@ -522,8 +527,33 @@ const TPMDriverOps tpm_passthrough_driver = {
.get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag,
};
+static void tpm_passthrough_inst_init(Object *obj)
+{
+}
+
+static void tpm_passthrough_inst_finalize(Object *obj)
+{
+}
+
+static void tpm_passthrough_class_init(ObjectClass *klass, void *data)
+{
+ TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);
+
+ tbc->ops = &tpm_passthrough_driver;
+}
+
+static const TypeInfo tpm_passthrough_info = {
+ .name = TYPE_TPM_PASSTHROUGH,
+ .parent = TYPE_TPM_BACKEND,
+ .instance_size = sizeof(TPMPassthruState),
+ .class_init = tpm_passthrough_class_init,
+ .instance_init = tpm_passthrough_inst_init,
+ .instance_finalize = tpm_passthrough_inst_finalize,
+};
+
static void tpm_passthrough_register(void)
{
+ type_register_static(&tpm_passthrough_info);
tpm_register_driver(&tpm_passthrough_driver);
}
diff --git a/tpm/tpm_tis.c b/tpm/tpm_tis.c
index e93825eec1..367f734dc4 100644
--- a/tpm/tpm_tis.c
+++ b/tpm/tpm_tis.c
@@ -19,6 +19,7 @@
* specification.
*/
+#include "backends/tpm.h"
#include "tpm_int.h"
#include "block/block.h"
#include "exec/address-spaces.h"
@@ -160,7 +161,7 @@ static void tpm_tis_tpm_send(TPMState *s, uint8_t locty)
*/
tis->loc[locty].state = TPM_TIS_STATE_EXECUTION;
- s->be_driver->ops->deliver_request(s->be_driver);
+ tpm_backend_deliver_request(s->be_driver);
}
/* raise an interrupt if allowed */
@@ -284,7 +285,7 @@ static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty)
* request the backend to cancel. Some backends may not
* support it
*/
- s->be_driver->ops->cancel_cmd(s->be_driver);
+ tpm_backend_cancel_cmd(s->be_driver);
return;
}
}
@@ -426,7 +427,7 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
uint8_t locty = tpm_tis_locality_from_addr(addr);
uint32_t avail;
- if (s->be_driver->ops->had_startup_error(s->be_driver)) {
+ if (tpm_backend_had_startup_error(s->be_driver)) {
return val;
}
@@ -438,7 +439,7 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
if (tpm_tis_check_request_use_except(s, locty)) {
val |= TPM_TIS_ACCESS_PENDING_REQUEST;
}
- val |= !s->be_driver->ops->get_tpm_established_flag(s->be_driver);
+ val |= !tpm_backend_get_tpm_established_flag(s->be_driver);
break;
case TPM_TIS_REG_INT_ENABLE:
val = tis->loc[locty].inte;
@@ -529,7 +530,7 @@ static void tpm_tis_mmio_write_intern(void *opaque, hwaddr addr,
return;
}
- if (s->be_driver->ops->had_startup_error(s->be_driver)) {
+ if (tpm_backend_had_startup_error(s->be_driver)) {
return;
}
@@ -804,7 +805,7 @@ static const MemoryRegionOps tpm_tis_memory_ops = {
static int tpm_tis_do_startup_tpm(TPMState *s)
{
- return s->be_driver->ops->startup_tpm(s->be_driver);
+ return tpm_backend_startup_tpm(s->be_driver);
}
/*
@@ -817,7 +818,7 @@ static void tpm_tis_reset(DeviceState *dev)
TPMTISEmuState *tis = &s->s.tis;
int c;
- s->be_driver->ops->reset(s->be_driver);
+ tpm_backend_reset(s->be_driver);
tis->active_locty = TPM_TIS_NO_LOCALITY;
tis->next_locty = TPM_TIS_NO_LOCALITY;
@@ -831,9 +832,9 @@ static void tpm_tis_reset(DeviceState *dev)
tis->loc[c].state = TPM_TIS_STATE_IDLE;
tis->loc[c].w_offset = 0;
- s->be_driver->ops->realloc_buffer(&tis->loc[c].w_buffer);
+ tpm_backend_realloc_buffer(s->be_driver, &tis->loc[c].w_buffer);
tis->loc[c].r_offset = 0;
- s->be_driver->ops->realloc_buffer(&tis->loc[c].r_buffer);
+ tpm_backend_realloc_buffer(s->be_driver, &tis->loc[c].r_buffer);
}
tpm_tis_do_startup_tpm(s);
@@ -865,7 +866,7 @@ static void tpm_tis_realizefn(DeviceState *dev, Error **errp)
s->be_driver->fe_model = TPM_MODEL_TPM_TIS;
- if (s->be_driver->ops->init(s->be_driver, s, tpm_tis_receive_cb)) {
+ if (tpm_backend_init(s->be_driver, s, tpm_tis_receive_cb)) {
error_setg(errp, "tpm_tis: backend driver with id %s could not be "
"initialized", s->backend);
return;
diff --git a/tpm/tpm_tis.h b/tpm/tpm_tis.h
index 0c8df80cce..7f216e56b2 100644
--- a/tpm/tpm_tis.h
+++ b/tpm/tpm_tis.h
@@ -35,10 +35,10 @@
#define TYPE_TPM_TIS "tpm-tis"
-typedef struct TPMSizedBuffer {
+struct TPMSizedBuffer {
uint32_t size;
uint8_t *buffer;
-} TPMSizedBuffer;
+};
typedef enum {
TPM_TIS_STATE_IDLE = 0,
diff --git a/trace-events b/trace-events
index 7f34112424..412f7e40f8 100644
--- a/trace-events
+++ b/trace-events
@@ -380,6 +380,7 @@ usb_xhci_xfer_nak(void *xfer) "%p"
usb_xhci_xfer_retry(void *xfer) "%p"
usb_xhci_xfer_success(void *xfer, uint32_t bytes) "%p: len %d"
usb_xhci_xfer_error(void *xfer, uint32_t ret) "%p: ret %d"
+usb_xhci_unimplemented(const char *item, int nr) "%s (0x%x)"
# hw/usb/desc.c
usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d"
diff --git a/ui/gtk.c b/ui/gtk.c
index a5a8156325..1a6bee616a 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -210,11 +210,11 @@ static void gd_update_caption(GtkDisplayState *s)
bool is_paused = !runstate_is_running();
if (gd_is_grab_active(s)) {
- grab = " - Press Ctrl+Alt+G to release grab";
+ grab = _(" - Press Ctrl+Alt+G to release grab");
}
if (is_paused) {
- status = " [Paused]";
+ status = _(" [Paused]");
}
s->external_pause_update = true;
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->pause_item),
@@ -1363,6 +1363,7 @@ static const DisplayChangeListenerOps dcl_ops = {
void gtk_display_init(DisplayState *ds)
{
GtkDisplayState *s = g_malloc0(sizeof(*s));
+ char *filename;
gtk_init(NULL, NULL);
@@ -1394,6 +1395,18 @@ void gtk_display_init(DisplayState *ds)
gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), s->drawing_area, gtk_label_new("VGA"));
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "qemu-icon.bmp");
+ if (filename) {
+ GError *error = NULL;
+ GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(filename, &error);
+ if (pixbuf) {
+ gtk_window_set_icon(GTK_WINDOW(s->window), pixbuf);
+ } else {
+ g_error_free(error);
+ }
+ g_free(filename);
+ }
+
gd_create_menus(s);
gd_connect_signals(s);
diff --git a/ui/vnc.c b/ui/vnc.c
index bbe1e0f179..5ddb696625 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -2732,7 +2732,7 @@ static void vnc_connect(VncDisplay *vd, int csock, int skipauth, bool websocket)
VNC_DEBUG("New client on socket %d\n", csock);
vd->dcl.idle = 0;
- socket_set_nonblock(vs->csock);
+ qemu_set_nonblock(vs->csock);
#ifdef CONFIG_VNC_WS
if (websocket) {
vs->websocket = 1;
diff --git a/util/oslib-posix.c b/util/oslib-posix.c
index 433dd6888b..4e4b8196be 100644
--- a/util/oslib-posix.c
+++ b/util/oslib-posix.c
@@ -134,14 +134,14 @@ void qemu_vfree(void *ptr)
free(ptr);
}
-void socket_set_block(int fd)
+void qemu_set_block(int fd)
{
int f;
f = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, f & ~O_NONBLOCK);
}
-void socket_set_nonblock(int fd)
+void qemu_set_nonblock(int fd)
{
int f;
f = fcntl(fd, F_GETFL);
diff --git a/util/oslib-win32.c b/util/oslib-win32.c
index 640194c0cf..dcfa0c2918 100644
--- a/util/oslib-win32.c
+++ b/util/oslib-win32.c
@@ -100,14 +100,14 @@ struct tm *localtime_r(const time_t *timep, struct tm *result)
return p;
}
-void socket_set_block(int fd)
+void qemu_set_block(int fd)
{
unsigned long opt = 0;
WSAEventSelect(fd, NULL, 0);
ioctlsocket(fd, FIONBIO, &opt);
}
-void socket_set_nonblock(int fd)
+void qemu_set_nonblock(int fd)
{
unsigned long opt = 1;
ioctlsocket(fd, FIONBIO, &opt);
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index b6b78f503a..94581aa236 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -277,7 +277,7 @@ static int inet_connect_addr(struct addrinfo *addr, bool *in_progress,
}
qemu_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
if (connect_state != NULL) {
- socket_set_nonblock(sock);
+ qemu_set_nonblock(sock);
}
/* connect to peer */
do {
@@ -737,7 +737,7 @@ int unix_connect_opts(QemuOpts *opts, Error **errp,
connect_state = g_malloc0(sizeof(*connect_state));
connect_state->callback = callback;
connect_state->opaque = opaque;
- socket_set_nonblock(sock);
+ qemu_set_nonblock(sock);
}
memset(&un, 0, sizeof(un));
@@ -910,6 +910,7 @@ int socket_connect(SocketAddress *addr, Error **errp,
case SOCKET_ADDRESS_KIND_FD:
fd = monitor_get_fd(cur_mon, addr->fd->str, errp);
if (callback) {
+ qemu_set_nonblock(fd);
callback(fd, opaque);
}
break;
diff --git a/util/qemu-timer-common.c b/util/qemu-timer-common.c
index 16f5e758b2..95e0847c76 100644
--- a/util/qemu-timer-common.c
+++ b/util/qemu-timer-common.c
@@ -49,9 +49,7 @@ int use_rt_clock;
static void __attribute__((constructor)) init_get_clock(void)
{
use_rt_clock = 0;
-#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \
- || defined(__DragonFly__) || defined(__FreeBSD_kernel__) \
- || defined(__OpenBSD__)
+#ifdef CLOCK_MONOTONIC
{
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
diff --git a/vl.c b/vl.c
index 52eacca35f..a8bba043a2 100644
--- a/vl.c
+++ b/vl.c
@@ -1278,9 +1278,9 @@ char *get_boot_devices_list(size_t *size)
if (boot_strict && *size > 0) {
list[total-1] = '\n';
- list = g_realloc(list, total + 4);
- memcpy(&list[total], "HALT", 4);
- *size = total + 4;
+ list = g_realloc(list, total + 5);
+ memcpy(&list[total], "HALT", 5);
+ *size = total + 5;
}
return list;
}
@@ -2396,6 +2396,7 @@ static int mon_init_func(QemuOpts *opts, void *opaque)
exit(1);
}
+ qemu_chr_fe_claim_no_fail(chr);
monitor_init(chr, flags);
return 0;
}
@@ -2545,7 +2546,7 @@ static int virtcon_parse(const char *devname)
qemu_opt_set(bus_opts, "driver", "virtio-serial-s390");
} else {
qemu_opt_set(bus_opts, "driver", "virtio-serial-pci");
- }
+ }
dev_opts = qemu_opts_create_nofail(device);
qemu_opt_set(dev_opts, "driver", "virtconsole");
@@ -2597,7 +2598,7 @@ static int sclp_parse(const char *devname)
}
static int debugcon_parse(const char *devname)
-{
+{
QemuOpts *opts;
if (!qemu_chr_new("debugcon", devname, NULL)) {
@@ -3586,7 +3587,9 @@ int main(int argc, char **argv, char **envp)
break;
}
case QEMU_OPTION_acpitable:
- do_acpitable_option(optarg);
+ opts = qemu_opts_parse(qemu_find_opts("acpi"), optarg, 1);
+ g_assert(opts != NULL);
+ do_acpitable_option(opts);
break;
case QEMU_OPTION_smbios:
do_smbios_option(optarg);
@@ -3734,8 +3737,8 @@ int main(int argc, char **argv, char **envp)
}
p += 8;
os_set_proc_name(p);
- }
- }
+ }
+ }
break;
case QEMU_OPTION_prom_env:
if (nb_prom_envs >= MAX_PROM_ENVS) {
diff --git a/xen-mapcache.c b/xen-mapcache.c
index dc6d1fadb7..5a626cdf84 100644
--- a/xen-mapcache.c
+++ b/xen-mapcache.c
@@ -74,8 +74,7 @@ typedef struct MapCache {
QTAILQ_HEAD(map_cache_head, MapCacheRev) locked_entries;
/* For most cases (>99.9%), the page address is the same. */
- hwaddr last_address_index;
- uint8_t *last_address_vaddr;
+ MapCacheEntry *last_entry;
unsigned long max_mcache_size;
unsigned int mcache_bucket_shift;
@@ -105,7 +104,6 @@ void xen_map_cache_init(phys_offset_to_gaddr_t f, void *opaque)
mapcache->opaque = opaque;
QTAILQ_INIT(&mapcache->locked_entries);
- mapcache->last_address_index = -1;
if (geteuid() == 0) {
rlimit_as.rlim_cur = RLIM_INFINITY;
@@ -202,6 +200,7 @@ uint8_t *xen_map_cache(hwaddr phys_addr, hwaddr size,
hwaddr address_index;
hwaddr address_offset;
hwaddr __size = size;
+ hwaddr __test_bit_size = size;
bool translated = false;
tryagain:
@@ -210,9 +209,25 @@ tryagain:
trace_xen_map_cache(phys_addr);
- if (address_index == mapcache->last_address_index && !lock && !__size) {
- trace_xen_map_cache_return(mapcache->last_address_vaddr + address_offset);
- return mapcache->last_address_vaddr + address_offset;
+ /* __test_bit_size is always a multiple of XC_PAGE_SIZE */
+ if (size) {
+ __test_bit_size = size + (phys_addr & (XC_PAGE_SIZE - 1));
+
+ if (__test_bit_size % XC_PAGE_SIZE) {
+ __test_bit_size += XC_PAGE_SIZE - (__test_bit_size % XC_PAGE_SIZE);
+ }
+ } else {
+ __test_bit_size = XC_PAGE_SIZE;
+ }
+
+ if (mapcache->last_entry != NULL &&
+ mapcache->last_entry->paddr_index == address_index &&
+ !lock && !__size &&
+ test_bits(address_offset >> XC_PAGE_SHIFT,
+ __test_bit_size >> XC_PAGE_SHIFT,
+ mapcache->last_entry->valid_mapping)) {
+ trace_xen_map_cache_return(mapcache->last_entry->vaddr_base + address_offset);
+ return mapcache->last_entry->vaddr_base + address_offset;
}
/* size is always a multiple of MCACHE_BUCKET_SIZE */
@@ -229,7 +244,8 @@ tryagain:
while (entry && entry->lock && entry->vaddr_base &&
(entry->paddr_index != address_index || entry->size != __size ||
- !test_bits(address_offset >> XC_PAGE_SHIFT, size >> XC_PAGE_SHIFT,
+ !test_bits(address_offset >> XC_PAGE_SHIFT,
+ __test_bit_size >> XC_PAGE_SHIFT,
entry->valid_mapping))) {
pentry = entry;
entry = entry->next;
@@ -241,15 +257,17 @@ tryagain:
} else if (!entry->lock) {
if (!entry->vaddr_base || entry->paddr_index != address_index ||
entry->size != __size ||
- !test_bits(address_offset >> XC_PAGE_SHIFT, size >> XC_PAGE_SHIFT,
+ !test_bits(address_offset >> XC_PAGE_SHIFT,
+ __test_bit_size >> XC_PAGE_SHIFT,
entry->valid_mapping)) {
xen_remap_bucket(entry, __size, address_index);
}
}
- if(!test_bits(address_offset >> XC_PAGE_SHIFT, size >> XC_PAGE_SHIFT,
+ if(!test_bits(address_offset >> XC_PAGE_SHIFT,
+ __test_bit_size >> XC_PAGE_SHIFT,
entry->valid_mapping)) {
- mapcache->last_address_index = -1;
+ mapcache->last_entry = NULL;
if (!translated && mapcache->phys_offset_to_gaddr) {
phys_addr = mapcache->phys_offset_to_gaddr(phys_addr, size, mapcache->opaque);
translated = true;
@@ -259,19 +277,18 @@ tryagain:
return NULL;
}
- mapcache->last_address_index = address_index;
- mapcache->last_address_vaddr = entry->vaddr_base;
+ mapcache->last_entry = entry;
if (lock) {
MapCacheRev *reventry = g_malloc0(sizeof(MapCacheRev));
entry->lock++;
- reventry->vaddr_req = mapcache->last_address_vaddr + address_offset;
- reventry->paddr_index = mapcache->last_address_index;
+ reventry->vaddr_req = mapcache->last_entry->vaddr_base + address_offset;
+ reventry->paddr_index = mapcache->last_entry->paddr_index;
reventry->size = entry->size;
QTAILQ_INSERT_HEAD(&mapcache->locked_entries, reventry, next);
}
- trace_xen_map_cache_return(mapcache->last_address_vaddr + address_offset);
- return mapcache->last_address_vaddr + address_offset;
+ trace_xen_map_cache_return(mapcache->last_entry->vaddr_base + address_offset);
+ return mapcache->last_entry->vaddr_base + address_offset;
}
ram_addr_t xen_ram_addr_from_mapcache(void *ptr)
@@ -338,9 +355,9 @@ void xen_invalidate_map_cache_entry(uint8_t *buffer)
QTAILQ_REMOVE(&mapcache->locked_entries, reventry, next);
g_free(reventry);
- if (mapcache->last_address_index == paddr_index) {
- mapcache->last_address_index = -1;
- mapcache->last_address_vaddr = NULL;
+ if (mapcache->last_entry != NULL &&
+ mapcache->last_entry->paddr_index == paddr_index) {
+ mapcache->last_entry = NULL;
}
entry = &mapcache->entry[paddr_index % mapcache->nr_buckets];
@@ -404,8 +421,7 @@ void xen_invalidate_map_cache(void)
entry->valid_mapping = NULL;
}
- mapcache->last_address_index = -1;
- mapcache->last_address_vaddr = NULL;
+ mapcache->last_entry = NULL;
mapcache_unlock();
}