aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2015-06-01 15:22:46 +0100
committerPeter Maydell <peter.maydell@linaro.org>2015-06-01 15:22:46 +0100
commitb821cbe274c5a5cacf1a7b28360d869ae1e6e0c3 (patch)
tree400b2e88bf5c577a4cbc5695d4fb12b30360df89
parent9657cafceb90accedd574a3accb3d344def8e764 (diff)
parent830d70db692e374b55555f4407f96a1ceefdcc97 (diff)
Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging
pc, pci, tpm, virtio, vhost enhancements and fixes A bunch of cleanups and fixes all over the place, enhancements in TPM, virtio and vhost. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # gpg: Signature made Mon Jun 1 13:19:48 2015 BST using RSA key ID D28D5469 # gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" # gpg: aka "Michael S. Tsirkin <mst@redhat.com>" * remotes/mst/tags/for_upstream: (60 commits) vhost-user: add multi queue support virtio: make features 64bit wide qdev: add 64bit properties virtio-mmio: ioeventfd support hw/acpi/aml-build: Fix memory leak acpi: add aml_while() term acpi: add aml_increment() term acpi: add aml_shiftright() term acpi: add aml_shiftleft() term acpi: add aml_index() term acpi: add aml_lless() term acpi: add aml_add() term TPM2 ACPI table support tpm: Probe for connected TPM 1.2 or TPM 2 Extend TPM TIS interface to support TPM 2 Add stream ID to MSI write acpi: Simplify printing to dynamic string i386: drop FDC in pc-q35-2.4+ if neither it nor floppy drives are wanted i386/pc_q35: don't insist on board FDC if there's no default floppy i386/pc: '-drive if=floppy' should imply a board-default FDC ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--backends/tpm.c14
-rw-r--r--docs/specs/vhost-user.txt5
-rw-r--r--hw/9pfs/virtio-9p-device.c2
-rw-r--r--hw/acpi/aml-build.c85
-rw-r--r--hw/block/virtio-blk.c2
-rw-r--r--hw/char/virtio-serial-bus.c4
-rw-r--r--hw/core/qdev-properties.c58
-rw-r--r--hw/i386/Makefile.objs2
-rw-r--r--hw/i386/acpi-build.c43
-rw-r--r--hw/i386/pc.c49
-rw-r--r--hw/i386/pc_piix.c697
-rw-r--r--hw/i386/pc_q35.c237
-rw-r--r--hw/i386/ssdt-tpm.dsl16
-rw-r--r--hw/i386/ssdt-tpm.hex.generated26
-rw-r--r--hw/i386/ssdt-tpm2.dsl29
-rw-r--r--hw/i386/ssdt-tpm2.hex.generated109
-rw-r--r--hw/input/virtio-input.c2
-rw-r--r--hw/net/vhost_net.c3
-rw-r--r--hw/net/virtio-net.c81
-rw-r--r--hw/pci/msi.c10
-rw-r--r--hw/pci/msix.c3
-rw-r--r--hw/ppc/spapr.c15
-rw-r--r--hw/s390x/s390-virtio-bus.c30
-rw-r--r--hw/s390x/s390-virtio-bus.h1
-rw-r--r--hw/s390x/s390-virtio-ccw.c2
-rw-r--r--hw/s390x/virtio-ccw.c89
-rw-r--r--hw/s390x/virtio-ccw.h4
-rw-r--r--hw/scsi/vhost-scsi.c4
-rw-r--r--hw/scsi/virtio-scsi.c8
-rw-r--r--hw/tpm/Makefile.objs2
-rw-r--r--hw/tpm/tpm_int.h7
-rw-r--r--hw/tpm/tpm_passthrough.c65
-rw-r--r--hw/tpm/tpm_tis.c119
-rw-r--r--hw/tpm/tpm_tis.h1
-rw-r--r--hw/tpm/tpm_util.c126
-rw-r--r--hw/tpm/tpm_util.h28
-rw-r--r--hw/virtio/vhost-user.c11
-rw-r--r--hw/virtio/virtio-balloon.c24
-rw-r--r--hw/virtio/virtio-bus.c23
-rw-r--r--hw/virtio/virtio-mmio.c205
-rw-r--r--hw/virtio/virtio-pci.c68
-rw-r--r--hw/virtio/virtio-pci.h1
-rw-r--r--hw/virtio/virtio-rng.c2
-rw-r--r--hw/virtio/virtio.c112
-rw-r--r--include/exec/memattrs.h2
-rw-r--r--include/hw/acpi/acpi-defs.h18
-rw-r--r--include/hw/acpi/aml-build.h7
-rw-r--r--include/hw/acpi/tpm.h5
-rw-r--r--include/hw/boards.h15
-rw-r--r--include/hw/compat.h8
-rw-r--r--include/hw/i386/pc.h89
-rw-r--r--include/hw/pci/msi.h1
-rw-r--r--include/hw/qdev-properties.h10
-rw-r--r--include/hw/s390x/s390_flic.h5
-rw-r--r--include/hw/virtio/virtio-bus.h5
-rw-r--r--include/hw/virtio/virtio.h32
-rw-r--r--include/sysemu/tpm.h17
-rw-r--r--include/sysemu/tpm_backend.h23
-rw-r--r--net/vhost-user.c37
-rw-r--r--qapi-schema.json6
-rw-r--r--qemu-options.hx5
-rw-r--r--vl.c15
62 files changed, 1651 insertions, 1073 deletions
diff --git a/backends/tpm.c b/backends/tpm.c
index 36c5d46f0a..f3ab3b30bd 100644
--- a/backends/tpm.c
+++ b/backends/tpm.c
@@ -96,6 +96,20 @@ bool tpm_backend_get_tpm_established_flag(TPMBackend *s)
return k->ops->get_tpm_established_flag(s);
}
+int tpm_backend_reset_tpm_established_flag(TPMBackend *s, uint8_t locty)
+{
+ TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+ return k->ops->reset_tpm_established_flag(s, locty);
+}
+
+TPMVersion tpm_backend_get_tpm_version(TPMBackend *s)
+{
+ TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+ return k->ops->get_tpm_version(s);
+}
+
static bool tpm_backend_prop_get_opened(Object *obj, Error **errp)
{
TPMBackend *s = TPM_BACKEND(obj);
diff --git a/docs/specs/vhost-user.txt b/docs/specs/vhost-user.txt
index 650bb18186..2c8e9347cc 100644
--- a/docs/specs/vhost-user.txt
+++ b/docs/specs/vhost-user.txt
@@ -127,6 +127,11 @@ in the ancillary data:
If Master is unable to send the full message or receives a wrong reply it will
close the connection. An optional reconnection mechanism can be implemented.
+Multi queue support
+-------------------
+The protocol supports multiple queues by setting all index fields in the sent
+messages to a properly calculated value.
+
Message types
-------------
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index 30492ecb02..60f9ff9a31 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -21,7 +21,7 @@
#include "virtio-9p-coth.h"
#include "hw/virtio/virtio-access.h"
-static uint32_t virtio_9p_get_features(VirtIODevice *vdev, uint32_t features)
+static uint64_t virtio_9p_get_features(VirtIODevice *vdev, uint64_t features)
{
virtio_add_feature(&features, VIRTIO_9P_MOUNT_TAG);
return features;
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index 323b7bc179..2bebf23db2 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -19,6 +19,7 @@
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
+#include <glib/gprintf.h>
#include <stdio.h>
#include <stdarg.h>
#include <assert.h>
@@ -59,7 +60,6 @@ static void build_append_array(GArray *array, GArray *val)
static void
build_append_nameseg(GArray *array, const char *seg)
{
- /* It would be nicer to use g_string_vprintf but it's only there in 2.22 */
int len;
len = strlen(seg);
@@ -73,22 +73,12 @@ build_append_nameseg(GArray *array, const char *seg)
static void GCC_FMT_ATTR(2, 0)
build_append_namestringv(GArray *array, const char *format, va_list ap)
{
- /* It would be nicer to use g_string_vprintf but it's only there in 2.22 */
char *s;
- int len;
- va_list va_len;
char **segs;
char **segs_iter;
int seg_count = 0;
- va_copy(va_len, ap);
- len = vsnprintf(NULL, 0, format, va_len);
- va_end(va_len);
- len += 1;
- s = g_new(typeof(*s), len);
-
- len = vsnprintf(s, len, format, ap);
-
+ s = g_strdup_vprintf(format, ap);
segs = g_strsplit(s, ".", 0);
g_free(s);
@@ -306,6 +296,7 @@ static void aml_free(gpointer data, gpointer user_data)
{
Aml *var = data;
build_free_array(var->buf);
+ g_free(var);
}
Aml *init_aml_allocator(void)
@@ -465,6 +456,63 @@ Aml *aml_or(Aml *arg1, Aml *arg2)
return var;
}
+/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefShiftLeft */
+Aml *aml_shiftleft(Aml *arg1, Aml *count)
+{
+ Aml *var = aml_opcode(0x79 /* ShiftLeftOp */);
+ aml_append(var, arg1);
+ aml_append(var, count);
+ build_append_byte(var->buf, 0x00); /* NullNameOp */
+ return var;
+}
+
+/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefShiftRight */
+Aml *aml_shiftright(Aml *arg1, Aml *count)
+{
+ Aml *var = aml_opcode(0x7A /* ShiftRightOp */);
+ aml_append(var, arg1);
+ aml_append(var, count);
+ build_append_byte(var->buf, 0x00); /* NullNameOp */
+ return var;
+}
+
+/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefLLess */
+Aml *aml_lless(Aml *arg1, Aml *arg2)
+{
+ Aml *var = aml_opcode(0x95 /* LLessOp */);
+ aml_append(var, arg1);
+ aml_append(var, arg2);
+ return var;
+}
+
+/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefAdd */
+Aml *aml_add(Aml *arg1, Aml *arg2)
+{
+ Aml *var = aml_opcode(0x72 /* AddOp */);
+ aml_append(var, arg1);
+ aml_append(var, arg2);
+ build_append_byte(var->buf, 0x00 /* NullNameOp */);
+ return var;
+}
+
+/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefIncrement */
+Aml *aml_increment(Aml *arg)
+{
+ Aml *var = aml_opcode(0x75 /* IncrementOp */);
+ aml_append(var, arg);
+ return var;
+}
+
+/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefIndex */
+Aml *aml_index(Aml *arg1, Aml *idx)
+{
+ Aml *var = aml_opcode(0x88 /* IndexOp */);
+ aml_append(var, arg1);
+ aml_append(var, idx);
+ build_append_byte(var->buf, 0x00 /* NullNameOp */);
+ return var;
+}
+
/* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefNotify */
Aml *aml_notify(Aml *arg1, Aml *arg2)
{
@@ -753,22 +801,15 @@ Aml *aml_create_dword_field(Aml *srcbuf, Aml *index, const char *name)
Aml *aml_string(const char *name_format, ...)
{
Aml *var = aml_opcode(0x0D /* StringPrefix */);
- va_list ap, va_len;
+ va_list ap;
char *s;
int len;
va_start(ap, name_format);
- va_copy(va_len, ap);
- len = vsnprintf(NULL, 0, name_format, va_len);
- va_end(va_len);
- len += 1;
- s = g_new0(typeof(*s), len);
-
- len = vsnprintf(s, len, name_format, ap);
+ len = g_vasprintf(&s, name_format, ap);
va_end(ap);
- g_array_append_vals(var->buf, s, len);
- build_append_byte(var->buf, 0x0); /* NullChar */
+ g_array_append_vals(var->buf, s, len + 1);
g_free(s);
return var;
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index e6afe9763d..cd539aa11c 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -718,7 +718,7 @@ static void virtio_blk_set_config(VirtIODevice *vdev, const uint8_t *config)
aio_context_release(blk_get_aio_context(s->blk));
}
-static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features)
+static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features)
{
VirtIOBlock *s = VIRTIO_BLK(vdev);
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
index 6e2ad8221b..f893523ef1 100644
--- a/hw/char/virtio-serial-bus.c
+++ b/hw/char/virtio-serial-bus.c
@@ -498,7 +498,7 @@ static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
}
}
-static uint32_t get_features(VirtIODevice *vdev, uint32_t features)
+static uint64_t get_features(VirtIODevice *vdev, uint64_t features)
{
VirtIOSerial *vser;
@@ -973,7 +973,7 @@ static void virtio_serial_device_realize(DeviceState *dev, Error **errp)
}
/* Each port takes 2 queues, and one pair is for the control queue */
- max_supported_ports = VIRTIO_PCI_QUEUE_MAX / 2 - 1;
+ max_supported_ports = VIRTIO_QUEUE_MAX / 2 - 1;
if (vser->serial.max_virtserial_ports > max_supported_ports) {
error_setg(errp, "maximum ports supported: %u", max_supported_ports);
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index 570d5f0bad..a1606deaca 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -125,6 +125,64 @@ PropertyInfo qdev_prop_bit = {
.set = prop_set_bit,
};
+/* Bit64 */
+
+static uint64_t qdev_get_prop_mask64(Property *prop)
+{
+ assert(prop->info == &qdev_prop_bit);
+ return 0x1 << prop->bitnr;
+}
+
+static void bit64_prop_set(DeviceState *dev, Property *props, bool val)
+{
+ uint64_t *p = qdev_get_prop_ptr(dev, props);
+ uint64_t mask = qdev_get_prop_mask64(props);
+ if (val) {
+ *p |= mask;
+ } else {
+ *p &= ~mask;
+ }
+}
+
+static void prop_get_bit64(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ DeviceState *dev = DEVICE(obj);
+ Property *prop = opaque;
+ uint64_t *p = qdev_get_prop_ptr(dev, prop);
+ bool value = (*p & qdev_get_prop_mask64(prop)) != 0;
+
+ visit_type_bool(v, &value, name, errp);
+}
+
+static void prop_set_bit64(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ DeviceState *dev = DEVICE(obj);
+ Property *prop = opaque;
+ Error *local_err = NULL;
+ bool value;
+
+ if (dev->realized) {
+ qdev_prop_set_after_realize(dev, name, errp);
+ return;
+ }
+
+ visit_type_bool(v, &value, name, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ bit64_prop_set(dev, prop, value);
+}
+
+PropertyInfo qdev_prop_bit64 = {
+ .name = "bool",
+ .description = "on/off",
+ .get = prop_get_bit64,
+ .set = prop_set_bit64,
+};
+
/* --- bool --- */
static void get_bool(Object *obj, Visitor *v, void *opaque,
diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs
index e058a39147..0be5d97c59 100644
--- a/hw/i386/Makefile.objs
+++ b/hw/i386/Makefile.objs
@@ -9,7 +9,7 @@ obj-y += kvmvapic.o
obj-y += acpi-build.o
hw/i386/acpi-build.o: hw/i386/acpi-build.c \
hw/i386/acpi-dsdt.hex hw/i386/q35-acpi-dsdt.hex \
- hw/i386/ssdt-tpm.hex
+ hw/i386/ssdt-tpm.hex hw/i386/ssdt-tpm2.hex
iasl-option=$(shell if test -z "`$(1) $(2) 2>&1 > /dev/null`" \
; then echo "$(2)"; else echo "$(3)"; fi ;)
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 3d19de68fc..2c7399b9db 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -41,6 +41,7 @@
#include "hw/acpi/memory_hotplug.h"
#include "sysemu/tpm.h"
#include "hw/acpi/tpm.h"
+#include "sysemu/tpm_backend.h"
/* Supported chipsets: */
#include "hw/acpi/piix4.h"
@@ -106,7 +107,7 @@ typedef struct AcpiPmInfo {
typedef struct AcpiMiscInfo {
bool has_hpet;
- bool has_tpm;
+ TPMVersion tpm_version;
const unsigned char *dsdt_code;
unsigned dsdt_size;
uint16_t pvpanic_port;
@@ -234,7 +235,7 @@ static void acpi_get_pm_info(AcpiPmInfo *pm)
static void acpi_get_misc_info(AcpiMiscInfo *info)
{
info->has_hpet = hpet_find();
- info->has_tpm = tpm_find();
+ info->tpm_version = tpm_get_version();
info->pvpanic_port = pvpanic_port();
info->applesmc_io_base = applesmc_port();
}
@@ -414,6 +415,7 @@ build_madt(GArray *table_data, GArray *linker, AcpiCpuInfo *cpu,
}
#include "hw/i386/ssdt-tpm.hex"
+#include "hw/i386/ssdt-tpm2.hex"
/* Assign BSEL property to all buses. In the future, this can be changed
* to only assign to buses that support hotplug.
@@ -733,7 +735,7 @@ build_ssdt(GArray *table_data, GArray *linker,
if (misc->pvpanic_port) {
scope = aml_scope("\\_SB.PCI0.ISA");
- dev = aml_device("PEVR");
+ dev = aml_device("PEVT");
aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0001")));
crs = aml_resource_template();
@@ -748,6 +750,9 @@ build_ssdt(GArray *table_data, GArray *linker,
aml_append(field, aml_named_field("PEPT", 8));
aml_append(dev, field);
+ /* device present, functioning, decoding, not shown in UI */
+ aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
+
method = aml_method("RDPT", 0);
aml_append(method, aml_store(aml_name("PEPT"), aml_local(0)));
aml_append(method, aml_return(aml_local(0)));
@@ -1026,6 +1031,25 @@ build_tpm_ssdt(GArray *table_data, GArray *linker)
memcpy(tpm_ptr, ssdt_tpm_aml, sizeof(ssdt_tpm_aml));
}
+static void
+build_tpm2(GArray *table_data, GArray *linker)
+{
+ Acpi20TPM2 *tpm2_ptr;
+ void *tpm_ptr;
+
+ tpm_ptr = acpi_data_push(table_data, sizeof(ssdt_tpm2_aml));
+ memcpy(tpm_ptr, ssdt_tpm2_aml, sizeof(ssdt_tpm2_aml));
+
+ tpm2_ptr = acpi_data_push(table_data, sizeof *tpm2_ptr);
+
+ tpm2_ptr->platform_class = cpu_to_le16(TPM2_ACPI_CLASS_CLIENT);
+ tpm2_ptr->control_area_address = cpu_to_le64(0);
+ tpm2_ptr->start_method = cpu_to_le32(TPM2_START_METHOD_MMIO);
+
+ build_header(linker, table_data,
+ (void *)tpm2_ptr, "TPM2", sizeof(*tpm2_ptr), 4);
+}
+
typedef enum {
MEM_AFFINITY_NOFLAGS = 0,
MEM_AFFINITY_ENABLED = (1 << 0),
@@ -1340,12 +1364,21 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables)
acpi_add_table(table_offsets, tables_blob);
build_hpet(tables_blob, tables->linker);
}
- if (misc.has_tpm) {
+ if (misc.tpm_version != TPM_VERSION_UNSPEC) {
acpi_add_table(table_offsets, tables_blob);
build_tpm_tcpa(tables_blob, tables->linker, tables->tcpalog);
acpi_add_table(table_offsets, tables_blob);
- build_tpm_ssdt(tables_blob, tables->linker);
+ switch (misc.tpm_version) {
+ case TPM_VERSION_1_2:
+ build_tpm_ssdt(tables_blob, tables->linker);
+ break;
+ case TPM_VERSION_2_0:
+ build_tpm2(tables_blob, tables->linker);
+ break;
+ default:
+ assert(false);
+ }
}
if (guest_info->numa_nodes) {
acpi_add_table(table_offsets, tables_blob);
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 769eb25048..1eb1db0372 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1395,6 +1395,7 @@ static const MemoryRegionOps ioportF0_io_ops = {
void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
ISADevice **rtc_state,
+ bool create_fdctrl,
ISADevice **floppy,
bool no_vmport,
uint32 hpet_irqs)
@@ -1489,8 +1490,9 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
for(i = 0; i < MAX_FD; i++) {
fd[i] = drive_get(IF_FLOPPY, 0, i);
+ create_fdctrl |= !!fd[i];
}
- *floppy = fdctrl_init_isa(isa_bus, fd);
+ *floppy = create_fdctrl ? fdctrl_init_isa(isa_bus, fd) : NULL;
}
void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus)
@@ -1543,51 +1545,6 @@ void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name)
}
}
-static void pc_generic_machine_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
- QEMUMachine *qm = data;
-
- mc->family = qm->family;
- mc->name = qm->name;
- mc->alias = qm->alias;
- mc->desc = qm->desc;
- mc->init = qm->init;
- mc->reset = qm->reset;
- mc->hot_add_cpu = qm->hot_add_cpu;
- mc->kvm_type = qm->kvm_type;
- mc->block_default_type = qm->block_default_type;
- mc->units_per_default_bus = qm->units_per_default_bus;
- mc->max_cpus = qm->max_cpus;
- mc->no_serial = qm->no_serial;
- mc->no_parallel = qm->no_parallel;
- mc->use_virtcon = qm->use_virtcon;
- mc->use_sclp = qm->use_sclp;
- mc->no_floppy = qm->no_floppy;
- mc->no_cdrom = qm->no_cdrom;
- mc->no_sdcard = qm->no_sdcard;
- mc->is_default = qm->is_default;
- mc->default_machine_opts = qm->default_machine_opts;
- mc->default_boot_order = qm->default_boot_order;
- mc->default_display = qm->default_display;
- mc->compat_props = qm->compat_props;
- mc->hw_version = qm->hw_version;
-}
-
-void qemu_register_pc_machine(QEMUMachine *m)
-{
- char *name = g_strconcat(m->name, TYPE_MACHINE_SUFFIX, NULL);
- TypeInfo ti = {
- .name = name,
- .parent = TYPE_PC_MACHINE,
- .class_init = pc_generic_machine_class_init,
- .class_data = (void *)m,
- };
-
- type_register(&ti);
- g_free(name);
-}
-
static void pc_dimm_plug(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 212e263404..6e7fa424b1 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -59,6 +59,7 @@ static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 };
static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
+static bool pci_enabled = true;
static bool has_acpi_build = true;
static bool rsdp_in_ram = true;
static int legacy_acpi_table_size;
@@ -71,11 +72,10 @@ static bool smbios_uuid_encoded = true;
*/
static bool gigabyte_align = true;
static bool has_reserved_memory = true;
+static bool kvmclock_enabled = true;
/* PC hardware initialisation */
-static void pc_init1(MachineState *machine,
- int pci_enabled,
- int kvmclock_enabled)
+static void pc_init1(MachineState *machine)
{
PCMachineState *pc_machine = PC_MACHINE(machine);
MemoryRegion *system_memory = get_system_memory();
@@ -242,7 +242,7 @@ static void pc_init1(MachineState *machine,
}
/* init basic PC hardware */
- pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy,
+ pc_basic_device_init(isa_bus, gsi, &rtc_state, true, &floppy,
(pc_machine->vmport != ON_OFF_AUTO_ON), 0x4);
pc_nic_init(isa_bus, pci_bus);
@@ -305,11 +305,6 @@ static void pc_init1(MachineState *machine,
}
}
-static void pc_init_pci(MachineState *machine)
-{
- pc_init1(machine, 1, 1);
-}
-
static void pc_compat_2_3(MachineState *machine)
{
}
@@ -418,217 +413,165 @@ static void pc_compat_1_2(MachineState *machine)
x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, 1 << KVM_FEATURE_PV_EOI);
}
-static void pc_init_pci_2_3(MachineState *machine)
+/* PC compat function for pc-0.10 to pc-0.13 */
+static void pc_compat_0_13(MachineState *machine)
{
- pc_compat_2_3(machine);
- pc_init_pci(machine);
+ pc_compat_1_2(machine);
+ kvmclock_enabled = false;
}
-static void pc_init_pci_2_2(MachineState *machine)
+static void pc_init_isa(MachineState *machine)
{
- pc_compat_2_2(machine);
- pc_init_pci(machine);
+ pci_enabled = false;
+ has_acpi_build = false;
+ smbios_defaults = false;
+ gigabyte_align = false;
+ smbios_legacy_mode = true;
+ has_reserved_memory = false;
+ option_rom_has_mr = true;
+ rom_file_has_mr = false;
+ if (!machine->cpu_model) {
+ machine->cpu_model = "486";
+ }
+ x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, 1 << KVM_FEATURE_PV_EOI);
+ enable_compat_apic_id_mode();
+ pc_init1(machine);
}
-static void pc_init_pci_2_1(MachineState *machine)
+#ifdef CONFIG_XEN
+static void pc_xen_hvm_init(MachineState *machine)
{
- pc_compat_2_1(machine);
- pc_init_pci(machine);
-}
+ PCIBus *bus;
-static void pc_init_pci_2_0(MachineState *machine)
-{
- pc_compat_2_0(machine);
- pc_init_pci(machine);
-}
+ pc_init1(machine);
-static void pc_init_pci_1_7(MachineState *machine)
-{
- pc_compat_1_7(machine);
- pc_init_pci(machine);
+ bus = pci_find_primary_bus();
+ if (bus != NULL) {
+ pci_create_simple(bus, -1, "xen-platform");
+ }
}
+#endif
-static void pc_init_pci_1_6(MachineState *machine)
+#define DEFINE_I440FX_MACHINE(suffix, name, compatfn, optionfn) \
+ static void pc_init_##suffix(MachineState *machine) \
+ { \
+ void (*compat)(MachineState *m) = (compatfn); \
+ if (compat) { \
+ compat(machine); \
+ } \
+ pc_init1(machine); \
+ } \
+ DEFINE_PC_MACHINE(suffix, name, pc_init_##suffix, optionfn)
+
+static void pc_i440fx_machine_options(MachineClass *m)
{
- pc_compat_1_6(machine);
- pc_init_pci(machine);
+ pc_default_machine_options(m);
+ m->family = "pc_piix";
+ m->desc = "Standard PC (i440FX + PIIX, 1996)";
+ m->hot_add_cpu = pc_hot_add_cpu;
}
-static void pc_init_pci_1_5(MachineState *machine)
+static void pc_i440fx_2_4_machine_options(MachineClass *m)
{
- pc_compat_1_5(machine);
- pc_init_pci(machine);
+ pc_i440fx_machine_options(m);
+ m->default_machine_opts = "firmware=bios-256k.bin";
+ m->default_display = "std";
+ m->alias = "pc";
+ m->is_default = 1;
}
-static void pc_init_pci_1_4(MachineState *machine)
+DEFINE_I440FX_MACHINE(v2_4, "pc-i440fx-2.4", NULL,
+ pc_i440fx_2_4_machine_options)
+
+
+static void pc_i440fx_2_3_machine_options(MachineClass *m)
{
- pc_compat_1_4(machine);
- pc_init_pci(machine);
+ pc_i440fx_machine_options(m);
+ m->alias = NULL;
+ m->is_default = 0;
+ SET_MACHINE_COMPAT(m, PC_COMPAT_2_3);
}
-static void pc_init_pci_1_3(MachineState *machine)
+DEFINE_I440FX_MACHINE(v2_3, "pc-i440fx-2.3", pc_compat_2_3,
+ pc_i440fx_2_3_machine_options);
+
+
+static void pc_i440fx_2_2_machine_options(MachineClass *m)
{
- pc_compat_1_3(machine);
- pc_init_pci(machine);
+ pc_i440fx_2_3_machine_options(m);
+ SET_MACHINE_COMPAT(m, PC_COMPAT_2_2);
}
-/* PC machine init function for pc-0.14 to pc-1.2 */
-static void pc_init_pci_1_2(MachineState *machine)
+DEFINE_I440FX_MACHINE(v2_2, "pc-i440fx-2.2", pc_compat_2_2,
+ pc_i440fx_2_2_machine_options);
+
+
+static void pc_i440fx_2_1_machine_options(MachineClass *m)
{
- pc_compat_1_2(machine);
- pc_init_pci(machine);
+ pc_i440fx_2_2_machine_options(m);
+ m->default_display = NULL;
+ SET_MACHINE_COMPAT(m, PC_COMPAT_2_1);
}
-/* PC init function for pc-0.10 to pc-0.13 */
-static void pc_init_pci_no_kvmclock(MachineState *machine)
+DEFINE_I440FX_MACHINE(v2_1, "pc-i440fx-2.1", pc_compat_2_1,
+ pc_i440fx_2_1_machine_options);
+
+
+
+static void pc_i440fx_2_0_machine_options(MachineClass *m)
{
- pc_compat_1_2(machine);
- pc_init1(machine, 1, 0);
+ pc_i440fx_2_1_machine_options(m);
+ SET_MACHINE_COMPAT(m, PC_COMPAT_2_0);
}
-static void pc_init_isa(MachineState *machine)
+DEFINE_I440FX_MACHINE(v2_0, "pc-i440fx-2.0", pc_compat_2_0,
+ pc_i440fx_2_0_machine_options);
+
+
+static void pc_i440fx_1_7_machine_options(MachineClass *m)
{
- has_acpi_build = false;
- smbios_defaults = false;
- gigabyte_align = false;
- smbios_legacy_mode = true;
- has_reserved_memory = false;
- option_rom_has_mr = true;
- rom_file_has_mr = false;
- if (!machine->cpu_model) {
- machine->cpu_model = "486";
- }
- x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, 1 << KVM_FEATURE_PV_EOI);
- enable_compat_apic_id_mode();
- pc_init1(machine, 0, 1);
+ pc_i440fx_2_0_machine_options(m);
+ m->default_machine_opts = NULL;
+ SET_MACHINE_COMPAT(m, PC_COMPAT_1_7);
}
-#ifdef CONFIG_XEN
-static void pc_xen_hvm_init(MachineState *machine)
-{
- PCIBus *bus;
+DEFINE_I440FX_MACHINE(v1_7, "pc-i440fx-1.7", pc_compat_1_7,
+ pc_i440fx_1_7_machine_options);
- pc_init_pci(machine);
- bus = pci_find_primary_bus();
- if (bus != NULL) {
- pci_create_simple(bus, -1, "xen-platform");
- }
+static void pc_i440fx_1_6_machine_options(MachineClass *m)
+{
+ pc_i440fx_1_7_machine_options(m);
+ SET_MACHINE_COMPAT(m, PC_COMPAT_1_6);
}
-#endif
-#define PC_I440FX_MACHINE_OPTIONS \
- PC_DEFAULT_MACHINE_OPTIONS, \
- .family = "pc_piix", \
- .desc = "Standard PC (i440FX + PIIX, 1996)", \
- .hot_add_cpu = pc_hot_add_cpu
-
-#define PC_I440FX_2_4_MACHINE_OPTIONS \
- PC_I440FX_MACHINE_OPTIONS, \
- .default_machine_opts = "firmware=bios-256k.bin", \
- .default_display = "std"
-
-
-static QEMUMachine pc_i440fx_machine_v2_4 = {
- PC_I440FX_2_4_MACHINE_OPTIONS,
- .name = "pc-i440fx-2.4",
- .alias = "pc",
- .init = pc_init_pci,
- .is_default = 1,
-};
-
-#define PC_I440FX_2_3_MACHINE_OPTIONS PC_I440FX_2_4_MACHINE_OPTIONS
-
-static QEMUMachine pc_i440fx_machine_v2_3 = {
- PC_I440FX_2_3_MACHINE_OPTIONS,
- .name = "pc-i440fx-2.3",
- .init = pc_init_pci_2_3,
-};
-
-#define PC_I440FX_2_2_MACHINE_OPTIONS PC_I440FX_2_3_MACHINE_OPTIONS
-
-static QEMUMachine pc_i440fx_machine_v2_2 = {
- PC_I440FX_2_2_MACHINE_OPTIONS,
- .name = "pc-i440fx-2.2",
- .init = pc_init_pci_2_2,
-};
-
-#define PC_I440FX_2_1_MACHINE_OPTIONS \
- PC_I440FX_MACHINE_OPTIONS, \
- .default_machine_opts = "firmware=bios-256k.bin"
-
-static QEMUMachine pc_i440fx_machine_v2_1 = {
- PC_I440FX_2_1_MACHINE_OPTIONS,
- .name = "pc-i440fx-2.1",
- .init = pc_init_pci_2_1,
- .compat_props = (GlobalProperty[]) {
- HW_COMPAT_2_1,
- { /* end of list */ }
- },
-};
+DEFINE_I440FX_MACHINE(v1_6, "pc-i440fx-1.6", pc_compat_1_6,
+ pc_i440fx_1_6_machine_options);
-#define PC_I440FX_2_0_MACHINE_OPTIONS PC_I440FX_2_1_MACHINE_OPTIONS
-static QEMUMachine pc_i440fx_machine_v2_0 = {
- PC_I440FX_2_0_MACHINE_OPTIONS,
- .name = "pc-i440fx-2.0",
- .init = pc_init_pci_2_0,
- .compat_props = (GlobalProperty[]) {
- PC_COMPAT_2_0,
- { /* end of list */ }
- },
-};
+static void pc_i440fx_1_5_machine_options(MachineClass *m)
+{
+ pc_i440fx_1_6_machine_options(m);
+ SET_MACHINE_COMPAT(m, PC_COMPAT_1_5);
+}
-#define PC_I440FX_1_7_MACHINE_OPTIONS PC_I440FX_MACHINE_OPTIONS
+DEFINE_I440FX_MACHINE(v1_5, "pc-i440fx-1.5", pc_compat_1_5,
+ pc_i440fx_1_5_machine_options);
-static QEMUMachine pc_i440fx_machine_v1_7 = {
- PC_I440FX_1_7_MACHINE_OPTIONS,
- .name = "pc-i440fx-1.7",
- .init = pc_init_pci_1_7,
- .compat_props = (GlobalProperty[]) {
- PC_COMPAT_1_7,
- { /* end of list */ }
- },
-};
-#define PC_I440FX_1_6_MACHINE_OPTIONS PC_I440FX_MACHINE_OPTIONS
+static void pc_i440fx_1_4_machine_options(MachineClass *m)
+{
+ pc_i440fx_1_5_machine_options(m);
+ m->hot_add_cpu = NULL;
+ SET_MACHINE_COMPAT(m, PC_COMPAT_1_4);
+}
+
+DEFINE_I440FX_MACHINE(v1_4, "pc-i440fx-1.4", pc_compat_1_4,
+ pc_i440fx_1_4_machine_options);
-static QEMUMachine pc_i440fx_machine_v1_6 = {
- PC_I440FX_1_6_MACHINE_OPTIONS,
- .name = "pc-i440fx-1.6",
- .init = pc_init_pci_1_6,
- .compat_props = (GlobalProperty[]) {
- PC_COMPAT_1_6,
- { /* end of list */ }
- },
-};
-
-static QEMUMachine pc_i440fx_machine_v1_5 = {
- PC_I440FX_1_6_MACHINE_OPTIONS,
- .name = "pc-i440fx-1.5",
- .init = pc_init_pci_1_5,
- .compat_props = (GlobalProperty[]) {
- PC_COMPAT_1_5,
- { /* end of list */ }
- },
-};
-
-#define PC_I440FX_1_4_MACHINE_OPTIONS \
- PC_I440FX_1_6_MACHINE_OPTIONS, \
- .hot_add_cpu = NULL
-
-static QEMUMachine pc_i440fx_machine_v1_4 = {
- PC_I440FX_1_4_MACHINE_OPTIONS,
- .name = "pc-i440fx-1.4",
- .init = pc_init_pci_1_4,
- .compat_props = (GlobalProperty[]) {
- PC_COMPAT_1_4,
- { /* end of list */ }
- },
-};
#define PC_COMPAT_1_3 \
- PC_COMPAT_1_4, \
+ PC_COMPAT_1_4 \
{\
.driver = "usb-tablet",\
.property = "usb_version",\
@@ -645,20 +588,21 @@ static QEMUMachine pc_i440fx_machine_v1_4 = {
.driver = "e1000",\
.property = "autonegotiation",\
.value = "off",\
- }
+ },
+
+
+static void pc_i440fx_1_3_machine_options(MachineClass *m)
+{
+ pc_i440fx_1_4_machine_options(m);
+ SET_MACHINE_COMPAT(m, PC_COMPAT_1_3);
+}
+
+DEFINE_I440FX_MACHINE(v1_3, "pc-1.3", pc_compat_1_3,
+ pc_i440fx_1_3_machine_options);
-static QEMUMachine pc_machine_v1_3 = {
- PC_I440FX_1_4_MACHINE_OPTIONS,
- .name = "pc-1.3",
- .init = pc_init_pci_1_3,
- .compat_props = (GlobalProperty[]) {
- PC_COMPAT_1_3,
- { /* end of list */ }
- },
-};
#define PC_COMPAT_1_2 \
- PC_COMPAT_1_3,\
+ PC_COMPAT_1_3 \
{\
.driver = "nec-usb-xhci",\
.property = "msi",\
@@ -683,23 +627,20 @@ static QEMUMachine pc_machine_v1_3 = {
.driver = "VGA",\
.property = "mmio",\
.value = "off",\
- }
+ },
-#define PC_I440FX_1_2_MACHINE_OPTIONS \
- PC_I440FX_1_4_MACHINE_OPTIONS, \
- .init = pc_init_pci_1_2
+static void pc_i440fx_1_2_machine_options(MachineClass *m)
+{
+ pc_i440fx_1_3_machine_options(m);
+ SET_MACHINE_COMPAT(m, PC_COMPAT_1_2);
+}
+
+DEFINE_I440FX_MACHINE(v1_2, "pc-1.2", pc_compat_1_2,
+ pc_i440fx_1_2_machine_options);
-static QEMUMachine pc_machine_v1_2 = {
- PC_I440FX_1_2_MACHINE_OPTIONS,
- .name = "pc-1.2",
- .compat_props = (GlobalProperty[]) {
- PC_COMPAT_1_2,
- { /* end of list */ }
- },
-};
#define PC_COMPAT_1_1 \
- PC_COMPAT_1_2,\
+ PC_COMPAT_1_2 \
{\
.driver = "virtio-scsi-pci",\
.property = "hotplug",\
@@ -728,19 +669,20 @@ static QEMUMachine pc_machine_v1_2 = {
.driver = "virtio-blk-pci",\
.property = "config-wce",\
.value = "off",\
- }
+ },
+
+static void pc_i440fx_1_1_machine_options(MachineClass *m)
+{
+ pc_i440fx_1_2_machine_options(m);
+ SET_MACHINE_COMPAT(m, PC_COMPAT_1_1);
+}
+
+DEFINE_I440FX_MACHINE(v1_1, "pc-1.1", pc_compat_1_2,
+ pc_i440fx_1_1_machine_options);
-static QEMUMachine pc_machine_v1_1 = {
- PC_I440FX_1_2_MACHINE_OPTIONS,
- .name = "pc-1.1",
- .compat_props = (GlobalProperty[]) {
- PC_COMPAT_1_1,
- { /* end of list */ }
- },
-};
#define PC_COMPAT_1_0 \
- PC_COMPAT_1_1,\
+ PC_COMPAT_1_1 \
{\
.driver = TYPE_ISA_FDC,\
.property = "check_media_rate",\
@@ -757,33 +699,35 @@ static QEMUMachine pc_machine_v1_1 = {
.driver = TYPE_USB_DEVICE,\
.property = "full-path",\
.value = "no",\
- }
+ },
+
+static void pc_i440fx_1_0_machine_options(MachineClass *m)
+{
+ pc_i440fx_1_1_machine_options(m);
+ m->hw_version = "1.0";
+ SET_MACHINE_COMPAT(m, PC_COMPAT_1_0);
+}
+
+DEFINE_I440FX_MACHINE(v1_0, "pc-1.0", pc_compat_1_2,
+ pc_i440fx_1_0_machine_options);
-static QEMUMachine pc_machine_v1_0 = {
- PC_I440FX_1_2_MACHINE_OPTIONS,
- .name = "pc-1.0",
- .compat_props = (GlobalProperty[]) {
- PC_COMPAT_1_0,
- { /* end of list */ }
- },
- .hw_version = "1.0",
-};
#define PC_COMPAT_0_15 \
PC_COMPAT_1_0
-static QEMUMachine pc_machine_v0_15 = {
- PC_I440FX_1_2_MACHINE_OPTIONS,
- .name = "pc-0.15",
- .compat_props = (GlobalProperty[]) {
- PC_COMPAT_0_15,
- { /* end of list */ }
- },
- .hw_version = "0.15",
-};
+static void pc_i440fx_0_15_machine_options(MachineClass *m)
+{
+ pc_i440fx_1_0_machine_options(m);
+ m->hw_version = "0.15";
+ SET_MACHINE_COMPAT(m, PC_COMPAT_0_15);
+}
+
+DEFINE_I440FX_MACHINE(v0_15, "pc-0.15", pc_compat_1_2,
+ pc_i440fx_0_15_machine_options);
+
#define PC_COMPAT_0_14 \
- PC_COMPAT_0_15,\
+ PC_COMPAT_0_15 \
{\
.driver = "virtio-blk-pci",\
.property = "event_idx",\
@@ -800,29 +744,29 @@ static QEMUMachine pc_machine_v0_15 = {
.driver = "virtio-balloon-pci",\
.property = "event_idx",\
.value = "off",\
- }
-
-static QEMUMachine pc_machine_v0_14 = {
- PC_I440FX_1_2_MACHINE_OPTIONS,
- .name = "pc-0.14",
- .compat_props = (GlobalProperty[]) {
- PC_COMPAT_0_14,
- {
- .driver = "qxl",
- .property = "revision",
- .value = stringify(2),
- },{
- .driver = "qxl-vga",
- .property = "revision",
- .value = stringify(2),
+ },{\
+ .driver = "qxl",\
+ .property = "revision",\
+ .value = stringify(2),\
+ },{\
+ .driver = "qxl-vga",\
+ .property = "revision",\
+ .value = stringify(2),\
},
- { /* end of list */ }
- },
- .hw_version = "0.14",
-};
+
+static void pc_i440fx_0_14_machine_options(MachineClass *m)
+{
+ pc_i440fx_0_15_machine_options(m);
+ m->hw_version = "0.14";
+ SET_MACHINE_COMPAT(m, PC_COMPAT_0_14);
+}
+
+DEFINE_I440FX_MACHINE(v0_14, "pc-0.14", pc_compat_1_2,
+ pc_i440fx_0_14_machine_options);
+
#define PC_COMPAT_0_13 \
- PC_COMPAT_0_14,\
+ PC_COMPAT_0_14 \
{\
.driver = TYPE_PCI_DEVICE,\
.property = "command_serr_enable",\
@@ -831,37 +775,33 @@ static QEMUMachine pc_machine_v0_14 = {
.driver = "AC97",\
.property = "use_broken_id",\
.value = stringify(1),\
- }
-
-#define PC_I440FX_0_13_MACHINE_OPTIONS \
- PC_I440FX_1_2_MACHINE_OPTIONS, \
- .init = pc_init_pci_no_kvmclock
-
-static QEMUMachine pc_machine_v0_13 = {
- PC_I440FX_0_13_MACHINE_OPTIONS,
- .name = "pc-0.13",
- .compat_props = (GlobalProperty[]) {
- PC_COMPAT_0_13,
- {
- .driver = "virtio-9p-pci",
- .property = "vectors",
- .value = stringify(0),
- },{
- .driver = "VGA",
- .property = "rombar",
- .value = stringify(0),
- },{
- .driver = "vmware-svga",
- .property = "rombar",
- .value = stringify(0),
+ },{\
+ .driver = "virtio-9p-pci",\
+ .property = "vectors",\
+ .value = stringify(0),\
+ },{\
+ .driver = "VGA",\
+ .property = "rombar",\
+ .value = stringify(0),\
+ },{\
+ .driver = "vmware-svga",\
+ .property = "rombar",\
+ .value = stringify(0),\
},
- { /* end of list */ }
- },
- .hw_version = "0.13",
-};
+
+static void pc_i440fx_0_13_machine_options(MachineClass *m)
+{
+ pc_i440fx_0_14_machine_options(m);
+ m->hw_version = "0.13";
+ SET_MACHINE_COMPAT(m, PC_COMPAT_0_13);
+}
+
+DEFINE_I440FX_MACHINE(v0_13, "pc-0.13", pc_compat_0_13,
+ pc_i440fx_0_13_machine_options);
+
#define PC_COMPAT_0_12 \
- PC_COMPAT_0_13,\
+ PC_COMPAT_0_13 \
{\
.driver = "virtio-serial-pci",\
.property = "max_ports",\
@@ -882,29 +822,21 @@ static QEMUMachine pc_machine_v0_13 = {
.driver = "usb-kbd",\
.property = "serial",\
.value = "1",\
- }
-
-static QEMUMachine pc_machine_v0_12 = {
- PC_I440FX_0_13_MACHINE_OPTIONS,
- .name = "pc-0.12",
- .compat_props = (GlobalProperty[]) {
- PC_COMPAT_0_12,
- {
- .driver = "VGA",
- .property = "rombar",
- .value = stringify(0),
- },{
- .driver = "vmware-svga",
- .property = "rombar",
- .value = stringify(0),
},
- { /* end of list */ }
- },
- .hw_version = "0.12",
-};
+
+static void pc_i440fx_0_12_machine_options(MachineClass *m)
+{
+ pc_i440fx_0_13_machine_options(m);
+ m->hw_version = "0.12";
+ SET_MACHINE_COMPAT(m, PC_COMPAT_0_12);
+}
+
+DEFINE_I440FX_MACHINE(v0_12, "pc-0.12", pc_compat_0_13,
+ pc_i440fx_0_12_machine_options);
+
#define PC_COMPAT_0_11 \
- PC_COMPAT_0_12,\
+ PC_COMPAT_0_12 \
{\
.driver = "virtio-blk-pci",\
.property = "vectors",\
@@ -913,106 +845,83 @@ static QEMUMachine pc_machine_v0_12 = {
.driver = TYPE_PCI_DEVICE,\
.property = "rombar",\
.value = stringify(0),\
- }
-
-static QEMUMachine pc_machine_v0_11 = {
- PC_I440FX_0_13_MACHINE_OPTIONS,
- .name = "pc-0.11",
- .compat_props = (GlobalProperty[]) {
- PC_COMPAT_0_11,
- {
- .driver = "ide-drive",
- .property = "ver",
- .value = "0.11",
- },{
- .driver = "scsi-disk",
- .property = "ver",
- .value = "0.11",
- },
- { /* end of list */ }
- },
- .hw_version = "0.11",
-};
-
-static QEMUMachine pc_machine_v0_10 = {
- PC_I440FX_0_13_MACHINE_OPTIONS,
- .name = "pc-0.10",
- .compat_props = (GlobalProperty[]) {
- PC_COMPAT_0_11,
- {
- .driver = "virtio-blk-pci",
- .property = "class",
- .value = stringify(PCI_CLASS_STORAGE_OTHER),
- },{
- .driver = "virtio-serial-pci",
- .property = "class",
- .value = stringify(PCI_CLASS_DISPLAY_OTHER),
- },{
- .driver = "virtio-net-pci",
- .property = "vectors",
- .value = stringify(0),
- },{
- .driver = "ide-drive",
- .property = "ver",
- .value = "0.10",
- },{
- .driver = "scsi-disk",
- .property = "ver",
- .value = "0.10",
+ },{\
+ .driver = "ide-drive",\
+ .property = "ver",\
+ .value = "0.11",\
+ },{\
+ .driver = "scsi-disk",\
+ .property = "ver",\
+ .value = "0.11",\
},
- { /* end of list */ }
- },
- .hw_version = "0.10",
-};
-
-static QEMUMachine isapc_machine = {
- PC_COMMON_MACHINE_OPTIONS,
- .name = "isapc",
- .desc = "ISA-only PC",
- .init = pc_init_isa,
- .max_cpus = 1,
- .compat_props = (GlobalProperty[]) {
- { /* end of list */ }
+
+static void pc_i440fx_0_11_machine_options(MachineClass *m)
+{
+ pc_i440fx_0_12_machine_options(m);
+ m->hw_version = "0.11";
+ SET_MACHINE_COMPAT(m, PC_COMPAT_0_11);
+}
+
+DEFINE_I440FX_MACHINE(v0_11, "pc-0.11", pc_compat_0_13,
+ pc_i440fx_0_11_machine_options);
+
+
+#define PC_COMPAT_0_10 \
+ PC_COMPAT_0_11 \
+ {\
+ .driver = "virtio-blk-pci",\
+ .property = "class",\
+ .value = stringify(PCI_CLASS_STORAGE_OTHER),\
+ },{\
+ .driver = "virtio-serial-pci",\
+ .property = "class",\
+ .value = stringify(PCI_CLASS_DISPLAY_OTHER),\
+ },{\
+ .driver = "virtio-net-pci",\
+ .property = "vectors",\
+ .value = stringify(0),\
+ },{\
+ .driver = "ide-drive",\
+ .property = "ver",\
+ .value = "0.10",\
+ },{\
+ .driver = "scsi-disk",\
+ .property = "ver",\
+ .value = "0.10",\
},
-};
-#ifdef CONFIG_XEN
-static QEMUMachine xenfv_machine = {
- PC_COMMON_MACHINE_OPTIONS,
- .name = "xenfv",
- .desc = "Xen Fully-virtualized PC",
- .init = pc_xen_hvm_init,
- .max_cpus = HVM_MAX_VCPUS,
- .default_machine_opts = "accel=xen",
- .hot_add_cpu = pc_hot_add_cpu,
-};
-#endif
+static void pc_i440fx_0_10_machine_options(MachineClass *m)
+{
+ pc_i440fx_0_11_machine_options(m);
+ m->hw_version = "0.10";
+ SET_MACHINE_COMPAT(m, PC_COMPAT_0_10);
+}
+
+DEFINE_I440FX_MACHINE(v0_10, "pc-0.10", pc_compat_0_13,
+ pc_i440fx_0_10_machine_options);
+
+
+static void isapc_machine_options(MachineClass *m)
+{
+ pc_common_machine_options(m);
+ m->desc = "ISA-only PC";
+ m->max_cpus = 1;
+}
+
+DEFINE_PC_MACHINE(isapc, "isapc", pc_init_isa,
+ isapc_machine_options);
+
-static void pc_machine_init(void)
-{
- qemu_register_pc_machine(&pc_i440fx_machine_v2_4);
- qemu_register_pc_machine(&pc_i440fx_machine_v2_3);
- qemu_register_pc_machine(&pc_i440fx_machine_v2_2);
- qemu_register_pc_machine(&pc_i440fx_machine_v2_1);
- qemu_register_pc_machine(&pc_i440fx_machine_v2_0);
- qemu_register_pc_machine(&pc_i440fx_machine_v1_7);
- qemu_register_pc_machine(&pc_i440fx_machine_v1_6);
- qemu_register_pc_machine(&pc_i440fx_machine_v1_5);
- qemu_register_pc_machine(&pc_i440fx_machine_v1_4);
- qemu_register_pc_machine(&pc_machine_v1_3);
- qemu_register_pc_machine(&pc_machine_v1_2);
- qemu_register_pc_machine(&pc_machine_v1_1);
- qemu_register_pc_machine(&pc_machine_v1_0);
- qemu_register_pc_machine(&pc_machine_v0_15);
- qemu_register_pc_machine(&pc_machine_v0_14);
- qemu_register_pc_machine(&pc_machine_v0_13);
- qemu_register_pc_machine(&pc_machine_v0_12);
- qemu_register_pc_machine(&pc_machine_v0_11);
- qemu_register_pc_machine(&pc_machine_v0_10);
- qemu_register_pc_machine(&isapc_machine);
#ifdef CONFIG_XEN
- qemu_register_pc_machine(&xenfv_machine);
-#endif
+static void xenfv_machine_options(MachineClass *m)
+{
+ pc_common_machine_options(m);
+ m->desc = "Xen Fully-virtualized PC";
+ m->max_cpus = HVM_MAX_VCPUS;
+ m->default_machine_opts = "accel=xen";
+ m->hot_add_cpu = pc_hot_add_cpu;
}
-machine_init(pc_machine_init);
+DEFINE_PC_MACHINE(xenfv, "xenfv", pc_xen_hvm_init,
+ xenfv_machine_options);
+#endif
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index e67f2dead7..66220b352b 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -89,6 +89,7 @@ static void pc_q35_init(MachineState *machine)
PcGuestInfo *guest_info;
ram_addr_t lowmem;
DriveInfo *hd[MAX_SATA_PORTS];
+ MachineClass *mc = MACHINE_GET_CLASS(machine);
/* Check whether RAM fits below 4G (leaving 1/2 GByte for IO memory
* and 256 Mbytes for PCI Express Enhanced Configuration Access Mapping
@@ -163,7 +164,6 @@ static void pc_q35_init(MachineState *machine)
guest_info->legacy_acpi_table_size = 0;
if (smbios_defaults) {
- MachineClass *mc = MACHINE_GET_CLASS(machine);
/* These values are guest ABI, do not change */
smbios_set_defaults("QEMU", "Standard PC (Q35 + ICH9, 2009)",
mc->name, smbios_legacy_mode, smbios_uuid_encoded);
@@ -250,7 +250,7 @@ static void pc_q35_init(MachineState *machine)
}
/* init basic PC hardware */
- pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy,
+ pc_basic_device_init(isa_bus, gsi, &rtc_state, !mc->no_floppy, &floppy,
(pc_machine->vmport != ON_OFF_AUTO_ON), 0xff0104);
/* connect pm stuff to lpc */
@@ -366,174 +366,119 @@ static void pc_compat_1_4(MachineState *machine)
x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ);
}
-static void pc_q35_init_2_3(MachineState *machine)
+#define DEFINE_Q35_MACHINE(suffix, name, compatfn, optionfn) \
+ static void pc_init_##suffix(MachineState *machine) \
+ { \
+ void (*compat)(MachineState *m) = (compatfn); \
+ if (compat) { \
+ compat(machine); \
+ } \
+ pc_q35_init(machine); \
+ } \
+ DEFINE_PC_MACHINE(suffix, name, pc_init_##suffix, optionfn)
+
+
+static void pc_q35_machine_options(MachineClass *m)
{
- pc_compat_2_3(machine);
- pc_q35_init(machine);
+ pc_default_machine_options(m);
+ m->family = "pc_q35";
+ m->desc = "Standard PC (Q35 + ICH9, 2009)";
+ m->hot_add_cpu = pc_hot_add_cpu;
+ m->units_per_default_bus = 1;
}
-static void pc_q35_init_2_2(MachineState *machine)
+static void pc_q35_2_4_machine_options(MachineClass *m)
{
- pc_compat_2_2(machine);
- pc_q35_init(machine);
+ pc_q35_machine_options(m);
+ m->default_machine_opts = "firmware=bios-256k.bin";
+ m->default_display = "std";
+ m->no_floppy = 1;
+ m->alias = "q35";
}
-static void pc_q35_init_2_1(MachineState *machine)
+DEFINE_Q35_MACHINE(v2_4, "pc-q35-2.4", NULL,
+ pc_q35_2_4_machine_options);
+
+
+static void pc_q35_2_3_machine_options(MachineClass *m)
{
- pc_compat_2_1(machine);
- pc_q35_init(machine);
+ pc_q35_2_4_machine_options(m);
+ m->alias = NULL;
+ SET_MACHINE_COMPAT(m, PC_COMPAT_2_3);
}
-static void pc_q35_init_2_0(MachineState *machine)
+DEFINE_Q35_MACHINE(v2_3, "pc-q35-2.3", pc_compat_2_3,
+ pc_q35_2_3_machine_options);
+
+
+static void pc_q35_2_2_machine_options(MachineClass *m)
{
- pc_compat_2_0(machine);
- pc_q35_init(machine);
+ pc_q35_2_3_machine_options(m);
+ SET_MACHINE_COMPAT(m, PC_COMPAT_2_2);
}
-static void pc_q35_init_1_7(MachineState *machine)
+DEFINE_Q35_MACHINE(v2_2, "pc-q35-2.2", pc_compat_2_2,
+ pc_q35_2_2_machine_options);
+
+
+static void pc_q35_2_1_machine_options(MachineClass *m)
{
- pc_compat_1_7(machine);
- pc_q35_init(machine);
+ pc_q35_2_2_machine_options(m);
+ m->default_display = NULL;
+ SET_MACHINE_COMPAT(m, PC_COMPAT_2_1);
+}
+
+DEFINE_Q35_MACHINE(v2_1, "pc-q35-2.1", pc_compat_2_1,
+ pc_q35_2_1_machine_options);
+
+
+static void pc_q35_2_0_machine_options(MachineClass *m)
+{
+ pc_q35_2_1_machine_options(m);
+ SET_MACHINE_COMPAT(m, PC_COMPAT_2_0);
}
-static void pc_q35_init_1_6(MachineState *machine)
+DEFINE_Q35_MACHINE(v2_0, "pc-q35-2.0", pc_compat_2_0,
+ pc_q35_2_0_machine_options);
+
+
+static void pc_q35_1_7_machine_options(MachineClass *m)
{
- pc_compat_1_6(machine);
- pc_q35_init(machine);
+ pc_q35_2_0_machine_options(m);
+ m->default_machine_opts = NULL;
+ SET_MACHINE_COMPAT(m, PC_COMPAT_1_7);
}
-static void pc_q35_init_1_5(MachineState *machine)
+DEFINE_Q35_MACHINE(v1_7, "pc-q35-1.7", pc_compat_1_7,
+ pc_q35_1_7_machine_options);
+
+
+static void pc_q35_1_6_machine_options(MachineClass *m)
{
- pc_compat_1_5(machine);
- pc_q35_init(machine);
+ pc_q35_machine_options(m);
+ SET_MACHINE_COMPAT(m, PC_COMPAT_1_6);
}
-static void pc_q35_init_1_4(MachineState *machine)
+DEFINE_Q35_MACHINE(v1_6, "pc-q35-1.6", pc_compat_1_6,
+ pc_q35_1_6_machine_options);
+
+
+static void pc_q35_1_5_machine_options(MachineClass *m)
{
- pc_compat_1_4(machine);
- pc_q35_init(machine);
+ pc_q35_1_6_machine_options(m);
+ SET_MACHINE_COMPAT(m, PC_COMPAT_1_5);
}
-#define PC_Q35_MACHINE_OPTIONS \
- PC_DEFAULT_MACHINE_OPTIONS, \
- .family = "pc_q35", \
- .desc = "Standard PC (Q35 + ICH9, 2009)", \
- .hot_add_cpu = pc_hot_add_cpu, \
- .units_per_default_bus = 1
-
-#define PC_Q35_2_4_MACHINE_OPTIONS \
- PC_Q35_MACHINE_OPTIONS, \
- .default_machine_opts = "firmware=bios-256k.bin", \
- .default_display = "std"
-
-static QEMUMachine pc_q35_machine_v2_4 = {
- PC_Q35_2_4_MACHINE_OPTIONS,
- .name = "pc-q35-2.4",
- .alias = "q35",
- .init = pc_q35_init,
-};
-
-#define PC_Q35_2_3_MACHINE_OPTIONS PC_Q35_2_4_MACHINE_OPTIONS
-
-static QEMUMachine pc_q35_machine_v2_3 = {
- PC_Q35_2_3_MACHINE_OPTIONS,
- .name = "pc-q35-2.3",
- .init = pc_q35_init_2_3,
-};
-
-#define PC_Q35_2_2_MACHINE_OPTIONS PC_Q35_2_3_MACHINE_OPTIONS
-
-static QEMUMachine pc_q35_machine_v2_2 = {
- PC_Q35_2_2_MACHINE_OPTIONS,
- .name = "pc-q35-2.2",
- .init = pc_q35_init_2_2,
-};
-
-#define PC_Q35_2_1_MACHINE_OPTIONS \
- PC_Q35_MACHINE_OPTIONS, \
- .default_machine_opts = "firmware=bios-256k.bin"
-
-static QEMUMachine pc_q35_machine_v2_1 = {
- PC_Q35_2_1_MACHINE_OPTIONS,
- .name = "pc-q35-2.1",
- .init = pc_q35_init_2_1,
- .compat_props = (GlobalProperty[]) {
- HW_COMPAT_2_1,
- { /* end of list */ }
- },
-};
-
-#define PC_Q35_2_0_MACHINE_OPTIONS PC_Q35_2_1_MACHINE_OPTIONS
-
-static QEMUMachine pc_q35_machine_v2_0 = {
- PC_Q35_2_0_MACHINE_OPTIONS,
- .name = "pc-q35-2.0",
- .init = pc_q35_init_2_0,
- .compat_props = (GlobalProperty[]) {
- PC_COMPAT_2_0,
- { /* end of list */ }
- },
-};
-
-#define PC_Q35_1_7_MACHINE_OPTIONS PC_Q35_MACHINE_OPTIONS
-
-static QEMUMachine pc_q35_machine_v1_7 = {
- PC_Q35_1_7_MACHINE_OPTIONS,
- .name = "pc-q35-1.7",
- .init = pc_q35_init_1_7,
- .compat_props = (GlobalProperty[]) {
- PC_COMPAT_1_7,
- { /* end of list */ }
- },
-};
-
-#define PC_Q35_1_6_MACHINE_OPTIONS PC_Q35_MACHINE_OPTIONS
-
-static QEMUMachine pc_q35_machine_v1_6 = {
- PC_Q35_1_6_MACHINE_OPTIONS,
- .name = "pc-q35-1.6",
- .init = pc_q35_init_1_6,
- .compat_props = (GlobalProperty[]) {
- PC_COMPAT_1_6,
- { /* end of list */ }
- },
-};
-
-static QEMUMachine pc_q35_machine_v1_5 = {
- PC_Q35_1_6_MACHINE_OPTIONS,
- .name = "pc-q35-1.5",
- .init = pc_q35_init_1_5,
- .compat_props = (GlobalProperty[]) {
- PC_COMPAT_1_5,
- { /* end of list */ }
- },
-};
-
-#define PC_Q35_1_4_MACHINE_OPTIONS \
- PC_Q35_1_6_MACHINE_OPTIONS, \
- .hot_add_cpu = NULL
-
-static QEMUMachine pc_q35_machine_v1_4 = {
- PC_Q35_1_4_MACHINE_OPTIONS,
- .name = "pc-q35-1.4",
- .init = pc_q35_init_1_4,
- .compat_props = (GlobalProperty[]) {
- PC_COMPAT_1_4,
- { /* end of list */ }
- },
-};
-
-static void pc_q35_machine_init(void)
+DEFINE_Q35_MACHINE(v1_5, "pc-q35-1.5", pc_compat_1_5,
+ pc_q35_1_5_machine_options);
+
+
+static void pc_q35_1_4_machine_options(MachineClass *m)
{
- qemu_register_pc_machine(&pc_q35_machine_v2_4);
- qemu_register_pc_machine(&pc_q35_machine_v2_3);
- qemu_register_pc_machine(&pc_q35_machine_v2_2);
- qemu_register_pc_machine(&pc_q35_machine_v2_1);
- qemu_register_pc_machine(&pc_q35_machine_v2_0);
- qemu_register_pc_machine(&pc_q35_machine_v1_7);
- qemu_register_pc_machine(&pc_q35_machine_v1_6);
- qemu_register_pc_machine(&pc_q35_machine_v1_5);
- qemu_register_pc_machine(&pc_q35_machine_v1_4);
+ pc_q35_1_5_machine_options(m);
+ m->hot_add_cpu = NULL;
+ SET_MACHINE_COMPAT(m, PC_COMPAT_1_4);
}
-machine_init(pc_q35_machine_init);
+DEFINE_Q35_MACHINE(v1_4, "pc-q35-1.4", pc_compat_1_4,
+ pc_q35_1_4_machine_options);
diff --git a/hw/i386/ssdt-tpm.dsl b/hw/i386/ssdt-tpm.dsl
index 75d96910bf..d81478c1b5 100644
--- a/hw/i386/ssdt-tpm.dsl
+++ b/hw/i386/ssdt-tpm.dsl
@@ -25,19 +25,5 @@ DefinitionBlock (
0x1 // OEM Revision
)
{
- Scope(\_SB) {
- /* TPM with emulated TPM TIS interface */
- Device (TPM) {
- Name (_HID, EisaID ("PNP0C31"))
- Name (_CRS, ResourceTemplate ()
- {
- Memory32Fixed (ReadWrite, TPM_TIS_ADDR_BASE, TPM_TIS_ADDR_SIZE)
- // older Linux tpm_tis drivers do not work with IRQ
- //IRQNoFlags () {TPM_TIS_IRQ}
- })
- Method (_STA, 0, NotSerialized) {
- Return (0x0F)
- }
- }
- }
+#include "ssdt-tpm-common.dsl"
}
diff --git a/hw/i386/ssdt-tpm.hex.generated b/hw/i386/ssdt-tpm.hex.generated
index e84dc6cfc0..874418c946 100644
--- a/hw/i386/ssdt-tpm.hex.generated
+++ b/hw/i386/ssdt-tpm.hex.generated
@@ -3,12 +3,12 @@ static unsigned char ssdt_tpm_aml[] = {
0x53,
0x44,
0x54,
-0x5d,
+0x6b,
0x0,
0x0,
0x0,
0x1,
-0x1c,
+0x37,
0x42,
0x58,
0x50,
@@ -36,15 +36,26 @@ static unsigned char ssdt_tpm_aml[] = {
0x14,
0x20,
0x10,
-0x38,
+0x46,
+0x4,
0x5c,
+0x2f,
+0x3,
0x5f,
0x53,
0x42,
0x5f,
+0x50,
+0x43,
+0x49,
+0x30,
+0x49,
+0x53,
+0x41,
+0x5f,
0x5b,
0x82,
-0x30,
+0x33,
0x54,
0x50,
0x4d,
@@ -65,9 +76,9 @@ static unsigned char ssdt_tpm_aml[] = {
0x52,
0x53,
0x11,
-0x11,
+0x14,
0xa,
-0xe,
+0x11,
0x86,
0x9,
0x0,
@@ -80,6 +91,9 @@ static unsigned char ssdt_tpm_aml[] = {
0x50,
0x0,
0x0,
+0x22,
+0x20,
+0x0,
0x79,
0x0,
0x14,
diff --git a/hw/i386/ssdt-tpm2.dsl b/hw/i386/ssdt-tpm2.dsl
new file mode 100644
index 0000000000..58bbbf806d
--- /dev/null
+++ b/hw/i386/ssdt-tpm2.dsl
@@ -0,0 +1,29 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "hw/acpi/tpm.h"
+
+ACPI_EXTRACT_ALL_CODE ssdt_tpm2_aml
+
+DefinitionBlock (
+ "ssdt-tpm2.aml", // Output Filename
+ "SSDT", // Signature
+ 0x01, // SSDT Compliance Revision
+ "BXPC", // OEMID
+ "BXSSDT", // TABLE ID
+ 0x1 // OEM Revision
+ )
+{
+#include "ssdt-tpm-common.dsl"
+}
diff --git a/hw/i386/ssdt-tpm2.hex.generated b/hw/i386/ssdt-tpm2.hex.generated
new file mode 100644
index 0000000000..9ea827151a
--- /dev/null
+++ b/hw/i386/ssdt-tpm2.hex.generated
@@ -0,0 +1,109 @@
+static unsigned char ssdt_tpm2_aml[] = {
+0x53,
+0x53,
+0x44,
+0x54,
+0x6b,
+0x0,
+0x0,
+0x0,
+0x1,
+0x37,
+0x42,
+0x58,
+0x50,
+0x43,
+0x0,
+0x0,
+0x42,
+0x58,
+0x53,
+0x53,
+0x44,
+0x54,
+0x0,
+0x0,
+0x1,
+0x0,
+0x0,
+0x0,
+0x49,
+0x4e,
+0x54,
+0x4c,
+0x7,
+0x11,
+0x14,
+0x20,
+0x10,
+0x46,
+0x4,
+0x5c,
+0x2f,
+0x3,
+0x5f,
+0x53,
+0x42,
+0x5f,
+0x50,
+0x43,
+0x49,
+0x30,
+0x49,
+0x53,
+0x41,
+0x5f,
+0x5b,
+0x82,
+0x33,
+0x54,
+0x50,
+0x4d,
+0x5f,
+0x8,
+0x5f,
+0x48,
+0x49,
+0x44,
+0xc,
+0x41,
+0xd0,
+0xc,
+0x31,
+0x8,
+0x5f,
+0x43,
+0x52,
+0x53,
+0x11,
+0x14,
+0xa,
+0x11,
+0x86,
+0x9,
+0x0,
+0x1,
+0x0,
+0x0,
+0xd4,
+0xfe,
+0x0,
+0x50,
+0x0,
+0x0,
+0x22,
+0x20,
+0x0,
+0x79,
+0x0,
+0x14,
+0x9,
+0x5f,
+0x53,
+0x54,
+0x41,
+0x0,
+0xa4,
+0xa,
+0xf
+};
diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c
index e615c5cc7c..c4f4b3c150 100644
--- a/hw/input/virtio-input.c
+++ b/hw/input/virtio-input.c
@@ -166,7 +166,7 @@ static void virtio_input_set_config(VirtIODevice *vdev,
virtio_notify_config(vdev);
}
-static uint32_t virtio_input_get_features(VirtIODevice *vdev, uint32_t f)
+static uint64_t virtio_input_get_features(VirtIODevice *vdev, uint64_t f)
{
return f;
}
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index 47f8b89d51..426b23e7e3 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -157,6 +157,7 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
net->dev.nvqs = 2;
net->dev.vqs = net->vqs;
+ net->dev.vq_index = net->nc->queue_index;
r = vhost_dev_init(&net->dev, options->opaque,
options->backend_type, options->force);
@@ -267,7 +268,7 @@ static void vhost_net_stop_one(struct vhost_net *net,
for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
const VhostOps *vhost_ops = net->dev.vhost_ops;
int r = vhost_ops->vhost_call(&net->dev, VHOST_RESET_OWNER,
- NULL);
+ &file);
assert(r >= 0);
}
}
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 3af6faf4c8..012ab7fae8 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -435,7 +435,7 @@ static void virtio_net_set_queues(VirtIONet *n)
static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue);
-static uint32_t virtio_net_get_features(VirtIODevice *vdev, uint32_t features)
+static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features)
{
VirtIONet *n = VIRTIO_NET(vdev);
NetClientState *nc = qemu_get_queue(n->nic);
@@ -468,9 +468,9 @@ static uint32_t virtio_net_get_features(VirtIODevice *vdev, uint32_t features)
return vhost_net_get_features(get_vhost_net(nc->peer), features);
}
-static uint32_t virtio_net_bad_features(VirtIODevice *vdev)
+static uint64_t virtio_net_bad_features(VirtIODevice *vdev)
{
- uint32_t features = 0;
+ uint64_t features = 0;
/* Linux kernel 2.6.25. It understood MAC (as everyone must),
* but also these: */
@@ -1032,10 +1032,12 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t
if (i == 0)
return -1;
error_report("virtio-net unexpected empty queue: "
- "i %zd mergeable %d offset %zd, size %zd, "
- "guest hdr len %zd, host hdr len %zd guest features 0x%x",
- i, n->mergeable_rx_bufs, offset, size,
- n->guest_hdr_len, n->host_hdr_len, vdev->guest_features);
+ "i %zd mergeable %d offset %zd, size %zd, "
+ "guest hdr len %zd, host hdr len %zd "
+ "guest features 0x%" PRIx64,
+ i, n->mergeable_rx_bufs, offset, size,
+ n->guest_hdr_len, n->host_hdr_len,
+ vdev->guest_features);
exit(1);
}
@@ -1301,39 +1303,8 @@ static void virtio_net_tx_bh(void *opaque)
static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue)
{
- VirtIODevice *vdev = VIRTIO_DEVICE(n);
- int i, max = multiqueue ? n->max_queues : 1;
-
n->multiqueue = multiqueue;
- for (i = 2; i < n->max_queues * 2 + 1; i++) {
- virtio_del_queue(vdev, i);
- }
-
- for (i = 1; i < max; i++) {
- n->vqs[i].rx_vq = virtio_add_queue(vdev, 256, virtio_net_handle_rx);
- if (n->vqs[i].tx_timer) {
- n->vqs[i].tx_vq =
- virtio_add_queue(vdev, 256, virtio_net_handle_tx_timer);
- n->vqs[i].tx_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
- virtio_net_tx_timer,
- &n->vqs[i]);
- } else {
- n->vqs[i].tx_vq =
- virtio_add_queue(vdev, 256, virtio_net_handle_tx_bh);
- n->vqs[i].tx_bh = qemu_bh_new(virtio_net_tx_bh, &n->vqs[i]);
- }
-
- n->vqs[i].tx_waiting = 0;
- n->vqs[i].n = n;
- }
-
- /* Note: Minux Guests (version 3.2.1) use ctrl vq but don't ack
- * VIRTIO_NET_F_CTRL_VQ. Create ctrl vq unconditionally to avoid
- * breaking them.
- */
- n->ctrl_vq = virtio_add_queue(vdev, 64, virtio_net_handle_ctrl);
-
virtio_net_set_queues(n);
}
@@ -1549,7 +1520,7 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx,
vdev, idx, mask);
}
-static void virtio_net_set_config_size(VirtIONet *n, uint32_t host_features)
+static void virtio_net_set_config_size(VirtIONet *n, uint64_t host_features)
{
int i, config_size = 0;
virtio_add_feature(&host_features, VIRTIO_NET_F_MAC);
@@ -1586,17 +1557,15 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
virtio_init(vdev, "virtio-net", VIRTIO_ID_NET, n->config_size);
n->max_queues = MAX(n->nic_conf.peers.queues, 1);
- if (n->max_queues * 2 + 1 > VIRTIO_PCI_QUEUE_MAX) {
+ if (n->max_queues * 2 + 1 > VIRTIO_QUEUE_MAX) {
error_setg(errp, "Invalid number of queues (= %" PRIu32 "), "
"must be a positive integer less than %d.",
- n->max_queues, (VIRTIO_PCI_QUEUE_MAX - 1) / 2);
+ n->max_queues, (VIRTIO_QUEUE_MAX - 1) / 2);
virtio_cleanup(vdev);
return;
}
n->vqs = g_malloc0(sizeof(VirtIONetQueue) * n->max_queues);
- n->vqs[0].rx_vq = virtio_add_queue(vdev, 256, virtio_net_handle_rx);
n->curr_queues = 1;
- n->vqs[0].n = n;
n->tx_timeout = n->net_conf.txtimer;
if (n->net_conf.tx && strcmp(n->net_conf.tx, "timer")
@@ -1607,16 +1576,24 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
error_report("Defaulting to \"bh\"");
}
- if (n->net_conf.tx && !strcmp(n->net_conf.tx, "timer")) {
- n->vqs[0].tx_vq = virtio_add_queue(vdev, 256,
- virtio_net_handle_tx_timer);
- n->vqs[0].tx_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, virtio_net_tx_timer,
- &n->vqs[0]);
- } else {
- n->vqs[0].tx_vq = virtio_add_queue(vdev, 256,
- virtio_net_handle_tx_bh);
- n->vqs[0].tx_bh = qemu_bh_new(virtio_net_tx_bh, &n->vqs[0]);
+ for (i = 0; i < n->max_queues; i++) {
+ n->vqs[i].rx_vq = virtio_add_queue(vdev, 256, virtio_net_handle_rx);
+ if (n->net_conf.tx && !strcmp(n->net_conf.tx, "timer")) {
+ n->vqs[i].tx_vq =
+ virtio_add_queue(vdev, 256, virtio_net_handle_tx_timer);
+ n->vqs[i].tx_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+ virtio_net_tx_timer,
+ &n->vqs[i]);
+ } else {
+ n->vqs[i].tx_vq =
+ virtio_add_queue(vdev, 256, virtio_net_handle_tx_bh);
+ n->vqs[i].tx_bh = qemu_bh_new(virtio_net_tx_bh, &n->vqs[i]);
+ }
+
+ n->vqs[i].tx_waiting = 0;
+ n->vqs[i].n = n;
}
+
n->ctrl_vq = virtio_add_queue(vdev, 64, virtio_net_handle_ctrl);
qemu_macaddr_default_if_unset(&n->nic_conf.macaddr);
memcpy(&n->mac[0], &n->nic_conf.macaddr, sizeof(n->mac));
diff --git a/hw/pci/msi.c b/hw/pci/msi.c
index 2949938223..c111dbaff6 100644
--- a/hw/pci/msi.c
+++ b/hw/pci/msi.c
@@ -291,8 +291,16 @@ void msi_notify(PCIDevice *dev, unsigned int vector)
"notify vector 0x%x"
" address: 0x%"PRIx64" data: 0x%"PRIx32"\n",
vector, msg.address, msg.data);
+ msi_send_message(dev, msg);
+}
+
+void msi_send_message(PCIDevice *dev, MSIMessage msg)
+{
+ MemTxAttrs attrs = {};
+
+ attrs.stream_id = (pci_bus_num(dev->bus) << 8) | dev->devfn;
address_space_stl_le(&dev->bus_master_as, msg.address, msg.data,
- MEMTXATTRS_UNSPECIFIED, NULL);
+ attrs, NULL);
}
/* Normally called by pci_default_write_config(). */
diff --git a/hw/pci/msix.c b/hw/pci/msix.c
index 9935f98ae5..7716bf3649 100644
--- a/hw/pci/msix.c
+++ b/hw/pci/msix.c
@@ -443,8 +443,7 @@ void msix_notify(PCIDevice *dev, unsigned vector)
msg = msix_get_message(dev, vector);
- address_space_stl_le(&dev->bus_master_as, msg.address, msg.data,
- MEMTXATTRS_UNSPECIFIED, NULL);
+ msi_send_message(dev, msg);
}
void msix_reset(PCIDevice *dev)
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index ac261ef050..a15fa3c965 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -1815,15 +1815,21 @@ static const TypeInfo spapr_machine_info = {
},
};
+#define SPAPR_COMPAT_2_3 \
+ HW_COMPAT_2_3
+
#define SPAPR_COMPAT_2_2 \
+ SPAPR_COMPAT_2_3 \
+ HW_COMPAT_2_2 \
{\
.driver = TYPE_SPAPR_PCI_HOST_BRIDGE,\
.property = "mem_win_size",\
.value = "0x20000000",\
- }
+ },
#define SPAPR_COMPAT_2_1 \
- SPAPR_COMPAT_2_2
+ SPAPR_COMPAT_2_2 \
+ HW_COMPAT_2_1
static void spapr_compat_2_3(Object *obj)
{
@@ -1861,8 +1867,7 @@ static void spapr_machine_2_1_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
static GlobalProperty compat_props[] = {
- HW_COMPAT_2_1,
- SPAPR_COMPAT_2_1,
+ SPAPR_COMPAT_2_1
{ /* end of list */ }
};
@@ -1881,7 +1886,7 @@ static const TypeInfo spapr_machine_2_1_info = {
static void spapr_machine_2_2_class_init(ObjectClass *oc, void *data)
{
static GlobalProperty compat_props[] = {
- SPAPR_COMPAT_2_2,
+ SPAPR_COMPAT_2_2
{ /* end of list */ }
};
MachineClass *mc = MACHINE_CLASS(oc);
diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c
index 0e35ac970a..8a6e27eac1 100644
--- a/hw/s390x/s390-virtio-bus.c
+++ b/hw/s390x/s390-virtio-bus.c
@@ -45,6 +45,8 @@
do { } while (0)
#endif
+#define VIRTIO_S390_QUEUE_MAX 64
+
static void virtio_s390_bus_new(VirtioBusState *bus, size_t bus_size,
VirtIOS390Device *dev);
@@ -139,8 +141,6 @@ static void s390_virtio_device_init(VirtIOS390Device *dev,
bus->dev_offs += dev_len;
- dev->host_features = virtio_bus_get_vdev_features(&dev->bus,
- dev->host_features);
s390_virtio_device_sync(dev);
s390_virtio_reset_idx(dev);
if (dev->qdev.hotplugged) {
@@ -354,7 +354,7 @@ static ram_addr_t s390_virtio_device_num_vq(VirtIOS390Device *dev)
VirtIODevice *vdev = dev->vdev;
int num_vq;
- for (num_vq = 0; num_vq < VIRTIO_PCI_QUEUE_MAX; num_vq++) {
+ for (num_vq = 0; num_vq < VIRTIO_S390_QUEUE_MAX; num_vq++) {
if (!virtio_queue_get_num(vdev, num_vq)) {
break;
}
@@ -433,7 +433,8 @@ void s390_virtio_device_sync(VirtIOS390Device *dev)
cur_offs += num_vq * VIRTIO_VQCONFIG_LEN;
/* Sync feature bitmap */
- address_space_stl_le(&address_space_memory, cur_offs, dev->host_features,
+ address_space_stl_le(&address_space_memory, cur_offs,
+ dev->vdev->host_features,
MEMTXATTRS_UNSPECIFIED, NULL);
dev->feat_offs = cur_offs + dev->feat_len;
@@ -476,7 +477,7 @@ VirtIOS390Device *s390_virtio_bus_find_vring(VirtIOS390Bus *bus,
QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
VirtIOS390Device *dev = (VirtIOS390Device *)kid->child;
- for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
+ for (i = 0; i < VIRTIO_S390_QUEUE_MAX; i++) {
if (!virtio_queue_get_addr(dev->vdev, i))
break;
if (virtio_queue_get_addr(dev->vdev, i) == mem) {
@@ -528,10 +529,17 @@ static void virtio_s390_notify(DeviceState *d, uint16_t vector)
s390_virtio_irq(0, token);
}
-static unsigned virtio_s390_get_features(DeviceState *d)
+static void virtio_s390_device_plugged(DeviceState *d, Error **errp)
{
VirtIOS390Device *dev = to_virtio_s390_device(d);
- return dev->host_features;
+ VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
+ int n = virtio_get_num_queues(vdev);
+
+ if (n > VIRTIO_S390_QUEUE_MAX) {
+ error_setg(errp, "The nubmer of virtqueues %d "
+ "exceeds s390 limit %d", n,
+ VIRTIO_S390_QUEUE_MAX);
+ }
}
/**************** S390 Virtio Bus Device Descriptions *******************/
@@ -626,16 +634,10 @@ static void s390_virtio_busdev_reset(DeviceState *dev)
virtio_reset(_dev->vdev);
}
-static Property virtio_s390_properties[] = {
- DEFINE_VIRTIO_COMMON_FEATURES(VirtIOS390Device, host_features),
- DEFINE_PROP_END_OF_LIST(),
-};
-
static void virtio_s390_device_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->props = virtio_s390_properties;
dc->realize = s390_virtio_busdev_realize;
dc->bus_type = TYPE_S390_VIRTIO_BUS;
dc->reset = s390_virtio_busdev_reset;
@@ -733,7 +735,7 @@ static void virtio_s390_bus_class_init(ObjectClass *klass, void *data)
BusClass *bus_class = BUS_CLASS(klass);
bus_class->max_dev = 1;
k->notify = virtio_s390_notify;
- k->get_features = virtio_s390_get_features;
+ k->device_plugged = virtio_s390_device_plugged;
}
static const TypeInfo virtio_s390_bus_info = {
diff --git a/hw/s390x/s390-virtio-bus.h b/hw/s390x/s390-virtio-bus.h
index 96b1890b4c..7ad295e68f 100644
--- a/hw/s390x/s390-virtio-bus.h
+++ b/hw/s390x/s390-virtio-bus.h
@@ -92,7 +92,6 @@ struct VirtIOS390Device {
ram_addr_t feat_offs;
uint8_t feat_len;
VirtIODevice *vdev;
- uint32_t host_features;
VirtioBusState bus;
};
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index afb539adea..8a565f657a 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -67,7 +67,7 @@ static int virtio_ccw_hcall_notify(const uint64_t *args)
if (!sch || !css_subch_visible(sch)) {
return -EINVAL;
}
- if (queue >= VIRTIO_PCI_QUEUE_MAX) {
+ if (queue >= VIRTIO_CCW_QUEUE_MAX) {
return -EINVAL;
}
virtio_queue_notify(virtio_ccw_get_vdev(sch), queue);
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index c96101aa7c..ef90feddea 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -170,7 +170,7 @@ static void virtio_ccw_start_ioeventfd(VirtioCcwDevice *dev)
return;
}
vdev = virtio_bus_get_device(&dev->bus);
- for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
+ for (n = 0; n < VIRTIO_CCW_QUEUE_MAX; n++) {
if (!virtio_queue_get_num(vdev, n)) {
continue;
}
@@ -205,7 +205,7 @@ static void virtio_ccw_stop_ioeventfd(VirtioCcwDevice *dev)
return;
}
vdev = virtio_bus_get_device(&dev->bus);
- for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
+ for (n = 0; n < VIRTIO_CCW_QUEUE_MAX; n++) {
if (!virtio_queue_get_num(vdev, n)) {
continue;
}
@@ -266,7 +266,7 @@ static int virtio_ccw_set_vqs(SubchDev *sch, uint64_t addr, uint32_t align,
{
VirtIODevice *vdev = virtio_ccw_get_vdev(sch);
- if (index >= VIRTIO_PCI_QUEUE_MAX) {
+ if (index >= VIRTIO_CCW_QUEUE_MAX) {
return -EINVAL;
}
@@ -291,7 +291,7 @@ static int virtio_ccw_set_vqs(SubchDev *sch, uint64_t addr, uint32_t align,
virtio_queue_set_vector(vdev, index, index);
}
/* tell notify handler in case of config change */
- vdev->config_vector = VIRTIO_PCI_QUEUE_MAX;
+ vdev->config_vector = VIRTIO_CCW_QUEUE_MAX;
return 0;
}
@@ -381,8 +381,8 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
+ sizeof(features.features),
MEMTXATTRS_UNSPECIFIED,
NULL);
- if (features.index < ARRAY_SIZE(dev->host_features)) {
- features.features = dev->host_features[features.index];
+ if (features.index == 0) {
+ features.features = vdev->host_features;
} else {
/* Return zeroes if the guest supports more feature bits. */
features.features = 0;
@@ -417,7 +417,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
ccw.cda,
MEMTXATTRS_UNSPECIFIED,
NULL);
- if (features.index < ARRAY_SIZE(dev->host_features)) {
+ if (features.index == 0) {
virtio_set_features(vdev, features.features);
} else {
/*
@@ -573,7 +573,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
ccw.cda,
MEMTXATTRS_UNSPECIFIED,
NULL);
- if (vq_config.index >= VIRTIO_PCI_QUEUE_MAX) {
+ if (vq_config.index >= VIRTIO_CCW_QUEUE_MAX) {
ret = -EINVAL;
break;
}
@@ -896,44 +896,17 @@ static void virtio_ccw_balloon_realize(VirtioCcwDevice *ccw_dev, Error **errp)
}
}
-static void balloon_ccw_stats_get_all(Object *obj, struct Visitor *v,
- void *opaque, const char *name,
- Error **errp)
-{
- VirtIOBalloonCcw *dev = opaque;
- object_property_get(OBJECT(&dev->vdev), v, "guest-stats", errp);
-}
-
-static void balloon_ccw_stats_get_poll_interval(Object *obj, struct Visitor *v,
- void *opaque, const char *name,
- Error **errp)
-{
- VirtIOBalloonCcw *dev = opaque;
- object_property_get(OBJECT(&dev->vdev), v, "guest-stats-polling-interval",
- errp);
-}
-
-static void balloon_ccw_stats_set_poll_interval(Object *obj, struct Visitor *v,
- void *opaque, const char *name,
- Error **errp)
-{
- VirtIOBalloonCcw *dev = opaque;
- object_property_set(OBJECT(&dev->vdev), v, "guest-stats-polling-interval",
- errp);
-}
-
static void virtio_ccw_balloon_instance_init(Object *obj)
{
VirtIOBalloonCcw *dev = VIRTIO_BALLOON_CCW(obj);
+
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
TYPE_VIRTIO_BALLOON);
- object_property_add(obj, "guest-stats", "guest statistics",
- balloon_ccw_stats_get_all, NULL, NULL, dev, NULL);
-
- object_property_add(obj, "guest-stats-polling-interval", "int",
- balloon_ccw_stats_get_poll_interval,
- balloon_ccw_stats_set_poll_interval,
- NULL, dev, NULL);
+ object_property_add_alias(obj, "guest-stats", OBJECT(&dev->vdev),
+ "guest-stats", &error_abort);
+ object_property_add_alias(obj, "guest-stats-polling-interval",
+ OBJECT(&dev->vdev),
+ "guest-stats-polling-interval", &error_abort);
}
static void virtio_ccw_scsi_realize(VirtioCcwDevice *ccw_dev, Error **errp)
@@ -1052,7 +1025,7 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
return;
}
- if (vector < VIRTIO_PCI_QUEUE_MAX) {
+ if (vector < VIRTIO_CCW_QUEUE_MAX) {
if (!dev->indicators) {
return;
}
@@ -1098,14 +1071,6 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
}
}
-static unsigned virtio_ccw_get_features(DeviceState *d)
-{
- VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
-
- /* Only the first 32 feature bits are used. */
- return dev->host_features[0];
-}
-
static void virtio_ccw_reset(DeviceState *d)
{
VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
@@ -1413,18 +1378,21 @@ static int virtio_ccw_load_config(DeviceState *d, QEMUFile *f)
}
/* This is called by virtio-bus just after the device is plugged. */
-static void virtio_ccw_device_plugged(DeviceState *d)
+static void virtio_ccw_device_plugged(DeviceState *d, Error **errp)
{
VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
+ VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
SubchDev *sch = dev->sch;
+ int n = virtio_get_num_queues(vdev);
- sch->id.cu_model = virtio_bus_get_vdev_id(&dev->bus);
+ if (virtio_get_num_queues(vdev) > VIRTIO_CCW_QUEUE_MAX) {
+ error_setg(errp, "The nubmer of virtqueues %d "
+ "exceeds ccw limit %d", n,
+ VIRTIO_CCW_QUEUE_MAX);
+ return;
+ }
- /* Only the first 32 feature bits are used. */
- virtio_add_feature(&dev->host_features[0], VIRTIO_F_NOTIFY_ON_EMPTY);
- virtio_add_feature(&dev->host_features[0], VIRTIO_F_BAD_FEATURE);
- dev->host_features[0] = virtio_bus_get_vdev_features(&dev->bus,
- dev->host_features[0]);
+ sch->id.cu_model = virtio_bus_get_vdev_id(&dev->bus);
css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid,
d->hotplugged, 1);
@@ -1675,16 +1643,10 @@ static void virtio_ccw_busdev_unplug(HotplugHandler *hotplug_dev,
object_unparent(OBJECT(dev));
}
-static Property virtio_ccw_properties[] = {
- DEFINE_VIRTIO_COMMON_FEATURES(VirtioCcwDevice, host_features[0]),
- DEFINE_PROP_END_OF_LIST(),
-};
-
static void virtio_ccw_device_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->props = virtio_ccw_properties;
dc->realize = virtio_ccw_busdev_realize;
dc->exit = virtio_ccw_busdev_exit;
dc->bus_type = TYPE_VIRTUAL_CSS_BUS;
@@ -1749,7 +1711,6 @@ static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data)
bus_class->max_dev = 1;
k->notify = virtio_ccw_notify;
- k->get_features = virtio_ccw_get_features;
k->vmstate_change = virtio_ccw_vmstate_change;
k->query_guest_notifiers = virtio_ccw_query_guest_notifiers;
k->set_host_notifier = virtio_ccw_set_host_notifier;
diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h
index 4fceda735a..ad3af7626a 100644
--- a/hw/s390x/virtio-ccw.h
+++ b/hw/s390x/virtio-ccw.h
@@ -68,9 +68,6 @@ typedef struct VirtIOCCWDeviceClass {
int (*exit)(VirtioCcwDevice *dev);
} VirtIOCCWDeviceClass;
-/* Change here if we want to support more feature bits. */
-#define VIRTIO_CCW_FEATURE_SIZE 1
-
/* Performance improves when virtqueue kick processing is decoupled from the
* vcpu thread using ioeventfd for some devices. */
#define VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT 1
@@ -88,7 +85,6 @@ struct VirtioCcwDevice {
DeviceState parent_obj;
SubchDev *sch;
char *bus_id;
- uint32_t host_features[VIRTIO_CCW_FEATURE_SIZE];
VirtioBusState bus;
bool ioeventfd_started;
bool ioeventfd_disabled;
diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c
index 335f4429a9..9c76486fa9 100644
--- a/hw/scsi/vhost-scsi.c
+++ b/hw/scsi/vhost-scsi.c
@@ -151,8 +151,8 @@ static void vhost_scsi_stop(VHostSCSI *s)
vhost_dev_disable_notifiers(&s->dev, vdev);
}
-static uint32_t vhost_scsi_get_features(VirtIODevice *vdev,
- uint32_t features)
+static uint64_t vhost_scsi_get_features(VirtIODevice *vdev,
+ uint64_t features)
{
VHostSCSI *s = VHOST_SCSI(vdev);
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index e242fefa84..b0dee295d8 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -628,8 +628,8 @@ static void virtio_scsi_set_config(VirtIODevice *vdev,
vs->cdb_size = virtio_ldl_p(vdev, &scsiconf->cdb_size);
}
-static uint32_t virtio_scsi_get_features(VirtIODevice *vdev,
- uint32_t requested_features)
+static uint64_t virtio_scsi_get_features(VirtIODevice *vdev,
+ uint64_t requested_features)
{
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
@@ -830,10 +830,10 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp,
sizeof(VirtIOSCSIConfig));
if (s->conf.num_queues == 0 ||
- s->conf.num_queues > VIRTIO_PCI_QUEUE_MAX - 2) {
+ s->conf.num_queues > VIRTIO_QUEUE_MAX - 2) {
error_setg(errp, "Invalid number of queues (= %" PRIu32 "), "
"must be a positive integer less than %d.",
- s->conf.num_queues, VIRTIO_PCI_QUEUE_MAX - 2);
+ s->conf.num_queues, VIRTIO_QUEUE_MAX - 2);
virtio_cleanup(vdev);
return;
}
diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs
index 99f5983143..64cecc3b67 100644
--- a/hw/tpm/Makefile.objs
+++ b/hw/tpm/Makefile.objs
@@ -1,2 +1,2 @@
common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
-common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
+common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o tpm_util.o
diff --git a/hw/tpm/tpm_int.h b/hw/tpm/tpm_int.h
index 2b35fe21ec..f2f285b3cc 100644
--- a/hw/tpm/tpm_int.h
+++ b/hw/tpm/tpm_int.h
@@ -29,6 +29,7 @@ struct TPMState {
char *backend;
TPMBackend *be_driver;
+ TPMVersion be_tpm_version;
};
#define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS)
@@ -65,4 +66,10 @@ struct tpm_resp_hdr {
#define TPM_ORD_ContinueSelfTest 0x53
#define TPM_ORD_GetTicks 0xf1
+
+/* TPM2 defines */
+#define TPM2_ST_NO_SESSIONS 0x8001
+
+#define TPM2_CC_ReadClock 0x00000181
+
#endif /* TPM_TPM_INT_H */
diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
index 73ca906282..8d8523a535 100644
--- a/hw/tpm/tpm_passthrough.c
+++ b/hw/tpm/tpm_passthrough.c
@@ -33,6 +33,7 @@
#include "hw/i386/pc.h"
#include "sysemu/tpm_backend_int.h"
#include "tpm_tis.h"
+#include "tpm_util.h"
#define DEBUG_TPM 0
@@ -69,6 +70,8 @@ struct TPMPassthruState {
bool tpm_op_canceled;
int cancel_fd;
bool had_startup_error;
+
+ TPMVersion tpm_version;
};
typedef struct TPMPassthruState TPMPassthruState;
@@ -267,6 +270,13 @@ static bool tpm_passthrough_get_tpm_established_flag(TPMBackend *tb)
return false;
}
+static int tpm_passthrough_reset_tpm_established_flag(TPMBackend *tb,
+ uint8_t locty)
+{
+ /* only a TPM 2.0 will support this */
+ return 0;
+}
+
static bool tpm_passthrough_get_startup_error(TPMBackend *tb)
{
TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
@@ -324,56 +334,11 @@ static const char *tpm_passthrough_create_desc(void)
return "Passthrough TPM backend driver";
}
-/*
- * A basic test of a TPM device. We expect a well formatted response header
- * (error response is fine) within one second.
- */
-static int tpm_passthrough_test_tpmdev(int fd)
+static TPMVersion tpm_passthrough_get_tpm_version(TPMBackend *tb)
{
- struct tpm_req_hdr req = {
- .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
- .len = cpu_to_be32(sizeof(req)),
- .ordinal = cpu_to_be32(TPM_ORD_GetTicks),
- };
- struct tpm_resp_hdr *resp;
- fd_set readfds;
- int n;
- struct timeval tv = {
- .tv_sec = 1,
- .tv_usec = 0,
- };
- unsigned char buf[1024];
-
- n = write(fd, &req, sizeof(req));
- if (n < 0) {
- return errno;
- }
- if (n != sizeof(req)) {
- return EFAULT;
- }
-
- FD_ZERO(&readfds);
- FD_SET(fd, &readfds);
-
- /* wait for a second */
- n = select(fd + 1, &readfds, NULL, NULL, &tv);
- if (n != 1) {
- return errno;
- }
-
- n = read(fd, &buf, sizeof(buf));
- if (n < sizeof(struct tpm_resp_hdr)) {
- return EFAULT;
- }
-
- resp = (struct tpm_resp_hdr *)buf;
- /* check the header */
- if (be16_to_cpu(resp->tag) != TPM_TAG_RSP_COMMAND ||
- be32_to_cpu(resp->len) != n) {
- return EBADMSG;
- }
+ TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
- return 0;
+ return tpm_pt->tpm_version;
}
/*
@@ -443,7 +408,7 @@ static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb)
goto err_free_parameters;
}
- if (tpm_passthrough_test_tpmdev(tpm_pt->tpm_fd)) {
+ if (tpm_util_test_tpmdev(tpm_pt->tpm_fd, &tpm_pt->tpm_version)) {
error_report("'%s' is not a TPM device.",
tpm_pt->tpm_dev);
goto err_close_tpmdev;
@@ -540,6 +505,8 @@ static const TPMDriverOps tpm_passthrough_driver = {
.deliver_request = tpm_passthrough_deliver_request,
.cancel_cmd = tpm_passthrough_cancel_cmd,
.get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag,
+ .reset_tpm_established_flag = tpm_passthrough_reset_tpm_established_flag,
+ .get_tpm_version = tpm_passthrough_get_tpm_version,
};
static void tpm_passthrough_inst_init(Object *obj)
diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c
index b8235d5c9f..0806b5f82e 100644
--- a/hw/tpm/tpm_tis.c
+++ b/hw/tpm/tpm_tis.c
@@ -17,6 +17,9 @@
* supports version 1.3, 21 March 2013
* In the developers menu choose the PC Client section then find the TIS
* specification.
+ *
+ * TPM TIS for TPM 2 implementation following TCG PC Client Platform
+ * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43
*/
#include "sysemu/tpm_backend.h"
@@ -29,6 +32,7 @@
#include "tpm_tis.h"
#include "qemu-common.h"
#include "qemu/main-loop.h"
+#include "sysemu/tpm_backend.h"
#define DEBUG_TIS 0
@@ -49,6 +53,7 @@
#define TPM_TIS_REG_INTF_CAPABILITY 0x14
#define TPM_TIS_REG_STS 0x18
#define TPM_TIS_REG_DATA_FIFO 0x24
+#define TPM_TIS_REG_INTERFACE_ID 0x30
#define TPM_TIS_REG_DATA_XFIFO 0x80
#define TPM_TIS_REG_DATA_XFIFO_END 0xbc
#define TPM_TIS_REG_DID_VID 0xf00
@@ -57,6 +62,12 @@
/* vendor-specific registers */
#define TPM_TIS_REG_DEBUG 0xf90
+#define TPM_TIS_STS_TPM_FAMILY_MASK (0x3 << 26)/* TPM 2.0 */
+#define TPM_TIS_STS_TPM_FAMILY1_2 (0 << 26) /* TPM 2.0 */
+#define TPM_TIS_STS_TPM_FAMILY2_0 (1 << 26) /* TPM 2.0 */
+#define TPM_TIS_STS_RESET_ESTABLISHMENT_BIT (1 << 25) /* TPM 2.0 */
+#define TPM_TIS_STS_COMMAND_CANCEL (1 << 24) /* TPM 2.0 */
+
#define TPM_TIS_STS_VALID (1 << 7)
#define TPM_TIS_STS_COMMAND_READY (1 << 6)
#define TPM_TIS_STS_TPM_GO (1 << 5)
@@ -102,15 +113,42 @@
#endif
#define TPM_TIS_CAP_INTERFACE_VERSION1_3 (2 << 28)
+#define TPM_TIS_CAP_INTERFACE_VERSION1_3_FOR_TPM2_0 (3 << 28)
#define TPM_TIS_CAP_DATA_TRANSFER_64B (3 << 9)
#define TPM_TIS_CAP_DATA_TRANSFER_LEGACY (0 << 9)
#define TPM_TIS_CAP_BURST_COUNT_DYNAMIC (0 << 8)
#define TPM_TIS_CAP_INTERRUPT_LOW_LEVEL (1 << 4) /* support is mandatory */
-#define TPM_TIS_CAPABILITIES_SUPPORTED (TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \
- TPM_TIS_CAP_BURST_COUNT_DYNAMIC | \
- TPM_TIS_CAP_DATA_TRANSFER_64B | \
- TPM_TIS_CAP_INTERFACE_VERSION1_3 | \
- TPM_TIS_INTERRUPTS_SUPPORTED)
+#define TPM_TIS_CAPABILITIES_SUPPORTED1_3 \
+ (TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \
+ TPM_TIS_CAP_BURST_COUNT_DYNAMIC | \
+ TPM_TIS_CAP_DATA_TRANSFER_64B | \
+ TPM_TIS_CAP_INTERFACE_VERSION1_3 | \
+ TPM_TIS_INTERRUPTS_SUPPORTED)
+
+#define TPM_TIS_CAPABILITIES_SUPPORTED2_0 \
+ (TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \
+ TPM_TIS_CAP_BURST_COUNT_DYNAMIC | \
+ TPM_TIS_CAP_DATA_TRANSFER_64B | \
+ TPM_TIS_CAP_INTERFACE_VERSION1_3_FOR_TPM2_0 | \
+ TPM_TIS_INTERRUPTS_SUPPORTED)
+
+#define TPM_TIS_IFACE_ID_INTERFACE_TIS1_3 (0xf) /* TPM 2.0 */
+#define TPM_TIS_IFACE_ID_INTERFACE_FIFO (0x0) /* TPM 2.0 */
+#define TPM_TIS_IFACE_ID_INTERFACE_VER_FIFO (0 << 4) /* TPM 2.0 */
+#define TPM_TIS_IFACE_ID_CAP_5_LOCALITIES (1 << 8) /* TPM 2.0 */
+#define TPM_TIS_IFACE_ID_CAP_TIS_SUPPORTED (1 << 13) /* TPM 2.0 */
+#define TPM_TIS_IFACE_ID_INT_SEL_LOCK (1 << 19) /* TPM 2.0 */
+
+#define TPM_TIS_IFACE_ID_SUPPORTED_FLAGS1_3 \
+ (TPM_TIS_IFACE_ID_INTERFACE_TIS1_3 | \
+ (~0 << 4)/* all of it is don't care */)
+
+/* if backend was a TPM 2.0: */
+#define TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0 \
+ (TPM_TIS_IFACE_ID_INTERFACE_FIFO | \
+ TPM_TIS_IFACE_ID_INTERFACE_VER_FIFO | \
+ TPM_TIS_IFACE_ID_CAP_5_LOCALITIES | \
+ TPM_TIS_IFACE_ID_CAP_TIS_SUPPORTED)
#define TPM_TIS_TPM_DID 0x0001
#define TPM_TIS_TPM_VID PCI_VENDOR_ID_IBM
@@ -154,7 +192,8 @@ static void tpm_tis_show_buffer(const TPMSizedBuffer *sb, const char *string)
/*
* Set the given flags in the STS register by clearing the register but
- * preserving the SELFTEST_DONE flag and then setting the new flags.
+ * preserving the SELFTEST_DONE and TPM_FAMILY_MASK flags and then setting
+ * the new flags.
*
* The SELFTEST_DONE flag is acquired from the backend that determines it by
* peeking into TPM commands.
@@ -166,7 +205,7 @@ static void tpm_tis_show_buffer(const TPMSizedBuffer *sb, const char *string)
*/
static void tpm_tis_sts_set(TPMLocality *l, uint32_t flags)
{
- l->sts &= TPM_TIS_STS_SELFTEST_DONE;
+ l->sts &= TPM_TIS_STS_SELFTEST_DONE | TPM_TIS_STS_TPM_FAMILY_MASK;
l->sts |= flags;
}
@@ -489,7 +528,17 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
val = tis->loc[locty].ints;
break;
case TPM_TIS_REG_INTF_CAPABILITY:
- val = TPM_TIS_CAPABILITIES_SUPPORTED;
+ switch (s->be_tpm_version) {
+ case TPM_VERSION_UNSPEC:
+ val = 0;
+ break;
+ case TPM_VERSION_1_2:
+ val = TPM_TIS_CAPABILITIES_SUPPORTED1_3;
+ break;
+ case TPM_VERSION_2_0:
+ val = TPM_TIS_CAPABILITIES_SUPPORTED2_0;
+ break;
+ }
break;
case TPM_TIS_REG_STS:
if (tis->active_locty == locty) {
@@ -536,6 +585,9 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
shift = 0; /* no more adjustments */
}
break;
+ case TPM_TIS_REG_INTERFACE_ID:
+ val = tis->loc[locty].iface_id;
+ break;
case TPM_TIS_REG_DID_VID:
val = (TPM_TIS_TPM_DID << 16) | TPM_TIS_TPM_VID;
break;
@@ -736,6 +788,25 @@ static void tpm_tis_mmio_write_intern(void *opaque, hwaddr addr,
break;
}
+ if (s->be_tpm_version == TPM_VERSION_2_0) {
+ /* some flags that are only supported for TPM 2 */
+ if (val & TPM_TIS_STS_COMMAND_CANCEL) {
+ if (tis->loc[locty].state == TPM_TIS_STATE_EXECUTION) {
+ /*
+ * request the backend to cancel. Some backends may not
+ * support it
+ */
+ tpm_backend_cancel_cmd(s->be_driver);
+ }
+ }
+
+ if (val & TPM_TIS_STS_RESET_ESTABLISHMENT_BIT) {
+ if (locty == 3 || locty == 4) {
+ tpm_backend_reset_tpm_established_flag(s->be_driver, locty);
+ }
+ }
+ }
+
val &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO |
TPM_TIS_STS_RESPONSE_RETRY);
@@ -860,6 +931,13 @@ static void tpm_tis_mmio_write_intern(void *opaque, hwaddr addr,
}
}
break;
+ case TPM_TIS_REG_INTERFACE_ID:
+ if (val & TPM_TIS_IFACE_ID_INT_SEL_LOCK) {
+ for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
+ tis->loc[l].iface_id |= TPM_TIS_IFACE_ID_INT_SEL_LOCK;
+ }
+ }
+ break;
}
}
@@ -885,6 +963,16 @@ static int tpm_tis_do_startup_tpm(TPMState *s)
}
/*
+ * Get the TPMVersion of the backend device being used
+ */
+TPMVersion tpm_tis_get_tpm_version(Object *obj)
+{
+ TPMState *s = TPM(obj);
+
+ return tpm_backend_get_tpm_version(s->be_driver);
+}
+
+/*
* This function is called when the machine starts, resets or due to
* S3 resume.
*/
@@ -894,6 +982,8 @@ static void tpm_tis_reset(DeviceState *dev)
TPMTISEmuState *tis = &s->s.tis;
int c;
+ s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver);
+
tpm_backend_reset(s->be_driver);
tis->active_locty = TPM_TIS_NO_LOCALITY;
@@ -902,7 +992,18 @@ static void tpm_tis_reset(DeviceState *dev)
for (c = 0; c < TPM_TIS_NUM_LOCALITIES; c++) {
tis->loc[c].access = TPM_TIS_ACCESS_TPM_REG_VALID_STS;
- tis->loc[c].sts = 0;
+ switch (s->be_tpm_version) {
+ case TPM_VERSION_UNSPEC:
+ break;
+ case TPM_VERSION_1_2:
+ tis->loc[c].sts = TPM_TIS_STS_TPM_FAMILY1_2;
+ tis->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS1_3;
+ break;
+ case TPM_VERSION_2_0:
+ tis->loc[c].sts = TPM_TIS_STS_TPM_FAMILY2_0;
+ tis->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0;
+ break;
+ }
tis->loc[c].inte = TPM_TIS_INT_POLARITY_LOW_LEVEL;
tis->loc[c].ints = 0;
tis->loc[c].state = TPM_TIS_STATE_IDLE;
diff --git a/hw/tpm/tpm_tis.h b/hw/tpm/tpm_tis.h
index db78d51e4f..a1df41fa21 100644
--- a/hw/tpm/tpm_tis.h
+++ b/hw/tpm/tpm_tis.h
@@ -42,6 +42,7 @@ typedef struct TPMLocality {
TPMTISState state;
uint8_t access;
uint32_t sts;
+ uint32_t iface_id;
uint32_t inte;
uint32_t ints;
diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c
new file mode 100644
index 0000000000..4ace5852e0
--- /dev/null
+++ b/hw/tpm/tpm_util.c
@@ -0,0 +1,126 @@
+/*
+ * TPM utility functions
+ *
+ * Copyright (c) 2010 - 2015 IBM Corporation
+ * Authors:
+ * Stefan Berger <stefanb@us.ibm.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "tpm_util.h"
+#include "tpm_int.h"
+
+/*
+ * A basic test of a TPM device. We expect a well formatted response header
+ * (error response is fine) within one second.
+ */
+static int tpm_util_test(int fd,
+ unsigned char *request,
+ size_t requestlen,
+ uint16_t *return_tag)
+{
+ struct tpm_resp_hdr *resp;
+ fd_set readfds;
+ int n;
+ struct timeval tv = {
+ .tv_sec = 1,
+ .tv_usec = 0,
+ };
+ unsigned char buf[1024];
+
+ n = write(fd, request, requestlen);
+ if (n < 0) {
+ return errno;
+ }
+ if (n != requestlen) {
+ return EFAULT;
+ }
+
+ FD_ZERO(&readfds);
+ FD_SET(fd, &readfds);
+
+ /* wait for a second */
+ n = select(fd + 1, &readfds, NULL, NULL, &tv);
+ if (n != 1) {
+ return errno;
+ }
+
+ n = read(fd, &buf, sizeof(buf));
+ if (n < sizeof(struct tpm_resp_hdr)) {
+ return EFAULT;
+ }
+
+ resp = (struct tpm_resp_hdr *)buf;
+ /* check the header */
+ if (be32_to_cpu(resp->len) != n) {
+ return EBADMSG;
+ }
+
+ *return_tag = be16_to_cpu(resp->tag);
+
+ return 0;
+}
+
+/*
+ * Probe for the TPM device in the back
+ * Returns 0 on success with the version of the probed TPM set, 1 on failure.
+ */
+int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_version)
+{
+ /*
+ * Sending a TPM1.2 command to a TPM2 should return a TPM1.2
+ * header (tag = 0xc4) and error code (TPM_BADTAG = 0x1e)
+ *
+ * Sending a TPM2 command to a TPM 2 will give a TPM 2 tag in the
+ * header.
+ * Sending a TPM2 command to a TPM 1.2 will give a TPM 1.2 tag
+ * in the header and an error code.
+ */
+ const struct tpm_req_hdr test_req = {
+ .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
+ .len = cpu_to_be32(sizeof(test_req)),
+ .ordinal = cpu_to_be32(TPM_ORD_GetTicks),
+ };
+
+ const struct tpm_req_hdr test_req_tpm2 = {
+ .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
+ .len = cpu_to_be32(sizeof(test_req_tpm2)),
+ .ordinal = cpu_to_be32(TPM2_CC_ReadClock),
+ };
+ uint16_t return_tag;
+ int ret;
+
+ /* Send TPM 2 command */
+ ret = tpm_util_test(tpm_fd, (unsigned char *)&test_req_tpm2,
+ sizeof(test_req_tpm2), &return_tag);
+ /* TPM 2 would respond with a tag of TPM2_ST_NO_SESSIONS */
+ if (!ret && return_tag == TPM2_ST_NO_SESSIONS) {
+ *tpm_version = TPM_VERSION_2_0;
+ return 0;
+ }
+
+ /* Send TPM 1.2 command */
+ ret = tpm_util_test(tpm_fd, (unsigned char *)&test_req,
+ sizeof(test_req), &return_tag);
+ if (!ret && return_tag == TPM_TAG_RSP_COMMAND) {
+ *tpm_version = TPM_VERSION_1_2;
+ /* this is a TPM 1.2 */
+ return 0;
+ }
+
+ *tpm_version = TPM_VERSION_UNSPEC;
+
+ return 1;
+}
diff --git a/hw/tpm/tpm_util.h b/hw/tpm/tpm_util.h
new file mode 100644
index 0000000000..e7f354a52d
--- /dev/null
+++ b/hw/tpm/tpm_util.h
@@ -0,0 +1,28 @@
+/*
+ * TPM utility functions
+ *
+ * Copyright (c) 2010 - 2015 IBM Corporation
+ * Authors:
+ * Stefan Berger <stefanb@us.ibm.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+#ifndef TPM_TPM_UTILS_H
+#define TPM_TPM_UTILS_H
+
+#include "sysemu/tpm_backend.h"
+
+int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_version);
+
+#endif /* TPM_TPM_UTILS_H */
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index e7ab8293d1..d6f21634ef 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -210,7 +210,12 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,
break;
case VHOST_SET_OWNER:
+ break;
+
case VHOST_RESET_OWNER:
+ memcpy(&msg.state, arg, sizeof(struct vhost_vring_state));
+ msg.state.index += dev->vq_index;
+ msg.size = sizeof(m.state);
break;
case VHOST_SET_MEM_TABLE:
@@ -253,17 +258,20 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,
case VHOST_SET_VRING_NUM:
case VHOST_SET_VRING_BASE:
memcpy(&msg.state, arg, sizeof(struct vhost_vring_state));
+ msg.state.index += dev->vq_index;
msg.size = sizeof(m.state);
break;
case VHOST_GET_VRING_BASE:
memcpy(&msg.state, arg, sizeof(struct vhost_vring_state));
+ msg.state.index += dev->vq_index;
msg.size = sizeof(m.state);
need_reply = 1;
break;
case VHOST_SET_VRING_ADDR:
memcpy(&msg.addr, arg, sizeof(struct vhost_vring_addr));
+ msg.addr.index += dev->vq_index;
msg.size = sizeof(m.addr);
break;
@@ -271,7 +279,7 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,
case VHOST_SET_VRING_CALL:
case VHOST_SET_VRING_ERR:
file = arg;
- msg.u64 = file->index & VHOST_USER_VRING_IDX_MASK;
+ msg.u64 = (file->index + dev->vq_index) & VHOST_USER_VRING_IDX_MASK;
msg.size = sizeof(m.u64);
if (ioeventfd_enabled() && file->fd > 0) {
fds[fd_num++] = file->fd;
@@ -313,6 +321,7 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,
error_report("Received bad msg size.");
return -1;
}
+ msg.state.index -= dev->vq_index;
memcpy(arg, &msg.state, sizeof(struct vhost_vring_state));
break;
default:
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index 484c3c333c..f915c7bd73 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -310,7 +310,7 @@ static void virtio_balloon_set_config(VirtIODevice *vdev,
trace_virtio_balloon_set_config(dev->actual, oldactual);
}
-static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f)
+static uint64_t virtio_balloon_get_features(VirtIODevice *vdev, uint64_t f)
{
f |= (1 << VIRTIO_BALLOON_F_STATS_VQ);
return f;
@@ -396,14 +396,6 @@ static void virtio_balloon_device_realize(DeviceState *dev, Error **errp)
register_savevm(dev, "virtio-balloon", -1, 1,
virtio_balloon_save, virtio_balloon_load, s);
-
- object_property_add(OBJECT(dev), "guest-stats", "guest statistics",
- balloon_stats_get_all, NULL, NULL, s, NULL);
-
- object_property_add(OBJECT(dev), "guest-stats-polling-interval", "int",
- balloon_stats_get_poll_interval,
- balloon_stats_set_poll_interval,
- NULL, s, NULL);
}
static void virtio_balloon_device_unrealize(DeviceState *dev, Error **errp)
@@ -417,6 +409,19 @@ static void virtio_balloon_device_unrealize(DeviceState *dev, Error **errp)
virtio_cleanup(vdev);
}
+static void virtio_balloon_instance_init(Object *obj)
+{
+ VirtIOBalloon *s = VIRTIO_BALLOON(obj);
+
+ object_property_add(obj, "guest-stats", "guest statistics",
+ balloon_stats_get_all, NULL, NULL, s, NULL);
+
+ object_property_add(obj, "guest-stats-polling-interval", "int",
+ balloon_stats_get_poll_interval,
+ balloon_stats_set_poll_interval,
+ NULL, s, NULL);
+}
+
static Property virtio_balloon_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
@@ -441,6 +446,7 @@ static const TypeInfo virtio_balloon_info = {
.name = TYPE_VIRTIO_BALLOON,
.parent = TYPE_VIRTIO_DEVICE,
.instance_size = sizeof(VirtIOBalloon),
+ .instance_init = virtio_balloon_instance_init,
.class_init = virtio_balloon_class_init,
};
diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c
index be886e75af..3926f7ee1e 100644
--- a/hw/virtio/virtio-bus.c
+++ b/hw/virtio/virtio-bus.c
@@ -38,19 +38,23 @@ do { printf("virtio_bus: " fmt , ## __VA_ARGS__); } while (0)
#endif
/* A VirtIODevice is being plugged */
-int virtio_bus_device_plugged(VirtIODevice *vdev)
+void virtio_bus_device_plugged(VirtIODevice *vdev, Error **errp)
{
DeviceState *qdev = DEVICE(vdev);
BusState *qbus = BUS(qdev_get_parent_bus(qdev));
VirtioBusState *bus = VIRTIO_BUS(qbus);
VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(bus);
+ VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
+
DPRINTF("%s: plug device.\n", qbus->name);
if (klass->device_plugged != NULL) {
- klass->device_plugged(qbus->parent);
+ klass->device_plugged(qbus->parent, errp);
}
- return 0;
+ /* Get the features of the plugged device. */
+ assert(vdc->get_features != NULL);
+ vdev->host_features = vdc->get_features(vdev, vdev->host_features);
}
/* Reset the virtio_bus */
@@ -96,19 +100,6 @@ size_t virtio_bus_get_vdev_config_len(VirtioBusState *bus)
return vdev->config_len;
}
-/* Get the features of the plugged device. */
-uint32_t virtio_bus_get_vdev_features(VirtioBusState *bus,
- uint32_t requested_features)
-{
- VirtIODevice *vdev = virtio_bus_get_device(bus);
- VirtioDeviceClass *k;
-
- assert(vdev != NULL);
- k = VIRTIO_DEVICE_GET_CLASS(vdev);
- assert(k->get_features != NULL);
- return k->get_features(vdev, requested_features);
-}
-
/* Get bad features of the plugged device. */
uint32_t virtio_bus_get_vdev_bad_features(VirtioBusState *bus)
{
diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c
index 10123f34b2..c8f72947d4 100644
--- a/hw/virtio/virtio-mmio.c
+++ b/hw/virtio/virtio-mmio.c
@@ -22,7 +22,9 @@
#include "hw/sysbus.h"
#include "hw/virtio/virtio.h"
#include "qemu/host-utils.h"
+#include "sysemu/kvm.h"
#include "hw/virtio/virtio-bus.h"
+#include "qemu/error-report.h"
/* #define DEBUG_VIRTIO_MMIO */
@@ -80,15 +82,102 @@ typedef struct {
SysBusDevice parent_obj;
MemoryRegion iomem;
qemu_irq irq;
- uint32_t host_features;
/* Guest accessible state needing migration and reset */
uint32_t host_features_sel;
uint32_t guest_features_sel;
uint32_t guest_page_shift;
/* virtio-bus */
VirtioBusState bus;
+ bool ioeventfd_disabled;
+ bool ioeventfd_started;
} VirtIOMMIOProxy;
+static int virtio_mmio_set_host_notifier_internal(VirtIOMMIOProxy *proxy,
+ int n, bool assign,
+ bool set_handler)
+{
+ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
+ VirtQueue *vq = virtio_get_queue(vdev, n);
+ EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
+ int r = 0;
+
+ if (assign) {
+ r = event_notifier_init(notifier, 1);
+ if (r < 0) {
+ error_report("%s: unable to init event notifier: %d",
+ __func__, r);
+ return r;
+ }
+ virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler);
+ memory_region_add_eventfd(&proxy->iomem, VIRTIO_MMIO_QUEUENOTIFY, 4,
+ true, n, notifier);
+ } else {
+ memory_region_del_eventfd(&proxy->iomem, VIRTIO_MMIO_QUEUENOTIFY, 4,
+ true, n, notifier);
+ virtio_queue_set_host_notifier_fd_handler(vq, false, false);
+ event_notifier_cleanup(notifier);
+ }
+ return r;
+}
+
+static void virtio_mmio_start_ioeventfd(VirtIOMMIOProxy *proxy)
+{
+ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
+ int n, r;
+
+ if (!kvm_eventfds_enabled() ||
+ proxy->ioeventfd_disabled ||
+ proxy->ioeventfd_started) {
+ return;
+ }
+
+ for (n = 0; n < VIRTIO_QUEUE_MAX; n++) {
+ if (!virtio_queue_get_num(vdev, n)) {
+ continue;
+ }
+
+ r = virtio_mmio_set_host_notifier_internal(proxy, n, true, true);
+ if (r < 0) {
+ goto assign_error;
+ }
+ }
+ proxy->ioeventfd_started = true;
+ return;
+
+assign_error:
+ while (--n >= 0) {
+ if (!virtio_queue_get_num(vdev, n)) {
+ continue;
+ }
+
+ r = virtio_mmio_set_host_notifier_internal(proxy, n, false, false);
+ assert(r >= 0);
+ }
+ proxy->ioeventfd_started = false;
+ error_report("%s: failed. Fallback to a userspace (slower).", __func__);
+}
+
+static void virtio_mmio_stop_ioeventfd(VirtIOMMIOProxy *proxy)
+{
+ int r;
+ int n;
+ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
+
+ if (!proxy->ioeventfd_started) {
+ return;
+ }
+
+ for (n = 0; n < VIRTIO_QUEUE_MAX; n++) {
+ if (!virtio_queue_get_num(vdev, n)) {
+ continue;
+ }
+
+ r = virtio_mmio_set_host_notifier_internal(proxy, n, false, false);
+ assert(r >= 0);
+ }
+ proxy->ioeventfd_started = false;
+}
+
static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
{
VirtIOMMIOProxy *proxy = (VirtIOMMIOProxy *)opaque;
@@ -147,7 +236,7 @@ static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
if (proxy->host_features_sel) {
return 0;
}
- return proxy->host_features;
+ return vdev->host_features;
case VIRTIO_MMIO_QUEUENUMMAX:
if (!virtio_queue_get_num(vdev, vdev->queue_sel)) {
return 0;
@@ -237,7 +326,7 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
proxy->guest_page_shift);
break;
case VIRTIO_MMIO_QUEUESEL:
- if (value < VIRTIO_PCI_QUEUE_MAX) {
+ if (value < VIRTIO_QUEUE_MAX) {
vdev->queue_sel = value;
}
break;
@@ -257,7 +346,7 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
}
break;
case VIRTIO_MMIO_QUEUENOTIFY:
- if (value < VIRTIO_PCI_QUEUE_MAX) {
+ if (value < VIRTIO_QUEUE_MAX) {
virtio_queue_notify(vdev, value);
}
break;
@@ -266,7 +355,16 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
virtio_update_irq(vdev);
break;
case VIRTIO_MMIO_STATUS:
+ if (!(value & VIRTIO_CONFIG_S_DRIVER_OK)) {
+ virtio_mmio_stop_ioeventfd(proxy);
+ }
+
virtio_set_status(vdev, value & 0xff);
+
+ if (value & VIRTIO_CONFIG_S_DRIVER_OK) {
+ virtio_mmio_start_ioeventfd(proxy);
+ }
+
if (vdev->status == 0) {
virtio_reset(vdev);
}
@@ -306,13 +404,6 @@ static void virtio_mmio_update_irq(DeviceState *opaque, uint16_t vector)
qemu_set_irq(proxy->irq, level);
}
-static unsigned int virtio_mmio_get_features(DeviceState *opaque)
-{
- VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
-
- return proxy->host_features;
-}
-
static int virtio_mmio_load_config(DeviceState *opaque, QEMUFile *f)
{
VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
@@ -336,24 +427,94 @@ static void virtio_mmio_reset(DeviceState *d)
{
VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
+ virtio_mmio_stop_ioeventfd(proxy);
virtio_bus_reset(&proxy->bus);
proxy->host_features_sel = 0;
proxy->guest_features_sel = 0;
proxy->guest_page_shift = 0;
}
-/* virtio-mmio device */
+static int virtio_mmio_set_guest_notifier(DeviceState *d, int n, bool assign,
+ bool with_irqfd)
+{
+ VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
+ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
+ VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
+ VirtQueue *vq = virtio_get_queue(vdev, n);
+ EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
+
+ if (assign) {
+ int r = event_notifier_init(notifier, 0);
+ if (r < 0) {
+ return r;
+ }
+ virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd);
+ } else {
+ virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd);
+ event_notifier_cleanup(notifier);
+ }
+
+ if (vdc->guest_notifier_mask) {
+ vdc->guest_notifier_mask(vdev, n, !assign);
+ }
-/* This is called by virtio-bus just after the device is plugged. */
-static void virtio_mmio_device_plugged(DeviceState *opaque)
+ return 0;
+}
+
+static int virtio_mmio_set_guest_notifiers(DeviceState *d, int nvqs,
+ bool assign)
+{
+ VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
+ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
+ /* TODO: need to check if kvm-arm supports irqfd */
+ bool with_irqfd = false;
+ int r, n;
+
+ nvqs = MIN(nvqs, VIRTIO_QUEUE_MAX);
+
+ for (n = 0; n < nvqs; n++) {
+ if (!virtio_queue_get_num(vdev, n)) {
+ break;
+ }
+
+ r = virtio_mmio_set_guest_notifier(d, n, assign, with_irqfd);
+ if (r < 0) {
+ goto assign_error;
+ }
+ }
+
+ return 0;
+
+assign_error:
+ /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
+ assert(assign);
+ while (--n >= 0) {
+ virtio_mmio_set_guest_notifier(d, n, !assign, false);
+ }
+ return r;
+}
+
+static int virtio_mmio_set_host_notifier(DeviceState *opaque, int n,
+ bool assign)
{
VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
- virtio_add_feature(&proxy->host_features, VIRTIO_F_NOTIFY_ON_EMPTY);
- proxy->host_features = virtio_bus_get_vdev_features(&proxy->bus,
- proxy->host_features);
+ /* Stop using ioeventfd for virtqueue kick if the device starts using host
+ * notifiers. This makes it easy to avoid stepping on each others' toes.
+ */
+ proxy->ioeventfd_disabled = assign;
+ if (assign) {
+ virtio_mmio_stop_ioeventfd(proxy);
+ }
+ /* We don't need to start here: it's not needed because backend
+ * currently only stops on status change away from ok,
+ * reset, vmstop and such. If we do add code to start here,
+ * need to check vmstate, device state etc. */
+ return virtio_mmio_set_host_notifier_internal(proxy, n, assign, false);
}
+/* virtio-mmio device */
+
static void virtio_mmio_realizefn(DeviceState *d, Error **errp)
{
VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
@@ -367,16 +528,10 @@ static void virtio_mmio_realizefn(DeviceState *d, Error **errp)
sysbus_init_mmio(sbd, &proxy->iomem);
}
-static Property virtio_mmio_properties[] = {
- DEFINE_VIRTIO_COMMON_FEATURES(VirtIOMMIOProxy, host_features),
- DEFINE_PROP_END_OF_LIST(),
-};
-
static void virtio_mmio_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->props = virtio_mmio_properties;
dc->realize = virtio_mmio_realizefn;
dc->reset = virtio_mmio_reset;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
@@ -399,8 +554,8 @@ static void virtio_mmio_bus_class_init(ObjectClass *klass, void *data)
k->notify = virtio_mmio_update_irq;
k->save_config = virtio_mmio_save_config;
k->load_config = virtio_mmio_load_config;
- k->get_features = virtio_mmio_get_features;
- k->device_plugged = virtio_mmio_device_plugged;
+ k->set_host_notifier = virtio_mmio_set_host_notifier;
+ k->set_guest_notifiers = virtio_mmio_set_guest_notifiers;
k->has_variable_vring_alignment = true;
bus_class->max_dev = 1;
}
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 867c9d17ca..d1ddc39b6f 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -171,7 +171,7 @@ static void virtio_pci_start_ioeventfd(VirtIOPCIProxy *proxy)
return;
}
- for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
+ for (n = 0; n < VIRTIO_QUEUE_MAX; n++) {
if (!virtio_queue_get_num(vdev, n)) {
continue;
}
@@ -207,7 +207,7 @@ static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy)
return;
}
- for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
+ for (n = 0; n < VIRTIO_QUEUE_MAX; n++) {
if (!virtio_queue_get_num(vdev, n)) {
continue;
}
@@ -243,11 +243,11 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
virtio_queue_set_addr(vdev, vdev->queue_sel, pa);
break;
case VIRTIO_PCI_QUEUE_SEL:
- if (val < VIRTIO_PCI_QUEUE_MAX)
+ if (val < VIRTIO_QUEUE_MAX)
vdev->queue_sel = val;
break;
case VIRTIO_PCI_QUEUE_NOTIFY:
- if (val < VIRTIO_PCI_QUEUE_MAX) {
+ if (val < VIRTIO_QUEUE_MAX) {
virtio_queue_notify(vdev, val);
}
break;
@@ -306,7 +306,7 @@ static uint32_t virtio_ioport_read(VirtIOPCIProxy *proxy, uint32_t addr)
switch (addr) {
case VIRTIO_PCI_HOST_FEATURES:
- ret = proxy->host_features;
+ ret = vdev->host_features;
break;
case VIRTIO_PCI_GUEST_FEATURES:
ret = vdev->guest_features;
@@ -434,12 +434,6 @@ static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
}
}
-static unsigned virtio_pci_get_features(DeviceState *d)
-{
- VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
- return proxy->host_features;
-}
-
static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy,
unsigned int queue_no,
unsigned int vector,
@@ -750,7 +744,7 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign)
bool with_irqfd = msix_enabled(&proxy->pci_dev) &&
kvm_msi_via_irqfd_enabled();
- nvqs = MIN(nvqs, VIRTIO_PCI_QUEUE_MAX);
+ nvqs = MIN(nvqs, VIRTIO_QUEUE_MAX);
/* When deassigning, pass a consistent nvqs value
* to avoid leaking notifiers.
@@ -918,12 +912,13 @@ static int virtio_pci_query_nvectors(DeviceState *d)
}
/* This is called by virtio-bus just after the device is plugged. */
-static void virtio_pci_device_plugged(DeviceState *d)
+static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
{
VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
VirtioBusState *bus = &proxy->bus;
uint8_t *config;
uint32_t size;
+ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
config = proxy->pci_dev.config;
if (proxy->class_code) {
@@ -958,10 +953,7 @@ static void virtio_pci_device_plugged(DeviceState *d)
proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
}
- virtio_add_feature(&proxy->host_features, VIRTIO_F_NOTIFY_ON_EMPTY);
- virtio_add_feature(&proxy->host_features, VIRTIO_F_BAD_FEATURE);
- proxy->host_features = virtio_bus_get_vdev_features(bus,
- proxy->host_features);
+ virtio_add_feature(&vdev->host_features, VIRTIO_F_BAD_FEATURE);
}
static void virtio_pci_device_unplugged(DeviceState *d)
@@ -999,7 +991,6 @@ static void virtio_pci_reset(DeviceState *qdev)
static Property virtio_pci_properties[] = {
DEFINE_PROP_BIT("virtio-pci-bus-master-bug-migration", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT, false),
- DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1207,32 +1198,6 @@ static const TypeInfo vhost_scsi_pci_info = {
/* virtio-balloon-pci */
-static void balloon_pci_stats_get_all(Object *obj, struct Visitor *v,
- void *opaque, const char *name,
- Error **errp)
-{
- VirtIOBalloonPCI *dev = opaque;
- object_property_get(OBJECT(&dev->vdev), v, "guest-stats", errp);
-}
-
-static void balloon_pci_stats_get_poll_interval(Object *obj, struct Visitor *v,
- void *opaque, const char *name,
- Error **errp)
-{
- VirtIOBalloonPCI *dev = opaque;
- object_property_get(OBJECT(&dev->vdev), v, "guest-stats-polling-interval",
- errp);
-}
-
-static void balloon_pci_stats_set_poll_interval(Object *obj, struct Visitor *v,
- void *opaque, const char *name,
- Error **errp)
-{
- VirtIOBalloonPCI *dev = opaque;
- object_property_set(OBJECT(&dev->vdev), v, "guest-stats-polling-interval",
- errp);
-}
-
static Property virtio_balloon_pci_properties[] = {
DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
DEFINE_PROP_END_OF_LIST(),
@@ -1269,16 +1234,14 @@ static void virtio_balloon_pci_class_init(ObjectClass *klass, void *data)
static void virtio_balloon_pci_instance_init(Object *obj)
{
VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(obj);
+
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
TYPE_VIRTIO_BALLOON);
- object_property_add(obj, "guest-stats", "guest statistics",
- balloon_pci_stats_get_all, NULL, NULL, dev,
- NULL);
-
- object_property_add(obj, "guest-stats-polling-interval", "int",
- balloon_pci_stats_get_poll_interval,
- balloon_pci_stats_set_poll_interval,
- NULL, dev, NULL);
+ object_property_add_alias(obj, "guest-stats", OBJECT(&dev->vdev),
+ "guest-stats", &error_abort);
+ object_property_add_alias(obj, "guest-stats-polling-interval",
+ OBJECT(&dev->vdev),
+ "guest-stats-polling-interval", &error_abort);
}
static const TypeInfo virtio_balloon_pci_info = {
@@ -1497,7 +1460,6 @@ static void virtio_pci_bus_class_init(ObjectClass *klass, void *data)
k->load_config = virtio_pci_load_config;
k->save_queue = virtio_pci_save_queue;
k->load_queue = virtio_pci_load_queue;
- k->get_features = virtio_pci_get_features;
k->query_guest_notifiers = virtio_pci_query_guest_notifiers;
k->set_host_notifier = virtio_pci_set_host_notifier;
k->set_guest_notifiers = virtio_pci_set_guest_notifiers;
diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h
index 3bac016999..de394687ef 100644
--- a/hw/virtio/virtio-pci.h
+++ b/hw/virtio/virtio-pci.h
@@ -91,7 +91,6 @@ struct VirtIOPCIProxy {
uint32_t flags;
uint32_t class_code;
uint32_t nvectors;
- uint32_t host_features;
bool ioeventfd_disabled;
bool ioeventfd_started;
VirtIOIRQFD *vector_irqfd;
diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c
index 06e71782b2..420c39fb50 100644
--- a/hw/virtio/virtio-rng.c
+++ b/hw/virtio/virtio-rng.c
@@ -99,7 +99,7 @@ static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
virtio_rng_process(vrng);
}
-static uint32_t get_features(VirtIODevice *vdev, uint32_t f)
+static uint64_t get_features(VirtIODevice *vdev, uint64_t f)
{
return f;
}
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 6985e76b64..596e3d8aaf 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -600,7 +600,7 @@ void virtio_reset(void *opaque)
vdev->config_vector = VIRTIO_NO_VECTOR;
virtio_notify_vector(vdev, vdev->config_vector);
- for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
+ for(i = 0; i < VIRTIO_QUEUE_MAX; i++) {
vdev->vq[i].vring.desc = 0;
vdev->vq[i].vring.avail = 0;
vdev->vq[i].vring.used = 0;
@@ -746,10 +746,23 @@ int virtio_queue_get_num(VirtIODevice *vdev, int n)
return vdev->vq[n].vring.num;
}
+int virtio_get_num_queues(VirtIODevice *vdev)
+{
+ int i;
+
+ for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
+ if (!virtio_queue_get_num(vdev, i)) {
+ break;
+ }
+ }
+
+ return i;
+}
+
int virtio_queue_get_id(VirtQueue *vq)
{
VirtIODevice *vdev = vq->vdev;
- assert(vq >= &vdev->vq[0] && vq < &vdev->vq[VIRTIO_PCI_QUEUE_MAX]);
+ assert(vq >= &vdev->vq[0] && vq < &vdev->vq[VIRTIO_QUEUE_MAX]);
return vq - &vdev->vq[0];
}
@@ -785,7 +798,7 @@ void virtio_queue_notify(VirtIODevice *vdev, int n)
uint16_t virtio_queue_vector(VirtIODevice *vdev, int n)
{
- return n < VIRTIO_PCI_QUEUE_MAX ? vdev->vq[n].vector :
+ return n < VIRTIO_QUEUE_MAX ? vdev->vq[n].vector :
VIRTIO_NO_VECTOR;
}
@@ -793,7 +806,7 @@ void virtio_queue_set_vector(VirtIODevice *vdev, int n, uint16_t vector)
{
VirtQueue *vq = &vdev->vq[n];
- if (n < VIRTIO_PCI_QUEUE_MAX) {
+ if (n < VIRTIO_QUEUE_MAX) {
if (vdev->vector_queues &&
vdev->vq[n].vector != VIRTIO_NO_VECTOR) {
QLIST_REMOVE(vq, node);
@@ -811,12 +824,12 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
{
int i;
- for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
+ for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
if (vdev->vq[i].vring.num == 0)
break;
}
- if (i == VIRTIO_PCI_QUEUE_MAX || queue_size > VIRTQUEUE_MAX_SIZE)
+ if (i == VIRTIO_QUEUE_MAX || queue_size > VIRTQUEUE_MAX_SIZE)
abort();
vdev->vq[i].vring.num = queue_size;
@@ -828,7 +841,7 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
void virtio_del_queue(VirtIODevice *vdev, int n)
{
- if (n < 0 || n >= VIRTIO_PCI_QUEUE_MAX) {
+ if (n < 0 || n >= VIRTIO_QUEUE_MAX) {
abort();
}
@@ -893,6 +906,13 @@ static bool virtio_device_endian_needed(void *opaque)
return vdev->device_endian != virtio_default_endian();
}
+static bool virtio_64bit_features_needed(void *opaque)
+{
+ VirtIODevice *vdev = opaque;
+
+ return (vdev->host_features >> 32) != 0;
+}
+
static const VMStateDescription vmstate_virtio_device_endian = {
.name = "virtio/device_endian",
.version_id = 1,
@@ -903,6 +923,16 @@ static const VMStateDescription vmstate_virtio_device_endian = {
}
};
+static const VMStateDescription vmstate_virtio_64bit_features = {
+ .name = "virtio/64bit_features",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64(guest_features, VirtIODevice),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_virtio = {
.name = "virtio",
.version_id = 1,
@@ -916,6 +946,10 @@ static const VMStateDescription vmstate_virtio = {
.vmsd = &vmstate_virtio_device_endian,
.needed = &virtio_device_endian_needed
},
+ {
+ .vmsd = &vmstate_virtio_64bit_features,
+ .needed = &virtio_64bit_features_needed
+ },
{ 0 }
}
};
@@ -925,6 +959,7 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f)
BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
+ uint32_t guest_features_lo = (vdev->guest_features & 0xffffffff);
int i;
if (k->save_config) {
@@ -934,18 +969,18 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f)
qemu_put_8s(f, &vdev->status);
qemu_put_8s(f, &vdev->isr);
qemu_put_be16s(f, &vdev->queue_sel);
- qemu_put_be32s(f, &vdev->guest_features);
+ qemu_put_be32s(f, &guest_features_lo);
qemu_put_be32(f, vdev->config_len);
qemu_put_buffer(f, vdev->config, vdev->config_len);
- for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
+ for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
if (vdev->vq[i].vring.num == 0)
break;
}
qemu_put_be32(f, i);
- for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
+ for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
if (vdev->vq[i].vring.num == 0)
break;
@@ -970,13 +1005,10 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f)
int virtio_set_features(VirtIODevice *vdev, uint32_t val)
{
- BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
- VirtioBusClass *vbusk = VIRTIO_BUS_GET_CLASS(qbus);
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- uint32_t supported_features = vbusk->get_features(qbus->parent);
- bool bad = (val & ~supported_features) != 0;
+ bool bad = (val & ~(vdev->host_features)) != 0;
- val &= supported_features;
+ val &= vdev->host_features;
if (k->set_features) {
k->set_features(vdev, val);
}
@@ -990,7 +1022,6 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
int32_t config_len;
uint32_t num;
uint32_t features;
- uint32_t supported_features;
BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
@@ -1010,17 +1041,11 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
qemu_get_8s(f, &vdev->status);
qemu_get_8s(f, &vdev->isr);
qemu_get_be16s(f, &vdev->queue_sel);
- if (vdev->queue_sel >= VIRTIO_PCI_QUEUE_MAX) {
+ if (vdev->queue_sel >= VIRTIO_QUEUE_MAX) {
return -1;
}
qemu_get_be32s(f, &features);
- if (virtio_set_features(vdev, features) < 0) {
- supported_features = k->get_features(qbus->parent);
- error_report("Features 0x%x unsupported. Allowed features: 0x%x",
- features, supported_features);
- return -1;
- }
config_len = qemu_get_be32(f);
/*
@@ -1037,7 +1062,7 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
num = qemu_get_be32(f);
- if (num > VIRTIO_PCI_QUEUE_MAX) {
+ if (num > VIRTIO_QUEUE_MAX) {
error_report("Invalid number of PCI queues: 0x%x", num);
return -1;
}
@@ -1086,6 +1111,28 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
vdev->device_endian = virtio_default_endian();
}
+ if (virtio_64bit_features_needed(vdev)) {
+ /*
+ * Subsection load filled vdev->guest_features. Run them
+ * through virtio_set_features to sanity-check them against
+ * host_features.
+ */
+ uint64_t features64 = vdev->guest_features;
+ if (virtio_set_features(vdev, features64) < 0) {
+ error_report("Features 0x%" PRIx64 " unsupported. "
+ "Allowed features: 0x%" PRIx64,
+ features64, vdev->host_features);
+ return -1;
+ }
+ } else {
+ if (virtio_set_features(vdev, features) < 0) {
+ error_report("Features 0x%x unsupported. "
+ "Allowed features: 0x%" PRIx64,
+ features, vdev->host_features);
+ return -1;
+ }
+ }
+
for (i = 0; i < num; i++) {
if (vdev->vq[i].pa) {
uint16_t nheads;
@@ -1163,9 +1210,9 @@ void virtio_init(VirtIODevice *vdev, const char *name,
vdev->isr = 0;
vdev->queue_sel = 0;
vdev->config_vector = VIRTIO_NO_VECTOR;
- vdev->vq = g_malloc0(sizeof(VirtQueue) * VIRTIO_PCI_QUEUE_MAX);
+ vdev->vq = g_malloc0(sizeof(VirtQueue) * VIRTIO_QUEUE_MAX);
vdev->vm_running = runstate_is_running();
- for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
+ for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
vdev->vq[i].vector = VIRTIO_NO_VECTOR;
vdev->vq[i].vdev = vdev;
vdev->vq[i].queue_index = i;
@@ -1328,7 +1375,12 @@ static void virtio_device_realize(DeviceState *dev, Error **errp)
return;
}
}
- virtio_bus_device_plugged(vdev);
+
+ virtio_bus_device_plugged(vdev, &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
}
static void virtio_device_unrealize(DeviceState *dev, Error **errp)
@@ -1351,6 +1403,11 @@ static void virtio_device_unrealize(DeviceState *dev, Error **errp)
vdev->bus_name = NULL;
}
+static Property virtio_properties[] = {
+ DEFINE_VIRTIO_COMMON_FEATURES(VirtIODevice, host_features),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static void virtio_device_class_init(ObjectClass *klass, void *data)
{
/* Set the default value here. */
@@ -1359,6 +1416,7 @@ static void virtio_device_class_init(ObjectClass *klass, void *data)
dc->realize = virtio_device_realize;
dc->unrealize = virtio_device_unrealize;
dc->bus_type = TYPE_VIRTIO_BUS;
+ dc->props = virtio_properties;
}
static const TypeInfo virtio_device_info = {
diff --git a/include/exec/memattrs.h b/include/exec/memattrs.h
index 1389b4b01d..96dc440423 100644
--- a/include/exec/memattrs.h
+++ b/include/exec/memattrs.h
@@ -33,6 +33,8 @@ typedef struct MemTxAttrs {
unsigned int secure:1;
/* Memory access is usermode (unprivileged) */
unsigned int user:1;
+ /* Stream ID (for MSI for example) */
+ unsigned int stream_id:16;
} MemTxAttrs;
/* Bus masters which don't specify any attributes will get this,
diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h
index f503ec4a97..59cf277434 100644
--- a/include/hw/acpi/acpi-defs.h
+++ b/include/hw/acpi/acpi-defs.h
@@ -450,6 +450,9 @@ typedef struct AcpiTableMcfg AcpiTableMcfg;
/*
* TCPA Description Table
+ *
+ * Following Level 00, Rev 00.37 of specs:
+ * http://www.trustedcomputinggroup.org/resources/tcg_acpi_specification
*/
struct Acpi20Tcpa {
ACPI_TABLE_HEADER_DEF /* ACPI common table header */
@@ -459,6 +462,21 @@ struct Acpi20Tcpa {
} QEMU_PACKED;
typedef struct Acpi20Tcpa Acpi20Tcpa;
+/*
+ * TPM2
+ *
+ * Following Level 00, Rev 00.37 of specs:
+ * http://www.trustedcomputinggroup.org/resources/tcg_acpi_specification
+ */
+struct Acpi20TPM2 {
+ ACPI_TABLE_HEADER_DEF
+ uint16_t platform_class;
+ uint16_t reserved;
+ uint64_t control_area_address;
+ uint32_t start_method;
+} QEMU_PACKED;
+typedef struct Acpi20TPM2 Acpi20TPM2;
+
/* DMAR - DMA Remapping table r2.2 */
struct AcpiTableDmar {
ACPI_TABLE_HEADER_DEF
diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
index 9773bfd06b..e3afa13678 100644
--- a/include/hw/acpi/aml-build.h
+++ b/include/hw/acpi/aml-build.h
@@ -202,6 +202,12 @@ Aml *aml_arg(int pos);
Aml *aml_store(Aml *val, Aml *target);
Aml *aml_and(Aml *arg1, Aml *arg2);
Aml *aml_or(Aml *arg1, Aml *arg2);
+Aml *aml_shiftleft(Aml *arg1, Aml *count);
+Aml *aml_shiftright(Aml *arg1, Aml *count);
+Aml *aml_lless(Aml *arg1, Aml *arg2);
+Aml *aml_add(Aml *arg1, Aml *arg2);
+Aml *aml_increment(Aml *arg);
+Aml *aml_index(Aml *arg1, Aml *idx);
Aml *aml_notify(Aml *arg1, Aml *arg2);
Aml *aml_call1(const char *method, Aml *arg1);
Aml *aml_call2(const char *method, Aml *arg1, Aml *arg2);
@@ -260,6 +266,7 @@ Aml *aml_device(const char *name_format, ...) GCC_FMT_ATTR(1, 2);
Aml *aml_method(const char *name, int arg_count);
Aml *aml_if(Aml *predicate);
Aml *aml_else(void);
+Aml *aml_while(Aml *predicate);
Aml *aml_package(uint8_t num_elements);
Aml *aml_buffer(int buffer_size, uint8_t *byte_list);
Aml *aml_resource_template(void);
diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
index 792fcbf5b1..6d516c6a7f 100644
--- a/include/hw/acpi/tpm.h
+++ b/include/hw/acpi/tpm.h
@@ -26,4 +26,9 @@
#define TPM_TCPA_ACPI_CLASS_CLIENT 0
#define TPM_TCPA_ACPI_CLASS_SERVER 1
+#define TPM2_ACPI_CLASS_CLIENT 0
+#define TPM2_ACPI_CLASS_SERVER 1
+
+#define TPM2_START_METHOD_MMIO 6
+
#endif /* HW_ACPI_TPM_H */
diff --git a/include/hw/boards.h b/include/hw/boards.h
index 1f118811a2..ff79797ce4 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -19,31 +19,18 @@ typedef void QEMUMachineHotAddCPUFunc(const int64_t id, Error **errp);
typedef int QEMUMachineGetKvmtypeFunc(const char *arg);
struct QEMUMachine {
- const char *family; /* NULL iff @name identifies a standalone machtype */
const char *name;
- const char *alias;
const char *desc;
QEMUMachineInitFunc *init;
- QEMUMachineResetFunc *reset;
- QEMUMachineHotAddCPUFunc *hot_add_cpu;
QEMUMachineGetKvmtypeFunc *kvm_type;
BlockInterfaceType block_default_type;
- int units_per_default_bus;
int max_cpus;
- unsigned int no_serial:1,
- no_parallel:1,
- use_virtcon:1,
- use_sclp:1,
- no_floppy:1,
- no_cdrom:1,
+ unsigned int
no_sdcard:1,
has_dynamic_sysbus:1;
int is_default;
const char *default_machine_opts;
const char *default_boot_order;
- const char *default_display;
- GlobalProperty *compat_props;
- const char *hw_version;
};
void memory_region_allocate_system_memory(MemoryRegion *mr, Object *owner,
diff --git a/include/hw/compat.h b/include/hw/compat.h
index 313682a708..4a43466f03 100644
--- a/include/hw/compat.h
+++ b/include/hw/compat.h
@@ -1,6 +1,12 @@
#ifndef HW_COMPAT_H
#define HW_COMPAT_H
+#define HW_COMPAT_2_3 \
+ /* empty */
+
+#define HW_COMPAT_2_2 \
+ /* empty */
+
#define HW_COMPAT_2_1 \
{\
.driver = "intel-hda",\
@@ -30,6 +36,6 @@
.driver = "virtio-pci",\
.property = "virtio-pci-bus-master-bug-migration",\
.value = "on",\
- }
+ },
#endif /* HW_COMPAT_H */
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 1b35168e96..27bd748eab 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -73,8 +73,6 @@ typedef struct PCMachineClass PCMachineClass;
#define PC_MACHINE_CLASS(klass) \
OBJECT_CLASS_CHECK(PCMachineClass, (klass), TYPE_PC_MACHINE)
-void qemu_register_pc_machine(QEMUMachine *m);
-
/* PC-style peripherals (also used by other machines). */
typedef struct PcPciInfo {
@@ -199,6 +197,7 @@ qemu_irq *pc_allocate_cpu_irq(void);
DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus);
void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
ISADevice **rtc_state,
+ bool create_fdctrl,
ISADevice **floppy,
bool no_vmport,
uint32 hpet_irqs);
@@ -295,8 +294,19 @@ int e820_add_entry(uint64_t, uint64_t, uint32_t);
int e820_get_num_entries(void);
bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
+#define PC_COMPAT_2_3 \
+ HW_COMPAT_2_3
+
+#define PC_COMPAT_2_2 \
+ PC_COMPAT_2_3 \
+ HW_COMPAT_2_2
+
+#define PC_COMPAT_2_1 \
+ PC_COMPAT_2_2 \
+ HW_COMPAT_2_1
+
#define PC_COMPAT_2_0 \
- HW_COMPAT_2_1, \
+ PC_COMPAT_2_1 \
{\
.driver = "virtio-scsi-pci",\
.property = "any_layout",\
@@ -353,10 +363,10 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
.driver = "ioh3420",\
.property = COMPAT_PROP_PCP,\
.value = "off",\
- }
+ },
#define PC_COMPAT_1_7 \
- PC_COMPAT_2_0, \
+ PC_COMPAT_2_0 \
{\
.driver = TYPE_USB_DEVICE,\
.property = "msos-desc",\
@@ -371,10 +381,10 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
.driver = "hpet",\
.property = HPET_INTCAP,\
.value = stringify(4),\
- }
+ },
#define PC_COMPAT_1_6 \
- PC_COMPAT_1_7, \
+ PC_COMPAT_1_7 \
{\
.driver = "e1000",\
.property = "mitigation",\
@@ -395,10 +405,10 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
.driver = "q35-pcihost",\
.property = "short_root_bus",\
.value = stringify(1),\
- }
+ },
#define PC_COMPAT_1_5 \
- PC_COMPAT_1_6, \
+ PC_COMPAT_1_6 \
{\
.driver = "Conroe-" TYPE_X86_CPU,\
.property = "model",\
@@ -439,31 +449,31 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
.driver = "q35-pcihost",\
.property = "short_root_bus",\
.value = stringify(0),\
- }
+ },
#define PC_COMPAT_1_4 \
- PC_COMPAT_1_5, \
+ PC_COMPAT_1_5 \
{\
.driver = "scsi-hd",\
.property = "discard_granularity",\
.value = stringify(0),\
- },{\
+ },{\
.driver = "scsi-cd",\
.property = "discard_granularity",\
.value = stringify(0),\
- },{\
+ },{\
.driver = "scsi-disk",\
.property = "discard_granularity",\
.value = stringify(0),\
- },{\
+ },{\
.driver = "ide-hd",\
.property = "discard_granularity",\
.value = stringify(0),\
- },{\
+ },{\
.driver = "ide-cd",\
.property = "discard_granularity",\
.value = stringify(0),\
- },{\
+ },{\
.driver = "ide-drive",\
.property = "discard_granularity",\
.value = stringify(0),\
@@ -471,7 +481,7 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
.driver = "virtio-blk-pci",\
.property = "discard_granularity",\
.value = stringify(0),\
- },{\
+ },{\
.driver = "virtio-serial-pci",\
.property = "vectors",\
/* DEV_NVECTORS_UNSPECIFIED as a uint32_t string */\
@@ -504,14 +514,45 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
.driver = "486-" TYPE_X86_CPU,\
.property = "model",\
.value = stringify(0),\
- }
+ },
-#define PC_COMMON_MACHINE_OPTIONS \
- .default_boot_order = "cad"
+static inline void pc_common_machine_options(MachineClass *m)
+{
+ m->default_boot_order = "cad";
+}
+
+static inline void pc_default_machine_options(MachineClass *m)
+{
+ pc_common_machine_options(m);
+ m->hot_add_cpu = pc_hot_add_cpu;
+ m->max_cpus = 255;
+}
-#define PC_DEFAULT_MACHINE_OPTIONS \
- PC_COMMON_MACHINE_OPTIONS, \
- .hot_add_cpu = pc_hot_add_cpu, \
- .max_cpus = 255
+#define DEFINE_PC_MACHINE(suffix, namestr, initfn, optsfn) \
+ static void pc_machine_##suffix##_class_init(ObjectClass *oc, void *data) \
+ { \
+ MachineClass *mc = MACHINE_CLASS(oc); \
+ optsfn(mc); \
+ mc->name = namestr; \
+ mc->init = initfn; \
+ } \
+ static const TypeInfo pc_machine_type_##suffix = { \
+ .name = namestr TYPE_MACHINE_SUFFIX, \
+ .parent = TYPE_PC_MACHINE, \
+ .class_init = pc_machine_##suffix##_class_init, \
+ }; \
+ static void pc_machine_init_##suffix(void) \
+ { \
+ type_register(&pc_machine_type_##suffix); \
+ } \
+ machine_init(pc_machine_init_##suffix)
+
+#define SET_MACHINE_COMPAT(m, COMPAT) do { \
+ static GlobalProperty props[] = { \
+ COMPAT \
+ { /* end of list */ } \
+ }; \
+ (m)->compat_props = props; \
+} while (0)
#endif
diff --git a/include/hw/pci/msi.h b/include/hw/pci/msi.h
index 81a3848a31..50e452bd05 100644
--- a/include/hw/pci/msi.h
+++ b/include/hw/pci/msi.h
@@ -39,6 +39,7 @@ int msi_init(struct PCIDevice *dev, uint8_t offset,
void msi_uninit(struct PCIDevice *dev);
void msi_reset(PCIDevice *dev);
void msi_notify(PCIDevice *dev, unsigned int vector);
+void msi_send_message(PCIDevice *dev, MSIMessage msg);
void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len);
unsigned int msi_nr_vectors_allocated(const PCIDevice *dev);
diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
index d67dad5f77..0cfff1c77c 100644
--- a/include/hw/qdev-properties.h
+++ b/include/hw/qdev-properties.h
@@ -6,6 +6,7 @@
/*** qdev-properties.c ***/
extern PropertyInfo qdev_prop_bit;
+extern PropertyInfo qdev_prop_bit64;
extern PropertyInfo qdev_prop_bool;
extern PropertyInfo qdev_prop_uint8;
extern PropertyInfo qdev_prop_uint16;
@@ -50,6 +51,15 @@ extern PropertyInfo qdev_prop_arraylen;
.qtype = QTYPE_QBOOL, \
.defval = (bool)_defval, \
}
+#define DEFINE_PROP_BIT64(_name, _state, _field, _bit, _defval) { \
+ .name = (_name), \
+ .info = &(qdev_prop_bit), \
+ .bitnr = (_bit), \
+ .offset = offsetof(_state, _field) \
+ + type_check(uint64_t, typeof_field(_state, _field)), \
+ .qtype = QTYPE_QBOOL, \
+ .defval = (bool)_defval, \
+ }
#define DEFINE_PROP_BOOL(_name, _state, _field, _defval) { \
.name = (_name), \
diff --git a/include/hw/s390x/s390_flic.h b/include/hw/s390x/s390_flic.h
index 489d73b9b3..200e7e93fa 100644
--- a/include/hw/s390x/s390_flic.h
+++ b/include/hw/s390x/s390_flic.h
@@ -17,10 +17,13 @@
#include "hw/s390x/adapter.h"
#include "hw/virtio/virtio.h"
+#define ADAPTER_ROUTES_MAX_GSI 64
+#define VIRTIO_CCW_QUEUE_MAX ADAPTER_ROUTES_MAX_GSI
+
typedef struct AdapterRoutes {
AdapterInfo adapter;
int num_routes;
- int gsi[VIRTIO_PCI_QUEUE_MAX];
+ int gsi[ADAPTER_ROUTES_MAX_GSI];
} AdapterRoutes;
#define TYPE_S390_FLIC_COMMON "s390-flic"
diff --git a/include/hw/virtio/virtio-bus.h b/include/hw/virtio/virtio-bus.h
index a4588ca4d9..8811415fa6 100644
--- a/include/hw/virtio/virtio-bus.h
+++ b/include/hw/virtio/virtio-bus.h
@@ -47,7 +47,6 @@ typedef struct VirtioBusClass {
int (*load_config)(DeviceState *d, QEMUFile *f);
int (*load_queue)(DeviceState *d, int n, QEMUFile *f);
int (*load_done)(DeviceState *d, QEMUFile *f);
- unsigned (*get_features)(DeviceState *d);
bool (*query_guest_notifiers)(DeviceState *d);
int (*set_guest_notifiers)(DeviceState *d, int nvqs, bool assign);
int (*set_host_notifier)(DeviceState *d, int n, bool assigned);
@@ -56,7 +55,7 @@ typedef struct VirtioBusClass {
* transport independent init function.
* This is called by virtio-bus just after the device is plugged.
*/
- void (*device_plugged)(DeviceState *d);
+ void (*device_plugged)(DeviceState *d, Error **errp);
/*
* transport independent exit function.
* This is called by virtio-bus just before the device is unplugged.
@@ -75,7 +74,7 @@ struct VirtioBusState {
BusState parent_obj;
};
-int virtio_bus_device_plugged(VirtIODevice *vdev);
+void virtio_bus_device_plugged(VirtIODevice *vdev, Error **errp);
void virtio_bus_reset(VirtioBusState *bus);
void virtio_bus_device_unplugged(VirtIODevice *bus);
/* Get the device id of the plugged device. */
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index ba74765d0b..7222a904dc 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -48,7 +48,7 @@ typedef struct VirtQueueElement
struct iovec out_sg[VIRTQUEUE_MAX_SIZE];
} VirtQueueElement;
-#define VIRTIO_PCI_QUEUE_MAX 64
+#define VIRTIO_QUEUE_MAX 1024
#define VIRTIO_NO_VECTOR 0xffff
@@ -73,7 +73,8 @@ struct VirtIODevice
uint8_t status;
uint8_t isr;
uint16_t queue_sel;
- uint32_t guest_features;
+ uint64_t guest_features;
+ uint64_t host_features;
size_t config_len;
void *config;
uint16_t config_vector;
@@ -95,8 +96,8 @@ typedef struct VirtioDeviceClass {
/* This is what a VirtioDevice must implement */
DeviceRealize realize;
DeviceUnrealize unrealize;
- uint32_t (*get_features)(VirtIODevice *vdev, uint32_t requested_features);
- uint32_t (*bad_features)(VirtIODevice *vdev);
+ uint64_t (*get_features)(VirtIODevice *vdev, uint64_t requested_features);
+ uint64_t (*bad_features)(VirtIODevice *vdev);
void (*set_features)(VirtIODevice *vdev, uint32_t val);
void (*get_config)(VirtIODevice *vdev, uint8_t *config);
void (*set_config)(VirtIODevice *vdev, const uint8_t *config);
@@ -175,6 +176,7 @@ void virtio_queue_set_addr(VirtIODevice *vdev, int n, hwaddr addr);
hwaddr virtio_queue_get_addr(VirtIODevice *vdev, int n);
void virtio_queue_set_num(VirtIODevice *vdev, int n, int num);
int virtio_queue_get_num(VirtIODevice *vdev, int n);
+int virtio_get_num_queues(VirtIODevice *vdev);
void virtio_queue_set_align(VirtIODevice *vdev, int n, int align);
void virtio_queue_notify(VirtIODevice *vdev, int n);
uint16_t virtio_queue_vector(VirtIODevice *vdev, int n);
@@ -193,10 +195,12 @@ typedef struct VirtIOSCSIConf VirtIOSCSIConf;
typedef struct VirtIORNGConf VirtIORNGConf;
#define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \
- DEFINE_PROP_BIT("indirect_desc", _state, _field, \
- VIRTIO_RING_F_INDIRECT_DESC, true), \
- DEFINE_PROP_BIT("event_idx", _state, _field, \
- VIRTIO_RING_F_EVENT_IDX, true)
+ DEFINE_PROP_BIT64("indirect_desc", _state, _field, \
+ VIRTIO_RING_F_INDIRECT_DESC, true), \
+ DEFINE_PROP_BIT64("event_idx", _state, _field, \
+ VIRTIO_RING_F_EVENT_IDX, true), \
+ DEFINE_PROP_BIT64("notify_on_empty", _state, _field, \
+ VIRTIO_F_NOTIFY_ON_EMPTY, true)
hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n);
hwaddr virtio_queue_get_avail_addr(VirtIODevice *vdev, int n);
@@ -223,21 +227,21 @@ void virtio_irq(VirtQueue *vq);
VirtQueue *virtio_vector_first_queue(VirtIODevice *vdev, uint16_t vector);
VirtQueue *virtio_vector_next_queue(VirtQueue *vq);
-static inline void virtio_add_feature(uint32_t *features, unsigned int fbit)
+static inline void virtio_add_feature(uint64_t *features, unsigned int fbit)
{
- assert(fbit < 32);
+ assert(fbit < 64);
*features |= (1 << fbit);
}
-static inline void virtio_clear_feature(uint32_t *features, unsigned int fbit)
+static inline void virtio_clear_feature(uint64_t *features, unsigned int fbit)
{
- assert(fbit < 32);
+ assert(fbit < 64);
*features &= ~(1 << fbit);
}
-static inline bool __virtio_has_feature(uint32_t features, unsigned int fbit)
+static inline bool __virtio_has_feature(uint64_t features, unsigned int fbit)
{
- assert(fbit < 32);
+ assert(fbit < 64);
return !!(features & (1 << fbit));
}
diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h
index 9b81ce9189..c1438907de 100644
--- a/include/sysemu/tpm.h
+++ b/include/sysemu/tpm.h
@@ -20,11 +20,24 @@ int tpm_config_parse(QemuOptsList *opts_list, const char *optarg);
int tpm_init(void);
void tpm_cleanup(void);
+typedef enum TPMVersion {
+ TPM_VERSION_UNSPEC = 0,
+ TPM_VERSION_1_2 = 1,
+ TPM_VERSION_2_0 = 2,
+} TPMVersion;
+
+TPMVersion tpm_tis_get_tpm_version(Object *obj);
+
#define TYPE_TPM_TIS "tpm-tis"
-static inline bool tpm_find(void)
+static inline TPMVersion tpm_get_version(void)
{
- return object_resolve_path_type("", TYPE_TPM_TIS, NULL);
+ Object *obj = object_resolve_path_type("", TYPE_TPM_TIS, NULL);
+
+ if (obj) {
+ return tpm_tis_get_tpm_version(obj);
+ }
+ return TPM_VERSION_UNSPEC;
}
#endif /* QEMU_TPM_H */
diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h
index 540ee25477..0a366be0f2 100644
--- a/include/sysemu/tpm_backend.h
+++ b/include/sysemu/tpm_backend.h
@@ -88,6 +88,10 @@ struct TPMDriverOps {
void (*cancel_cmd)(TPMBackend *t);
bool (*get_tpm_established_flag)(TPMBackend *t);
+
+ int (*reset_tpm_established_flag)(TPMBackend *t, uint8_t locty);
+
+ TPMVersion (*get_tpm_version)(TPMBackend *t);
};
@@ -192,6 +196,15 @@ void tpm_backend_cancel_cmd(TPMBackend *s);
bool tpm_backend_get_tpm_established_flag(TPMBackend *s);
/**
+ * tpm_backend_reset_tpm_established_flag:
+ * @s: the backend
+ * @locty: the locality number
+ *
+ * Reset the TPM establishment flag.
+ */
+int tpm_backend_reset_tpm_established_flag(TPMBackend *s, uint8_t locty);
+
+/**
* tpm_backend_open:
* @s: the backend to open
* @errp: a pointer to return the #Error object if an error occurs.
@@ -201,6 +214,16 @@ bool tpm_backend_get_tpm_established_flag(TPMBackend *s);
*/
void tpm_backend_open(TPMBackend *s, Error **errp);
+/**
+ * tpm_backend_get_tpm_version:
+ * @s: the backend to call into
+ *
+ * Get the TPM Version that is emulated at the backend.
+ *
+ * Returns TPMVersion.
+ */
+TPMVersion tpm_backend_get_tpm_version(TPMBackend *s);
+
TPMBackend *qemu_find_tpm(const char *id);
const TPMDriverOps *tpm_get_backend_driver(const char *type);
diff --git a/net/vhost-user.c b/net/vhost-user.c
index 11899c53c0..8d2672846f 100644
--- a/net/vhost-user.c
+++ b/net/vhost-user.c
@@ -121,35 +121,39 @@ static void net_vhost_user_event(void *opaque, int event)
case CHR_EVENT_OPENED:
vhost_user_start(s);
net_vhost_link_down(s, false);
- error_report("chardev \"%s\" went up", s->chr->label);
+ error_report("chardev \"%s\" went up", s->nc.info_str);
break;
case CHR_EVENT_CLOSED:
net_vhost_link_down(s, true);
vhost_user_stop(s);
- error_report("chardev \"%s\" went down", s->chr->label);
+ error_report("chardev \"%s\" went down", s->nc.info_str);
break;
}
}
static int net_vhost_user_init(NetClientState *peer, const char *device,
- const char *name, CharDriverState *chr)
+ const char *name, CharDriverState *chr,
+ uint32_t queues)
{
NetClientState *nc;
VhostUserState *s;
+ int i;
- nc = qemu_new_net_client(&net_vhost_user_info, peer, device, name);
+ for (i = 0; i < queues; i++) {
+ nc = qemu_new_net_client(&net_vhost_user_info, peer, device, name);
- snprintf(nc->info_str, sizeof(nc->info_str), "vhost-user to %s",
- chr->label);
+ snprintf(nc->info_str, sizeof(nc->info_str), "vhost-user%d to %s",
+ i, chr->label);
- s = DO_UPCAST(VhostUserState, nc, nc);
+ s = DO_UPCAST(VhostUserState, nc, nc);
- /* We don't provide a receive callback */
- s->nc.receive_disabled = 1;
- s->chr = chr;
-
- qemu_chr_add_handlers(s->chr, NULL, NULL, net_vhost_user_event, s);
+ /* We don't provide a receive callback */
+ s->nc.receive_disabled = 1;
+ s->chr = chr;
+ s->nc.queue_index = i;
+ qemu_chr_add_handlers(s->chr, NULL, NULL, net_vhost_user_event, s);
+ }
return 0;
}
@@ -226,6 +230,7 @@ int net_init_vhost_user(const NetClientOptions *opts, const char *name,
NetClientState *peer, Error **errp)
{
/* FIXME error_setg(errp, ...) on failure */
+ uint32_t queues;
const NetdevVhostUserOptions *vhost_user_opts;
CharDriverState *chr;
@@ -244,6 +249,12 @@ int net_init_vhost_user(const NetClientOptions *opts, const char *name,
return -1;
}
+ /* number of queues for multiqueue */
+ if (vhost_user_opts->has_queues) {
+ queues = vhost_user_opts->queues;
+ } else {
+ queues = 1;
+ }
- return net_vhost_user_init(peer, "vhost_user", name, chr);
+ return net_vhost_user_init(peer, "vhost_user", name, chr, queues);
}
diff --git a/qapi-schema.json b/qapi-schema.json
index 25df463863..0662a9b445 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2444,12 +2444,16 @@
#
# @vhostforce: #optional vhost on for non-MSIX virtio guests (default: false).
#
+# @queues: #optional number of queues to be created for multiqueue vhost-user
+# (default: 1) (Since 2.4)
+#
# Since 2.1
##
{ 'struct': 'NetdevVhostUserOptions',
'data': {
'chardev': 'str',
- '*vhostforce': 'bool' } }
+ '*vhostforce': 'bool',
+ '*queues': 'uint32' } }
##
# @NetClientOptions
diff --git a/qemu-options.hx b/qemu-options.hx
index dad49cf06a..7edd1f18ce 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1955,13 +1955,14 @@ The hubport netdev lets you connect a NIC to a QEMU "vlan" instead of a single
netdev. @code{-net} and @code{-device} with parameter @option{vlan} create the
required hub automatically.
-@item -netdev vhost-user,chardev=@var{id}[,vhostforce=on|off]
+@item -netdev vhost-user,chardev=@var{id}[,vhostforce=on|off][,queues=n]
Establish a vhost-user netdev, backed by a chardev @var{id}. The chardev should
be a unix domain socket backed one. The vhost-user uses a specifically defined
protocol to pass vhost ioctl replacement messages to an application on the other
end of the socket. On non-MSIX guests, the feature can be forced with
-@var{vhostforce}.
+@var{vhostforce}. Use 'queues=@var{n}' to specify the number of queues to
+be created for multiqueue vhost-user.
Example:
@example
diff --git a/vl.c b/vl.c
index 26b1e7e28c..1d4c0890f2 100644
--- a/vl.c
+++ b/vl.c
@@ -1314,32 +1314,17 @@ static void machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
QEMUMachine *qm = data;
-
- mc->family = qm->family;
mc->name = qm->name;
- mc->alias = qm->alias;
mc->desc = qm->desc;
mc->init = qm->init;
- mc->reset = qm->reset;
- mc->hot_add_cpu = qm->hot_add_cpu;
mc->kvm_type = qm->kvm_type;
mc->block_default_type = qm->block_default_type;
- mc->units_per_default_bus = qm->units_per_default_bus;
mc->max_cpus = qm->max_cpus;
- mc->no_serial = qm->no_serial;
- mc->no_parallel = qm->no_parallel;
- mc->use_virtcon = qm->use_virtcon;
- mc->use_sclp = qm->use_sclp;
- mc->no_floppy = qm->no_floppy;
- mc->no_cdrom = qm->no_cdrom;
mc->no_sdcard = qm->no_sdcard;
mc->has_dynamic_sysbus = qm->has_dynamic_sysbus;
mc->is_default = qm->is_default;
mc->default_machine_opts = qm->default_machine_opts;
mc->default_boot_order = qm->default_boot_order;
- mc->default_display = qm->default_display;
- mc->compat_props = qm->compat_props;
- mc->hw_version = qm->hw_version;
}
int qemu_register_machine(QEMUMachine *m)