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