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>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABAgAGBQJVbE3kAAoJECgfDbjSjVRphV4H/jEnq16oMP72H6xgbAIKjvrP
 uEx4jgkj9qGfgqLQJURPKemgzNbP+dXjd4LkIdgbUvlknCgFeKyJVPxzCCIhjc7R
 5D70Aptg1CdVNaMeqsIOyJIYe0hIXQjbF7a/jtxf8nR9+kLIOpcQ200oRJtxpGVu
 VfzWnBj48PRXi/W03OinWYrkqeAqx0BNHRxXQ5Ylr/DxTBoJKmmp13wW/5U+Xtmi
 g5hDS5IF/qqrIKftisR7sDEfXENJf3ZulqP/2N8Lvufyj1lQxGkEGTKD5FDzeaj6
 X0/UvUv7I2OzCbcTyeCwzF1GfZOgGceiXxopEp359SkvyoJILF7/C0Na5LY/fiw=
 =fckd
 -----END PGP SIGNATURE-----

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>
This commit is contained in:
Peter Maydell 2015-06-01 15:22:46 +01:00
commit b821cbe274
62 changed files with 1642 additions and 1064 deletions

View File

@ -96,6 +96,20 @@ bool tpm_backend_get_tpm_established_flag(TPMBackend *s)
return k->ops->get_tpm_established_flag(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) static bool tpm_backend_prop_get_opened(Object *obj, Error **errp)
{ {
TPMBackend *s = TPM_BACKEND(obj); TPMBackend *s = TPM_BACKEND(obj);

View File

@ -127,6 +127,11 @@ in the ancillary data:
If Master is unable to send the full message or receives a wrong reply it will 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. 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 Message types
------------- -------------

View File

@ -21,7 +21,7 @@
#include "virtio-9p-coth.h" #include "virtio-9p-coth.h"
#include "hw/virtio/virtio-access.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); virtio_add_feature(&features, VIRTIO_9P_MOUNT_TAG);
return features; return features;

View File

@ -19,6 +19,7 @@
* with this program; if not, see <http://www.gnu.org/licenses/>. * with this program; if not, see <http://www.gnu.org/licenses/>.
*/ */
#include <glib/gprintf.h>
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include <assert.h> #include <assert.h>
@ -59,7 +60,6 @@ static void build_append_array(GArray *array, GArray *val)
static void static void
build_append_nameseg(GArray *array, const char *seg) 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; int len;
len = strlen(seg); len = strlen(seg);
@ -73,22 +73,12 @@ build_append_nameseg(GArray *array, const char *seg)
static void GCC_FMT_ATTR(2, 0) static void GCC_FMT_ATTR(2, 0)
build_append_namestringv(GArray *array, const char *format, va_list ap) 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; char *s;
int len;
va_list va_len;
char **segs; char **segs;
char **segs_iter; char **segs_iter;
int seg_count = 0; int seg_count = 0;
va_copy(va_len, ap); s = g_strdup_vprintf(format, 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);
segs = g_strsplit(s, ".", 0); segs = g_strsplit(s, ".", 0);
g_free(s); g_free(s);
@ -306,6 +296,7 @@ static void aml_free(gpointer data, gpointer user_data)
{ {
Aml *var = data; Aml *var = data;
build_free_array(var->buf); build_free_array(var->buf);
g_free(var);
} }
Aml *init_aml_allocator(void) Aml *init_aml_allocator(void)
@ -465,6 +456,63 @@ Aml *aml_or(Aml *arg1, Aml *arg2)
return var; 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 */ /* ACPI 1.0b: 16.2.5.3 Type 1 Opcodes Encoding: DefNotify */
Aml *aml_notify(Aml *arg1, Aml *arg2) 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 *aml_string(const char *name_format, ...)
{ {
Aml *var = aml_opcode(0x0D /* StringPrefix */); Aml *var = aml_opcode(0x0D /* StringPrefix */);
va_list ap, va_len; va_list ap;
char *s; char *s;
int len; int len;
va_start(ap, name_format); va_start(ap, name_format);
va_copy(va_len, ap); len = g_vasprintf(&s, name_format, 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);
va_end(ap); va_end(ap);
g_array_append_vals(var->buf, s, len); g_array_append_vals(var->buf, s, len + 1);
build_append_byte(var->buf, 0x0); /* NullChar */
g_free(s); g_free(s);
return var; return var;

View File

@ -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)); 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); VirtIOBlock *s = VIRTIO_BLK(vdev);

View File

@ -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; 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 */ /* 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) { if (vser->serial.max_virtserial_ports > max_supported_ports) {
error_setg(errp, "maximum ports supported: %u", max_supported_ports); error_setg(errp, "maximum ports supported: %u", max_supported_ports);

View File

@ -125,6 +125,64 @@ PropertyInfo qdev_prop_bit = {
.set = prop_set_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 --- */ /* --- bool --- */
static void get_bool(Object *obj, Visitor *v, void *opaque, static void get_bool(Object *obj, Visitor *v, void *opaque,

View File

@ -9,7 +9,7 @@ obj-y += kvmvapic.o
obj-y += acpi-build.o obj-y += acpi-build.o
hw/i386/acpi-build.o: hw/i386/acpi-build.c \ hw/i386/acpi-build.o: hw/i386/acpi-build.c \
hw/i386/acpi-dsdt.hex hw/i386/q35-acpi-dsdt.hex \ 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`" \ iasl-option=$(shell if test -z "`$(1) $(2) 2>&1 > /dev/null`" \
; then echo "$(2)"; else echo "$(3)"; fi ;) ; then echo "$(2)"; else echo "$(3)"; fi ;)

View File

@ -41,6 +41,7 @@
#include "hw/acpi/memory_hotplug.h" #include "hw/acpi/memory_hotplug.h"
#include "sysemu/tpm.h" #include "sysemu/tpm.h"
#include "hw/acpi/tpm.h" #include "hw/acpi/tpm.h"
#include "sysemu/tpm_backend.h"
/* Supported chipsets: */ /* Supported chipsets: */
#include "hw/acpi/piix4.h" #include "hw/acpi/piix4.h"
@ -106,7 +107,7 @@ typedef struct AcpiPmInfo {
typedef struct AcpiMiscInfo { typedef struct AcpiMiscInfo {
bool has_hpet; bool has_hpet;
bool has_tpm; TPMVersion tpm_version;
const unsigned char *dsdt_code; const unsigned char *dsdt_code;
unsigned dsdt_size; unsigned dsdt_size;
uint16_t pvpanic_port; uint16_t pvpanic_port;
@ -234,7 +235,7 @@ static void acpi_get_pm_info(AcpiPmInfo *pm)
static void acpi_get_misc_info(AcpiMiscInfo *info) static void acpi_get_misc_info(AcpiMiscInfo *info)
{ {
info->has_hpet = hpet_find(); info->has_hpet = hpet_find();
info->has_tpm = tpm_find(); info->tpm_version = tpm_get_version();
info->pvpanic_port = pvpanic_port(); info->pvpanic_port = pvpanic_port();
info->applesmc_io_base = applesmc_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-tpm.hex"
#include "hw/i386/ssdt-tpm2.hex"
/* Assign BSEL property to all buses. In the future, this can be changed /* Assign BSEL property to all buses. In the future, this can be changed
* to only assign to buses that support hotplug. * to only assign to buses that support hotplug.
@ -733,7 +735,7 @@ build_ssdt(GArray *table_data, GArray *linker,
if (misc->pvpanic_port) { if (misc->pvpanic_port) {
scope = aml_scope("\\_SB.PCI0.ISA"); scope = aml_scope("\\_SB.PCI0.ISA");
dev = aml_device("PEVR"); dev = aml_device("PEVT");
aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0001"))); aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0001")));
crs = aml_resource_template(); 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(field, aml_named_field("PEPT", 8));
aml_append(dev, field); 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); method = aml_method("RDPT", 0);
aml_append(method, aml_store(aml_name("PEPT"), aml_local(0))); aml_append(method, aml_store(aml_name("PEPT"), aml_local(0)));
aml_append(method, aml_return(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)); 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 { typedef enum {
MEM_AFFINITY_NOFLAGS = 0, MEM_AFFINITY_NOFLAGS = 0,
MEM_AFFINITY_ENABLED = (1 << 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); acpi_add_table(table_offsets, tables_blob);
build_hpet(tables_blob, tables->linker); build_hpet(tables_blob, tables->linker);
} }
if (misc.has_tpm) { if (misc.tpm_version != TPM_VERSION_UNSPEC) {
acpi_add_table(table_offsets, tables_blob); acpi_add_table(table_offsets, tables_blob);
build_tpm_tcpa(tables_blob, tables->linker, tables->tcpalog); build_tpm_tcpa(tables_blob, tables->linker, tables->tcpalog);
acpi_add_table(table_offsets, tables_blob); acpi_add_table(table_offsets, tables_blob);
switch (misc.tpm_version) {
case TPM_VERSION_1_2:
build_tpm_ssdt(tables_blob, tables->linker); 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) { if (guest_info->numa_nodes) {
acpi_add_table(table_offsets, tables_blob); acpi_add_table(table_offsets, tables_blob);

View File

@ -1395,6 +1395,7 @@ static const MemoryRegionOps ioportF0_io_ops = {
void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
ISADevice **rtc_state, ISADevice **rtc_state,
bool create_fdctrl,
ISADevice **floppy, ISADevice **floppy,
bool no_vmport, bool no_vmport,
uint32 hpet_irqs) 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++) { for(i = 0; i < MAX_FD; i++) {
fd[i] = drive_get(IF_FLOPPY, 0, 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) 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, static void pc_dimm_plug(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp) DeviceState *dev, Error **errp)
{ {

View File

@ -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_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
static const int ide_irq[MAX_IDE_BUS] = { 14, 15 }; static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
static bool pci_enabled = true;
static bool has_acpi_build = true; static bool has_acpi_build = true;
static bool rsdp_in_ram = true; static bool rsdp_in_ram = true;
static int legacy_acpi_table_size; static int legacy_acpi_table_size;
@ -71,11 +72,10 @@ static bool smbios_uuid_encoded = true;
*/ */
static bool gigabyte_align = true; static bool gigabyte_align = true;
static bool has_reserved_memory = true; static bool has_reserved_memory = true;
static bool kvmclock_enabled = true;
/* PC hardware initialisation */ /* PC hardware initialisation */
static void pc_init1(MachineState *machine, static void pc_init1(MachineState *machine)
int pci_enabled,
int kvmclock_enabled)
{ {
PCMachineState *pc_machine = PC_MACHINE(machine); PCMachineState *pc_machine = PC_MACHINE(machine);
MemoryRegion *system_memory = get_system_memory(); MemoryRegion *system_memory = get_system_memory();
@ -242,7 +242,7 @@ static void pc_init1(MachineState *machine,
} }
/* init basic PC hardware */ /* 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_machine->vmport != ON_OFF_AUTO_ON), 0x4);
pc_nic_init(isa_bus, pci_bus); 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) static void pc_compat_2_3(MachineState *machine)
{ {
} }
@ -418,76 +413,16 @@ static void pc_compat_1_2(MachineState *machine)
x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, 1 << KVM_FEATURE_PV_EOI); 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);
}
static void pc_init_pci_2_2(MachineState *machine)
{
pc_compat_2_2(machine);
pc_init_pci(machine);
}
static void pc_init_pci_2_1(MachineState *machine)
{
pc_compat_2_1(machine);
pc_init_pci(machine);
}
static void pc_init_pci_2_0(MachineState *machine)
{
pc_compat_2_0(machine);
pc_init_pci(machine);
}
static void pc_init_pci_1_7(MachineState *machine)
{
pc_compat_1_7(machine);
pc_init_pci(machine);
}
static void pc_init_pci_1_6(MachineState *machine)
{
pc_compat_1_6(machine);
pc_init_pci(machine);
}
static void pc_init_pci_1_5(MachineState *machine)
{
pc_compat_1_5(machine);
pc_init_pci(machine);
}
static void pc_init_pci_1_4(MachineState *machine)
{
pc_compat_1_4(machine);
pc_init_pci(machine);
}
static void pc_init_pci_1_3(MachineState *machine)
{
pc_compat_1_3(machine);
pc_init_pci(machine);
}
/* PC machine init function for pc-0.14 to pc-1.2 */
static void pc_init_pci_1_2(MachineState *machine)
{ {
pc_compat_1_2(machine); pc_compat_1_2(machine);
pc_init_pci(machine); kvmclock_enabled = false;
}
/* PC init function for pc-0.10 to pc-0.13 */
static void pc_init_pci_no_kvmclock(MachineState *machine)
{
pc_compat_1_2(machine);
pc_init1(machine, 1, 0);
} }
static void pc_init_isa(MachineState *machine) static void pc_init_isa(MachineState *machine)
{ {
pci_enabled = false;
has_acpi_build = false; has_acpi_build = false;
smbios_defaults = false; smbios_defaults = false;
gigabyte_align = false; gigabyte_align = false;
@ -500,7 +435,7 @@ static void pc_init_isa(MachineState *machine)
} }
x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, 1 << KVM_FEATURE_PV_EOI); x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, 1 << KVM_FEATURE_PV_EOI);
enable_compat_apic_id_mode(); enable_compat_apic_id_mode();
pc_init1(machine, 0, 1); pc_init1(machine);
} }
#ifdef CONFIG_XEN #ifdef CONFIG_XEN
@ -508,7 +443,7 @@ static void pc_xen_hvm_init(MachineState *machine)
{ {
PCIBus *bus; PCIBus *bus;
pc_init_pci(machine); pc_init1(machine);
bus = pci_find_primary_bus(); bus = pci_find_primary_bus();
if (bus != NULL) { if (bus != NULL) {
@ -517,118 +452,126 @@ static void pc_xen_hvm_init(MachineState *machine)
} }
#endif #endif
#define PC_I440FX_MACHINE_OPTIONS \ #define DEFINE_I440FX_MACHINE(suffix, name, compatfn, optionfn) \
PC_DEFAULT_MACHINE_OPTIONS, \ static void pc_init_##suffix(MachineState *machine) \
.family = "pc_piix", \ { \
.desc = "Standard PC (i440FX + PIIX, 1996)", \ void (*compat)(MachineState *m) = (compatfn); \
.hot_add_cpu = pc_hot_add_cpu if (compat) { \
compat(machine); \
} \
pc_init1(machine); \
} \
DEFINE_PC_MACHINE(suffix, name, pc_init_##suffix, optionfn)
#define PC_I440FX_2_4_MACHINE_OPTIONS \ static void pc_i440fx_machine_options(MachineClass *m)
PC_I440FX_MACHINE_OPTIONS, \ {
.default_machine_opts = "firmware=bios-256k.bin", \ pc_default_machine_options(m);
.default_display = "std" m->family = "pc_piix";
m->desc = "Standard PC (i440FX + PIIX, 1996)";
m->hot_add_cpu = pc_hot_add_cpu;
}
static void pc_i440fx_2_4_machine_options(MachineClass *m)
{
pc_i440fx_machine_options(m);
m->default_machine_opts = "firmware=bios-256k.bin";
m->default_display = "std";
m->alias = "pc";
m->is_default = 1;
}
DEFINE_I440FX_MACHINE(v2_4, "pc-i440fx-2.4", NULL,
pc_i440fx_2_4_machine_options)
static QEMUMachine pc_i440fx_machine_v2_4 = { static void pc_i440fx_2_3_machine_options(MachineClass *m)
PC_I440FX_2_4_MACHINE_OPTIONS, {
.name = "pc-i440fx-2.4", pc_i440fx_machine_options(m);
.alias = "pc", m->alias = NULL;
.init = pc_init_pci, m->is_default = 0;
.is_default = 1, SET_MACHINE_COMPAT(m, PC_COMPAT_2_3);
}; }
#define PC_I440FX_2_3_MACHINE_OPTIONS PC_I440FX_2_4_MACHINE_OPTIONS DEFINE_I440FX_MACHINE(v2_3, "pc-i440fx-2.3", pc_compat_2_3,
pc_i440fx_2_3_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 void pc_i440fx_2_2_machine_options(MachineClass *m)
{
pc_i440fx_2_3_machine_options(m);
SET_MACHINE_COMPAT(m, PC_COMPAT_2_2);
}
static QEMUMachine pc_i440fx_machine_v2_2 = { DEFINE_I440FX_MACHINE(v2_2, "pc-i440fx-2.2", pc_compat_2_2,
PC_I440FX_2_2_MACHINE_OPTIONS, 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 = { static void pc_i440fx_2_1_machine_options(MachineClass *m)
PC_I440FX_2_1_MACHINE_OPTIONS, {
.name = "pc-i440fx-2.1", pc_i440fx_2_2_machine_options(m);
.init = pc_init_pci_2_1, m->default_display = NULL;
.compat_props = (GlobalProperty[]) { SET_MACHINE_COMPAT(m, PC_COMPAT_2_1);
HW_COMPAT_2_1, }
{ /* end of list */ }
},
};
#define PC_I440FX_2_0_MACHINE_OPTIONS PC_I440FX_2_1_MACHINE_OPTIONS DEFINE_I440FX_MACHINE(v2_1, "pc-i440fx-2.1", pc_compat_2_1,
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 */ }
},
};
#define PC_I440FX_1_7_MACHINE_OPTIONS PC_I440FX_MACHINE_OPTIONS
static QEMUMachine pc_i440fx_machine_v1_7 = { static void pc_i440fx_2_0_machine_options(MachineClass *m)
PC_I440FX_1_7_MACHINE_OPTIONS, {
.name = "pc-i440fx-1.7", pc_i440fx_2_1_machine_options(m);
.init = pc_init_pci_1_7, SET_MACHINE_COMPAT(m, PC_COMPAT_2_0);
.compat_props = (GlobalProperty[]) { }
PC_COMPAT_1_7,
{ /* end of list */ }
},
};
#define PC_I440FX_1_6_MACHINE_OPTIONS PC_I440FX_MACHINE_OPTIONS DEFINE_I440FX_MACHINE(v2_0, "pc-i440fx-2.0", pc_compat_2_0,
pc_i440fx_2_0_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 = { static void pc_i440fx_1_7_machine_options(MachineClass *m)
PC_I440FX_1_6_MACHINE_OPTIONS, {
.name = "pc-i440fx-1.5", pc_i440fx_2_0_machine_options(m);
.init = pc_init_pci_1_5, m->default_machine_opts = NULL;
.compat_props = (GlobalProperty[]) { SET_MACHINE_COMPAT(m, PC_COMPAT_1_7);
PC_COMPAT_1_5, }
{ /* end of list */ }
},
};
#define PC_I440FX_1_4_MACHINE_OPTIONS \ DEFINE_I440FX_MACHINE(v1_7, "pc-i440fx-1.7", pc_compat_1_7,
PC_I440FX_1_6_MACHINE_OPTIONS, \ pc_i440fx_1_7_machine_options);
.hot_add_cpu = NULL
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);
}
DEFINE_I440FX_MACHINE(v1_6, "pc-i440fx-1.6", pc_compat_1_6,
pc_i440fx_1_6_machine_options);
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_I440FX_MACHINE(v1_5, "pc-i440fx-1.5", pc_compat_1_5,
pc_i440fx_1_5_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_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 \ #define PC_COMPAT_1_3 \
PC_COMPAT_1_4, \ PC_COMPAT_1_4 \
{\ {\
.driver = "usb-tablet",\ .driver = "usb-tablet",\
.property = "usb_version",\ .property = "usb_version",\
@ -645,20 +588,21 @@ static QEMUMachine pc_i440fx_machine_v1_4 = {
.driver = "e1000",\ .driver = "e1000",\
.property = "autonegotiation",\ .property = "autonegotiation",\
.value = "off",\ .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);
} }
static QEMUMachine pc_machine_v1_3 = { DEFINE_I440FX_MACHINE(v1_3, "pc-1.3", pc_compat_1_3,
PC_I440FX_1_4_MACHINE_OPTIONS, pc_i440fx_1_3_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 \ #define PC_COMPAT_1_2 \
PC_COMPAT_1_3,\ PC_COMPAT_1_3 \
{\ {\
.driver = "nec-usb-xhci",\ .driver = "nec-usb-xhci",\
.property = "msi",\ .property = "msi",\
@ -683,23 +627,20 @@ static QEMUMachine pc_machine_v1_3 = {
.driver = "VGA",\ .driver = "VGA",\
.property = "mmio",\ .property = "mmio",\
.value = "off",\ .value = "off",\
},
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 PC_I440FX_1_2_MACHINE_OPTIONS \ DEFINE_I440FX_MACHINE(v1_2, "pc-1.2", pc_compat_1_2,
PC_I440FX_1_4_MACHINE_OPTIONS, \ pc_i440fx_1_2_machine_options);
.init = pc_init_pci_1_2
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 \ #define PC_COMPAT_1_1 \
PC_COMPAT_1_2,\ PC_COMPAT_1_2 \
{\ {\
.driver = "virtio-scsi-pci",\ .driver = "virtio-scsi-pci",\
.property = "hotplug",\ .property = "hotplug",\
@ -728,19 +669,20 @@ static QEMUMachine pc_machine_v1_2 = {
.driver = "virtio-blk-pci",\ .driver = "virtio-blk-pci",\
.property = "config-wce",\ .property = "config-wce",\
.value = "off",\ .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);
} }
static QEMUMachine pc_machine_v1_1 = { DEFINE_I440FX_MACHINE(v1_1, "pc-1.1", pc_compat_1_2,
PC_I440FX_1_2_MACHINE_OPTIONS, pc_i440fx_1_1_machine_options);
.name = "pc-1.1",
.compat_props = (GlobalProperty[]) {
PC_COMPAT_1_1,
{ /* end of list */ }
},
};
#define PC_COMPAT_1_0 \ #define PC_COMPAT_1_0 \
PC_COMPAT_1_1,\ PC_COMPAT_1_1 \
{\ {\
.driver = TYPE_ISA_FDC,\ .driver = TYPE_ISA_FDC,\
.property = "check_media_rate",\ .property = "check_media_rate",\
@ -757,33 +699,35 @@ static QEMUMachine pc_machine_v1_1 = {
.driver = TYPE_USB_DEVICE,\ .driver = TYPE_USB_DEVICE,\
.property = "full-path",\ .property = "full-path",\
.value = "no",\ .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);
} }
static QEMUMachine pc_machine_v1_0 = { DEFINE_I440FX_MACHINE(v1_0, "pc-1.0", pc_compat_1_2,
PC_I440FX_1_2_MACHINE_OPTIONS, pc_i440fx_1_0_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 \ #define PC_COMPAT_0_15 \
PC_COMPAT_1_0 PC_COMPAT_1_0
static QEMUMachine pc_machine_v0_15 = { static void pc_i440fx_0_15_machine_options(MachineClass *m)
PC_I440FX_1_2_MACHINE_OPTIONS, {
.name = "pc-0.15", pc_i440fx_1_0_machine_options(m);
.compat_props = (GlobalProperty[]) { m->hw_version = "0.15";
PC_COMPAT_0_15, SET_MACHINE_COMPAT(m, PC_COMPAT_0_15);
{ /* end of list */ } }
},
.hw_version = "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 \ #define PC_COMPAT_0_14 \
PC_COMPAT_0_15,\ PC_COMPAT_0_15 \
{\ {\
.driver = "virtio-blk-pci",\ .driver = "virtio-blk-pci",\
.property = "event_idx",\ .property = "event_idx",\
@ -800,29 +744,29 @@ static QEMUMachine pc_machine_v0_15 = {
.driver = "virtio-balloon-pci",\ .driver = "virtio-balloon-pci",\
.property = "event_idx",\ .property = "event_idx",\
.value = "off",\ .value = "off",\
},{\
.driver = "qxl",\
.property = "revision",\
.value = stringify(2),\
},{\
.driver = "qxl-vga",\
.property = "revision",\
.value = stringify(2),\
},
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);
} }
static QEMUMachine pc_machine_v0_14 = { DEFINE_I440FX_MACHINE(v0_14, "pc-0.14", pc_compat_1_2,
PC_I440FX_1_2_MACHINE_OPTIONS, pc_i440fx_0_14_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),
},
{ /* end of list */ }
},
.hw_version = "0.14",
};
#define PC_COMPAT_0_13 \ #define PC_COMPAT_0_13 \
PC_COMPAT_0_14,\ PC_COMPAT_0_14 \
{\ {\
.driver = TYPE_PCI_DEVICE,\ .driver = TYPE_PCI_DEVICE,\
.property = "command_serr_enable",\ .property = "command_serr_enable",\
@ -831,37 +775,33 @@ static QEMUMachine pc_machine_v0_14 = {
.driver = "AC97",\ .driver = "AC97",\
.property = "use_broken_id",\ .property = "use_broken_id",\
.value = stringify(1),\ .value = stringify(1),\
},{\
.driver = "virtio-9p-pci",\
.property = "vectors",\
.value = stringify(0),\
},{\
.driver = "VGA",\
.property = "rombar",\
.value = stringify(0),\
},{\
.driver = "vmware-svga",\
.property = "rombar",\
.value = stringify(0),\
},
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 PC_I440FX_0_13_MACHINE_OPTIONS \ DEFINE_I440FX_MACHINE(v0_13, "pc-0.13", pc_compat_0_13,
PC_I440FX_1_2_MACHINE_OPTIONS, \ pc_i440fx_0_13_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),
},
{ /* end of list */ }
},
.hw_version = "0.13",
};
#define PC_COMPAT_0_12 \ #define PC_COMPAT_0_12 \
PC_COMPAT_0_13,\ PC_COMPAT_0_13 \
{\ {\
.driver = "virtio-serial-pci",\ .driver = "virtio-serial-pci",\
.property = "max_ports",\ .property = "max_ports",\
@ -882,29 +822,21 @@ static QEMUMachine pc_machine_v0_13 = {
.driver = "usb-kbd",\ .driver = "usb-kbd",\
.property = "serial",\ .property = "serial",\
.value = "1",\ .value = "1",\
},
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);
} }
static QEMUMachine pc_machine_v0_12 = { DEFINE_I440FX_MACHINE(v0_12, "pc-0.12", pc_compat_0_13,
PC_I440FX_0_13_MACHINE_OPTIONS, pc_i440fx_0_12_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",
};
#define PC_COMPAT_0_11 \ #define PC_COMPAT_0_11 \
PC_COMPAT_0_12,\ PC_COMPAT_0_12 \
{\ {\
.driver = "virtio-blk-pci",\ .driver = "virtio-blk-pci",\
.property = "vectors",\ .property = "vectors",\
@ -913,106 +845,83 @@ static QEMUMachine pc_machine_v0_12 = {
.driver = TYPE_PCI_DEVICE,\ .driver = TYPE_PCI_DEVICE,\
.property = "rombar",\ .property = "rombar",\
.value = stringify(0),\ .value = stringify(0),\
},{\
.driver = "ide-drive",\
.property = "ver",\
.value = "0.11",\
},{\
.driver = "scsi-disk",\
.property = "ver",\
.value = "0.11",\
},
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);
} }
static QEMUMachine pc_machine_v0_11 = { DEFINE_I440FX_MACHINE(v0_11, "pc-0.11", pc_compat_0_13,
PC_I440FX_0_13_MACHINE_OPTIONS, pc_i440fx_0_11_machine_options);
.name = "pc-0.11",
.compat_props = (GlobalProperty[]) {
PC_COMPAT_0_11, #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",\
},
static void pc_i440fx_0_10_machine_options(MachineClass *m)
{ {
.driver = "ide-drive", pc_i440fx_0_11_machine_options(m);
.property = "ver", m->hw_version = "0.10";
.value = "0.11", SET_MACHINE_COMPAT(m, PC_COMPAT_0_10);
},{
.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",
},
{ /* 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 */ }
},
};
#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_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
} }
machine_init(pc_machine_init); 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);
#ifdef CONFIG_XEN
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;
}
DEFINE_PC_MACHINE(xenfv, "xenfv", pc_xen_hvm_init,
xenfv_machine_options);
#endif

View File

@ -89,6 +89,7 @@ static void pc_q35_init(MachineState *machine)
PcGuestInfo *guest_info; PcGuestInfo *guest_info;
ram_addr_t lowmem; ram_addr_t lowmem;
DriveInfo *hd[MAX_SATA_PORTS]; DriveInfo *hd[MAX_SATA_PORTS];
MachineClass *mc = MACHINE_GET_CLASS(machine);
/* Check whether RAM fits below 4G (leaving 1/2 GByte for IO memory /* Check whether RAM fits below 4G (leaving 1/2 GByte for IO memory
* and 256 Mbytes for PCI Express Enhanced Configuration Access Mapping * 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; guest_info->legacy_acpi_table_size = 0;
if (smbios_defaults) { if (smbios_defaults) {
MachineClass *mc = MACHINE_GET_CLASS(machine);
/* These values are guest ABI, do not change */ /* These values are guest ABI, do not change */
smbios_set_defaults("QEMU", "Standard PC (Q35 + ICH9, 2009)", smbios_set_defaults("QEMU", "Standard PC (Q35 + ICH9, 2009)",
mc->name, smbios_legacy_mode, smbios_uuid_encoded); mc->name, smbios_legacy_mode, smbios_uuid_encoded);
@ -250,7 +250,7 @@ static void pc_q35_init(MachineState *machine)
} }
/* init basic PC hardware */ /* 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); (pc_machine->vmport != ON_OFF_AUTO_ON), 0xff0104);
/* connect pm stuff to lpc */ /* 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); 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_default_machine_options(m);
pc_q35_init(machine); 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_machine_options(m);
pc_q35_init(machine); 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_2_4_machine_options(m);
pc_q35_init(machine); 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_2_3_machine_options(m);
pc_q35_init(machine); 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_2_2_machine_options(m);
pc_q35_init(machine); m->default_display = NULL;
SET_MACHINE_COMPAT(m, PC_COMPAT_2_1);
} }
static void pc_q35_init_1_6(MachineState *machine) 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_compat_1_6(machine); pc_q35_2_1_machine_options(m);
pc_q35_init(machine); SET_MACHINE_COMPAT(m, PC_COMPAT_2_0);
} }
static void pc_q35_init_1_5(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_5(machine); pc_q35_2_0_machine_options(m);
pc_q35_init(machine); m->default_machine_opts = NULL;
SET_MACHINE_COMPAT(m, PC_COMPAT_1_7);
} }
static void pc_q35_init_1_4(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_4(machine); pc_q35_machine_options(m);
pc_q35_init(machine); SET_MACHINE_COMPAT(m, PC_COMPAT_1_6);
} }
#define PC_Q35_MACHINE_OPTIONS \ DEFINE_Q35_MACHINE(v1_6, "pc-q35-1.6", pc_compat_1_6,
PC_DEFAULT_MACHINE_OPTIONS, \ pc_q35_1_6_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 = { static void pc_q35_1_5_machine_options(MachineClass *m)
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)
{ {
qemu_register_pc_machine(&pc_q35_machine_v2_4); pc_q35_1_6_machine_options(m);
qemu_register_pc_machine(&pc_q35_machine_v2_3); SET_MACHINE_COMPAT(m, PC_COMPAT_1_5);
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);
} }
machine_init(pc_q35_machine_init); 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)
{
pc_q35_1_5_machine_options(m);
m->hot_add_cpu = NULL;
SET_MACHINE_COMPAT(m, PC_COMPAT_1_4);
}
DEFINE_Q35_MACHINE(v1_4, "pc-q35-1.4", pc_compat_1_4,
pc_q35_1_4_machine_options);

View File

@ -25,19 +25,5 @@ DefinitionBlock (
0x1 // OEM Revision 0x1 // OEM Revision
) )
{ {
Scope(\_SB) { #include "ssdt-tpm-common.dsl"
/* 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)
}
}
}
} }

View File

@ -3,12 +3,12 @@ static unsigned char ssdt_tpm_aml[] = {
0x53, 0x53,
0x44, 0x44,
0x54, 0x54,
0x5d, 0x6b,
0x0, 0x0,
0x0, 0x0,
0x0, 0x0,
0x1, 0x1,
0x1c, 0x37,
0x42, 0x42,
0x58, 0x58,
0x50, 0x50,
@ -36,15 +36,26 @@ static unsigned char ssdt_tpm_aml[] = {
0x14, 0x14,
0x20, 0x20,
0x10, 0x10,
0x38, 0x46,
0x4,
0x5c, 0x5c,
0x2f,
0x3,
0x5f, 0x5f,
0x53, 0x53,
0x42, 0x42,
0x5f, 0x5f,
0x50,
0x43,
0x49,
0x30,
0x49,
0x53,
0x41,
0x5f,
0x5b, 0x5b,
0x82, 0x82,
0x30, 0x33,
0x54, 0x54,
0x50, 0x50,
0x4d, 0x4d,
@ -65,9 +76,9 @@ static unsigned char ssdt_tpm_aml[] = {
0x52, 0x52,
0x53, 0x53,
0x11, 0x11,
0x11, 0x14,
0xa, 0xa,
0xe, 0x11,
0x86, 0x86,
0x9, 0x9,
0x0, 0x0,
@ -80,6 +91,9 @@ static unsigned char ssdt_tpm_aml[] = {
0x50, 0x50,
0x0, 0x0,
0x0, 0x0,
0x22,
0x20,
0x0,
0x79, 0x79,
0x0, 0x0,
0x14, 0x14,

29
hw/i386/ssdt-tpm2.dsl Normal file
View File

@ -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"
}

View File

@ -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
};

View File

@ -166,7 +166,7 @@ static void virtio_input_set_config(VirtIODevice *vdev,
virtio_notify_config(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; return f;
} }

View File

@ -157,6 +157,7 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
net->dev.nvqs = 2; net->dev.nvqs = 2;
net->dev.vqs = net->vqs; net->dev.vqs = net->vqs;
net->dev.vq_index = net->nc->queue_index;
r = vhost_dev_init(&net->dev, options->opaque, r = vhost_dev_init(&net->dev, options->opaque,
options->backend_type, options->force); 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) { for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
const VhostOps *vhost_ops = net->dev.vhost_ops; const VhostOps *vhost_ops = net->dev.vhost_ops;
int r = vhost_ops->vhost_call(&net->dev, VHOST_RESET_OWNER, int r = vhost_ops->vhost_call(&net->dev, VHOST_RESET_OWNER,
NULL); &file);
assert(r >= 0); assert(r >= 0);
} }
} }

View File

@ -435,7 +435,7 @@ static void virtio_net_set_queues(VirtIONet *n)
static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue); 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); VirtIONet *n = VIRTIO_NET(vdev);
NetClientState *nc = qemu_get_queue(n->nic); 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); 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), /* Linux kernel 2.6.25. It understood MAC (as everyone must),
* but also these: */ * but also these: */
@ -1033,9 +1033,11 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t
return -1; return -1;
error_report("virtio-net unexpected empty queue: " error_report("virtio-net unexpected empty queue: "
"i %zd mergeable %d offset %zd, size %zd, " "i %zd mergeable %d offset %zd, size %zd, "
"guest hdr len %zd, host hdr len %zd guest features 0x%x", "guest hdr len %zd, host hdr len %zd "
"guest features 0x%" PRIx64,
i, n->mergeable_rx_bufs, offset, size, i, n->mergeable_rx_bufs, offset, size,
n->guest_hdr_len, n->host_hdr_len, vdev->guest_features); n->guest_hdr_len, n->host_hdr_len,
vdev->guest_features);
exit(1); exit(1);
} }
@ -1301,39 +1303,8 @@ static void virtio_net_tx_bh(void *opaque)
static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue) 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; 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); virtio_net_set_queues(n);
} }
@ -1549,7 +1520,7 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx,
vdev, idx, mask); 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; int i, config_size = 0;
virtio_add_feature(&host_features, VIRTIO_NET_F_MAC); 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); virtio_init(vdev, "virtio-net", VIRTIO_ID_NET, n->config_size);
n->max_queues = MAX(n->nic_conf.peers.queues, 1); 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 "), " error_setg(errp, "Invalid number of queues (= %" PRIu32 "), "
"must be a positive integer less than %d.", "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); virtio_cleanup(vdev);
return; return;
} }
n->vqs = g_malloc0(sizeof(VirtIONetQueue) * n->max_queues); 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->curr_queues = 1;
n->vqs[0].n = n;
n->tx_timeout = n->net_conf.txtimer; n->tx_timeout = n->net_conf.txtimer;
if (n->net_conf.tx && strcmp(n->net_conf.tx, "timer") 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\""); error_report("Defaulting to \"bh\"");
} }
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")) { if (n->net_conf.tx && !strcmp(n->net_conf.tx, "timer")) {
n->vqs[0].tx_vq = virtio_add_queue(vdev, 256, n->vqs[i].tx_vq =
virtio_net_handle_tx_timer); 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[i].tx_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
&n->vqs[0]); virtio_net_tx_timer,
&n->vqs[i]);
} else { } else {
n->vqs[0].tx_vq = virtio_add_queue(vdev, 256, n->vqs[i].tx_vq =
virtio_net_handle_tx_bh); 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]); 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); n->ctrl_vq = virtio_add_queue(vdev, 64, virtio_net_handle_ctrl);
qemu_macaddr_default_if_unset(&n->nic_conf.macaddr); qemu_macaddr_default_if_unset(&n->nic_conf.macaddr);
memcpy(&n->mac[0], &n->nic_conf.macaddr, sizeof(n->mac)); memcpy(&n->mac[0], &n->nic_conf.macaddr, sizeof(n->mac));

View File

@ -291,8 +291,16 @@ void msi_notify(PCIDevice *dev, unsigned int vector)
"notify vector 0x%x" "notify vector 0x%x"
" address: 0x%"PRIx64" data: 0x%"PRIx32"\n", " address: 0x%"PRIx64" data: 0x%"PRIx32"\n",
vector, msg.address, msg.data); 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, address_space_stl_le(&dev->bus_master_as, msg.address, msg.data,
MEMTXATTRS_UNSPECIFIED, NULL); attrs, NULL);
} }
/* Normally called by pci_default_write_config(). */ /* Normally called by pci_default_write_config(). */

View File

@ -443,8 +443,7 @@ void msix_notify(PCIDevice *dev, unsigned vector)
msg = msix_get_message(dev, vector); msg = msix_get_message(dev, vector);
address_space_stl_le(&dev->bus_master_as, msg.address, msg.data, msi_send_message(dev, msg);
MEMTXATTRS_UNSPECIFIED, NULL);
} }
void msix_reset(PCIDevice *dev) void msix_reset(PCIDevice *dev)

View File

@ -1815,15 +1815,21 @@ static const TypeInfo spapr_machine_info = {
}, },
}; };
#define SPAPR_COMPAT_2_3 \
HW_COMPAT_2_3
#define SPAPR_COMPAT_2_2 \ #define SPAPR_COMPAT_2_2 \
SPAPR_COMPAT_2_3 \
HW_COMPAT_2_2 \
{\ {\
.driver = TYPE_SPAPR_PCI_HOST_BRIDGE,\ .driver = TYPE_SPAPR_PCI_HOST_BRIDGE,\
.property = "mem_win_size",\ .property = "mem_win_size",\
.value = "0x20000000",\ .value = "0x20000000",\
} },
#define SPAPR_COMPAT_2_1 \ #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) 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); MachineClass *mc = MACHINE_CLASS(oc);
static GlobalProperty compat_props[] = { static GlobalProperty compat_props[] = {
HW_COMPAT_2_1, SPAPR_COMPAT_2_1
SPAPR_COMPAT_2_1,
{ /* end of list */ } { /* 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 void spapr_machine_2_2_class_init(ObjectClass *oc, void *data)
{ {
static GlobalProperty compat_props[] = { static GlobalProperty compat_props[] = {
SPAPR_COMPAT_2_2, SPAPR_COMPAT_2_2
{ /* end of list */ } { /* end of list */ }
}; };
MachineClass *mc = MACHINE_CLASS(oc); MachineClass *mc = MACHINE_CLASS(oc);

View File

@ -45,6 +45,8 @@
do { } while (0) do { } while (0)
#endif #endif
#define VIRTIO_S390_QUEUE_MAX 64
static void virtio_s390_bus_new(VirtioBusState *bus, size_t bus_size, static void virtio_s390_bus_new(VirtioBusState *bus, size_t bus_size,
VirtIOS390Device *dev); VirtIOS390Device *dev);
@ -139,8 +141,6 @@ static void s390_virtio_device_init(VirtIOS390Device *dev,
bus->dev_offs += dev_len; 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_device_sync(dev);
s390_virtio_reset_idx(dev); s390_virtio_reset_idx(dev);
if (dev->qdev.hotplugged) { if (dev->qdev.hotplugged) {
@ -354,7 +354,7 @@ static ram_addr_t s390_virtio_device_num_vq(VirtIOS390Device *dev)
VirtIODevice *vdev = dev->vdev; VirtIODevice *vdev = dev->vdev;
int num_vq; 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)) { if (!virtio_queue_get_num(vdev, num_vq)) {
break; break;
} }
@ -433,7 +433,8 @@ void s390_virtio_device_sync(VirtIOS390Device *dev)
cur_offs += num_vq * VIRTIO_VQCONFIG_LEN; cur_offs += num_vq * VIRTIO_VQCONFIG_LEN;
/* Sync feature bitmap */ /* 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); MEMTXATTRS_UNSPECIFIED, NULL);
dev->feat_offs = cur_offs + dev->feat_len; 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) { QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
VirtIOS390Device *dev = (VirtIOS390Device *)kid->child; 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)) if (!virtio_queue_get_addr(dev->vdev, i))
break; break;
if (virtio_queue_get_addr(dev->vdev, i) == mem) { 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); 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); 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 *******************/ /**************** S390 Virtio Bus Device Descriptions *******************/
@ -626,16 +634,10 @@ static void s390_virtio_busdev_reset(DeviceState *dev)
virtio_reset(_dev->vdev); 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) static void virtio_s390_device_class_init(ObjectClass *klass, void *data)
{ {
DeviceClass *dc = DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass);
dc->props = virtio_s390_properties;
dc->realize = s390_virtio_busdev_realize; dc->realize = s390_virtio_busdev_realize;
dc->bus_type = TYPE_S390_VIRTIO_BUS; dc->bus_type = TYPE_S390_VIRTIO_BUS;
dc->reset = s390_virtio_busdev_reset; 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); BusClass *bus_class = BUS_CLASS(klass);
bus_class->max_dev = 1; bus_class->max_dev = 1;
k->notify = virtio_s390_notify; 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 = { static const TypeInfo virtio_s390_bus_info = {

View File

@ -92,7 +92,6 @@ struct VirtIOS390Device {
ram_addr_t feat_offs; ram_addr_t feat_offs;
uint8_t feat_len; uint8_t feat_len;
VirtIODevice *vdev; VirtIODevice *vdev;
uint32_t host_features;
VirtioBusState bus; VirtioBusState bus;
}; };

View File

@ -67,7 +67,7 @@ static int virtio_ccw_hcall_notify(const uint64_t *args)
if (!sch || !css_subch_visible(sch)) { if (!sch || !css_subch_visible(sch)) {
return -EINVAL; return -EINVAL;
} }
if (queue >= VIRTIO_PCI_QUEUE_MAX) { if (queue >= VIRTIO_CCW_QUEUE_MAX) {
return -EINVAL; return -EINVAL;
} }
virtio_queue_notify(virtio_ccw_get_vdev(sch), queue); virtio_queue_notify(virtio_ccw_get_vdev(sch), queue);

View File

@ -170,7 +170,7 @@ static void virtio_ccw_start_ioeventfd(VirtioCcwDevice *dev)
return; return;
} }
vdev = virtio_bus_get_device(&dev->bus); 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)) { if (!virtio_queue_get_num(vdev, n)) {
continue; continue;
} }
@ -205,7 +205,7 @@ static void virtio_ccw_stop_ioeventfd(VirtioCcwDevice *dev)
return; return;
} }
vdev = virtio_bus_get_device(&dev->bus); 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)) { if (!virtio_queue_get_num(vdev, n)) {
continue; 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); VirtIODevice *vdev = virtio_ccw_get_vdev(sch);
if (index >= VIRTIO_PCI_QUEUE_MAX) { if (index >= VIRTIO_CCW_QUEUE_MAX) {
return -EINVAL; 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); virtio_queue_set_vector(vdev, index, index);
} }
/* tell notify handler in case of config change */ /* tell notify handler in case of config change */
vdev->config_vector = VIRTIO_PCI_QUEUE_MAX; vdev->config_vector = VIRTIO_CCW_QUEUE_MAX;
return 0; return 0;
} }
@ -381,8 +381,8 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
+ sizeof(features.features), + sizeof(features.features),
MEMTXATTRS_UNSPECIFIED, MEMTXATTRS_UNSPECIFIED,
NULL); NULL);
if (features.index < ARRAY_SIZE(dev->host_features)) { if (features.index == 0) {
features.features = dev->host_features[features.index]; features.features = vdev->host_features;
} else { } else {
/* Return zeroes if the guest supports more feature bits. */ /* Return zeroes if the guest supports more feature bits. */
features.features = 0; features.features = 0;
@ -417,7 +417,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
ccw.cda, ccw.cda,
MEMTXATTRS_UNSPECIFIED, MEMTXATTRS_UNSPECIFIED,
NULL); NULL);
if (features.index < ARRAY_SIZE(dev->host_features)) { if (features.index == 0) {
virtio_set_features(vdev, features.features); virtio_set_features(vdev, features.features);
} else { } else {
/* /*
@ -573,7 +573,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
ccw.cda, ccw.cda,
MEMTXATTRS_UNSPECIFIED, MEMTXATTRS_UNSPECIFIED,
NULL); NULL);
if (vq_config.index >= VIRTIO_PCI_QUEUE_MAX) { if (vq_config.index >= VIRTIO_CCW_QUEUE_MAX) {
ret = -EINVAL; ret = -EINVAL;
break; 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) static void virtio_ccw_balloon_instance_init(Object *obj)
{ {
VirtIOBalloonCcw *dev = VIRTIO_BALLOON_CCW(obj); VirtIOBalloonCcw *dev = VIRTIO_BALLOON_CCW(obj);
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
TYPE_VIRTIO_BALLOON); TYPE_VIRTIO_BALLOON);
object_property_add(obj, "guest-stats", "guest statistics", object_property_add_alias(obj, "guest-stats", OBJECT(&dev->vdev),
balloon_ccw_stats_get_all, NULL, NULL, dev, NULL); "guest-stats", &error_abort);
object_property_add_alias(obj, "guest-stats-polling-interval",
object_property_add(obj, "guest-stats-polling-interval", "int", OBJECT(&dev->vdev),
balloon_ccw_stats_get_poll_interval, "guest-stats-polling-interval", &error_abort);
balloon_ccw_stats_set_poll_interval,
NULL, dev, NULL);
} }
static void virtio_ccw_scsi_realize(VirtioCcwDevice *ccw_dev, Error **errp) 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; return;
} }
if (vector < VIRTIO_PCI_QUEUE_MAX) { if (vector < VIRTIO_CCW_QUEUE_MAX) {
if (!dev->indicators) { if (!dev->indicators) {
return; 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) static void virtio_ccw_reset(DeviceState *d)
{ {
VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
@ -1413,19 +1378,22 @@ static int virtio_ccw_load_config(DeviceState *d, QEMUFile *f)
} }
/* This is called by virtio-bus just after the device is plugged. */ /* 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); VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
SubchDev *sch = dev->sch; SubchDev *sch = dev->sch;
int n = virtio_get_num_queues(vdev);
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;
}
sch->id.cu_model = virtio_bus_get_vdev_id(&dev->bus); sch->id.cu_model = virtio_bus_get_vdev_id(&dev->bus);
/* 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]);
css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid,
d->hotplugged, 1); d->hotplugged, 1);
} }
@ -1675,16 +1643,10 @@ static void virtio_ccw_busdev_unplug(HotplugHandler *hotplug_dev,
object_unparent(OBJECT(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) static void virtio_ccw_device_class_init(ObjectClass *klass, void *data)
{ {
DeviceClass *dc = DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass);
dc->props = virtio_ccw_properties;
dc->realize = virtio_ccw_busdev_realize; dc->realize = virtio_ccw_busdev_realize;
dc->exit = virtio_ccw_busdev_exit; dc->exit = virtio_ccw_busdev_exit;
dc->bus_type = TYPE_VIRTUAL_CSS_BUS; 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; bus_class->max_dev = 1;
k->notify = virtio_ccw_notify; k->notify = virtio_ccw_notify;
k->get_features = virtio_ccw_get_features;
k->vmstate_change = virtio_ccw_vmstate_change; k->vmstate_change = virtio_ccw_vmstate_change;
k->query_guest_notifiers = virtio_ccw_query_guest_notifiers; k->query_guest_notifiers = virtio_ccw_query_guest_notifiers;
k->set_host_notifier = virtio_ccw_set_host_notifier; k->set_host_notifier = virtio_ccw_set_host_notifier;

View File

@ -68,9 +68,6 @@ typedef struct VirtIOCCWDeviceClass {
int (*exit)(VirtioCcwDevice *dev); int (*exit)(VirtioCcwDevice *dev);
} VirtIOCCWDeviceClass; } 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 /* Performance improves when virtqueue kick processing is decoupled from the
* vcpu thread using ioeventfd for some devices. */ * vcpu thread using ioeventfd for some devices. */
#define VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT 1 #define VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT 1
@ -88,7 +85,6 @@ struct VirtioCcwDevice {
DeviceState parent_obj; DeviceState parent_obj;
SubchDev *sch; SubchDev *sch;
char *bus_id; char *bus_id;
uint32_t host_features[VIRTIO_CCW_FEATURE_SIZE];
VirtioBusState bus; VirtioBusState bus;
bool ioeventfd_started; bool ioeventfd_started;
bool ioeventfd_disabled; bool ioeventfd_disabled;

View File

@ -151,8 +151,8 @@ static void vhost_scsi_stop(VHostSCSI *s)
vhost_dev_disable_notifiers(&s->dev, vdev); vhost_dev_disable_notifiers(&s->dev, vdev);
} }
static uint32_t vhost_scsi_get_features(VirtIODevice *vdev, static uint64_t vhost_scsi_get_features(VirtIODevice *vdev,
uint32_t features) uint64_t features)
{ {
VHostSCSI *s = VHOST_SCSI(vdev); VHostSCSI *s = VHOST_SCSI(vdev);

View File

@ -628,8 +628,8 @@ static void virtio_scsi_set_config(VirtIODevice *vdev,
vs->cdb_size = virtio_ldl_p(vdev, &scsiconf->cdb_size); vs->cdb_size = virtio_ldl_p(vdev, &scsiconf->cdb_size);
} }
static uint32_t virtio_scsi_get_features(VirtIODevice *vdev, static uint64_t virtio_scsi_get_features(VirtIODevice *vdev,
uint32_t requested_features) uint64_t requested_features)
{ {
VirtIOSCSI *s = VIRTIO_SCSI(vdev); VirtIOSCSI *s = VIRTIO_SCSI(vdev);
@ -830,10 +830,10 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp,
sizeof(VirtIOSCSIConfig)); sizeof(VirtIOSCSIConfig));
if (s->conf.num_queues == 0 || 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 "), " error_setg(errp, "Invalid number of queues (= %" PRIu32 "), "
"must be a positive integer less than %d.", "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); virtio_cleanup(vdev);
return; return;
} }

View File

@ -1,2 +1,2 @@
common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o 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

View File

@ -29,6 +29,7 @@ struct TPMState {
char *backend; char *backend;
TPMBackend *be_driver; TPMBackend *be_driver;
TPMVersion be_tpm_version;
}; };
#define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS) #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_ContinueSelfTest 0x53
#define TPM_ORD_GetTicks 0xf1 #define TPM_ORD_GetTicks 0xf1
/* TPM2 defines */
#define TPM2_ST_NO_SESSIONS 0x8001
#define TPM2_CC_ReadClock 0x00000181
#endif /* TPM_TPM_INT_H */ #endif /* TPM_TPM_INT_H */

View File

@ -33,6 +33,7 @@
#include "hw/i386/pc.h" #include "hw/i386/pc.h"
#include "sysemu/tpm_backend_int.h" #include "sysemu/tpm_backend_int.h"
#include "tpm_tis.h" #include "tpm_tis.h"
#include "tpm_util.h"
#define DEBUG_TPM 0 #define DEBUG_TPM 0
@ -69,6 +70,8 @@ struct TPMPassthruState {
bool tpm_op_canceled; bool tpm_op_canceled;
int cancel_fd; int cancel_fd;
bool had_startup_error; bool had_startup_error;
TPMVersion tpm_version;
}; };
typedef struct TPMPassthruState TPMPassthruState; typedef struct TPMPassthruState TPMPassthruState;
@ -267,6 +270,13 @@ static bool tpm_passthrough_get_tpm_established_flag(TPMBackend *tb)
return false; 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) static bool tpm_passthrough_get_startup_error(TPMBackend *tb)
{ {
TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
@ -324,56 +334,11 @@ static const char *tpm_passthrough_create_desc(void)
return "Passthrough TPM backend driver"; return "Passthrough TPM backend driver";
} }
/* static TPMVersion tpm_passthrough_get_tpm_version(TPMBackend *tb)
* 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)
{ {
struct tpm_req_hdr req = { TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
.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)); return tpm_pt->tpm_version;
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;
}
return 0;
} }
/* /*
@ -443,7 +408,7 @@ static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb)
goto err_free_parameters; 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.", error_report("'%s' is not a TPM device.",
tpm_pt->tpm_dev); tpm_pt->tpm_dev);
goto err_close_tpmdev; goto err_close_tpmdev;
@ -540,6 +505,8 @@ static const TPMDriverOps tpm_passthrough_driver = {
.deliver_request = tpm_passthrough_deliver_request, .deliver_request = tpm_passthrough_deliver_request,
.cancel_cmd = tpm_passthrough_cancel_cmd, .cancel_cmd = tpm_passthrough_cancel_cmd,
.get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag, .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) static void tpm_passthrough_inst_init(Object *obj)

View File

@ -17,6 +17,9 @@
* supports version 1.3, 21 March 2013 * supports version 1.3, 21 March 2013
* In the developers menu choose the PC Client section then find the TIS * In the developers menu choose the PC Client section then find the TIS
* specification. * 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" #include "sysemu/tpm_backend.h"
@ -29,6 +32,7 @@
#include "tpm_tis.h" #include "tpm_tis.h"
#include "qemu-common.h" #include "qemu-common.h"
#include "qemu/main-loop.h" #include "qemu/main-loop.h"
#include "sysemu/tpm_backend.h"
#define DEBUG_TIS 0 #define DEBUG_TIS 0
@ -49,6 +53,7 @@
#define TPM_TIS_REG_INTF_CAPABILITY 0x14 #define TPM_TIS_REG_INTF_CAPABILITY 0x14
#define TPM_TIS_REG_STS 0x18 #define TPM_TIS_REG_STS 0x18
#define TPM_TIS_REG_DATA_FIFO 0x24 #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 0x80
#define TPM_TIS_REG_DATA_XFIFO_END 0xbc #define TPM_TIS_REG_DATA_XFIFO_END 0xbc
#define TPM_TIS_REG_DID_VID 0xf00 #define TPM_TIS_REG_DID_VID 0xf00
@ -57,6 +62,12 @@
/* vendor-specific registers */ /* vendor-specific registers */
#define TPM_TIS_REG_DEBUG 0xf90 #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_VALID (1 << 7)
#define TPM_TIS_STS_COMMAND_READY (1 << 6) #define TPM_TIS_STS_COMMAND_READY (1 << 6)
#define TPM_TIS_STS_TPM_GO (1 << 5) #define TPM_TIS_STS_TPM_GO (1 << 5)
@ -102,16 +113,43 @@
#endif #endif
#define TPM_TIS_CAP_INTERFACE_VERSION1_3 (2 << 28) #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_64B (3 << 9)
#define TPM_TIS_CAP_DATA_TRANSFER_LEGACY (0 << 9) #define TPM_TIS_CAP_DATA_TRANSFER_LEGACY (0 << 9)
#define TPM_TIS_CAP_BURST_COUNT_DYNAMIC (0 << 8) #define TPM_TIS_CAP_BURST_COUNT_DYNAMIC (0 << 8)
#define TPM_TIS_CAP_INTERRUPT_LOW_LEVEL (1 << 4) /* support is mandatory */ #define TPM_TIS_CAP_INTERRUPT_LOW_LEVEL (1 << 4) /* support is mandatory */
#define TPM_TIS_CAPABILITIES_SUPPORTED (TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \ #define TPM_TIS_CAPABILITIES_SUPPORTED1_3 \
(TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \
TPM_TIS_CAP_BURST_COUNT_DYNAMIC | \ TPM_TIS_CAP_BURST_COUNT_DYNAMIC | \
TPM_TIS_CAP_DATA_TRANSFER_64B | \ TPM_TIS_CAP_DATA_TRANSFER_64B | \
TPM_TIS_CAP_INTERFACE_VERSION1_3 | \ TPM_TIS_CAP_INTERFACE_VERSION1_3 | \
TPM_TIS_INTERRUPTS_SUPPORTED) 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_DID 0x0001
#define TPM_TIS_TPM_VID PCI_VENDOR_ID_IBM #define TPM_TIS_TPM_VID PCI_VENDOR_ID_IBM
#define TPM_TIS_TPM_RID 0x0001 #define TPM_TIS_TPM_RID 0x0001
@ -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 * 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 * The SELFTEST_DONE flag is acquired from the backend that determines it by
* peeking into TPM commands. * 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) 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; l->sts |= flags;
} }
@ -489,7 +528,17 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
val = tis->loc[locty].ints; val = tis->loc[locty].ints;
break; break;
case TPM_TIS_REG_INTF_CAPABILITY: 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; break;
case TPM_TIS_REG_STS: case TPM_TIS_REG_STS:
if (tis->active_locty == locty) { 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 */ shift = 0; /* no more adjustments */
} }
break; break;
case TPM_TIS_REG_INTERFACE_ID:
val = tis->loc[locty].iface_id;
break;
case TPM_TIS_REG_DID_VID: case TPM_TIS_REG_DID_VID:
val = (TPM_TIS_TPM_DID << 16) | TPM_TIS_TPM_VID; val = (TPM_TIS_TPM_DID << 16) | TPM_TIS_TPM_VID;
break; break;
@ -736,6 +788,25 @@ static void tpm_tis_mmio_write_intern(void *opaque, hwaddr addr,
break; 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 | val &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO |
TPM_TIS_STS_RESPONSE_RETRY); TPM_TIS_STS_RESPONSE_RETRY);
@ -860,6 +931,13 @@ static void tpm_tis_mmio_write_intern(void *opaque, hwaddr addr,
} }
} }
break; 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;
} }
} }
@ -884,6 +962,16 @@ static int tpm_tis_do_startup_tpm(TPMState *s)
return tpm_backend_startup_tpm(s->be_driver); return tpm_backend_startup_tpm(s->be_driver);
} }
/*
* 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 * This function is called when the machine starts, resets or due to
* S3 resume. * S3 resume.
@ -894,6 +982,8 @@ static void tpm_tis_reset(DeviceState *dev)
TPMTISEmuState *tis = &s->s.tis; TPMTISEmuState *tis = &s->s.tis;
int c; int c;
s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver);
tpm_backend_reset(s->be_driver); tpm_backend_reset(s->be_driver);
tis->active_locty = TPM_TIS_NO_LOCALITY; 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++) { for (c = 0; c < TPM_TIS_NUM_LOCALITIES; c++) {
tis->loc[c].access = TPM_TIS_ACCESS_TPM_REG_VALID_STS; 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].inte = TPM_TIS_INT_POLARITY_LOW_LEVEL;
tis->loc[c].ints = 0; tis->loc[c].ints = 0;
tis->loc[c].state = TPM_TIS_STATE_IDLE; tis->loc[c].state = TPM_TIS_STATE_IDLE;

View File

@ -42,6 +42,7 @@ typedef struct TPMLocality {
TPMTISState state; TPMTISState state;
uint8_t access; uint8_t access;
uint32_t sts; uint32_t sts;
uint32_t iface_id;
uint32_t inte; uint32_t inte;
uint32_t ints; uint32_t ints;

126
hw/tpm/tpm_util.c Normal file
View File

@ -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;
}

28
hw/tpm/tpm_util.h Normal file
View File

@ -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 */

View File

@ -210,7 +210,12 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,
break; break;
case VHOST_SET_OWNER: case VHOST_SET_OWNER:
break;
case VHOST_RESET_OWNER: 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; break;
case VHOST_SET_MEM_TABLE: 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_NUM:
case VHOST_SET_VRING_BASE: case VHOST_SET_VRING_BASE:
memcpy(&msg.state, arg, sizeof(struct vhost_vring_state)); memcpy(&msg.state, arg, sizeof(struct vhost_vring_state));
msg.state.index += dev->vq_index;
msg.size = sizeof(m.state); msg.size = sizeof(m.state);
break; break;
case VHOST_GET_VRING_BASE: case VHOST_GET_VRING_BASE:
memcpy(&msg.state, arg, sizeof(struct vhost_vring_state)); memcpy(&msg.state, arg, sizeof(struct vhost_vring_state));
msg.state.index += dev->vq_index;
msg.size = sizeof(m.state); msg.size = sizeof(m.state);
need_reply = 1; need_reply = 1;
break; break;
case VHOST_SET_VRING_ADDR: case VHOST_SET_VRING_ADDR:
memcpy(&msg.addr, arg, sizeof(struct vhost_vring_addr)); memcpy(&msg.addr, arg, sizeof(struct vhost_vring_addr));
msg.addr.index += dev->vq_index;
msg.size = sizeof(m.addr); msg.size = sizeof(m.addr);
break; 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_CALL:
case VHOST_SET_VRING_ERR: case VHOST_SET_VRING_ERR:
file = arg; 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); msg.size = sizeof(m.u64);
if (ioeventfd_enabled() && file->fd > 0) { if (ioeventfd_enabled() && file->fd > 0) {
fds[fd_num++] = file->fd; 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."); error_report("Received bad msg size.");
return -1; return -1;
} }
msg.state.index -= dev->vq_index;
memcpy(arg, &msg.state, sizeof(struct vhost_vring_state)); memcpy(arg, &msg.state, sizeof(struct vhost_vring_state));
break; break;
default: default:

View File

@ -310,7 +310,7 @@ static void virtio_balloon_set_config(VirtIODevice *vdev,
trace_virtio_balloon_set_config(dev->actual, oldactual); 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); f |= (1 << VIRTIO_BALLOON_F_STATS_VQ);
return f; return f;
@ -396,14 +396,6 @@ static void virtio_balloon_device_realize(DeviceState *dev, Error **errp)
register_savevm(dev, "virtio-balloon", -1, 1, register_savevm(dev, "virtio-balloon", -1, 1,
virtio_balloon_save, virtio_balloon_load, s); 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) 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); 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[] = { static Property virtio_balloon_properties[] = {
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };
@ -441,6 +446,7 @@ static const TypeInfo virtio_balloon_info = {
.name = TYPE_VIRTIO_BALLOON, .name = TYPE_VIRTIO_BALLOON,
.parent = TYPE_VIRTIO_DEVICE, .parent = TYPE_VIRTIO_DEVICE,
.instance_size = sizeof(VirtIOBalloon), .instance_size = sizeof(VirtIOBalloon),
.instance_init = virtio_balloon_instance_init,
.class_init = virtio_balloon_class_init, .class_init = virtio_balloon_class_init,
}; };

View File

@ -38,19 +38,23 @@ do { printf("virtio_bus: " fmt , ## __VA_ARGS__); } while (0)
#endif #endif
/* A VirtIODevice is being plugged */ /* 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); DeviceState *qdev = DEVICE(vdev);
BusState *qbus = BUS(qdev_get_parent_bus(qdev)); BusState *qbus = BUS(qdev_get_parent_bus(qdev));
VirtioBusState *bus = VIRTIO_BUS(qbus); VirtioBusState *bus = VIRTIO_BUS(qbus);
VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(bus); VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(bus);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
DPRINTF("%s: plug device.\n", qbus->name); DPRINTF("%s: plug device.\n", qbus->name);
if (klass->device_plugged != NULL) { 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 */ /* Reset the virtio_bus */
@ -96,19 +100,6 @@ size_t virtio_bus_get_vdev_config_len(VirtioBusState *bus)
return vdev->config_len; 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. */ /* Get bad features of the plugged device. */
uint32_t virtio_bus_get_vdev_bad_features(VirtioBusState *bus) uint32_t virtio_bus_get_vdev_bad_features(VirtioBusState *bus)
{ {

View File

@ -22,7 +22,9 @@
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "hw/virtio/virtio.h" #include "hw/virtio/virtio.h"
#include "qemu/host-utils.h" #include "qemu/host-utils.h"
#include "sysemu/kvm.h"
#include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-bus.h"
#include "qemu/error-report.h"
/* #define DEBUG_VIRTIO_MMIO */ /* #define DEBUG_VIRTIO_MMIO */
@ -80,15 +82,102 @@ typedef struct {
SysBusDevice parent_obj; SysBusDevice parent_obj;
MemoryRegion iomem; MemoryRegion iomem;
qemu_irq irq; qemu_irq irq;
uint32_t host_features;
/* Guest accessible state needing migration and reset */ /* Guest accessible state needing migration and reset */
uint32_t host_features_sel; uint32_t host_features_sel;
uint32_t guest_features_sel; uint32_t guest_features_sel;
uint32_t guest_page_shift; uint32_t guest_page_shift;
/* virtio-bus */ /* virtio-bus */
VirtioBusState bus; VirtioBusState bus;
bool ioeventfd_disabled;
bool ioeventfd_started;
} VirtIOMMIOProxy; } 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) static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
{ {
VirtIOMMIOProxy *proxy = (VirtIOMMIOProxy *)opaque; 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) { if (proxy->host_features_sel) {
return 0; return 0;
} }
return proxy->host_features; return vdev->host_features;
case VIRTIO_MMIO_QUEUENUMMAX: case VIRTIO_MMIO_QUEUENUMMAX:
if (!virtio_queue_get_num(vdev, vdev->queue_sel)) { if (!virtio_queue_get_num(vdev, vdev->queue_sel)) {
return 0; return 0;
@ -237,7 +326,7 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
proxy->guest_page_shift); proxy->guest_page_shift);
break; break;
case VIRTIO_MMIO_QUEUESEL: case VIRTIO_MMIO_QUEUESEL:
if (value < VIRTIO_PCI_QUEUE_MAX) { if (value < VIRTIO_QUEUE_MAX) {
vdev->queue_sel = value; vdev->queue_sel = value;
} }
break; break;
@ -257,7 +346,7 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
} }
break; break;
case VIRTIO_MMIO_QUEUENOTIFY: case VIRTIO_MMIO_QUEUENOTIFY:
if (value < VIRTIO_PCI_QUEUE_MAX) { if (value < VIRTIO_QUEUE_MAX) {
virtio_queue_notify(vdev, value); virtio_queue_notify(vdev, value);
} }
break; break;
@ -266,7 +355,16 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
virtio_update_irq(vdev); virtio_update_irq(vdev);
break; break;
case VIRTIO_MMIO_STATUS: case VIRTIO_MMIO_STATUS:
if (!(value & VIRTIO_CONFIG_S_DRIVER_OK)) {
virtio_mmio_stop_ioeventfd(proxy);
}
virtio_set_status(vdev, value & 0xff); virtio_set_status(vdev, value & 0xff);
if (value & VIRTIO_CONFIG_S_DRIVER_OK) {
virtio_mmio_start_ioeventfd(proxy);
}
if (vdev->status == 0) { if (vdev->status == 0) {
virtio_reset(vdev); virtio_reset(vdev);
} }
@ -306,13 +404,6 @@ static void virtio_mmio_update_irq(DeviceState *opaque, uint16_t vector)
qemu_set_irq(proxy->irq, level); 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) static int virtio_mmio_load_config(DeviceState *opaque, QEMUFile *f)
{ {
VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque); VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
@ -336,23 +427,93 @@ static void virtio_mmio_reset(DeviceState *d)
{ {
VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d); VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
virtio_mmio_stop_ioeventfd(proxy);
virtio_bus_reset(&proxy->bus); virtio_bus_reset(&proxy->bus);
proxy->host_features_sel = 0; proxy->host_features_sel = 0;
proxy->guest_features_sel = 0; proxy->guest_features_sel = 0;
proxy->guest_page_shift = 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);
/* This is called by virtio-bus just after the device is plugged. */ if (assign) {
static void virtio_mmio_device_plugged(DeviceState *opaque) 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);
}
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); VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
virtio_add_feature(&proxy->host_features, VIRTIO_F_NOTIFY_ON_EMPTY); /* Stop using ioeventfd for virtqueue kick if the device starts using host
proxy->host_features = virtio_bus_get_vdev_features(&proxy->bus, * notifiers. This makes it easy to avoid stepping on each others' toes.
proxy->host_features); */
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) static void virtio_mmio_realizefn(DeviceState *d, Error **errp)
{ {
@ -367,16 +528,10 @@ static void virtio_mmio_realizefn(DeviceState *d, Error **errp)
sysbus_init_mmio(sbd, &proxy->iomem); 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) static void virtio_mmio_class_init(ObjectClass *klass, void *data)
{ {
DeviceClass *dc = DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass);
dc->props = virtio_mmio_properties;
dc->realize = virtio_mmio_realizefn; dc->realize = virtio_mmio_realizefn;
dc->reset = virtio_mmio_reset; dc->reset = virtio_mmio_reset;
set_bit(DEVICE_CATEGORY_MISC, dc->categories); 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->notify = virtio_mmio_update_irq;
k->save_config = virtio_mmio_save_config; k->save_config = virtio_mmio_save_config;
k->load_config = virtio_mmio_load_config; k->load_config = virtio_mmio_load_config;
k->get_features = virtio_mmio_get_features; k->set_host_notifier = virtio_mmio_set_host_notifier;
k->device_plugged = virtio_mmio_device_plugged; k->set_guest_notifiers = virtio_mmio_set_guest_notifiers;
k->has_variable_vring_alignment = true; k->has_variable_vring_alignment = true;
bus_class->max_dev = 1; bus_class->max_dev = 1;
} }

View File

@ -171,7 +171,7 @@ static void virtio_pci_start_ioeventfd(VirtIOPCIProxy *proxy)
return; 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)) { if (!virtio_queue_get_num(vdev, n)) {
continue; continue;
} }
@ -207,7 +207,7 @@ static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy)
return; 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)) { if (!virtio_queue_get_num(vdev, n)) {
continue; 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); virtio_queue_set_addr(vdev, vdev->queue_sel, pa);
break; break;
case VIRTIO_PCI_QUEUE_SEL: case VIRTIO_PCI_QUEUE_SEL:
if (val < VIRTIO_PCI_QUEUE_MAX) if (val < VIRTIO_QUEUE_MAX)
vdev->queue_sel = val; vdev->queue_sel = val;
break; break;
case VIRTIO_PCI_QUEUE_NOTIFY: case VIRTIO_PCI_QUEUE_NOTIFY:
if (val < VIRTIO_PCI_QUEUE_MAX) { if (val < VIRTIO_QUEUE_MAX) {
virtio_queue_notify(vdev, val); virtio_queue_notify(vdev, val);
} }
break; break;
@ -306,7 +306,7 @@ static uint32_t virtio_ioport_read(VirtIOPCIProxy *proxy, uint32_t addr)
switch (addr) { switch (addr) {
case VIRTIO_PCI_HOST_FEATURES: case VIRTIO_PCI_HOST_FEATURES:
ret = proxy->host_features; ret = vdev->host_features;
break; break;
case VIRTIO_PCI_GUEST_FEATURES: case VIRTIO_PCI_GUEST_FEATURES:
ret = vdev->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, static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy,
unsigned int queue_no, unsigned int queue_no,
unsigned int vector, 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) && bool with_irqfd = msix_enabled(&proxy->pci_dev) &&
kvm_msi_via_irqfd_enabled(); 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 /* When deassigning, pass a consistent nvqs value
* to avoid leaking notifiers. * 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. */ /* 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); VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
VirtioBusState *bus = &proxy->bus; VirtioBusState *bus = &proxy->bus;
uint8_t *config; uint8_t *config;
uint32_t size; uint32_t size;
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
config = proxy->pci_dev.config; config = proxy->pci_dev.config;
if (proxy->class_code) { if (proxy->class_code) {
@ -958,10 +953,7 @@ static void virtio_pci_device_plugged(DeviceState *d)
proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD; proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
} }
virtio_add_feature(&proxy->host_features, VIRTIO_F_NOTIFY_ON_EMPTY); virtio_add_feature(&vdev->host_features, VIRTIO_F_BAD_FEATURE);
virtio_add_feature(&proxy->host_features, VIRTIO_F_BAD_FEATURE);
proxy->host_features = virtio_bus_get_vdev_features(bus,
proxy->host_features);
} }
static void virtio_pci_device_unplugged(DeviceState *d) static void virtio_pci_device_unplugged(DeviceState *d)
@ -999,7 +991,6 @@ static void virtio_pci_reset(DeviceState *qdev)
static Property virtio_pci_properties[] = { static Property virtio_pci_properties[] = {
DEFINE_PROP_BIT("virtio-pci-bus-master-bug-migration", VirtIOPCIProxy, flags, DEFINE_PROP_BIT("virtio-pci-bus-master-bug-migration", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT, false), VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT, false),
DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };
@ -1207,32 +1198,6 @@ static const TypeInfo vhost_scsi_pci_info = {
/* virtio-balloon-pci */ /* 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[] = { static Property virtio_balloon_pci_properties[] = {
DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0), DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
DEFINE_PROP_END_OF_LIST(), 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) static void virtio_balloon_pci_instance_init(Object *obj)
{ {
VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(obj); VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(obj);
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
TYPE_VIRTIO_BALLOON); TYPE_VIRTIO_BALLOON);
object_property_add(obj, "guest-stats", "guest statistics", object_property_add_alias(obj, "guest-stats", OBJECT(&dev->vdev),
balloon_pci_stats_get_all, NULL, NULL, dev, "guest-stats", &error_abort);
NULL); object_property_add_alias(obj, "guest-stats-polling-interval",
OBJECT(&dev->vdev),
object_property_add(obj, "guest-stats-polling-interval", "int", "guest-stats-polling-interval", &error_abort);
balloon_pci_stats_get_poll_interval,
balloon_pci_stats_set_poll_interval,
NULL, dev, NULL);
} }
static const TypeInfo virtio_balloon_pci_info = { 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->load_config = virtio_pci_load_config;
k->save_queue = virtio_pci_save_queue; k->save_queue = virtio_pci_save_queue;
k->load_queue = virtio_pci_load_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->query_guest_notifiers = virtio_pci_query_guest_notifiers;
k->set_host_notifier = virtio_pci_set_host_notifier; k->set_host_notifier = virtio_pci_set_host_notifier;
k->set_guest_notifiers = virtio_pci_set_guest_notifiers; k->set_guest_notifiers = virtio_pci_set_guest_notifiers;

View File

@ -91,7 +91,6 @@ struct VirtIOPCIProxy {
uint32_t flags; uint32_t flags;
uint32_t class_code; uint32_t class_code;
uint32_t nvectors; uint32_t nvectors;
uint32_t host_features;
bool ioeventfd_disabled; bool ioeventfd_disabled;
bool ioeventfd_started; bool ioeventfd_started;
VirtIOIRQFD *vector_irqfd; VirtIOIRQFD *vector_irqfd;

View File

@ -99,7 +99,7 @@ static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
virtio_rng_process(vrng); 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; return f;
} }

View File

@ -600,7 +600,7 @@ void virtio_reset(void *opaque)
vdev->config_vector = VIRTIO_NO_VECTOR; vdev->config_vector = VIRTIO_NO_VECTOR;
virtio_notify_vector(vdev, vdev->config_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.desc = 0;
vdev->vq[i].vring.avail = 0; vdev->vq[i].vring.avail = 0;
vdev->vq[i].vring.used = 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; 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) int virtio_queue_get_id(VirtQueue *vq)
{ {
VirtIODevice *vdev = vq->vdev; 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]; 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) 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; VIRTIO_NO_VECTOR;
} }
@ -793,7 +806,7 @@ void virtio_queue_set_vector(VirtIODevice *vdev, int n, uint16_t vector)
{ {
VirtQueue *vq = &vdev->vq[n]; VirtQueue *vq = &vdev->vq[n];
if (n < VIRTIO_PCI_QUEUE_MAX) { if (n < VIRTIO_QUEUE_MAX) {
if (vdev->vector_queues && if (vdev->vector_queues &&
vdev->vq[n].vector != VIRTIO_NO_VECTOR) { vdev->vq[n].vector != VIRTIO_NO_VECTOR) {
QLIST_REMOVE(vq, node); QLIST_REMOVE(vq, node);
@ -811,12 +824,12 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
{ {
int i; 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) if (vdev->vq[i].vring.num == 0)
break; break;
} }
if (i == VIRTIO_PCI_QUEUE_MAX || queue_size > VIRTQUEUE_MAX_SIZE) if (i == VIRTIO_QUEUE_MAX || queue_size > VIRTQUEUE_MAX_SIZE)
abort(); abort();
vdev->vq[i].vring.num = queue_size; 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) void virtio_del_queue(VirtIODevice *vdev, int n)
{ {
if (n < 0 || n >= VIRTIO_PCI_QUEUE_MAX) { if (n < 0 || n >= VIRTIO_QUEUE_MAX) {
abort(); abort();
} }
@ -893,6 +906,13 @@ static bool virtio_device_endian_needed(void *opaque)
return vdev->device_endian != virtio_default_endian(); 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 = { static const VMStateDescription vmstate_virtio_device_endian = {
.name = "virtio/device_endian", .name = "virtio/device_endian",
.version_id = 1, .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 = { static const VMStateDescription vmstate_virtio = {
.name = "virtio", .name = "virtio",
.version_id = 1, .version_id = 1,
@ -916,6 +946,10 @@ static const VMStateDescription vmstate_virtio = {
.vmsd = &vmstate_virtio_device_endian, .vmsd = &vmstate_virtio_device_endian,
.needed = &virtio_device_endian_needed .needed = &virtio_device_endian_needed
}, },
{
.vmsd = &vmstate_virtio_64bit_features,
.needed = &virtio_64bit_features_needed
},
{ 0 } { 0 }
} }
}; };
@ -925,6 +959,7 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f)
BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
uint32_t guest_features_lo = (vdev->guest_features & 0xffffffff);
int i; int i;
if (k->save_config) { 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->status);
qemu_put_8s(f, &vdev->isr); qemu_put_8s(f, &vdev->isr);
qemu_put_be16s(f, &vdev->queue_sel); 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_be32(f, vdev->config_len);
qemu_put_buffer(f, vdev->config, 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) if (vdev->vq[i].vring.num == 0)
break; break;
} }
qemu_put_be32(f, i); 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) if (vdev->vq[i].vring.num == 0)
break; break;
@ -970,13 +1005,10 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f)
int virtio_set_features(VirtIODevice *vdev, uint32_t val) 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); VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
uint32_t supported_features = vbusk->get_features(qbus->parent); bool bad = (val & ~(vdev->host_features)) != 0;
bool bad = (val & ~supported_features) != 0;
val &= supported_features; val &= vdev->host_features;
if (k->set_features) { if (k->set_features) {
k->set_features(vdev, val); k->set_features(vdev, val);
} }
@ -990,7 +1022,6 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
int32_t config_len; int32_t config_len;
uint32_t num; uint32_t num;
uint32_t features; uint32_t features;
uint32_t supported_features;
BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); 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->status);
qemu_get_8s(f, &vdev->isr); qemu_get_8s(f, &vdev->isr);
qemu_get_be16s(f, &vdev->queue_sel); qemu_get_be16s(f, &vdev->queue_sel);
if (vdev->queue_sel >= VIRTIO_PCI_QUEUE_MAX) { if (vdev->queue_sel >= VIRTIO_QUEUE_MAX) {
return -1; return -1;
} }
qemu_get_be32s(f, &features); 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); 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); 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); error_report("Invalid number of PCI queues: 0x%x", num);
return -1; return -1;
} }
@ -1086,6 +1111,28 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
vdev->device_endian = virtio_default_endian(); 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++) { for (i = 0; i < num; i++) {
if (vdev->vq[i].pa) { if (vdev->vq[i].pa) {
uint16_t nheads; uint16_t nheads;
@ -1163,9 +1210,9 @@ void virtio_init(VirtIODevice *vdev, const char *name,
vdev->isr = 0; vdev->isr = 0;
vdev->queue_sel = 0; vdev->queue_sel = 0;
vdev->config_vector = VIRTIO_NO_VECTOR; 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(); 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].vector = VIRTIO_NO_VECTOR;
vdev->vq[i].vdev = vdev; vdev->vq[i].vdev = vdev;
vdev->vq[i].queue_index = i; vdev->vq[i].queue_index = i;
@ -1328,7 +1375,12 @@ static void virtio_device_realize(DeviceState *dev, Error **errp)
return; 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) 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; 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) static void virtio_device_class_init(ObjectClass *klass, void *data)
{ {
/* Set the default value here. */ /* 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->realize = virtio_device_realize;
dc->unrealize = virtio_device_unrealize; dc->unrealize = virtio_device_unrealize;
dc->bus_type = TYPE_VIRTIO_BUS; dc->bus_type = TYPE_VIRTIO_BUS;
dc->props = virtio_properties;
} }
static const TypeInfo virtio_device_info = { static const TypeInfo virtio_device_info = {

View File

@ -33,6 +33,8 @@ typedef struct MemTxAttrs {
unsigned int secure:1; unsigned int secure:1;
/* Memory access is usermode (unprivileged) */ /* Memory access is usermode (unprivileged) */
unsigned int user:1; unsigned int user:1;
/* Stream ID (for MSI for example) */
unsigned int stream_id:16;
} MemTxAttrs; } MemTxAttrs;
/* Bus masters which don't specify any attributes will get this, /* Bus masters which don't specify any attributes will get this,

View File

@ -450,6 +450,9 @@ typedef struct AcpiTableMcfg AcpiTableMcfg;
/* /*
* TCPA Description Table * TCPA Description Table
*
* Following Level 00, Rev 00.37 of specs:
* http://www.trustedcomputinggroup.org/resources/tcg_acpi_specification
*/ */
struct Acpi20Tcpa { struct Acpi20Tcpa {
ACPI_TABLE_HEADER_DEF /* ACPI common table header */ ACPI_TABLE_HEADER_DEF /* ACPI common table header */
@ -459,6 +462,21 @@ struct Acpi20Tcpa {
} QEMU_PACKED; } QEMU_PACKED;
typedef struct Acpi20Tcpa Acpi20Tcpa; 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 */ /* DMAR - DMA Remapping table r2.2 */
struct AcpiTableDmar { struct AcpiTableDmar {
ACPI_TABLE_HEADER_DEF ACPI_TABLE_HEADER_DEF

View File

@ -202,6 +202,12 @@ Aml *aml_arg(int pos);
Aml *aml_store(Aml *val, Aml *target); Aml *aml_store(Aml *val, Aml *target);
Aml *aml_and(Aml *arg1, Aml *arg2); Aml *aml_and(Aml *arg1, Aml *arg2);
Aml *aml_or(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_notify(Aml *arg1, Aml *arg2);
Aml *aml_call1(const char *method, Aml *arg1); Aml *aml_call1(const char *method, Aml *arg1);
Aml *aml_call2(const char *method, Aml *arg1, Aml *arg2); 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_method(const char *name, int arg_count);
Aml *aml_if(Aml *predicate); Aml *aml_if(Aml *predicate);
Aml *aml_else(void); Aml *aml_else(void);
Aml *aml_while(Aml *predicate);
Aml *aml_package(uint8_t num_elements); Aml *aml_package(uint8_t num_elements);
Aml *aml_buffer(int buffer_size, uint8_t *byte_list); Aml *aml_buffer(int buffer_size, uint8_t *byte_list);
Aml *aml_resource_template(void); Aml *aml_resource_template(void);

View File

@ -26,4 +26,9 @@
#define TPM_TCPA_ACPI_CLASS_CLIENT 0 #define TPM_TCPA_ACPI_CLASS_CLIENT 0
#define TPM_TCPA_ACPI_CLASS_SERVER 1 #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 */ #endif /* HW_ACPI_TPM_H */

View File

@ -19,31 +19,18 @@ typedef void QEMUMachineHotAddCPUFunc(const int64_t id, Error **errp);
typedef int QEMUMachineGetKvmtypeFunc(const char *arg); typedef int QEMUMachineGetKvmtypeFunc(const char *arg);
struct QEMUMachine { struct QEMUMachine {
const char *family; /* NULL iff @name identifies a standalone machtype */
const char *name; const char *name;
const char *alias;
const char *desc; const char *desc;
QEMUMachineInitFunc *init; QEMUMachineInitFunc *init;
QEMUMachineResetFunc *reset;
QEMUMachineHotAddCPUFunc *hot_add_cpu;
QEMUMachineGetKvmtypeFunc *kvm_type; QEMUMachineGetKvmtypeFunc *kvm_type;
BlockInterfaceType block_default_type; BlockInterfaceType block_default_type;
int units_per_default_bus;
int max_cpus; int max_cpus;
unsigned int no_serial:1, unsigned int
no_parallel:1,
use_virtcon:1,
use_sclp:1,
no_floppy:1,
no_cdrom:1,
no_sdcard:1, no_sdcard:1,
has_dynamic_sysbus:1; has_dynamic_sysbus:1;
int is_default; int is_default;
const char *default_machine_opts; const char *default_machine_opts;
const char *default_boot_order; 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, void memory_region_allocate_system_memory(MemoryRegion *mr, Object *owner,

View File

@ -1,6 +1,12 @@
#ifndef HW_COMPAT_H #ifndef HW_COMPAT_H
#define HW_COMPAT_H #define HW_COMPAT_H
#define HW_COMPAT_2_3 \
/* empty */
#define HW_COMPAT_2_2 \
/* empty */
#define HW_COMPAT_2_1 \ #define HW_COMPAT_2_1 \
{\ {\
.driver = "intel-hda",\ .driver = "intel-hda",\
@ -30,6 +36,6 @@
.driver = "virtio-pci",\ .driver = "virtio-pci",\
.property = "virtio-pci-bus-master-bug-migration",\ .property = "virtio-pci-bus-master-bug-migration",\
.value = "on",\ .value = "on",\
} },
#endif /* HW_COMPAT_H */ #endif /* HW_COMPAT_H */

View File

@ -73,8 +73,6 @@ typedef struct PCMachineClass PCMachineClass;
#define PC_MACHINE_CLASS(klass) \ #define PC_MACHINE_CLASS(klass) \
OBJECT_CLASS_CHECK(PCMachineClass, (klass), TYPE_PC_MACHINE) OBJECT_CLASS_CHECK(PCMachineClass, (klass), TYPE_PC_MACHINE)
void qemu_register_pc_machine(QEMUMachine *m);
/* PC-style peripherals (also used by other machines). */ /* PC-style peripherals (also used by other machines). */
typedef struct PcPciInfo { typedef struct PcPciInfo {
@ -199,6 +197,7 @@ qemu_irq *pc_allocate_cpu_irq(void);
DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus); DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus);
void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
ISADevice **rtc_state, ISADevice **rtc_state,
bool create_fdctrl,
ISADevice **floppy, ISADevice **floppy,
bool no_vmport, bool no_vmport,
uint32 hpet_irqs); uint32 hpet_irqs);
@ -295,8 +294,19 @@ int e820_add_entry(uint64_t, uint64_t, uint32_t);
int e820_get_num_entries(void); int e820_get_num_entries(void);
bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *); 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 \ #define PC_COMPAT_2_0 \
HW_COMPAT_2_1, \ PC_COMPAT_2_1 \
{\ {\
.driver = "virtio-scsi-pci",\ .driver = "virtio-scsi-pci",\
.property = "any_layout",\ .property = "any_layout",\
@ -353,10 +363,10 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
.driver = "ioh3420",\ .driver = "ioh3420",\
.property = COMPAT_PROP_PCP,\ .property = COMPAT_PROP_PCP,\
.value = "off",\ .value = "off",\
} },
#define PC_COMPAT_1_7 \ #define PC_COMPAT_1_7 \
PC_COMPAT_2_0, \ PC_COMPAT_2_0 \
{\ {\
.driver = TYPE_USB_DEVICE,\ .driver = TYPE_USB_DEVICE,\
.property = "msos-desc",\ .property = "msos-desc",\
@ -371,10 +381,10 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
.driver = "hpet",\ .driver = "hpet",\
.property = HPET_INTCAP,\ .property = HPET_INTCAP,\
.value = stringify(4),\ .value = stringify(4),\
} },
#define PC_COMPAT_1_6 \ #define PC_COMPAT_1_6 \
PC_COMPAT_1_7, \ PC_COMPAT_1_7 \
{\ {\
.driver = "e1000",\ .driver = "e1000",\
.property = "mitigation",\ .property = "mitigation",\
@ -395,10 +405,10 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
.driver = "q35-pcihost",\ .driver = "q35-pcihost",\
.property = "short_root_bus",\ .property = "short_root_bus",\
.value = stringify(1),\ .value = stringify(1),\
} },
#define PC_COMPAT_1_5 \ #define PC_COMPAT_1_5 \
PC_COMPAT_1_6, \ PC_COMPAT_1_6 \
{\ {\
.driver = "Conroe-" TYPE_X86_CPU,\ .driver = "Conroe-" TYPE_X86_CPU,\
.property = "model",\ .property = "model",\
@ -439,10 +449,10 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
.driver = "q35-pcihost",\ .driver = "q35-pcihost",\
.property = "short_root_bus",\ .property = "short_root_bus",\
.value = stringify(0),\ .value = stringify(0),\
} },
#define PC_COMPAT_1_4 \ #define PC_COMPAT_1_4 \
PC_COMPAT_1_5, \ PC_COMPAT_1_5 \
{\ {\
.driver = "scsi-hd",\ .driver = "scsi-hd",\
.property = "discard_granularity",\ .property = "discard_granularity",\
@ -504,14 +514,45 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
.driver = "486-" TYPE_X86_CPU,\ .driver = "486-" TYPE_X86_CPU,\
.property = "model",\ .property = "model",\
.value = stringify(0),\ .value = stringify(0),\
},
static inline void pc_common_machine_options(MachineClass *m)
{
m->default_boot_order = "cad";
} }
#define PC_COMMON_MACHINE_OPTIONS \ static inline void pc_default_machine_options(MachineClass *m)
.default_boot_order = "cad" {
pc_common_machine_options(m);
m->hot_add_cpu = pc_hot_add_cpu;
m->max_cpus = 255;
}
#define PC_DEFAULT_MACHINE_OPTIONS \ #define DEFINE_PC_MACHINE(suffix, namestr, initfn, optsfn) \
PC_COMMON_MACHINE_OPTIONS, \ static void pc_machine_##suffix##_class_init(ObjectClass *oc, void *data) \
.hot_add_cpu = pc_hot_add_cpu, \ { \
.max_cpus = 255 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 #endif

View File

@ -39,6 +39,7 @@ int msi_init(struct PCIDevice *dev, uint8_t offset,
void msi_uninit(struct PCIDevice *dev); void msi_uninit(struct PCIDevice *dev);
void msi_reset(PCIDevice *dev); void msi_reset(PCIDevice *dev);
void msi_notify(PCIDevice *dev, unsigned int vector); 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); void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len);
unsigned int msi_nr_vectors_allocated(const PCIDevice *dev); unsigned int msi_nr_vectors_allocated(const PCIDevice *dev);

View File

@ -6,6 +6,7 @@
/*** qdev-properties.c ***/ /*** qdev-properties.c ***/
extern PropertyInfo qdev_prop_bit; extern PropertyInfo qdev_prop_bit;
extern PropertyInfo qdev_prop_bit64;
extern PropertyInfo qdev_prop_bool; extern PropertyInfo qdev_prop_bool;
extern PropertyInfo qdev_prop_uint8; extern PropertyInfo qdev_prop_uint8;
extern PropertyInfo qdev_prop_uint16; extern PropertyInfo qdev_prop_uint16;
@ -50,6 +51,15 @@ extern PropertyInfo qdev_prop_arraylen;
.qtype = QTYPE_QBOOL, \ .qtype = QTYPE_QBOOL, \
.defval = (bool)_defval, \ .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) { \ #define DEFINE_PROP_BOOL(_name, _state, _field, _defval) { \
.name = (_name), \ .name = (_name), \

View File

@ -17,10 +17,13 @@
#include "hw/s390x/adapter.h" #include "hw/s390x/adapter.h"
#include "hw/virtio/virtio.h" #include "hw/virtio/virtio.h"
#define ADAPTER_ROUTES_MAX_GSI 64
#define VIRTIO_CCW_QUEUE_MAX ADAPTER_ROUTES_MAX_GSI
typedef struct AdapterRoutes { typedef struct AdapterRoutes {
AdapterInfo adapter; AdapterInfo adapter;
int num_routes; int num_routes;
int gsi[VIRTIO_PCI_QUEUE_MAX]; int gsi[ADAPTER_ROUTES_MAX_GSI];
} AdapterRoutes; } AdapterRoutes;
#define TYPE_S390_FLIC_COMMON "s390-flic" #define TYPE_S390_FLIC_COMMON "s390-flic"

View File

@ -47,7 +47,6 @@ typedef struct VirtioBusClass {
int (*load_config)(DeviceState *d, QEMUFile *f); int (*load_config)(DeviceState *d, QEMUFile *f);
int (*load_queue)(DeviceState *d, int n, QEMUFile *f); int (*load_queue)(DeviceState *d, int n, QEMUFile *f);
int (*load_done)(DeviceState *d, QEMUFile *f); int (*load_done)(DeviceState *d, QEMUFile *f);
unsigned (*get_features)(DeviceState *d);
bool (*query_guest_notifiers)(DeviceState *d); bool (*query_guest_notifiers)(DeviceState *d);
int (*set_guest_notifiers)(DeviceState *d, int nvqs, bool assign); int (*set_guest_notifiers)(DeviceState *d, int nvqs, bool assign);
int (*set_host_notifier)(DeviceState *d, int n, bool assigned); int (*set_host_notifier)(DeviceState *d, int n, bool assigned);
@ -56,7 +55,7 @@ typedef struct VirtioBusClass {
* transport independent init function. * transport independent init function.
* This is called by virtio-bus just after the device is plugged. * 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. * transport independent exit function.
* This is called by virtio-bus just before the device is unplugged. * This is called by virtio-bus just before the device is unplugged.
@ -75,7 +74,7 @@ struct VirtioBusState {
BusState parent_obj; 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_reset(VirtioBusState *bus);
void virtio_bus_device_unplugged(VirtIODevice *bus); void virtio_bus_device_unplugged(VirtIODevice *bus);
/* Get the device id of the plugged device. */ /* Get the device id of the plugged device. */

View File

@ -48,7 +48,7 @@ typedef struct VirtQueueElement
struct iovec out_sg[VIRTQUEUE_MAX_SIZE]; struct iovec out_sg[VIRTQUEUE_MAX_SIZE];
} VirtQueueElement; } VirtQueueElement;
#define VIRTIO_PCI_QUEUE_MAX 64 #define VIRTIO_QUEUE_MAX 1024
#define VIRTIO_NO_VECTOR 0xffff #define VIRTIO_NO_VECTOR 0xffff
@ -73,7 +73,8 @@ struct VirtIODevice
uint8_t status; uint8_t status;
uint8_t isr; uint8_t isr;
uint16_t queue_sel; uint16_t queue_sel;
uint32_t guest_features; uint64_t guest_features;
uint64_t host_features;
size_t config_len; size_t config_len;
void *config; void *config;
uint16_t config_vector; uint16_t config_vector;
@ -95,8 +96,8 @@ typedef struct VirtioDeviceClass {
/* This is what a VirtioDevice must implement */ /* This is what a VirtioDevice must implement */
DeviceRealize realize; DeviceRealize realize;
DeviceUnrealize unrealize; DeviceUnrealize unrealize;
uint32_t (*get_features)(VirtIODevice *vdev, uint32_t requested_features); uint64_t (*get_features)(VirtIODevice *vdev, uint64_t requested_features);
uint32_t (*bad_features)(VirtIODevice *vdev); uint64_t (*bad_features)(VirtIODevice *vdev);
void (*set_features)(VirtIODevice *vdev, uint32_t val); void (*set_features)(VirtIODevice *vdev, uint32_t val);
void (*get_config)(VirtIODevice *vdev, uint8_t *config); void (*get_config)(VirtIODevice *vdev, uint8_t *config);
void (*set_config)(VirtIODevice *vdev, const 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); hwaddr virtio_queue_get_addr(VirtIODevice *vdev, int n);
void virtio_queue_set_num(VirtIODevice *vdev, int n, int num); void virtio_queue_set_num(VirtIODevice *vdev, int n, int num);
int virtio_queue_get_num(VirtIODevice *vdev, int n); 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_set_align(VirtIODevice *vdev, int n, int align);
void virtio_queue_notify(VirtIODevice *vdev, int n); void virtio_queue_notify(VirtIODevice *vdev, int n);
uint16_t virtio_queue_vector(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; typedef struct VirtIORNGConf VirtIORNGConf;
#define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \ #define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \
DEFINE_PROP_BIT("indirect_desc", _state, _field, \ DEFINE_PROP_BIT64("indirect_desc", _state, _field, \
VIRTIO_RING_F_INDIRECT_DESC, true), \ VIRTIO_RING_F_INDIRECT_DESC, true), \
DEFINE_PROP_BIT("event_idx", _state, _field, \ DEFINE_PROP_BIT64("event_idx", _state, _field, \
VIRTIO_RING_F_EVENT_IDX, true) 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_desc_addr(VirtIODevice *vdev, int n);
hwaddr virtio_queue_get_avail_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_first_queue(VirtIODevice *vdev, uint16_t vector);
VirtQueue *virtio_vector_next_queue(VirtQueue *vq); 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); *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); *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)); return !!(features & (1 << fbit));
} }

View File

@ -20,11 +20,24 @@ int tpm_config_parse(QemuOptsList *opts_list, const char *optarg);
int tpm_init(void); int tpm_init(void);
void tpm_cleanup(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" #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 */ #endif /* QEMU_TPM_H */

View File

@ -88,6 +88,10 @@ struct TPMDriverOps {
void (*cancel_cmd)(TPMBackend *t); void (*cancel_cmd)(TPMBackend *t);
bool (*get_tpm_established_flag)(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);
}; };
@ -191,6 +195,15 @@ void tpm_backend_cancel_cmd(TPMBackend *s);
*/ */
bool tpm_backend_get_tpm_established_flag(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: * tpm_backend_open:
* @s: the backend to open * @s: the backend to open
@ -201,6 +214,16 @@ bool tpm_backend_get_tpm_established_flag(TPMBackend *s);
*/ */
void tpm_backend_open(TPMBackend *s, Error **errp); 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); TPMBackend *qemu_find_tpm(const char *id);
const TPMDriverOps *tpm_get_backend_driver(const char *type); const TPMDriverOps *tpm_get_backend_driver(const char *type);

View File

@ -121,35 +121,39 @@ static void net_vhost_user_event(void *opaque, int event)
case CHR_EVENT_OPENED: case CHR_EVENT_OPENED:
vhost_user_start(s); vhost_user_start(s);
net_vhost_link_down(s, false); 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; break;
case CHR_EVENT_CLOSED: case CHR_EVENT_CLOSED:
net_vhost_link_down(s, true); net_vhost_link_down(s, true);
vhost_user_stop(s); vhost_user_stop(s);
error_report("chardev \"%s\" went down", s->chr->label); error_report("chardev \"%s\" went down", s->nc.info_str);
break; break;
} }
} }
static int net_vhost_user_init(NetClientState *peer, const char *device, 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; NetClientState *nc;
VhostUserState *s; VhostUserState *s;
int i;
for (i = 0; i < queues; i++) {
nc = qemu_new_net_client(&net_vhost_user_info, peer, device, name); nc = qemu_new_net_client(&net_vhost_user_info, peer, device, name);
snprintf(nc->info_str, sizeof(nc->info_str), "vhost-user to %s", snprintf(nc->info_str, sizeof(nc->info_str), "vhost-user%d to %s",
chr->label); i, chr->label);
s = DO_UPCAST(VhostUserState, nc, nc); s = DO_UPCAST(VhostUserState, nc, nc);
/* We don't provide a receive callback */ /* We don't provide a receive callback */
s->nc.receive_disabled = 1; s->nc.receive_disabled = 1;
s->chr = chr; s->chr = chr;
s->nc.queue_index = i;
qemu_chr_add_handlers(s->chr, NULL, NULL, net_vhost_user_event, s); qemu_chr_add_handlers(s->chr, NULL, NULL, net_vhost_user_event, s);
}
return 0; return 0;
} }
@ -226,6 +230,7 @@ int net_init_vhost_user(const NetClientOptions *opts, const char *name,
NetClientState *peer, Error **errp) NetClientState *peer, Error **errp)
{ {
/* FIXME error_setg(errp, ...) on failure */ /* FIXME error_setg(errp, ...) on failure */
uint32_t queues;
const NetdevVhostUserOptions *vhost_user_opts; const NetdevVhostUserOptions *vhost_user_opts;
CharDriverState *chr; CharDriverState *chr;
@ -244,6 +249,12 @@ int net_init_vhost_user(const NetClientOptions *opts, const char *name,
return -1; return -1;
} }
/* number of queues for multiqueue */
return net_vhost_user_init(peer, "vhost_user", name, chr); if (vhost_user_opts->has_queues) {
queues = vhost_user_opts->queues;
} else {
queues = 1;
}
return net_vhost_user_init(peer, "vhost_user", name, chr, queues);
} }

View File

@ -2444,12 +2444,16 @@
# #
# @vhostforce: #optional vhost on for non-MSIX virtio guests (default: false). # @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 # Since 2.1
## ##
{ 'struct': 'NetdevVhostUserOptions', { 'struct': 'NetdevVhostUserOptions',
'data': { 'data': {
'chardev': 'str', 'chardev': 'str',
'*vhostforce': 'bool' } } '*vhostforce': 'bool',
'*queues': 'uint32' } }
## ##
# @NetClientOptions # @NetClientOptions

View File

@ -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 netdev. @code{-net} and @code{-device} with parameter @option{vlan} create the
required hub automatically. 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 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 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 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 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:
@example @example

15
vl.c
View File

@ -1314,32 +1314,17 @@ static void machine_class_init(ObjectClass *oc, void *data)
{ {
MachineClass *mc = MACHINE_CLASS(oc); MachineClass *mc = MACHINE_CLASS(oc);
QEMUMachine *qm = data; QEMUMachine *qm = data;
mc->family = qm->family;
mc->name = qm->name; mc->name = qm->name;
mc->alias = qm->alias;
mc->desc = qm->desc; mc->desc = qm->desc;
mc->init = qm->init; mc->init = qm->init;
mc->reset = qm->reset;
mc->hot_add_cpu = qm->hot_add_cpu;
mc->kvm_type = qm->kvm_type; mc->kvm_type = qm->kvm_type;
mc->block_default_type = qm->block_default_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->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->no_sdcard = qm->no_sdcard;
mc->has_dynamic_sysbus = qm->has_dynamic_sysbus; mc->has_dynamic_sysbus = qm->has_dynamic_sysbus;
mc->is_default = qm->is_default; mc->is_default = qm->is_default;
mc->default_machine_opts = qm->default_machine_opts; mc->default_machine_opts = qm->default_machine_opts;
mc->default_boot_order = qm->default_boot_order; 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) int qemu_register_machine(QEMUMachine *m)