diff options
Diffstat (limited to 'hw')
51 files changed, 2937 insertions, 1319 deletions
diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs index 11c35bcb44..2d46e3789a 100644 --- a/hw/acpi/Makefile.objs +++ b/hw/acpi/Makefile.objs @@ -11,6 +11,7 @@ common-obj-$(call lnot,$(CONFIG_ACPI_X86)) += acpi-stub.o common-obj-y += acpi_interface.o common-obj-y += bios-linker-loader.o common-obj-y += aml-build.o +common-obj-$(CONFIG_TPM) += tpm.o common-obj-$(CONFIG_IPMI) += ipmi.o common-obj-$(call lnot,$(CONFIG_IPMI)) += ipmi-stub.o diff --git a/hw/acpi/core.c b/hw/acpi/core.c index d6f0709691..47877c0ec1 100644 --- a/hw/acpi/core.c +++ b/hw/acpi/core.c @@ -35,14 +35,18 @@ struct acpi_table_header { uint16_t _length; /* our length, not actual part of the hdr */ /* allows easier parsing for fw_cfg clients */ - char sig[4]; /* ACPI signature (4 ASCII characters) */ + char sig[4] + QEMU_NONSTRING; /* ACPI signature (4 ASCII characters) */ uint32_t length; /* Length of table, in bytes, including header */ uint8_t revision; /* ACPI Specification minor version # */ uint8_t checksum; /* To make sum of entire table == 0 */ - char oem_id[6]; /* OEM identification */ - char oem_table_id[8]; /* OEM table identification */ + char oem_id[6] + QEMU_NONSTRING; /* OEM identification */ + char oem_table_id[8] + QEMU_NONSTRING; /* OEM table identification */ uint32_t oem_revision; /* OEM revision number */ - char asl_compiler_id[4]; /* ASL compiler vendor ID */ + char asl_compiler_id[4] + QEMU_NONSTRING; /* ASL compiler vendor ID */ uint32_t asl_compiler_revision; /* ASL compiler revision number */ } QEMU_PACKED; diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c index 8c7c1013f3..921cad2c5e 100644 --- a/hw/acpi/memory_hotplug.c +++ b/hw/acpi/memory_hotplug.c @@ -686,15 +686,15 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, method = aml_method("_OST", 3, AML_NOTSERIALIZED); s = MEMORY_SLOT_OST_METHOD; - aml_append(method, aml_return(aml_call4( - s, aml_name("_UID"), aml_arg(0), aml_arg(1), aml_arg(2) - ))); + aml_append(method, + aml_call4(s, aml_name("_UID"), aml_arg(0), + aml_arg(1), aml_arg(2))); aml_append(dev, method); method = aml_method("_EJ0", 1, AML_NOTSERIALIZED); s = MEMORY_SLOT_EJECT_METHOD; - aml_append(method, aml_return(aml_call2( - s, aml_name("_UID"), aml_arg(0)))); + aml_append(method, + aml_call2(s, aml_name("_UID"), aml_arg(0))); aml_append(dev, method); aml_append(dev_container, dev); diff --git a/hw/acpi/tpm.c b/hw/acpi/tpm.c new file mode 100644 index 0000000000..b96459e45b --- /dev/null +++ b/hw/acpi/tpm.c @@ -0,0 +1,459 @@ +/* Support for generating ACPI TPM tables + * + * Copyright (C) 2018 IBM, Corp. + * Copyright (C) 2018 Red Hat Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/acpi/tpm.h" + +void tpm_build_ppi_acpi(TPMIf *tpm, Aml *dev) +{ + Aml *method, *field, *ifctx, *ifctx2, *ifctx3, *func_mask, + *not_implemented, *pak, *tpm2, *tpm3, *pprm, *pprq, *zero, *one; + + if (!object_property_get_bool(OBJECT(tpm), "ppi", &error_abort)) { + return; + } + + zero = aml_int(0); + one = aml_int(1); + func_mask = aml_int(TPM_PPI_FUNC_MASK); + not_implemented = aml_int(TPM_PPI_FUNC_NOT_IMPLEMENTED); + + /* + * TPP2 is for the registers that ACPI code used to pass + * the PPI code and parameter (PPRQ, PPRM) to the firmware. + */ + aml_append(dev, + aml_operation_region("TPP2", AML_SYSTEM_MEMORY, + aml_int(TPM_PPI_ADDR_BASE + 0x100), + 0x5A)); + field = aml_field("TPP2", AML_ANY_ACC, AML_NOLOCK, AML_PRESERVE); + aml_append(field, aml_named_field("PPIN", 8)); + aml_append(field, aml_named_field("PPIP", 32)); + aml_append(field, aml_named_field("PPRP", 32)); + aml_append(field, aml_named_field("PPRQ", 32)); + aml_append(field, aml_named_field("PPRM", 32)); + aml_append(field, aml_named_field("LPPR", 32)); + aml_append(dev, field); + pprq = aml_name("PPRQ"); + pprm = aml_name("PPRM"); + + aml_append(dev, + aml_operation_region( + "TPP3", AML_SYSTEM_MEMORY, + aml_int(TPM_PPI_ADDR_BASE + + 0x15a /* movv, docs/specs/tpm.txt */), + 0x1)); + field = aml_field("TPP3", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE); + aml_append(field, aml_named_field("MOVV", 8)); + aml_append(dev, field); + + /* + * DerefOf in Windows is broken with SYSTEM_MEMORY. Use a dynamic + * operation region inside of a method for getting FUNC[op]. + */ + method = aml_method("TPFN", 1, AML_SERIALIZED); + { + Aml *op = aml_arg(0); + ifctx = aml_if(aml_lgreater_equal(op, aml_int(0x100))); + { + aml_append(ifctx, aml_return(zero)); + } + aml_append(method, ifctx); + + aml_append(method, + aml_operation_region("TPP1", AML_SYSTEM_MEMORY, + aml_add(aml_int(TPM_PPI_ADDR_BASE), op, NULL), 0x1)); + field = aml_field("TPP1", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE); + aml_append(field, aml_named_field("TPPF", 8)); + aml_append(method, field); + aml_append(method, aml_return(aml_name("TPPF"))); + } + aml_append(dev, method); + + /* + * Use global TPM2 & TPM3 variables to workaround Windows ACPI bug + * when returning packages. + */ + pak = aml_package(2); + aml_append(pak, zero); + aml_append(pak, zero); + aml_append(dev, aml_name_decl("TPM2", pak)); + tpm2 = aml_name("TPM2"); + + pak = aml_package(3); + aml_append(pak, zero); + aml_append(pak, zero); + aml_append(pak, zero); + aml_append(dev, aml_name_decl("TPM3", pak)); + tpm3 = aml_name("TPM3"); + + method = aml_method("_DSM", 4, AML_SERIALIZED); + { + uint8_t zerobyte[1] = { 0 }; + Aml *function, *arguments, *rev, *op, *op_arg, *op_flags, *uuid; + + uuid = aml_arg(0); + rev = aml_arg(1); + function = aml_arg(2); + arguments = aml_arg(3); + op = aml_local(0); + op_flags = aml_local(1); + + /* Physical Presence Interface */ + ifctx = aml_if( + aml_equal(uuid, + aml_touuid("3DDDFAA6-361B-4EB4-A424-8D10089D1653"))); + { + /* standard DSM query function */ + ifctx2 = aml_if(aml_equal(function, zero)); + { + uint8_t byte_list[2] = { 0xff, 0x01 }; /* functions 1-8 */ + + aml_append(ifctx2, + aml_return(aml_buffer(sizeof(byte_list), + byte_list))); + } + aml_append(ifctx, ifctx2); + + /* + * PPI 1.0: 2.1.1 Get Physical Presence Interface Version + * + * Arg 2 (Integer): Function Index = 1 + * Arg 3 (Package): Arguments = Empty Package + * Returns: Type: String + */ + ifctx2 = aml_if(aml_equal(function, one)); + { + aml_append(ifctx2, aml_return(aml_string("1.3"))); + } + aml_append(ifctx, ifctx2); + + /* + * PPI 1.0: 2.1.3 Submit TPM Operation Request to Pre-OS Environment + * + * Arg 2 (Integer): Function Index = 2 + * Arg 3 (Package): Arguments = Package: Type: Integer + * Operation Value of the Request + * Returns: Type: Integer + * 0: Success + * 1: Operation Value of the Request Not Supported + * 2: General Failure + */ + ifctx2 = aml_if(aml_equal(function, aml_int(2))); + { + /* get opcode */ + aml_append(ifctx2, + aml_store(aml_derefof(aml_index(arguments, + zero)), op)); + + /* get opcode flags */ + aml_append(ifctx2, + aml_store(aml_call1("TPFN", op), op_flags)); + + /* if func[opcode] & TPM_PPI_FUNC_NOT_IMPLEMENTED */ + ifctx3 = aml_if( + aml_equal( + aml_and(op_flags, func_mask, NULL), + not_implemented)); + { + /* 1: Operation Value of the Request Not Supported */ + aml_append(ifctx3, aml_return(one)); + } + aml_append(ifctx2, ifctx3); + + aml_append(ifctx2, aml_store(op, pprq)); + aml_append(ifctx2, aml_store(zero, pprm)); + /* 0: success */ + aml_append(ifctx2, aml_return(zero)); + } + aml_append(ifctx, ifctx2); + + /* + * PPI 1.0: 2.1.4 Get Pending TPM Operation Requested By the OS + * + * Arg 2 (Integer): Function Index = 3 + * Arg 3 (Package): Arguments = Empty Package + * Returns: Type: Package of Integers + * Integer 1: Function Return code + * 0: Success + * 1: General Failure + * Integer 2: Pending operation requested by the OS + * 0: None + * >0: Operation Value of the Pending Request + * Integer 3: Optional argument to pending operation + * requested by the OS + * 0: None + * >0: Argument Value of the Pending Request + */ + ifctx2 = aml_if(aml_equal(function, aml_int(3))); + { + /* + * Revision ID of 1, no integer parameter beyond + * parameter two are expected + */ + ifctx3 = aml_if(aml_equal(rev, one)); + { + /* TPM2[1] = PPRQ */ + aml_append(ifctx3, + aml_store(pprq, aml_index(tpm2, one))); + aml_append(ifctx3, aml_return(tpm2)); + } + aml_append(ifctx2, ifctx3); + + /* + * A return value of {0, 23, 1} indicates that + * operation 23 with argument 1 is pending. + */ + ifctx3 = aml_if(aml_equal(rev, aml_int(2))); + { + /* TPM3[1] = PPRQ */ + aml_append(ifctx3, + aml_store(pprq, aml_index(tpm3, one))); + /* TPM3[2] = PPRM */ + aml_append(ifctx3, + aml_store(pprm, aml_index(tpm3, aml_int(2)))); + aml_append(ifctx3, aml_return(tpm3)); + } + aml_append(ifctx2, ifctx3); + } + aml_append(ifctx, ifctx2); + + /* + * PPI 1.0: 2.1.5 Get Platform-Specific Action to Transition to + * Pre-OS Environment + * + * Arg 2 (Integer): Function Index = 4 + * Arg 3 (Package): Arguments = Empty Package + * Returns: Type: Integer + * 0: None + * 1: Shutdown + * 2: Reboot + * 3: OS Vendor-specific + */ + ifctx2 = aml_if(aml_equal(function, aml_int(4))); + { + /* reboot */ + aml_append(ifctx2, aml_return(aml_int(2))); + } + aml_append(ifctx, ifctx2); + + /* + * PPI 1.0: 2.1.6 Return TPM Operation Response to OS Environment + * + * Arg 2 (Integer): Function Index = 5 + * Arg 3 (Package): Arguments = Empty Package + * Returns: Type: Package of Integer + * Integer 1: Function Return code + * 0: Success + * 1: General Failure + * Integer 2: Most recent operation request + * 0: None + * >0: Operation Value of the most recent request + * Integer 3: Response to the most recent operation request + * 0: Success + * 0x00000001..0x00000FFF: Corresponding TPM + * error code + * 0xFFFFFFF0: User Abort or timeout of dialog + * 0xFFFFFFF1: firmware Failure + */ + ifctx2 = aml_if(aml_equal(function, aml_int(5))); + { + /* TPM3[1] = LPPR */ + aml_append(ifctx2, + aml_store(aml_name("LPPR"), + aml_index(tpm3, one))); + /* TPM3[2] = PPRP */ + aml_append(ifctx2, + aml_store(aml_name("PPRP"), + aml_index(tpm3, aml_int(2)))); + aml_append(ifctx2, aml_return(tpm3)); + } + aml_append(ifctx, ifctx2); + + /* + * PPI 1.0: 2.1.7 Submit preferred user language + * + * Arg 2 (Integer): Function Index = 6 + * Arg 3 (Package): Arguments = String Package + * Preferred language code + * Returns: Type: Integer + * Function Return Code + * 3: Not implemented + */ + ifctx2 = aml_if(aml_equal(function, aml_int(6))); + { + /* 3 = not implemented */ + aml_append(ifctx2, aml_return(aml_int(3))); + } + aml_append(ifctx, ifctx2); + + /* + * PPI 1.1: 2.1.7 Submit TPM Operation Request to + * Pre-OS Environment 2 + * + * Arg 2 (Integer): Function Index = 7 + * Arg 3 (Package): Arguments = Package: Type: Integer + * Integer 1: Operation Value of the Request + * Integer 2: Argument for Operation (optional) + * Returns: Type: Integer + * 0: Success + * 1: Not Implemented + * 2: General Failure + * 3: Operation blocked by current firmware settings + */ + ifctx2 = aml_if(aml_equal(function, aml_int(7))); + { + /* get opcode */ + aml_append(ifctx2, aml_store(aml_derefof(aml_index(arguments, + zero)), + op)); + + /* get opcode flags */ + aml_append(ifctx2, aml_store(aml_call1("TPFN", op), + op_flags)); + /* if func[opcode] & TPM_PPI_FUNC_NOT_IMPLEMENTED */ + ifctx3 = aml_if( + aml_equal( + aml_and(op_flags, func_mask, NULL), + not_implemented)); + { + /* 1: not implemented */ + aml_append(ifctx3, aml_return(one)); + } + aml_append(ifctx2, ifctx3); + + /* if func[opcode] & TPM_PPI_FUNC_BLOCKED */ + ifctx3 = aml_if( + aml_equal( + aml_and(op_flags, func_mask, NULL), + aml_int(TPM_PPI_FUNC_BLOCKED))); + { + /* 3: blocked by firmware */ + aml_append(ifctx3, aml_return(aml_int(3))); + } + aml_append(ifctx2, ifctx3); + + /* revision to integer */ + ifctx3 = aml_if(aml_equal(rev, one)); + { + /* revision 1 */ + /* PPRQ = op */ + aml_append(ifctx3, aml_store(op, pprq)); + /* no argument, PPRM = 0 */ + aml_append(ifctx3, aml_store(zero, pprm)); + } + aml_append(ifctx2, ifctx3); + + ifctx3 = aml_if(aml_equal(rev, aml_int(2))); + { + /* revision 2 */ + /* PPRQ = op */ + op_arg = aml_derefof(aml_index(arguments, one)); + aml_append(ifctx3, aml_store(op, pprq)); + /* PPRM = arg3[1] */ + aml_append(ifctx3, aml_store(op_arg, pprm)); + } + aml_append(ifctx2, ifctx3); + /* 0: success */ + aml_append(ifctx2, aml_return(zero)); + } + aml_append(ifctx, ifctx2); + + /* + * PPI 1.1: 2.1.8 Get User Confirmation Status for Operation + * + * Arg 2 (Integer): Function Index = 8 + * Arg 3 (Package): Arguments = Package: Type: Integer + * Operation Value that may need user confirmation + * Returns: Type: Integer + * 0: Not implemented + * 1: Firmware only + * 2: Blocked for OS by firmware configuration + * 3: Allowed and physically present user required + * 4: Allowed and physically present user not required + */ + ifctx2 = aml_if(aml_equal(function, aml_int(8))); + { + /* get opcode */ + aml_append(ifctx2, + aml_store(aml_derefof(aml_index(arguments, + zero)), + op)); + + /* get opcode flags */ + aml_append(ifctx2, aml_store(aml_call1("TPFN", op), + op_flags)); + /* return confirmation status code */ + aml_append(ifctx2, + aml_return( + aml_and(op_flags, func_mask, NULL))); + } + aml_append(ifctx, ifctx2); + + aml_append(ifctx, aml_return(aml_buffer(1, zerobyte))); + } + aml_append(method, ifctx); + + /* + * "TCG Platform Reset Attack Mitigation Specification 1.00", + * Chapter 6 "ACPI _DSM Function" + */ + ifctx = aml_if( + aml_equal(uuid, + aml_touuid("376054ED-CC13-4675-901C-4756D7F2D45D"))); + { + /* standard DSM query function */ + ifctx2 = aml_if(aml_equal(function, zero)); + { + uint8_t byte_list[1] = { 0x03 }; /* functions 1-2 supported */ + + aml_append(ifctx2, + aml_return(aml_buffer(sizeof(byte_list), + byte_list))); + } + aml_append(ifctx, ifctx2); + + /* + * TCG Platform Reset Attack Mitigation Specification 1.0 Ch.6 + * + * Arg 2 (Integer): Function Index = 1 + * Arg 3 (Package): Arguments = Package: Type: Integer + * Operation Value of the Request + * Returns: Type: Integer + * 0: Success + * 1: General Failure + */ + ifctx2 = aml_if(aml_equal(function, one)); + { + aml_append(ifctx2, + aml_store(aml_derefof(aml_index(arguments, zero)), + op)); + { + aml_append(ifctx2, aml_store(op, aml_name("MOVV"))); + + /* 0: success */ + aml_append(ifctx2, aml_return(zero)); + } + } + aml_append(ifctx, ifctx2); + } + aml_append(method, ifctx); + } + aml_append(dev, method); +} diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 95fad6f0ce..04b62c714d 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -418,6 +418,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) smmu->mapping_count = cpu_to_le32(1); smmu->mapping_offset = cpu_to_le32(sizeof(*smmu)); smmu->base_address = cpu_to_le64(vms->memmap[VIRT_SMMU].base); + smmu->flags = cpu_to_le32(ACPI_IORT_SMMU_V3_COHACC_OVERRIDE); smmu->event_gsiv = cpu_to_le32(irq); smmu->pri_gsiv = cpu_to_le32(irq + 1); smmu->gerr_gsiv = cpu_to_le32(irq + 2); diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index 1451940845..c3af28fad4 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -250,6 +250,7 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) VirtIODevice *vdev = VIRTIO_DEVICE(dev); VHostUserBlk *s = VHOST_USER_BLK(vdev); VhostUserState *user; + struct vhost_virtqueue *vqs = NULL; int i, ret; if (!s->chardev.chr) { @@ -288,6 +289,7 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) s->dev.vqs = g_new(struct vhost_virtqueue, s->dev.nvqs); s->dev.vq_index = 0; s->dev.backend_features = 0; + vqs = s->dev.vqs; vhost_dev_set_config_notifier(&s->dev, &blk_ops); @@ -314,7 +316,7 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) vhost_err: vhost_dev_cleanup(&s->dev); virtio_err: - g_free(s->dev.vqs); + g_free(vqs); virtio_cleanup(vdev); vhost_user_cleanup(user); @@ -326,10 +328,11 @@ static void vhost_user_blk_device_unrealize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VHostUserBlk *s = VHOST_USER_BLK(dev); + struct vhost_virtqueue *vqs = s->dev.vqs; vhost_user_blk_set_status(vdev, 0); vhost_dev_cleanup(&s->dev); - g_free(s->dev.vqs); + g_free(vqs); virtio_cleanup(vdev); if (s->vhost_user) { diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c index be28b63442..a636487b3e 100644 --- a/hw/block/xen-block.c +++ b/hw/block/xen-block.c @@ -215,7 +215,7 @@ static void xen_block_realize(XenDevice *xendev, Error **errp) xen_device_backend_printf(xendev, "sector-size", "%u", conf->logical_block_size); - xen_device_backend_printf(xendev, "sectors", "%lu", + xen_device_backend_printf(xendev, "sectors", "%"PRIi64, blk_getlength(conf->blk) / conf->logical_block_size); diff --git a/hw/char/stm32f2xx_usart.c b/hw/char/stm32f2xx_usart.c index f3363a2952..10392c70e2 100644 --- a/hw/char/stm32f2xx_usart.c +++ b/hw/char/stm32f2xx_usart.c @@ -53,14 +53,13 @@ static void stm32f2xx_usart_receive(void *opaque, const uint8_t *buf, int size) { STM32F2XXUsartState *s = opaque; - s->usart_dr = *buf; - if (!(s->usart_cr1 & USART_CR1_UE && s->usart_cr1 & USART_CR1_RE)) { /* USART not enabled - drop the chars */ DB_PRINT("Dropping the chars\n"); return; } + s->usart_dr = *buf; s->usart_sr |= USART_SR_RXNE; if (s->usart_cr1 & USART_CR1_RXNEIE) { diff --git a/hw/core/machine.c b/hw/core/machine.c index 95dc7c3913..2629515363 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -28,6 +28,8 @@ GlobalProperty hw_compat_3_1[] = { { "pcie-root-port", "x-width", "1" }, { "memory-backend-file", "x-use-canonical-path-for-ramblock-id", "true" }, { "memory-backend-memfd", "x-use-canonical-path-for-ramblock-id", "true" }, + { "tpm-crb", "ppi", "false" }, + { "tpm-tis", "ppi", "false" }, }; const size_t hw_compat_3_1_len = G_N_ELEMENTS(hw_compat_3_1); @@ -91,8 +93,9 @@ const size_t hw_compat_2_7_len = G_N_ELEMENTS(hw_compat_2_7); GlobalProperty hw_compat_2_6[] = { { "virtio-mmio", "format_transport_address", "off" }, - { "virtio-pci", "disable-modern", "on" }, - { "virtio-pci", "disable-legacy", "off" }, + /* Optional because not all virtio-pci devices support legacy mode */ + { "virtio-pci", "disable-modern", "on", .optional = true }, + { "virtio-pci", "disable-legacy", "off", .optional = true }, }; const size_t hw_compat_2_6_len = G_N_ELEMENTS(hw_compat_2_6); diff --git a/hw/display/virtio-gpu-pci.c b/hw/display/virtio-gpu-pci.c index faf76a8bc4..bdcd33c925 100644 --- a/hw/display/virtio-gpu-pci.c +++ b/hw/display/virtio-gpu-pci.c @@ -19,6 +19,20 @@ #include "hw/virtio/virtio-pci.h" #include "hw/virtio/virtio-gpu.h" +typedef struct VirtIOGPUPCI VirtIOGPUPCI; + +/* + * virtio-gpu-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VIRTIO_GPU_PCI "virtio-gpu-pci" +#define VIRTIO_GPU_PCI(obj) \ + OBJECT_CHECK(VirtIOGPUPCI, (obj), TYPE_VIRTIO_GPU_PCI) + +struct VirtIOGPUPCI { + VirtIOPCIProxy parent_obj; + VirtIOGPU vdev; +}; + static Property virtio_gpu_pci_properties[] = { DEFINE_VIRTIO_GPU_PCI_PROPERTIES(VirtIOPCIProxy), DEFINE_PROP_END_OF_LIST(), diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c index 8db4d916f2..1e48009b74 100644 --- a/hw/display/virtio-vga.c +++ b/hw/display/virtio-vga.c @@ -3,6 +3,7 @@ #include "hw/pci/pci.h" #include "vga_int.h" #include "hw/virtio/virtio-pci.h" +#include "hw/virtio/virtio-gpu.h" #include "qapi/error.h" /* diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 14f757fc36..2e21a31f82 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -119,6 +119,12 @@ typedef struct AcpiBuildPciBusHotplugState { bool pcihp_bridge_en; } AcpiBuildPciBusHotplugState; +typedef struct FwCfgTPMConfig { + uint32_t tpmppi_address; + uint8_t tpm_version; + uint8_t tpmppi_version; +} QEMU_PACKED FwCfgTPMConfig; + static void init_common_fadt_data(Object *o, AcpiFadtData *data) { uint32_t io = object_property_get_uint(o, ACPI_PM_PROP_PM_IO_BASE, NULL); @@ -1796,6 +1802,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, uint32_t nr_mem = machine->ram_slots; int root_bus_limit = 0xFF; PCIBus *bus = NULL; + TPMIf *tpm = tpm_find(); int i; dsdt = init_aml_allocator(); @@ -2133,7 +2140,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, /* Scan all PCI buses. Generate tables to support hotplug. */ build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en); - if (TPM_IS_TIS(tpm_find())) { + if (TPM_IS_TIS(tpm)) { dev = aml_device("ISA.TPM"); aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C31"))); aml_append(dev, aml_name_decl("_STA", aml_int(0xF))); @@ -2147,6 +2154,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, */ /* aml_append(crs, aml_irq_no_flags(TPM_TIS_IRQ)); */ aml_append(dev, aml_name_decl("_CRS", crs)); + + tpm_build_ppi_acpi(tpm, dev); + aml_append(scope, dev); } @@ -2154,7 +2164,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, } } - if (TPM_IS_CRB(tpm_find())) { + if (TPM_IS_CRB(tpm)) { dev = aml_device("TPM"); aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101"))); crs = aml_resource_template(); @@ -2166,6 +2176,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(method, aml_return(aml_int(0x0f))); aml_append(dev, method); + tpm_build_ppi_acpi(tpm, dev); + aml_append(sb_scope, dev); } @@ -2847,6 +2859,8 @@ void acpi_setup(void) AcpiBuildTables tables; AcpiBuildState *build_state; Object *vmgenid_dev; + TPMIf *tpm; + static FwCfgTPMConfig tpm_config; if (!pcms->fw_cfg) { ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n"); @@ -2881,6 +2895,17 @@ void acpi_setup(void) fw_cfg_add_file(pcms->fw_cfg, ACPI_BUILD_TPMLOG_FILE, tables.tcpalog->data, acpi_data_len(tables.tcpalog)); + tpm = tpm_find(); + if (tpm && object_property_get_bool(OBJECT(tpm), "ppi", &error_abort)) { + tpm_config = (FwCfgTPMConfig) { + .tpmppi_address = cpu_to_le32(TPM_PPI_ADDR_BASE), + .tpm_version = tpm_get_version(tpm), + .tpmppi_version = TPM_PPI_VERSION_1_30 + }; + fw_cfg_add_file(pcms->fw_cfg, "etc/tpm/config", + &tpm_config, sizeof tpm_config); + } + vmgenid_dev = find_vmgenid_dev(); if (vmgenid_dev) { vmgenid_add_fw_cfg(VMGENID(vmgenid_dev), pcms->fw_cfg, diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 5088e2f492..63c84e3827 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -715,7 +715,6 @@ static void pc_i440fx_1_2_machine_options(MachineClass *m) PC_CPU_MODEL_IDS("1.2.0") { "nec-usb-xhci", "msi", "off" }, { "nec-usb-xhci", "msix", "off" }, - { "ivshmem", "use64", "0" }, { "qxl", "revision", "3" }, { "qxl-vga", "revision", "3" }, { "VGA", "mmio", "off" }, diff --git a/hw/misc/edu.c b/hw/misc/edu.c index cdcf550dd7..ceaf688bfb 100644 --- a/hw/misc/edu.c +++ b/hw/misc/edu.c @@ -377,6 +377,7 @@ static void pci_edu_uninit(PCIDevice *pdev) qemu_mutex_destroy(&edu->thr_mutex); timer_del(&edu->dma_timer); + msi_uninit(pdev); } static void edu_obj_uint64(Object *obj, Visitor *v, const char *name, diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index 8213659602..c7b6bbc974 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -112,13 +112,6 @@ typedef struct IVShmemState { /* migration stuff */ OnOffAuto master; Error *migration_blocker; - - /* legacy cruft */ - char *role; - char *shmobj; - char *sizearg; - size_t legacy_size; - uint32_t not_legacy_32bit; } IVShmemState; /* registers for the Inter-VM shared memory device */ @@ -529,17 +522,6 @@ static void process_msg_shmem(IVShmemState *s, int fd, Error **errp) size = buf.st_size; - /* Legacy cruft */ - if (s->legacy_size != SIZE_MAX) { - if (size < s->legacy_size) { - error_setg(errp, "server sent only %zd bytes of shared memory", - (size_t)buf.st_size); - close(fd); - return; - } - size = s->legacy_size; - } - /* mmap the region and map into the BAR2 */ memory_region_init_ram_from_fd(&s->server_bar2, OBJECT(s), "ivshmem.bar2", size, true, fd, &local_err); @@ -882,8 +864,6 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp) IVShmemState *s = IVSHMEM_COMMON(dev); Error *err = NULL; uint8_t *pci_conf; - uint8_t attr = PCI_BASE_ADDRESS_SPACE_MEMORY | - PCI_BASE_ADDRESS_MEM_PREFETCH; Error *local_err = NULL; /* IRQFD requires MSI */ @@ -903,10 +883,6 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp) pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ivshmem_mmio); - if (s->not_legacy_32bit) { - attr |= PCI_BASE_ADDRESS_MEM_TYPE_64; - } - if (s->hostmem != NULL) { IVSHMEM_DPRINTF("using hostmem\n"); @@ -964,7 +940,11 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp) } vmstate_register_ram(s->ivshmem_bar2, DEVICE(s)); - pci_register_bar(PCI_DEVICE(s), 2, attr, s->ivshmem_bar2); + pci_register_bar(PCI_DEVICE(s), 2, + PCI_BASE_ADDRESS_SPACE_MEMORY | + PCI_BASE_ADDRESS_MEM_PREFETCH | + PCI_BASE_ADDRESS_MEM_TYPE_64, + s->ivshmem_bar2); } static void ivshmem_exit(PCIDevice *dev) @@ -1084,13 +1064,6 @@ static Property ivshmem_plain_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -static void ivshmem_plain_init(Object *obj) -{ - IVShmemState *s = IVSHMEM_PLAIN(obj); - - s->not_legacy_32bit = 1; -} - static void ivshmem_plain_realize(PCIDevice *dev, Error **errp) { IVShmemState *s = IVSHMEM_COMMON(dev); @@ -1122,7 +1095,6 @@ static const TypeInfo ivshmem_plain_info = { .name = TYPE_IVSHMEM_PLAIN, .parent = TYPE_IVSHMEM_COMMON, .instance_size = sizeof(IVShmemState), - .instance_init = ivshmem_plain_init, .class_init = ivshmem_plain_class_init, }; @@ -1155,8 +1127,6 @@ static void ivshmem_doorbell_init(Object *obj) IVShmemState *s = IVSHMEM_DOORBELL(obj); s->features |= (1 << IVSHMEM_MSI); - s->legacy_size = SIZE_MAX; /* whatever the server sends */ - s->not_legacy_32bit = 1; } static void ivshmem_doorbell_realize(PCIDevice *dev, Error **errp) @@ -1189,181 +1159,11 @@ static const TypeInfo ivshmem_doorbell_info = { .class_init = ivshmem_doorbell_class_init, }; -static int ivshmem_load_old(QEMUFile *f, void *opaque, int version_id) -{ - IVShmemState *s = opaque; - PCIDevice *pdev = PCI_DEVICE(s); - int ret; - - IVSHMEM_DPRINTF("ivshmem_load_old\n"); - - if (version_id != 0) { - return -EINVAL; - } - - ret = ivshmem_pre_load(s); - if (ret) { - return ret; - } - - ret = pci_device_load(pdev, f); - if (ret) { - return ret; - } - - if (ivshmem_has_feature(s, IVSHMEM_MSI)) { - msix_load(pdev, f); - ivshmem_msix_vector_use(s); - } else { - s->intrstatus = qemu_get_be32(f); - s->intrmask = qemu_get_be32(f); - } - - return 0; -} - -static bool test_msix(void *opaque, int version_id) -{ - IVShmemState *s = opaque; - - return ivshmem_has_feature(s, IVSHMEM_MSI); -} - -static bool test_no_msix(void *opaque, int version_id) -{ - return !test_msix(opaque, version_id); -} - -static const VMStateDescription ivshmem_vmsd = { - .name = "ivshmem", - .version_id = 1, - .minimum_version_id = 1, - .pre_load = ivshmem_pre_load, - .post_load = ivshmem_post_load, - .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE(parent_obj, IVShmemState), - - VMSTATE_MSIX_TEST(parent_obj, IVShmemState, test_msix), - VMSTATE_UINT32_TEST(intrstatus, IVShmemState, test_no_msix), - VMSTATE_UINT32_TEST(intrmask, IVShmemState, test_no_msix), - - VMSTATE_END_OF_LIST() - }, - .load_state_old = ivshmem_load_old, - .minimum_version_id_old = 0 -}; - -static Property ivshmem_properties[] = { - DEFINE_PROP_CHR("chardev", IVShmemState, server_chr), - DEFINE_PROP_STRING("size", IVShmemState, sizearg), - DEFINE_PROP_UINT32("vectors", IVShmemState, vectors, 1), - DEFINE_PROP_BIT("ioeventfd", IVShmemState, features, IVSHMEM_IOEVENTFD, - false), - DEFINE_PROP_BIT("msi", IVShmemState, features, IVSHMEM_MSI, true), - DEFINE_PROP_STRING("shm", IVShmemState, shmobj), - DEFINE_PROP_STRING("role", IVShmemState, role), - DEFINE_PROP_UINT32("use64", IVShmemState, not_legacy_32bit, 1), - DEFINE_PROP_END_OF_LIST(), -}; - -static void desugar_shm(IVShmemState *s) -{ - Object *obj; - char *path; - - obj = object_new("memory-backend-file"); - path = g_strdup_printf("/dev/shm/%s", s->shmobj); - object_property_set_str(obj, path, "mem-path", &error_abort); - g_free(path); - object_property_set_int(obj, s->legacy_size, "size", &error_abort); - object_property_set_bool(obj, true, "share", &error_abort); - object_property_add_child(OBJECT(s), "internal-shm-backend", obj, - &error_abort); - object_unref(obj); - user_creatable_complete(USER_CREATABLE(obj), &error_abort); - s->hostmem = MEMORY_BACKEND(obj); -} - -static void ivshmem_realize(PCIDevice *dev, Error **errp) -{ - IVShmemState *s = IVSHMEM_COMMON(dev); - - if (!qtest_enabled()) { - warn_report("ivshmem is deprecated, please use ivshmem-plain" - " or ivshmem-doorbell instead"); - } - - if (qemu_chr_fe_backend_connected(&s->server_chr) + !!s->shmobj != 1) { - error_setg(errp, "You must specify either 'shm' or 'chardev'"); - return; - } - - if (s->sizearg == NULL) { - s->legacy_size = 4 * MiB; /* 4 MB default */ - } else { - int ret; - uint64_t size; - - ret = qemu_strtosz_MiB(s->sizearg, NULL, &size); - if (ret < 0 || (size_t)size != size || !is_power_of_2(size)) { - error_setg(errp, "Invalid size %s", s->sizearg); - return; - } - s->legacy_size = size; - } - - /* check that role is reasonable */ - if (s->role) { - if (strncmp(s->role, "peer", 5) == 0) { - s->master = ON_OFF_AUTO_OFF; - } else if (strncmp(s->role, "master", 7) == 0) { - s->master = ON_OFF_AUTO_ON; - } else { - error_setg(errp, "'role' must be 'peer' or 'master'"); - return; - } - } else { - s->master = ON_OFF_AUTO_AUTO; - } - - if (s->shmobj) { - desugar_shm(s); - } - - /* - * Note: we don't use INTx with IVSHMEM_MSI at all, so this is a - * bald-faced lie then. But it's a backwards compatible lie. - */ - pci_config_set_interrupt_pin(dev->config, 1); - - ivshmem_common_realize(dev, errp); -} - -static void ivshmem_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->realize = ivshmem_realize; - k->revision = 0; - dc->desc = "Inter-VM shared memory (legacy)"; - dc->props = ivshmem_properties; - dc->vmsd = &ivshmem_vmsd; -} - -static const TypeInfo ivshmem_info = { - .name = TYPE_IVSHMEM, - .parent = TYPE_IVSHMEM_COMMON, - .instance_size = sizeof(IVShmemState), - .class_init = ivshmem_class_init, -}; - static void ivshmem_register_types(void) { type_register_static(&ivshmem_common_info); type_register_static(&ivshmem_plain_info); type_register_static(&ivshmem_doorbell_info); - type_register_static(&ivshmem_info); } type_init(ivshmem_register_types) diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c index 909c1182ee..790430346b 100644 --- a/hw/net/ftgmac100.c +++ b/hw/net/ftgmac100.c @@ -90,6 +90,18 @@ #define FTGMAC100_PHYDATA_MIIRDATA(x) (((x) >> 16) & 0xffff) /* + * PHY control register - New MDC/MDIO interface + */ +#define FTGMAC100_PHYCR_NEW_DATA(x) (((x) >> 16) & 0xffff) +#define FTGMAC100_PHYCR_NEW_FIRE (1 << 15) +#define FTGMAC100_PHYCR_NEW_ST_22 (1 << 12) +#define FTGMAC100_PHYCR_NEW_OP(x) (((x) >> 10) & 3) +#define FTGMAC100_PHYCR_NEW_OP_WRITE 0x1 +#define FTGMAC100_PHYCR_NEW_OP_READ 0x2 +#define FTGMAC100_PHYCR_NEW_DEV(x) (((x) >> 5) & 0x1f) +#define FTGMAC100_PHYCR_NEW_REG(x) ((x) & 0x1f) + +/* * Feature Register */ #define FTGMAC100_REVR_NEW_MDIO_INTERFACE (1 << 31) @@ -269,9 +281,9 @@ static void phy_reset(FTGMAC100State *s) s->phy_int = 0; } -static uint32_t do_phy_read(FTGMAC100State *s, int reg) +static uint16_t do_phy_read(FTGMAC100State *s, uint8_t reg) { - uint32_t val; + uint16_t val; switch (reg) { case MII_BMCR: /* Basic Control */ @@ -336,7 +348,7 @@ static uint32_t do_phy_read(FTGMAC100State *s, int reg) MII_BMCR_FD | MII_BMCR_CTST) #define MII_ANAR_MASK 0x2d7f -static void do_phy_write(FTGMAC100State *s, int reg, uint32_t val) +static void do_phy_write(FTGMAC100State *s, uint8_t reg, uint16_t val) { switch (reg) { case MII_BMCR: /* Basic Control */ @@ -373,6 +385,55 @@ static void do_phy_write(FTGMAC100State *s, int reg, uint32_t val) } } +static void do_phy_new_ctl(FTGMAC100State *s) +{ + uint8_t reg; + uint16_t data; + + if (!(s->phycr & FTGMAC100_PHYCR_NEW_ST_22)) { + qemu_log_mask(LOG_UNIMP, "%s: unsupported ST code\n", __func__); + return; + } + + /* Nothing to do */ + if (!(s->phycr & FTGMAC100_PHYCR_NEW_FIRE)) { + return; + } + + reg = FTGMAC100_PHYCR_NEW_REG(s->phycr); + data = FTGMAC100_PHYCR_NEW_DATA(s->phycr); + + switch (FTGMAC100_PHYCR_NEW_OP(s->phycr)) { + case FTGMAC100_PHYCR_NEW_OP_WRITE: + do_phy_write(s, reg, data); + break; + case FTGMAC100_PHYCR_NEW_OP_READ: + s->phydata = do_phy_read(s, reg) & 0xffff; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid OP code %08x\n", + __func__, s->phycr); + } + + s->phycr &= ~FTGMAC100_PHYCR_NEW_FIRE; +} + +static void do_phy_ctl(FTGMAC100State *s) +{ + uint8_t reg = FTGMAC100_PHYCR_REG(s->phycr); + + if (s->phycr & FTGMAC100_PHYCR_MIIWR) { + do_phy_write(s, reg, s->phydata & 0xffff); + s->phycr &= ~FTGMAC100_PHYCR_MIIWR; + } else if (s->phycr & FTGMAC100_PHYCR_MIIRD) { + s->phydata = do_phy_read(s, reg) << 16; + s->phycr &= ~FTGMAC100_PHYCR_MIIRD; + } else { + qemu_log_mask(LOG_GUEST_ERROR, "%s: no OP code %08x\n", + __func__, s->phycr); + } +} + static int ftgmac100_read_bd(FTGMAC100Desc *bd, dma_addr_t addr) { if (dma_memory_read(&address_space_memory, addr, bd, sizeof(*bd))) { @@ -628,7 +689,6 @@ static void ftgmac100_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { FTGMAC100State *s = FTGMAC100(opaque); - int reg; switch (addr & 0xff) { case FTGMAC100_ISR: /* Interrupt status */ @@ -711,14 +771,11 @@ static void ftgmac100_write(void *opaque, hwaddr addr, break; case FTGMAC100_PHYCR: /* PHY Device control */ - reg = FTGMAC100_PHYCR_REG(value); s->phycr = value; - if (value & FTGMAC100_PHYCR_MIIWR) { - do_phy_write(s, reg, s->phydata & 0xffff); - s->phycr &= ~FTGMAC100_PHYCR_MIIWR; + if (s->revr & FTGMAC100_REVR_NEW_MDIO_INTERFACE) { + do_phy_new_ctl(s); } else { - s->phydata = do_phy_read(s, reg) << 16; - s->phycr &= ~FTGMAC100_PHYCR_MIIRD; + do_phy_ctl(s); } break; case FTGMAC100_PHYDATA: @@ -728,8 +785,7 @@ static void ftgmac100_write(void *opaque, hwaddr addr, s->dblac = value; break; case FTGMAC100_REVR: /* Feature Register */ - /* TODO: Only Old MDIO interface is supported */ - s->revr = value & ~FTGMAC100_REVR_NEW_MDIO_INTERFACE; + s->revr = value; break; case FTGMAC100_FEAR1: /* Feature Register 1 */ s->fear1 = value; diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index e37fc34839..3f319ef723 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -41,6 +41,47 @@ #define VIRTIO_NET_RX_QUEUE_MIN_SIZE VIRTIO_NET_RX_QUEUE_DEFAULT_SIZE #define VIRTIO_NET_TX_QUEUE_MIN_SIZE VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE +#define VIRTIO_NET_IP4_ADDR_SIZE 8 /* ipv4 saddr + daddr */ + +#define VIRTIO_NET_TCP_FLAG 0x3F +#define VIRTIO_NET_TCP_HDR_LENGTH 0xF000 + +/* IPv4 max payload, 16 bits in the header */ +#define VIRTIO_NET_MAX_IP4_PAYLOAD (65535 - sizeof(struct ip_header)) +#define VIRTIO_NET_MAX_TCP_PAYLOAD 65535 + +/* header length value in ip header without option */ +#define VIRTIO_NET_IP4_HEADER_LENGTH 5 + +#define VIRTIO_NET_IP6_ADDR_SIZE 32 /* ipv6 saddr + daddr */ +#define VIRTIO_NET_MAX_IP6_PAYLOAD VIRTIO_NET_MAX_TCP_PAYLOAD + +/* Purge coalesced packets timer interval, This value affects the performance + a lot, and should be tuned carefully, '300000'(300us) is the recommended + value to pass the WHQL test, '50000' can gain 2x netperf throughput with + tso/gso/gro 'off'. */ +#define VIRTIO_NET_RSC_DEFAULT_INTERVAL 300000 + +/* temporary until standard header include it */ +#if !defined(VIRTIO_NET_HDR_F_RSC_INFO) + +#define VIRTIO_NET_HDR_F_RSC_INFO 4 /* rsc_ext data in csum_ fields */ +#define VIRTIO_NET_F_RSC_EXT 61 + +static inline __virtio16 *virtio_net_rsc_ext_num_packets( + struct virtio_net_hdr *hdr) +{ + return &hdr->csum_start; +} + +static inline __virtio16 *virtio_net_rsc_ext_num_dupacks( + struct virtio_net_hdr *hdr) +{ + return &hdr->csum_offset; +} + +#endif + /* * Calculate the number of bytes up to and including the given 'field' of * 'container'. @@ -628,6 +669,7 @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features, if (!get_vhost_net(nc->peer)) { return features; } + features = vhost_net_get_features(get_vhost_net(nc->peer), features); vdev->backend_features = features; @@ -701,6 +743,11 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features) virtio_has_feature(features, VIRTIO_F_VERSION_1)); + n->rsc4_enabled = virtio_has_feature(features, VIRTIO_NET_F_RSC_EXT) && + virtio_has_feature(features, VIRTIO_NET_F_GUEST_TSO4); + n->rsc6_enabled = virtio_has_feature(features, VIRTIO_NET_F_RSC_EXT) && + virtio_has_feature(features, VIRTIO_NET_F_GUEST_TSO6); + if (n->has_vnet_hdr) { n->curr_guest_offloads = virtio_net_guest_offloads_by_features(features); @@ -781,6 +828,12 @@ static int virtio_net_handle_offloads(VirtIONet *n, uint8_t cmd, return VIRTIO_NET_ERR; } + n->rsc4_enabled = virtio_has_feature(offloads, VIRTIO_NET_F_RSC_EXT) && + virtio_has_feature(offloads, VIRTIO_NET_F_GUEST_TSO4); + n->rsc6_enabled = virtio_has_feature(offloads, VIRTIO_NET_F_RSC_EXT) && + virtio_has_feature(offloads, VIRTIO_NET_F_GUEST_TSO6); + virtio_clear_feature(&offloads, VIRTIO_NET_F_RSC_EXT); + supported_offloads = virtio_net_supported_guest_offloads(n); if (offloads & ~supported_offloads) { return VIRTIO_NET_ERR; @@ -1292,7 +1345,7 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, return size; } -static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, +static ssize_t virtio_net_do_receive(NetClientState *nc, const uint8_t *buf, size_t size) { ssize_t r; @@ -1303,6 +1356,612 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, return r; } +static void virtio_net_rsc_extract_unit4(VirtioNetRscChain *chain, + const uint8_t *buf, + VirtioNetRscUnit *unit) +{ + uint16_t ip_hdrlen; + struct ip_header *ip; + + ip = (struct ip_header *)(buf + chain->n->guest_hdr_len + + sizeof(struct eth_header)); + unit->ip = (void *)ip; + ip_hdrlen = (ip->ip_ver_len & 0xF) << 2; + unit->ip_plen = &ip->ip_len; + unit->tcp = (struct tcp_header *)(((uint8_t *)unit->ip) + ip_hdrlen); + unit->tcp_hdrlen = (htons(unit->tcp->th_offset_flags) & 0xF000) >> 10; + unit->payload = htons(*unit->ip_plen) - ip_hdrlen - unit->tcp_hdrlen; +} + +static void virtio_net_rsc_extract_unit6(VirtioNetRscChain *chain, + const uint8_t *buf, + VirtioNetRscUnit *unit) +{ + struct ip6_header *ip6; + + ip6 = (struct ip6_header *)(buf + chain->n->guest_hdr_len + + sizeof(struct eth_header)); + unit->ip = ip6; + unit->ip_plen = &(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen); + unit->tcp = (struct tcp_header *)(((uint8_t *)unit->ip)\ + + sizeof(struct ip6_header)); + unit->tcp_hdrlen = (htons(unit->tcp->th_offset_flags) & 0xF000) >> 10; + + /* There is a difference between payload lenght in ipv4 and v6, + ip header is excluded in ipv6 */ + unit->payload = htons(*unit->ip_plen) - unit->tcp_hdrlen; +} + +static size_t virtio_net_rsc_drain_seg(VirtioNetRscChain *chain, + VirtioNetRscSeg *seg) +{ + int ret; + struct virtio_net_hdr *h; + + h = (struct virtio_net_hdr *)seg->buf; + h->flags = 0; + h->gso_type = VIRTIO_NET_HDR_GSO_NONE; + + if (seg->is_coalesced) { + *virtio_net_rsc_ext_num_packets(h) = seg->packets; + *virtio_net_rsc_ext_num_dupacks(h) = seg->dup_ack; + h->flags = VIRTIO_NET_HDR_F_RSC_INFO; + if (chain->proto == ETH_P_IP) { + h->gso_type = VIRTIO_NET_HDR_GSO_TCPV4; + } else { + h->gso_type = VIRTIO_NET_HDR_GSO_TCPV6; + } + } + + ret = virtio_net_do_receive(seg->nc, seg->buf, seg->size); + QTAILQ_REMOVE(&chain->buffers, seg, next); + g_free(seg->buf); + g_free(seg); + + return ret; +} + +static void virtio_net_rsc_purge(void *opq) +{ + VirtioNetRscSeg *seg, *rn; + VirtioNetRscChain *chain = (VirtioNetRscChain *)opq; + + QTAILQ_FOREACH_SAFE(seg, &chain->buffers, next, rn) { + if (virtio_net_rsc_drain_seg(chain, seg) == 0) { + chain->stat.purge_failed++; + continue; + } + } + + chain->stat.timer++; + if (!QTAILQ_EMPTY(&chain->buffers)) { + timer_mod(chain->drain_timer, + qemu_clock_get_ns(QEMU_CLOCK_HOST) + chain->n->rsc_timeout); + } +} + +static void virtio_net_rsc_cleanup(VirtIONet *n) +{ + VirtioNetRscChain *chain, *rn_chain; + VirtioNetRscSeg *seg, *rn_seg; + + QTAILQ_FOREACH_SAFE(chain, &n->rsc_chains, next, rn_chain) { + QTAILQ_FOREACH_SAFE(seg, &chain->buffers, next, rn_seg) { + QTAILQ_REMOVE(&chain->buffers, seg, next); + g_free(seg->buf); + g_free(seg); + } + + timer_del(chain->drain_timer); + timer_free(chain->drain_timer); + QTAILQ_REMOVE(&n->rsc_chains, chain, next); + g_free(chain); + } +} + +static void virtio_net_rsc_cache_buf(VirtioNetRscChain *chain, + NetClientState *nc, + const uint8_t *buf, size_t size) +{ + uint16_t hdr_len; + VirtioNetRscSeg *seg; + + hdr_len = chain->n->guest_hdr_len; + seg = g_malloc(sizeof(VirtioNetRscSeg)); + seg->buf = g_malloc(hdr_len + sizeof(struct eth_header) + + sizeof(struct ip6_header) + VIRTIO_NET_MAX_TCP_PAYLOAD); + memcpy(seg->buf, buf, size); + seg->size = size; + seg->packets = 1; + seg->dup_ack = 0; + seg->is_coalesced = 0; + seg->nc = nc; + + QTAILQ_INSERT_TAIL(&chain->buffers, seg, next); + chain->stat.cache++; + + switch (chain->proto) { + case ETH_P_IP: + virtio_net_rsc_extract_unit4(chain, seg->buf, &seg->unit); + break; + case ETH_P_IPV6: + virtio_net_rsc_extract_unit6(chain, seg->buf, &seg->unit); + break; + default: + g_assert_not_reached(); + } +} + +static int32_t virtio_net_rsc_handle_ack(VirtioNetRscChain *chain, + VirtioNetRscSeg *seg, + const uint8_t *buf, + struct tcp_header *n_tcp, + struct tcp_header *o_tcp) +{ + uint32_t nack, oack; + uint16_t nwin, owin; + + nack = htonl(n_tcp->th_ack); + nwin = htons(n_tcp->th_win); + oack = htonl(o_tcp->th_ack); + owin = htons(o_tcp->th_win); + + if ((nack - oack) >= VIRTIO_NET_MAX_TCP_PAYLOAD) { + chain->stat.ack_out_of_win++; + return RSC_FINAL; + } else if (nack == oack) { + /* duplicated ack or window probe */ + if (nwin == owin) { + /* duplicated ack, add dup ack count due to whql test up to 1 */ + chain->stat.dup_ack++; + return RSC_FINAL; + } else { + /* Coalesce window update */ + o_tcp->th_win = n_tcp->th_win; + chain->stat.win_update++; + return RSC_COALESCE; + } + } else { + /* pure ack, go to 'C', finalize*/ + chain->stat.pure_ack++; + return RSC_FINAL; + } +} + +static int32_t virtio_net_rsc_coalesce_data(VirtioNetRscChain *chain, + VirtioNetRscSeg *seg, + const uint8_t *buf, + VirtioNetRscUnit *n_unit) +{ + void *data; + uint16_t o_ip_len; + uint32_t nseq, oseq; + VirtioNetRscUnit *o_unit; + + o_unit = &seg->unit; + o_ip_len = htons(*o_unit->ip_plen); + nseq = htonl(n_unit->tcp->th_seq); + oseq = htonl(o_unit->tcp->th_seq); + + /* out of order or retransmitted. */ + if ((nseq - oseq) > VIRTIO_NET_MAX_TCP_PAYLOAD) { + chain->stat.data_out_of_win++; + return RSC_FINAL; + } + + data = ((uint8_t *)n_unit->tcp) + n_unit->tcp_hdrlen; + if (nseq == oseq) { + if ((o_unit->payload == 0) && n_unit->payload) { + /* From no payload to payload, normal case, not a dup ack or etc */ + chain->stat.data_after_pure_ack++; + goto coalesce; + } else { + return virtio_net_rsc_handle_ack(chain, seg, buf, + n_unit->tcp, o_unit->tcp); + } + } else if ((nseq - oseq) != o_unit->payload) { + /* Not a consistent packet, out of order */ + chain->stat.data_out_of_order++; + return RSC_FINAL; + } else { +coalesce: + if ((o_ip_len + n_unit->payload) > chain->max_payload) { + chain->stat.over_size++; + return RSC_FINAL; + } + + /* Here comes the right data, the payload length in v4/v6 is different, + so use the field value to update and record the new data len */ + o_unit->payload += n_unit->payload; /* update new data len */ + + /* update field in ip header */ + *o_unit->ip_plen = htons(o_ip_len + n_unit->payload); + + /* Bring 'PUSH' big, the whql test guide says 'PUSH' can be coalesced + for windows guest, while this may change the behavior for linux + guest (only if it uses RSC feature). */ + o_unit->tcp->th_offset_flags = n_unit->tcp->th_offset_flags; + + o_unit->tcp->th_ack = n_unit->tcp->th_ack; + o_unit->tcp->th_win = n_unit->tcp->th_win; + + memmove(seg->buf + seg->size, data, n_unit->payload); + seg->size += n_unit->payload; + seg->packets++; + chain->stat.coalesced++; + return RSC_COALESCE; + } +} + +static int32_t virtio_net_rsc_coalesce4(VirtioNetRscChain *chain, + VirtioNetRscSeg *seg, + const uint8_t *buf, size_t size, + VirtioNetRscUnit *unit) +{ + struct ip_header *ip1, *ip2; + + ip1 = (struct ip_header *)(unit->ip); + ip2 = (struct ip_header *)(seg->unit.ip); + if ((ip1->ip_src ^ ip2->ip_src) || (ip1->ip_dst ^ ip2->ip_dst) + || (unit->tcp->th_sport ^ seg->unit.tcp->th_sport) + || (unit->tcp->th_dport ^ seg->unit.tcp->th_dport)) { + chain->stat.no_match++; + return RSC_NO_MATCH; + } + + return virtio_net_rsc_coalesce_data(chain, seg, buf, unit); +} + +static int32_t virtio_net_rsc_coalesce6(VirtioNetRscChain *chain, + VirtioNetRscSeg *seg, + const uint8_t *buf, size_t size, + VirtioNetRscUnit *unit) +{ + struct ip6_header *ip1, *ip2; + + ip1 = (struct ip6_header *)(unit->ip); + ip2 = (struct ip6_header *)(seg->unit.ip); + if (memcmp(&ip1->ip6_src, &ip2->ip6_src, sizeof(struct in6_address)) + || memcmp(&ip1->ip6_dst, &ip2->ip6_dst, sizeof(struct in6_address)) + || (unit->tcp->th_sport ^ seg->unit.tcp->th_sport) + || (unit->tcp->th_dport ^ seg->unit.tcp->th_dport)) { + chain->stat.no_match++; + return RSC_NO_MATCH; + } + + return virtio_net_rsc_coalesce_data(chain, seg, buf, unit); +} + +/* Packets with 'SYN' should bypass, other flag should be sent after drain + * to prevent out of order */ +static int virtio_net_rsc_tcp_ctrl_check(VirtioNetRscChain *chain, + struct tcp_header *tcp) +{ + uint16_t tcp_hdr; + uint16_t tcp_flag; + + tcp_flag = htons(tcp->th_offset_flags); + tcp_hdr = (tcp_flag & VIRTIO_NET_TCP_HDR_LENGTH) >> 10; + tcp_flag &= VIRTIO_NET_TCP_FLAG; + tcp_flag = htons(tcp->th_offset_flags) & 0x3F; + if (tcp_flag & TH_SYN) { + chain->stat.tcp_syn++; + return RSC_BYPASS; + } + + if (tcp_flag & (TH_FIN | TH_URG | TH_RST | TH_ECE | TH_CWR)) { + chain->stat.tcp_ctrl_drain++; + return RSC_FINAL; + } + + if (tcp_hdr > sizeof(struct tcp_header)) { + chain->stat.tcp_all_opt++; + return RSC_FINAL; + } + + return RSC_CANDIDATE; +} + +static size_t virtio_net_rsc_do_coalesce(VirtioNetRscChain *chain, + NetClientState *nc, + const uint8_t *buf, size_t size, + VirtioNetRscUnit *unit) +{ + int ret; + VirtioNetRscSeg *seg, *nseg; + + if (QTAILQ_EMPTY(&chain->buffers)) { + chain->stat.empty_cache++; + virtio_net_rsc_cache_buf(chain, nc, buf, size); + timer_mod(chain->drain_timer, + qemu_clock_get_ns(QEMU_CLOCK_HOST) + chain->n->rsc_timeout); + return size; + } + + QTAILQ_FOREACH_SAFE(seg, &chain->buffers, next, nseg) { + if (chain->proto == ETH_P_IP) { + ret = virtio_net_rsc_coalesce4(chain, seg, buf, size, unit); + } else { + ret = virtio_net_rsc_coalesce6(chain, seg, buf, size, unit); + } + + if (ret == RSC_FINAL) { + if (virtio_net_rsc_drain_seg(chain, seg) == 0) { + /* Send failed */ + chain->stat.final_failed++; + return 0; + } + + /* Send current packet */ + return virtio_net_do_receive(nc, buf, size); + } else if (ret == RSC_NO_MATCH) { + continue; + } else { + /* Coalesced, mark coalesced flag to tell calc cksum for ipv4 */ + seg->is_coalesced = 1; + return size; + } + } + + chain->stat.no_match_cache++; + virtio_net_rsc_cache_buf(chain, nc, buf, size); + return size; +} + +/* Drain a connection data, this is to avoid out of order segments */ +static size_t virtio_net_rsc_drain_flow(VirtioNetRscChain *chain, + NetClientState *nc, + const uint8_t *buf, size_t size, + uint16_t ip_start, uint16_t ip_size, + uint16_t tcp_port) +{ + VirtioNetRscSeg *seg, *nseg; + uint32_t ppair1, ppair2; + + ppair1 = *(uint32_t *)(buf + tcp_port); + QTAILQ_FOREACH_SAFE(seg, &chain->buffers, next, nseg) { + ppair2 = *(uint32_t *)(seg->buf + tcp_port); + if (memcmp(buf + ip_start, seg->buf + ip_start, ip_size) + || (ppair1 != ppair2)) { + continue; + } + if (virtio_net_rsc_drain_seg(chain, seg) == 0) { + chain->stat.drain_failed++; + } + + break; + } + + return virtio_net_do_receive(nc, buf, size); +} + +static int32_t virtio_net_rsc_sanity_check4(VirtioNetRscChain *chain, + struct ip_header *ip, + const uint8_t *buf, size_t size) +{ + uint16_t ip_len; + + /* Not an ipv4 packet */ + if (((ip->ip_ver_len & 0xF0) >> 4) != IP_HEADER_VERSION_4) { + chain->stat.ip_option++; + return RSC_BYPASS; + } + + /* Don't handle packets with ip option */ + if ((ip->ip_ver_len & 0xF) != VIRTIO_NET_IP4_HEADER_LENGTH) { + chain->stat.ip_option++; + return RSC_BYPASS; + } + + if (ip->ip_p != IPPROTO_TCP) { + chain->stat.bypass_not_tcp++; + return RSC_BYPASS; + } + + /* Don't handle packets with ip fragment */ + if (!(htons(ip->ip_off) & IP_DF)) { + chain->stat.ip_frag++; + return RSC_BYPASS; + } + + /* Don't handle packets with ecn flag */ + if (IPTOS_ECN(ip->ip_tos)) { + chain->stat.ip_ecn++; + return RSC_BYPASS; + } + + ip_len = htons(ip->ip_len); + if (ip_len < (sizeof(struct ip_header) + sizeof(struct tcp_header)) + || ip_len > (size - chain->n->guest_hdr_len - + sizeof(struct eth_header))) { + chain->stat.ip_hacked++; + return RSC_BYPASS; + } + + return RSC_CANDIDATE; +} + +static size_t virtio_net_rsc_receive4(VirtioNetRscChain *chain, + NetClientState *nc, + const uint8_t *buf, size_t size) +{ + int32_t ret; + uint16_t hdr_len; + VirtioNetRscUnit unit; + + hdr_len = ((VirtIONet *)(chain->n))->guest_hdr_len; + + if (size < (hdr_len + sizeof(struct eth_header) + sizeof(struct ip_header) + + sizeof(struct tcp_header))) { + chain->stat.bypass_not_tcp++; + return virtio_net_do_receive(nc, buf, size); + } + + virtio_net_rsc_extract_unit4(chain, buf, &unit); + if (virtio_net_rsc_sanity_check4(chain, unit.ip, buf, size) + != RSC_CANDIDATE) { + return virtio_net_do_receive(nc, buf, size); + } + + ret = virtio_net_rsc_tcp_ctrl_check(chain, unit.tcp); + if (ret == RSC_BYPASS) { + return virtio_net_do_receive(nc, buf, size); + } else if (ret == RSC_FINAL) { + return virtio_net_rsc_drain_flow(chain, nc, buf, size, + ((hdr_len + sizeof(struct eth_header)) + 12), + VIRTIO_NET_IP4_ADDR_SIZE, + hdr_len + sizeof(struct eth_header) + sizeof(struct ip_header)); + } + + return virtio_net_rsc_do_coalesce(chain, nc, buf, size, &unit); +} + +static int32_t virtio_net_rsc_sanity_check6(VirtioNetRscChain *chain, + struct ip6_header *ip6, + const uint8_t *buf, size_t size) +{ + uint16_t ip_len; + + if (((ip6->ip6_ctlun.ip6_un1.ip6_un1_flow & 0xF0) >> 4) + != IP_HEADER_VERSION_6) { + return RSC_BYPASS; + } + + /* Both option and protocol is checked in this */ + if (ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt != IPPROTO_TCP) { + chain->stat.bypass_not_tcp++; + return RSC_BYPASS; + } + + ip_len = htons(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen); + if (ip_len < sizeof(struct tcp_header) || + ip_len > (size - chain->n->guest_hdr_len - sizeof(struct eth_header) + - sizeof(struct ip6_header))) { + chain->stat.ip_hacked++; + return RSC_BYPASS; + } + + /* Don't handle packets with ecn flag */ + if (IP6_ECN(ip6->ip6_ctlun.ip6_un3.ip6_un3_ecn)) { + chain->stat.ip_ecn++; + return RSC_BYPASS; + } + + return RSC_CANDIDATE; +} + +static size_t virtio_net_rsc_receive6(void *opq, NetClientState *nc, + const uint8_t *buf, size_t size) +{ + int32_t ret; + uint16_t hdr_len; + VirtioNetRscChain *chain; + VirtioNetRscUnit unit; + + chain = (VirtioNetRscChain *)opq; + hdr_len = ((VirtIONet *)(chain->n))->guest_hdr_len; + + if (size < (hdr_len + sizeof(struct eth_header) + sizeof(struct ip6_header) + + sizeof(tcp_header))) { + return virtio_net_do_receive(nc, buf, size); + } + + virtio_net_rsc_extract_unit6(chain, buf, &unit); + if (RSC_CANDIDATE != virtio_net_rsc_sanity_check6(chain, + unit.ip, buf, size)) { + return virtio_net_do_receive(nc, buf, size); + } + + ret = virtio_net_rsc_tcp_ctrl_check(chain, unit.tcp); + if (ret == RSC_BYPASS) { + return virtio_net_do_receive(nc, buf, size); + } else if (ret == RSC_FINAL) { + return virtio_net_rsc_drain_flow(chain, nc, buf, size, + ((hdr_len + sizeof(struct eth_header)) + 8), + VIRTIO_NET_IP6_ADDR_SIZE, + hdr_len + sizeof(struct eth_header) + + sizeof(struct ip6_header)); + } + + return virtio_net_rsc_do_coalesce(chain, nc, buf, size, &unit); +} + +static VirtioNetRscChain *virtio_net_rsc_lookup_chain(VirtIONet *n, + NetClientState *nc, + uint16_t proto) +{ + VirtioNetRscChain *chain; + + if ((proto != (uint16_t)ETH_P_IP) && (proto != (uint16_t)ETH_P_IPV6)) { + return NULL; + } + + QTAILQ_FOREACH(chain, &n->rsc_chains, next) { + if (chain->proto == proto) { + return chain; + } + } + + chain = g_malloc(sizeof(*chain)); + chain->n = n; + chain->proto = proto; + if (proto == (uint16_t)ETH_P_IP) { + chain->max_payload = VIRTIO_NET_MAX_IP4_PAYLOAD; + chain->gso_type = VIRTIO_NET_HDR_GSO_TCPV4; + } else { + chain->max_payload = VIRTIO_NET_MAX_IP6_PAYLOAD; + chain->gso_type = VIRTIO_NET_HDR_GSO_TCPV6; + } + chain->drain_timer = timer_new_ns(QEMU_CLOCK_HOST, + virtio_net_rsc_purge, chain); + memset(&chain->stat, 0, sizeof(chain->stat)); + + QTAILQ_INIT(&chain->buffers); + QTAILQ_INSERT_TAIL(&n->rsc_chains, chain, next); + + return chain; +} + +static ssize_t virtio_net_rsc_receive(NetClientState *nc, + const uint8_t *buf, + size_t size) +{ + uint16_t proto; + VirtioNetRscChain *chain; + struct eth_header *eth; + VirtIONet *n; + + n = qemu_get_nic_opaque(nc); + if (size < (n->host_hdr_len + sizeof(struct eth_header))) { + return virtio_net_do_receive(nc, buf, size); + } + + eth = (struct eth_header *)(buf + n->guest_hdr_len); + proto = htons(eth->h_proto); + + chain = virtio_net_rsc_lookup_chain(n, nc, proto); + if (chain) { + chain->stat.received++; + if (proto == (uint16_t)ETH_P_IP && n->rsc4_enabled) { + return virtio_net_rsc_receive4(chain, nc, buf, size); + } else if (proto == (uint16_t)ETH_P_IPV6 && n->rsc6_enabled) { + return virtio_net_rsc_receive6(chain, nc, buf, size); + } + } + return virtio_net_do_receive(nc, buf, size); +} + +static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, + size_t size) +{ + VirtIONet *n = qemu_get_nic_opaque(nc); + if ((n->rsc4_enabled || n->rsc6_enabled)) { + return virtio_net_rsc_receive(nc, buf, size); + } else { + return virtio_net_do_receive(nc, buf, size); + } +} + static int32_t virtio_net_flush_tx(VirtIONetQueue *q); static void virtio_net_tx_complete(NetClientState *nc, ssize_t len) @@ -2075,6 +2734,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) nc = qemu_get_queue(n->nic); nc->rxfilter_notify_enabled = 1; + QTAILQ_INIT(&n->rsc_chains); n->qdev = dev; } @@ -2104,6 +2764,7 @@ static void virtio_net_device_unrealize(DeviceState *dev, Error **errp) timer_free(n->announce_timer); g_free(n->vqs); qemu_del_nic(n->nic); + virtio_net_rsc_cleanup(n); virtio_cleanup(vdev); } @@ -2184,6 +2845,10 @@ static Property virtio_net_properties[] = { DEFINE_PROP_BIT64("ctrl_guest_offloads", VirtIONet, host_features, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, true), DEFINE_PROP_BIT64("mq", VirtIONet, host_features, VIRTIO_NET_F_MQ, false), + DEFINE_PROP_BIT64("guest_rsc_ext", VirtIONet, host_features, + VIRTIO_NET_F_RSC_EXT, false), + DEFINE_PROP_UINT32("rsc_interval", VirtIONet, rsc_timeout, + VIRTIO_NET_RSC_DEFAULT_INTERVAL), DEFINE_NIC_PROPERTIES(VirtIONet, nic_conf), DEFINE_PROP_UINT32("x-txtimer", VirtIONet, net_conf.txtimer, TX_TIMER_INTERVAL), diff --git a/hw/pci/msix.c b/hw/pci/msix.c index c7bdbeda9e..4e336416a7 100644 --- a/hw/pci/msix.c +++ b/hw/pci/msix.c @@ -345,7 +345,7 @@ int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries, char *name; uint32_t bar_size = 4096; uint32_t bar_pba_offset = bar_size / 2; - uint32_t bar_pba_size = (nentries / 8 + 1) * 8; + uint32_t bar_pba_size = QEMU_ALIGN_UP(nentries, 64) / 8; /* * Migration compatibility dictates that this remains a 4k diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index 2d3d8a047b..230478faab 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -391,10 +391,10 @@ static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event) } static void pcie_cap_slot_plug_common(PCIDevice *hotplug_dev, DeviceState *dev, - uint8_t **exp_cap, Error **errp) + Error **errp) { - *exp_cap = hotplug_dev->config + hotplug_dev->exp.exp_cap; - uint16_t sltsta = pci_get_word(*exp_cap + PCI_EXP_SLTSTA); + uint8_t *exp_cap = hotplug_dev->config + hotplug_dev->exp.exp_cap; + uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); PCIE_DEV_PRINTF(PCI_DEVICE(dev), "hotplug state: 0x%x\n", sltsta); if (sltsta & PCI_EXP_SLTSTA_EIS) { @@ -405,14 +405,19 @@ static void pcie_cap_slot_plug_common(PCIDevice *hotplug_dev, DeviceState *dev, } } +void pcie_cap_slot_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, + Error **errp) +{ + pcie_cap_slot_plug_common(PCI_DEVICE(hotplug_dev), dev, errp); +} + void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { - uint8_t *exp_cap; + PCIDevice *hotplug_pdev = PCI_DEVICE(hotplug_dev); + uint8_t *exp_cap = hotplug_pdev->config + hotplug_pdev->exp.exp_cap; PCIDevice *pci_dev = PCI_DEVICE(dev); - pcie_cap_slot_plug_common(PCI_DEVICE(hotplug_dev), dev, &exp_cap, errp); - /* Don't send event when device is enabled during qemu machine creation: * it is present on boot, no hotplug event is necessary. We do send an * event when the device is disabled later. */ @@ -458,11 +463,15 @@ static void pcie_unplug_device(PCIBus *bus, PCIDevice *dev, void *opaque) void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { - uint8_t *exp_cap; + Error *local_err = NULL; PCIDevice *pci_dev = PCI_DEVICE(dev); PCIBus *bus = pci_get_bus(pci_dev); - pcie_cap_slot_plug_common(PCI_DEVICE(hotplug_dev), dev, &exp_cap, errp); + pcie_cap_slot_plug_common(PCI_DEVICE(hotplug_dev), dev, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } /* In case user cancel the operation of multi-function hot-add, * remove the function that is unexposed to guest individually, diff --git a/hw/pci/pcie_port.c b/hw/pci/pcie_port.c index bc07abc31b..a30291ef54 100644 --- a/hw/pci/pcie_port.c +++ b/hw/pci/pcie_port.c @@ -154,6 +154,7 @@ static void pcie_slot_class_init(ObjectClass *oc, void *data) HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); dc->props = pcie_slot_props; + hc->pre_plug = pcie_cap_slot_pre_plug_cb; hc->plug = pcie_cap_slot_plug_cb; hc->unplug = pcie_cap_slot_unplug_cb; hc->unplug_request = pcie_cap_slot_unplug_request_cb; diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index 15759b6514..f017c1ded0 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -660,7 +660,7 @@ void s390_pci_iommu_enable(S390PCIIOMMU *iommu) char *name = g_strdup_printf("iommu-s390-%04x", iommu->pbdev->uid); memory_region_init_iommu(&iommu->iommu_mr, sizeof(iommu->iommu_mr), TYPE_S390_IOMMU_MEMORY_REGION, OBJECT(&iommu->mr), - name, iommu->pal + 1); + name, iommu->pal - iommu->pba + 1); iommu->enabled = true; memory_region_add_subregion(&iommu->mr, 0, MEMORY_REGION(&iommu->iommu_mr)); g_free(name); @@ -818,28 +818,43 @@ static bool s390_pci_alloc_idx(S390pciState *s, S390PCIBusDevice *pbdev) } pbdev->idx = idx; - s->next_idx = (idx + 1) & FH_MASK_INDEX; - return true; } +static void s390_pcihost_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + Error **errp) +{ + S390pciState *s = S390_PCI_HOST_BRIDGE(hotplug_dev); + + if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { + PCIDevice *pdev = PCI_DEVICE(dev); + + if (pdev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) { + error_setg(errp, "multifunction not supported in s390"); + return; + } + } else if (object_dynamic_cast(OBJECT(dev), TYPE_S390_PCI_DEVICE)) { + S390PCIBusDevice *pbdev = S390_PCI_DEVICE(dev); + + if (!s390_pci_alloc_idx(s, pbdev)) { + error_setg(errp, "no slot for plugging zpci device"); + return; + } + } +} + static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { + S390pciState *s = S390_PCI_HOST_BRIDGE(hotplug_dev); PCIDevice *pdev = NULL; S390PCIBusDevice *pbdev = NULL; - S390pciState *s = s390_get_phb(); if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) { BusState *bus; PCIBridge *pb = PCI_BRIDGE(dev); PCIDevice *pdev = PCI_DEVICE(dev); - if (pdev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) { - error_setg(errp, "multifunction not supported in s390"); - return; - } - pci_bridge_map_irq(pb, dev->id, s390_pci_map_irq); pci_setup_iommu(&pb->sec_bus, s390_pci_dma_iommu, s); @@ -859,11 +874,6 @@ static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev, } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { pdev = PCI_DEVICE(dev); - if (pdev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) { - error_setg(errp, "multifunction not supported in s390"); - return; - } - if (!dev->id) { /* In the case the PCI device does not define an id */ /* we generate one based on the PCI address */ @@ -899,19 +909,19 @@ static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev, } if (dev->hotplugged) { - s390_pci_generate_plug_event(HP_EVENT_RESERVED_TO_STANDBY, + s390_pci_generate_plug_event(HP_EVENT_TO_CONFIGURED , pbdev->fh, pbdev->fid); } } else if (object_dynamic_cast(OBJECT(dev), TYPE_S390_PCI_DEVICE)) { pbdev = S390_PCI_DEVICE(dev); - if (!s390_pci_alloc_idx(s, pbdev)) { - error_setg(errp, "no slot for plugging zpci device"); - return; - } + /* the allocated idx is actually getting used */ + s->next_idx = (pbdev->idx + 1) & FH_MASK_INDEX; pbdev->fh = pbdev->idx; QTAILQ_INSERT_TAIL(&s->zpci_devs, pbdev, link); g_hash_table_insert(s->zpci_table, &pbdev->idx, pbdev); + } else { + g_assert_not_reached(); } } @@ -935,11 +945,11 @@ static void s390_pcihost_timer_cb(void *opaque) static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { + S390pciState *s = S390_PCI_HOST_BRIDGE(hotplug_dev); PCIDevice *pci_dev = NULL; PCIBus *bus; int32_t devfn; S390PCIBusDevice *pbdev = NULL; - S390pciState *s = s390_get_phb(); if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) { error_setg(errp, "PCI bridge hot unplug currently not supported"); @@ -956,6 +966,8 @@ static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, } else if (object_dynamic_cast(OBJECT(dev), TYPE_S390_PCI_DEVICE)) { pbdev = S390_PCI_DEVICE(dev); pci_dev = pbdev->pdev; + } else { + g_assert_not_reached(); } switch (pbdev->state) { @@ -964,6 +976,9 @@ static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, case ZPCI_FS_STANDBY: break; default: + if (pbdev->release_timer) { + return; + } s390_pci_generate_plug_event(HP_EVENT_DECONFIGURE_REQUEST, pbdev->fh, pbdev->fid); pbdev->release_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, @@ -974,7 +989,7 @@ static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, return; } - if (pbdev->release_timer && timer_pending(pbdev->release_timer)) { + if (pbdev->release_timer) { timer_del(pbdev->release_timer); timer_free(pbdev->release_timer); pbdev->release_timer = NULL; @@ -985,6 +1000,7 @@ static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, bus = pci_get_bus(pci_dev); devfn = pci_dev->devfn; object_unparent(OBJECT(pci_dev)); + fmb_timer_free(pbdev); s390_pci_msix_free(pbdev); s390_pci_iommu_free(s, bus, devfn); pbdev->pdev = NULL; @@ -1041,6 +1057,7 @@ static void s390_pcihost_class_init(ObjectClass *klass, void *data) dc->reset = s390_pcihost_reset; dc->realize = s390_pcihost_realize; + hc->pre_plug = s390_pcihost_pre_plug; hc->plug = s390_pcihost_plug; hc->unplug = s390_pcihost_unplug; msi_nonbroken = true; @@ -1132,6 +1149,7 @@ static void s390_pci_device_realize(DeviceState *dev, Error **errp) } zpci->state = ZPCI_FS_RESERVED; + zpci->fmb.format = ZPCI_FMB_FORMAT; } static void s390_pci_device_reset(DeviceState *dev) @@ -1156,7 +1174,7 @@ static void s390_pci_device_reset(DeviceState *dev) pci_dereg_ioat(pbdev->iommu); } - pbdev->fmb_addr = 0; + fmb_timer_free(pbdev); } static void s390_pci_get_fid(Object *obj, Visitor *v, const char *name, diff --git a/hw/s390x/s390-pci-bus.h b/hw/s390x/s390-pci-bus.h index f47a0f2da5..dadad1f758 100644 --- a/hw/s390x/s390-pci-bus.h +++ b/hw/s390x/s390-pci-bus.h @@ -285,6 +285,33 @@ typedef struct S390PCIIOMMUTable { S390PCIIOMMU *iommu[PCI_SLOT_MAX]; } S390PCIIOMMUTable; +/* Function Measurement Block */ +#define DEFAULT_MUI 4000 +#define UPDATE_U_BIT 0x1ULL +#define FMBK_MASK 0xfULL + +typedef struct ZpciFmbFmt0 { + uint64_t dma_rbytes; + uint64_t dma_wbytes; +} ZpciFmbFmt0; + +#define ZPCI_FMB_CNT_LD 0 +#define ZPCI_FMB_CNT_ST 1 +#define ZPCI_FMB_CNT_STB 2 +#define ZPCI_FMB_CNT_RPCIT 3 +#define ZPCI_FMB_CNT_MAX 4 + +#define ZPCI_FMB_FORMAT 0 + +typedef struct ZpciFmb { + uint32_t format; + uint32_t sample; + uint64_t last_update; + uint64_t counter[ZPCI_FMB_CNT_MAX]; + ZpciFmbFmt0 fmt0; +} ZpciFmb; +QEMU_BUILD_BUG_MSG(offsetof(ZpciFmb, fmt0) != 48, "padding in ZpciFmb"); + struct S390PCIBusDevice { DeviceState qdev; PCIDevice *pdev; @@ -296,6 +323,8 @@ struct S390PCIBusDevice { uint32_t fid; bool fid_defined; uint64_t fmb_addr; + ZpciFmb fmb; + QEMUTimer *fmb_timer; uint8_t isc; uint16_t noi; uint16_t maxstbl; diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index 7b61367ee3..be2896232d 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -19,6 +19,7 @@ #include "exec/memory-internal.h" #include "qemu/error-report.h" #include "sysemu/hw_accel.h" +#include "hw/s390x/tod.h" #ifndef DEBUG_S390PCI_INST #define DEBUG_S390PCI_INST 0 @@ -293,7 +294,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra) resgrp->fr = 1; stq_p(&resgrp->dasm, 0); stq_p(&resgrp->msia, ZPCI_MSI_ADDR); - stw_p(&resgrp->mui, 0); + stw_p(&resgrp->mui, DEFAULT_MUI); stw_p(&resgrp->i, 128); stw_p(&resgrp->maxstbl, 128); resgrp->version = 0; @@ -456,6 +457,8 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) return 0; } + pbdev->fmb.counter[ZPCI_FMB_CNT_LD]++; + env->regs[r1] = data; setcc(cpu, ZPCI_PCI_LS_OK); return 0; @@ -561,6 +564,8 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) return 0; } + pbdev->fmb.counter[ZPCI_FMB_CNT_ST]++; + setcc(cpu, ZPCI_PCI_LS_OK); return 0; } @@ -681,6 +686,7 @@ err: s390_set_status_code(env, r1, ZPCI_PCI_ST_FUNC_IN_ERR); s390_pci_generate_error_event(error, pbdev->fh, pbdev->fid, start, 0); } else { + pbdev->fmb.counter[ZPCI_FMB_CNT_RPCIT]++; setcc(cpu, ZPCI_PCI_LS_OK); } return 0; @@ -783,6 +789,8 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, } } + pbdev->fmb.counter[ZPCI_FMB_CNT_STB]++; + setcc(cpu, ZPCI_PCI_LS_OK); return 0; @@ -889,6 +897,99 @@ void pci_dereg_ioat(S390PCIIOMMU *iommu) iommu->g_iota = 0; } +void fmb_timer_free(S390PCIBusDevice *pbdev) +{ + if (pbdev->fmb_timer) { + timer_del(pbdev->fmb_timer); + timer_free(pbdev->fmb_timer); + pbdev->fmb_timer = NULL; + } + pbdev->fmb_addr = 0; + memset(&pbdev->fmb, 0, sizeof(ZpciFmb)); +} + +static int fmb_do_update(S390PCIBusDevice *pbdev, int offset, uint64_t val, + int len) +{ + MemTxResult ret; + uint64_t dst = pbdev->fmb_addr + offset; + + switch (len) { + case 8: + address_space_stq_be(&address_space_memory, dst, val, + MEMTXATTRS_UNSPECIFIED, + &ret); + break; + case 4: + address_space_stl_be(&address_space_memory, dst, val, + MEMTXATTRS_UNSPECIFIED, + &ret); + break; + case 2: + address_space_stw_be(&address_space_memory, dst, val, + MEMTXATTRS_UNSPECIFIED, + &ret); + break; + case 1: + address_space_stb(&address_space_memory, dst, val, + MEMTXATTRS_UNSPECIFIED, + &ret); + break; + default: + ret = MEMTX_ERROR; + break; + } + if (ret != MEMTX_OK) { + s390_pci_generate_error_event(ERR_EVENT_FMBA, pbdev->fh, pbdev->fid, + pbdev->fmb_addr, 0); + fmb_timer_free(pbdev); + } + + return ret; +} + +static void fmb_update(void *opaque) +{ + S390PCIBusDevice *pbdev = opaque; + int64_t t = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL); + int i; + + /* Update U bit */ + pbdev->fmb.last_update *= 2; + pbdev->fmb.last_update |= UPDATE_U_BIT; + if (fmb_do_update(pbdev, offsetof(ZpciFmb, last_update), + pbdev->fmb.last_update, + sizeof(pbdev->fmb.last_update))) { + return; + } + + /* Update FMB sample count */ + if (fmb_do_update(pbdev, offsetof(ZpciFmb, sample), + pbdev->fmb.sample++, + sizeof(pbdev->fmb.sample))) { + return; + } + + /* Update FMB counters */ + for (i = 0; i < ZPCI_FMB_CNT_MAX; i++) { + if (fmb_do_update(pbdev, offsetof(ZpciFmb, counter[i]), + pbdev->fmb.counter[i], + sizeof(pbdev->fmb.counter[0]))) { + return; + } + } + + /* Clear U bit and update the time */ + pbdev->fmb.last_update = time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); + pbdev->fmb.last_update *= 2; + if (fmb_do_update(pbdev, offsetof(ZpciFmb, last_update), + pbdev->fmb.last_update, + sizeof(pbdev->fmb.last_update))) { + return; + } + timer_mod(pbdev->fmb_timer, t + DEFAULT_MUI); +} + int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, uintptr_t ra) { @@ -1018,9 +1119,35 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); } break; - case ZPCI_MOD_FC_SET_MEASURE: - pbdev->fmb_addr = ldq_p(&fib.fmb_addr); + case ZPCI_MOD_FC_SET_MEASURE: { + uint64_t fmb_addr = ldq_p(&fib.fmb_addr); + + if (fmb_addr & FMBK_MASK) { + cc = ZPCI_PCI_LS_ERR; + s390_pci_generate_error_event(ERR_EVENT_FMBPRO, pbdev->fh, + pbdev->fid, fmb_addr, 0); + fmb_timer_free(pbdev); + break; + } + + if (!fmb_addr) { + /* Stop updating FMB. */ + fmb_timer_free(pbdev); + break; + } + + if (!pbdev->fmb_timer) { + pbdev->fmb_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, + fmb_update, pbdev); + } else if (timer_pending(pbdev->fmb_timer)) { + /* Remove pending timer to update FMB address. */ + timer_del(pbdev->fmb_timer); + } + pbdev->fmb_addr = fmb_addr; + timer_mod(pbdev->fmb_timer, + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + DEFAULT_MUI); break; + } default: s390_program_interrupt(&cpu->env, PGM_OPERAND, 6, ra); cc = ZPCI_PCI_LS_ERR; diff --git a/hw/s390x/s390-pci-inst.h b/hw/s390x/s390-pci-inst.h index 91c3d61f2a..fa3bf8b5aa 100644 --- a/hw/s390x/s390-pci-inst.h +++ b/hw/s390x/s390-pci-inst.h @@ -303,6 +303,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, uintptr_t ra); int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, uintptr_t ra); +void fmb_timer_free(S390PCIBusDevice *pbdev); #define ZPCI_IO_BAR_MIN 0 #define ZPCI_IO_BAR_MAX 5 diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index 7f21b4f9d6..61e2e57da9 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -215,6 +215,7 @@ static void vhost_scsi_unrealize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VHostSCSICommon *vsc = VHOST_SCSI_COMMON(dev); + struct vhost_virtqueue *vqs = vsc->dev.vqs; migrate_del_blocker(vsc->migration_blocker); error_free(vsc->migration_blocker); @@ -223,7 +224,7 @@ static void vhost_scsi_unrealize(DeviceState *dev, Error **errp) vhost_scsi_set_status(vdev, 0); vhost_dev_cleanup(&vsc->dev); - g_free(vsc->dev.vqs); + g_free(vqs); virtio_scsi_common_unrealize(dev, errp); } diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c index 2e1ba4a87b..6728878a52 100644 --- a/hw/scsi/vhost-user-scsi.c +++ b/hw/scsi/vhost-user-scsi.c @@ -121,12 +121,13 @@ static void vhost_user_scsi_unrealize(DeviceState *dev, Error **errp) VirtIODevice *vdev = VIRTIO_DEVICE(dev); VHostUserSCSI *s = VHOST_USER_SCSI(dev); VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); + struct vhost_virtqueue *vqs = vsc->dev.vqs; /* This will stop the vhost backend. */ vhost_user_scsi_set_status(vdev, 0); vhost_dev_cleanup(&vsc->dev); - g_free(vsc->dev.vqs); + g_free(vqs); virtio_scsi_common_unrealize(dev, errp); diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs index 1dc9f8bf2c..700c878622 100644 --- a/hw/tpm/Makefile.objs +++ b/hw/tpm/Makefile.objs @@ -1,4 +1,5 @@ common-obj-y += tpm_util.o +obj-y += tpm_ppi.o common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c index a92dd50437..3087acc4ab 100644 --- a/hw/tpm/tpm_crb.c +++ b/hw/tpm/tpm_crb.c @@ -29,6 +29,7 @@ #include "sysemu/reset.h" #include "tpm_int.h" #include "tpm_util.h" +#include "tpm_ppi.h" #include "trace.h" typedef struct CRBState { @@ -41,6 +42,9 @@ typedef struct CRBState { MemoryRegion cmdmem; size_t be_buffer_size; + + bool ppi_enabled; + TPMPPI ppi; } CRBState; #define CRB(obj) OBJECT_CHECK(CRBState, (obj), TYPE_TPM_CRB) @@ -221,6 +225,7 @@ static const VMStateDescription vmstate_tpm_crb = { static Property tpm_crb_properties[] = { DEFINE_PROP_TPMBE("tpmdev", CRBState, tpmbe), + DEFINE_PROP_BOOL("ppi", CRBState, ppi_enabled, true), DEFINE_PROP_END_OF_LIST(), }; @@ -228,6 +233,9 @@ static void tpm_crb_reset(void *dev) { CRBState *s = CRB(dev); + if (s->ppi_enabled) { + tpm_ppi_reset(&s->ppi); + } tpm_backend_reset(s->tpmbe); memset(s->regs, 0, sizeof(s->regs)); @@ -291,6 +299,11 @@ static void tpm_crb_realize(DeviceState *dev, Error **errp) memory_region_add_subregion(get_system_memory(), TPM_CRB_ADDR_BASE + sizeof(s->regs), &s->cmdmem); + if (s->ppi_enabled) { + tpm_ppi_init(&s->ppi, get_system_memory(), + TPM_PPI_ADDR_BASE, OBJECT(s)); + } + qemu_register_reset(tpm_crb_reset, dev); } diff --git a/hw/tpm/tpm_ppi.c b/hw/tpm/tpm_ppi.c new file mode 100644 index 0000000000..cd8205f212 --- /dev/null +++ b/hw/tpm/tpm_ppi.c @@ -0,0 +1,53 @@ +/* + * tpm_ppi.c - TPM Physical Presence Interface + * + * Copyright (C) 2018 IBM Corporation + * + * Authors: + * Stefan Berger <stefanb@us.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" + +#include "qapi/error.h" +#include "cpu.h" +#include "sysemu/memory_mapping.h" +#include "sysemu/reset.h" +#include "migration/vmstate.h" +#include "tpm_ppi.h" +#include "trace.h" + +void tpm_ppi_reset(TPMPPI *tpmppi) +{ + if (tpmppi->buf[0x15a /* movv, docs/specs/tpm.txt */] & 0x1) { + GuestPhysBlockList guest_phys_blocks; + GuestPhysBlock *block; + + guest_phys_blocks_init(&guest_phys_blocks); + guest_phys_blocks_append(&guest_phys_blocks); + QTAILQ_FOREACH(block, &guest_phys_blocks.head, next) { + trace_tpm_ppi_memset(block->host_addr, + block->target_end - block->target_start); + memset(block->host_addr, 0, + block->target_end - block->target_start); + memory_region_set_dirty(block->mr, 0, + block->target_end - block->target_start); + } + guest_phys_blocks_free(&guest_phys_blocks); + } +} + +void tpm_ppi_init(TPMPPI *tpmppi, struct MemoryRegion *m, + hwaddr addr, Object *obj) +{ + tpmppi->buf = g_malloc0(HOST_PAGE_ALIGN(TPM_PPI_ADDR_SIZE)); + memory_region_init_ram_device_ptr(&tpmppi->ram, obj, "tpm-ppi", + TPM_PPI_ADDR_SIZE, tpmppi->buf); + vmstate_register_ram(&tpmppi->ram, DEVICE(obj)); + + memory_region_add_subregion(m, addr, &tpmppi->ram); +} diff --git a/hw/tpm/tpm_ppi.h b/hw/tpm/tpm_ppi.h new file mode 100644 index 0000000000..d33ef27de6 --- /dev/null +++ b/hw/tpm/tpm_ppi.h @@ -0,0 +1,46 @@ +/* + * TPM Physical Presence Interface + * + * Copyright (C) 2018 IBM Corporation + * + * Authors: + * Stefan Berger <stefanb@us.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#ifndef TPM_TPM_PPI_H +#define TPM_TPM_PPI_H + +#include "hw/acpi/tpm.h" +#include "exec/address-spaces.h" + +typedef struct TPMPPI { + MemoryRegion ram; + uint8_t *buf; +} TPMPPI; + +/** + * tpm_ppi_init: + * @tpmppi: a TPMPPI + * @m: the address-space / MemoryRegion to use + * @addr: the address of the PPI region + * @obj: the owner object + * + * Register the TPM PPI memory region at @addr on the given address + * space for the object @obj. + **/ +void tpm_ppi_init(TPMPPI *tpmppi, struct MemoryRegion *m, + hwaddr addr, Object *obj); + +/** + * tpm_ppi_reset: + * @tpmppi: a TPMPPI + * + * Function to call on machine reset. It will check if the "Memory + * overwrite" variable is set, and perform a memory clear on volatile + * memory if requested. + **/ +void tpm_ppi_reset(TPMPPI *tpmppi); + +#endif /* TPM_TPM_PPI_H */ diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index 2563d7501f..fd6bb9b59a 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -31,6 +31,7 @@ #include "sysemu/tpm_backend.h" #include "tpm_int.h" #include "tpm_util.h" +#include "tpm_ppi.h" #include "trace.h" #define TPM_TIS_NUM_LOCALITIES 5 /* per spec */ @@ -81,6 +82,9 @@ typedef struct TPMState { TPMVersion be_tpm_version; size_t be_buffer_size; + + bool ppi_enabled; + TPMPPI ppi; } TPMState; #define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS) @@ -868,6 +872,9 @@ static void tpm_tis_reset(DeviceState *dev) s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->be_driver), TPM_TIS_BUFFER_MAX); + if (s->ppi_enabled) { + tpm_ppi_reset(&s->ppi); + } tpm_backend_reset(s->be_driver); s->active_locty = TPM_TIS_NO_LOCALITY; @@ -954,6 +961,7 @@ static const VMStateDescription vmstate_tpm_tis = { static Property tpm_tis_properties[] = { DEFINE_PROP_UINT32("irq", TPMState, irq_num, TPM_TIS_IRQ), DEFINE_PROP_TPMBE("tpmdev", TPMState, be_driver), + DEFINE_PROP_BOOL("ppi", TPMState, ppi_enabled, true), DEFINE_PROP_END_OF_LIST(), }; @@ -980,6 +988,11 @@ static void tpm_tis_realizefn(DeviceState *dev, Error **errp) memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)), TPM_TIS_ADDR_BASE, &s->mmio); + + if (s->ppi_enabled) { + tpm_ppi_init(&s->ppi, isa_address_space(ISA_DEVICE(dev)), + TPM_PPI_ADDR_BASE, OBJECT(s)); + } } static void tpm_tis_initfn(Object *obj) diff --git a/hw/tpm/trace-events b/hw/tpm/trace-events index 25bee0cecf..920d32ad55 100644 --- a/hw/tpm/trace-events +++ b/hw/tpm/trace-events @@ -51,3 +51,6 @@ tpm_tis_mmio_write_init_abort(void) "Initiating abort" tpm_tis_mmio_write_lowering_irq(void) "Lowering IRQ" tpm_tis_mmio_write_data2send(uint32_t value, unsigned size) "Data to send to TPM: 0x%08x (size=%d)" tpm_tis_pre_save(uint8_t locty, uint32_t rw_offset) "locty: %d, rw_offset = %u" + +# hw/tpm/tpm_ppi.c +tpm_ppi_memset(uint8_t *ptr, size_t size) "memset: %p %zu" diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs index 1b2799cfd8..ea7913d532 100644 --- a/hw/virtio/Makefile.objs +++ b/hw/virtio/Makefile.objs @@ -11,6 +11,21 @@ obj-$(call land,$(CONFIG_VIRTIO_CRYPTO),$(CONFIG_VIRTIO_PCI)) += virtio-crypto-p obj-$(CONFIG_LINUX) += vhost.o vhost-backend.o vhost-user.o obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock.o +ifeq ($(CONFIG_PCI),y) +obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock-pci.o +obj-$(CONFIG_VHOST_USER_BLK) += vhost-user-blk-pci.o +obj-$(CONFIG_VHOST_USER_SCSI) += vhost-user-scsi-pci.o +obj-$(CONFIG_VHOST_SCSI) += vhost-scsi-pci.o +obj-$(CONFIG_VIRTIO_INPUT_HOST) += virtio-input-host-pci.o +obj-$(CONFIG_VIRTIO_INPUT) += virtio-input-pci.o +obj-$(CONFIG_VIRTIO_RNG) += virtio-rng-pci.o +obj-$(CONFIG_VIRTIO_BALLOON) += virtio-balloon-pci.o +obj-$(CONFIG_VIRTIO_9P) += virtio-9p-pci.o +obj-$(CONFIG_VIRTIO_SCSI) += virtio-scsi-pci.o +obj-$(CONFIG_VIRTIO_BLK) += virtio-blk-pci.o +obj-$(CONFIG_VIRTIO_NET) += virtio-net-pci.o +obj-$(CONFIG_VIRTIO_SERIAL) += virtio-serial-pci.o +endif endif common-obj-$(call lnot,$(call land,$(CONFIG_VIRTIO),$(CONFIG_LINUX))) += vhost-stub.o diff --git a/hw/virtio/vhost-scsi-pci.c b/hw/virtio/vhost-scsi-pci.c new file mode 100644 index 0000000000..523f7cb3ce --- /dev/null +++ b/hw/virtio/vhost-scsi-pci.c @@ -0,0 +1,97 @@ +/* + * Vhost scsi PCI bindings + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> + * + * Changes for QEMU mainline + tcm_vhost kernel upstream: + * Nicholas Bellinger <nab@risingtidesystems.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include "qemu/osdep.h" + +#include "standard-headers/linux/virtio_pci.h" +#include "hw/virtio/vhost-scsi.h" +#include "qapi/error.h" +#include "virtio-pci.h" + +typedef struct VHostSCSIPCI VHostSCSIPCI; + +/* + * vhost-scsi-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VHOST_SCSI_PCI "vhost-scsi-pci-base" +#define VHOST_SCSI_PCI(obj) \ + OBJECT_CHECK(VHostSCSIPCI, (obj), TYPE_VHOST_SCSI_PCI) + +struct VHostSCSIPCI { + VirtIOPCIProxy parent_obj; + VHostSCSI vdev; +}; + +static Property vhost_scsi_pci_properties[] = { + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, + DEV_NVECTORS_UNSPECIFIED), + DEFINE_PROP_END_OF_LIST(), +}; + +static void vhost_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VHostSCSIPCI *dev = VHOST_SCSI_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); + + if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { + vpci_dev->nvectors = vs->conf.num_queues + 3; + } + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + +static void vhost_scsi_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + k->realize = vhost_scsi_pci_realize; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); + dc->props = vhost_scsi_pci_properties; + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI; + pcidev_k->revision = 0x00; + pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI; +} + +static void vhost_scsi_pci_instance_init(Object *obj) +{ + VHostSCSIPCI *dev = VHOST_SCSI_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VHOST_SCSI); + object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), + "bootindex", &error_abort); +} + +static const VirtioPCIDeviceTypeInfo vhost_scsi_pci_info = { + .base_name = TYPE_VHOST_SCSI_PCI, + .generic_name = "vhost-scsi-pci", + .transitional_name = "vhost-scsi-pci-transitional", + .non_transitional_name = "vhost-scsi-pci-non-transitional", + .instance_size = sizeof(VHostSCSIPCI), + .instance_init = vhost_scsi_pci_instance_init, + .class_init = vhost_scsi_pci_class_init, +}; + +static void vhost_scsi_pci_register(void) +{ + virtio_pci_types_register(&vhost_scsi_pci_info); +} + +type_init(vhost_scsi_pci_register) diff --git a/hw/virtio/vhost-user-blk-pci.c b/hw/virtio/vhost-user-blk-pci.c new file mode 100644 index 0000000000..ca66c217a7 --- /dev/null +++ b/hw/virtio/vhost-user-blk-pci.c @@ -0,0 +1,103 @@ +/* + * Vhost user blk PCI Bindings + * + * Copyright(C) 2017 Intel Corporation. + * + * Authors: + * Changpeng Liu <changpeng.liu@intel.com> + * + * Largely based on the "vhost-user-scsi.c" and "vhost-scsi.c" implemented by: + * Felipe Franciosi <felipe@nutanix.com> + * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> + * Nicholas Bellinger <nab@risingtidesystems.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include "qemu/osdep.h" + +#include "standard-headers/linux/virtio_pci.h" +#include "hw/virtio/virtio.h" +#include "hw/virtio/vhost-user-blk.h" +#include "hw/pci/pci.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "virtio-pci.h" + +typedef struct VHostUserBlkPCI VHostUserBlkPCI; + +/* + * vhost-user-blk-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VHOST_USER_BLK_PCI "vhost-user-blk-pci-base" +#define VHOST_USER_BLK_PCI(obj) \ + OBJECT_CHECK(VHostUserBlkPCI, (obj), TYPE_VHOST_USER_BLK_PCI) + +struct VHostUserBlkPCI { + VirtIOPCIProxy parent_obj; + VHostUserBlk vdev; +}; + +static Property vhost_user_blk_pci_properties[] = { + DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, + DEV_NVECTORS_UNSPECIFIED), + DEFINE_PROP_END_OF_LIST(), +}; + +static void vhost_user_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VHostUserBlkPCI *dev = VHOST_USER_BLK_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + + if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { + vpci_dev->nvectors = dev->vdev.num_queues + 1; + } + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + +static void vhost_user_blk_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); + dc->props = vhost_user_blk_pci_properties; + k->realize = vhost_user_blk_pci_realize; + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK; + pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; + pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI; +} + +static void vhost_user_blk_pci_instance_init(Object *obj) +{ + VHostUserBlkPCI *dev = VHOST_USER_BLK_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VHOST_USER_BLK); + object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), + "bootindex", &error_abort); +} + +static const VirtioPCIDeviceTypeInfo vhost_user_blk_pci_info = { + .base_name = TYPE_VHOST_USER_BLK_PCI, + .generic_name = "vhost-user-blk-pci", + .transitional_name = "vhost-user-blk-pci-transitional", + .non_transitional_name = "vhost-user-blk-pci-non-transitional", + .instance_size = sizeof(VHostUserBlkPCI), + .instance_init = vhost_user_blk_pci_instance_init, + .class_init = vhost_user_blk_pci_class_init, +}; + +static void vhost_user_blk_pci_register(void) +{ + virtio_pci_types_register(&vhost_user_blk_pci_info); +} + +type_init(vhost_user_blk_pci_register) diff --git a/hw/virtio/vhost-user-scsi-pci.c b/hw/virtio/vhost-user-scsi-pci.c new file mode 100644 index 0000000000..46f7193cc7 --- /dev/null +++ b/hw/virtio/vhost-user-scsi-pci.c @@ -0,0 +1,103 @@ +/* + * Vhost user scsi PCI Bindings + * + * Copyright (c) 2016 Nutanix Inc. All rights reserved. + * + * Author: + * Felipe Franciosi <felipe@nutanix.com> + * + * This work is largely based on the "vhost-scsi" implementation by: + * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> + * Nicholas Bellinger <nab@risingtidesystems.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include "qemu/osdep.h" + +#include "standard-headers/linux/virtio_pci.h" +#include "hw/virtio/vhost-user-scsi.h" +#include "hw/virtio/virtio.h" +#include "hw/virtio/virtio-scsi.h" +#include "hw/pci/pci.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "hw/pci/msi.h" +#include "hw/pci/msix.h" +#include "hw/loader.h" +#include "sysemu/kvm.h" +#include "virtio-pci.h" + +typedef struct VHostUserSCSIPCI VHostUserSCSIPCI; + +#define TYPE_VHOST_USER_SCSI_PCI "vhost-user-scsi-pci-base" +#define VHOST_USER_SCSI_PCI(obj) \ + OBJECT_CHECK(VHostUserSCSIPCI, (obj), TYPE_VHOST_USER_SCSI_PCI) + +struct VHostUserSCSIPCI { + VirtIOPCIProxy parent_obj; + VHostUserSCSI vdev; +}; + +static Property vhost_user_scsi_pci_properties[] = { + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, + DEV_NVECTORS_UNSPECIFIED), + DEFINE_PROP_END_OF_LIST(), +}; + +static void vhost_user_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VHostUserSCSIPCI *dev = VHOST_USER_SCSI_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); + + if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { + vpci_dev->nvectors = vs->conf.num_queues + 3; + } + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + +static void vhost_user_scsi_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + k->realize = vhost_user_scsi_pci_realize; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); + dc->props = vhost_user_scsi_pci_properties; + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI; + pcidev_k->revision = 0x00; + pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI; +} + +static void vhost_user_scsi_pci_instance_init(Object *obj) +{ + VHostUserSCSIPCI *dev = VHOST_USER_SCSI_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VHOST_USER_SCSI); + object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), + "bootindex", &error_abort); +} + +static const VirtioPCIDeviceTypeInfo vhost_user_scsi_pci_info = { + .base_name = TYPE_VHOST_USER_SCSI_PCI, + .generic_name = "vhost-user-scsi-pci", + .transitional_name = "vhost-user-scsi-pci-transitional", + .non_transitional_name = "vhost-user-scsi-pci-non-transitional", + .instance_size = sizeof(VHostUserSCSIPCI), + .instance_init = vhost_user_scsi_pci_instance_init, + .class_init = vhost_user_scsi_pci_class_init, +}; + +static void vhost_user_scsi_pci_register(void) +{ + virtio_pci_types_register(&vhost_user_scsi_pci_info); +} + +type_init(vhost_user_scsi_pci_register) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index e09bed0e4a..564a31d12c 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -207,7 +207,7 @@ struct vhost_user { static bool ioeventfd_enabled(void) { - return kvm_enabled() && kvm_eventfds_enabled(); + return !kvm_enabled() || kvm_eventfds_enabled(); } static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg) diff --git a/hw/virtio/vhost-vsock-pci.c b/hw/virtio/vhost-vsock-pci.c new file mode 100644 index 0000000000..6f43ca35fb --- /dev/null +++ b/hw/virtio/vhost-vsock-pci.c @@ -0,0 +1,86 @@ +/* + * Vhost vsock PCI Bindings + * + * Copyright 2015 Red Hat, Inc. + * + * Authors: + * Stefan Hajnoczi <stefanha@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#include "qemu/osdep.h" + +#include "virtio-pci.h" +#include "hw/virtio/vhost-vsock.h" + +typedef struct VHostVSockPCI VHostVSockPCI; + +/* + * vhost-vsock-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VHOST_VSOCK_PCI "vhost-vsock-pci-base" +#define VHOST_VSOCK_PCI(obj) \ + OBJECT_CHECK(VHostVSockPCI, (obj), TYPE_VHOST_VSOCK_PCI) + +struct VHostVSockPCI { + VirtIOPCIProxy parent_obj; + VHostVSock vdev; +}; + +/* vhost-vsock-pci */ + +static Property vhost_vsock_pci_properties[] = { + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3), + DEFINE_PROP_END_OF_LIST(), +}; + +static void vhost_vsock_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VHostVSockPCI *dev = VHOST_VSOCK_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + +static void vhost_vsock_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + k->realize = vhost_vsock_pci_realize; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + dc->props = vhost_vsock_pci_properties; + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_VSOCK; + pcidev_k->revision = 0x00; + pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER; +} + +static void vhost_vsock_pci_instance_init(Object *obj) +{ + VHostVSockPCI *dev = VHOST_VSOCK_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VHOST_VSOCK); +} + +static const VirtioPCIDeviceTypeInfo vhost_vsock_pci_info = { + .base_name = TYPE_VHOST_VSOCK_PCI, + .generic_name = "vhost-vsock-pci", + .transitional_name = "vhost-vsock-pci-transitional", + .non_transitional_name = "vhost-vsock-pci-non-transitional", + .instance_size = sizeof(VHostVSockPCI), + .instance_init = vhost_vsock_pci_instance_init, + .class_init = vhost_vsock_pci_class_init, +}; + +static void virtio_pci_vhost_register(void) +{ + virtio_pci_types_register(&vhost_vsock_pci_info); +} + +type_init(virtio_pci_vhost_register) diff --git a/hw/virtio/virtio-9p-pci.c b/hw/virtio/virtio-9p-pci.c new file mode 100644 index 0000000000..7bf1130966 --- /dev/null +++ b/hw/virtio/virtio-9p-pci.c @@ -0,0 +1,88 @@ +/* + * Virtio 9p PCI Bindings + * + * Copyright IBM, Corp. 2010 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "qemu/osdep.h" + +#include "virtio-pci.h" +#include "hw/9pfs/virtio-9p.h" + +/* + * virtio-9p-pci: This extends VirtioPCIProxy. + */ + +#define TYPE_VIRTIO_9P_PCI "virtio-9p-pci-base" +#define VIRTIO_9P_PCI(obj) \ + OBJECT_CHECK(V9fsPCIState, (obj), TYPE_VIRTIO_9P_PCI) + +typedef struct V9fsPCIState { + VirtIOPCIProxy parent_obj; + V9fsVirtioState vdev; +} V9fsPCIState; + +static void virtio_9p_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + V9fsPCIState *dev = VIRTIO_9P_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + +static Property virtio_9p_pci_properties[] = { + DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, + VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_9p_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + + k->realize = virtio_9p_pci_realize; + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_9P; + pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; + pcidev_k->class_id = 0x2; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); + dc->props = virtio_9p_pci_properties; +} + +static void virtio_9p_pci_instance_init(Object *obj) +{ + V9fsPCIState *dev = VIRTIO_9P_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_9P); +} + +static const VirtioPCIDeviceTypeInfo virtio_9p_pci_info = { + .base_name = TYPE_VIRTIO_9P_PCI, + .generic_name = "virtio-9p-pci", + .transitional_name = "virtio-9p-pci-transitional", + .non_transitional_name = "virtio-9p-pci-non-transitional", + .instance_size = sizeof(V9fsPCIState), + .instance_init = virtio_9p_pci_instance_init, + .class_init = virtio_9p_pci_class_init, +}; + +static void virtio_9p_pci_register(void) +{ + virtio_pci_types_register(&virtio_9p_pci_info); +} + +type_init(virtio_9p_pci_register) diff --git a/hw/virtio/virtio-balloon-pci.c b/hw/virtio/virtio-balloon-pci.c new file mode 100644 index 0000000000..2a213bbb38 --- /dev/null +++ b/hw/virtio/virtio-balloon-pci.c @@ -0,0 +1,95 @@ +/* + * Virtio balloon PCI Bindings + * + * Copyright IBM, Corp. 2007 + * Copyright (c) 2009 CodeSourcery + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * Paul Brook <paul@codesourcery.com> + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "qemu/osdep.h" + +#include "virtio-pci.h" +#include "hw/virtio/virtio-balloon.h" +#include "qapi/error.h" + +typedef struct VirtIOBalloonPCI VirtIOBalloonPCI; + +/* + * virtio-balloon-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VIRTIO_BALLOON_PCI "virtio-balloon-pci-base" +#define VIRTIO_BALLOON_PCI(obj) \ + OBJECT_CHECK(VirtIOBalloonPCI, (obj), TYPE_VIRTIO_BALLOON_PCI) + +struct VirtIOBalloonPCI { + VirtIOPCIProxy parent_obj; + VirtIOBalloon vdev; +}; +static Property virtio_balloon_pci_properties[] = { + DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_balloon_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + + if (vpci_dev->class_code != PCI_CLASS_OTHERS && + vpci_dev->class_code != PCI_CLASS_MEMORY_RAM) { /* qemu < 1.1 */ + vpci_dev->class_code = PCI_CLASS_OTHERS; + } + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + +static void virtio_balloon_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + k->realize = virtio_balloon_pci_realize; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + dc->props = virtio_balloon_pci_properties; + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON; + pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; + pcidev_k->class_id = PCI_CLASS_OTHERS; +} + +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_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 VirtioPCIDeviceTypeInfo virtio_balloon_pci_info = { + .base_name = TYPE_VIRTIO_BALLOON_PCI, + .generic_name = "virtio-balloon-pci", + .transitional_name = "virtio-balloon-pci-transitional", + .non_transitional_name = "virtio-balloon-pci-non-transitional", + .instance_size = sizeof(VirtIOBalloonPCI), + .instance_init = virtio_balloon_pci_instance_init, + .class_init = virtio_balloon_pci_class_init, +}; + +static void virtio_balloon_pci_register(void) +{ + virtio_pci_types_register(&virtio_balloon_pci_info); +} + +type_init(virtio_balloon_pci_register) diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 1728e4f83a..a12677d4d5 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -311,7 +311,7 @@ out: static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data) { VirtIOBalloon *dev = VIRTIO_BALLOON(vdev); - struct virtio_balloon_config config; + struct virtio_balloon_config config = {}; config.num_pages = cpu_to_le32(dev->num_pages); config.actual = cpu_to_le32(dev->actual); diff --git a/hw/virtio/virtio-blk-pci.c b/hw/virtio/virtio-blk-pci.c new file mode 100644 index 0000000000..60c9185c39 --- /dev/null +++ b/hw/virtio/virtio-blk-pci.c @@ -0,0 +1,100 @@ +/* + * Virtio blk PCI Bindings + * + * Copyright IBM, Corp. 2007 + * Copyright (c) 2009 CodeSourcery + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * Paul Brook <paul@codesourcery.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "qemu/osdep.h" + +#include "hw/virtio/virtio-blk.h" +#include "virtio-pci.h" +#include "qapi/error.h" + +typedef struct VirtIOBlkPCI VirtIOBlkPCI; + +/* + * virtio-blk-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VIRTIO_BLK_PCI "virtio-blk-pci-base" +#define VIRTIO_BLK_PCI(obj) \ + OBJECT_CHECK(VirtIOBlkPCI, (obj), TYPE_VIRTIO_BLK_PCI) + +struct VirtIOBlkPCI { + VirtIOPCIProxy parent_obj; + VirtIOBlock vdev; +}; + +static Property virtio_blk_pci_properties[] = { + DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0), + DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, + VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, + DEV_NVECTORS_UNSPECIFIED), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + + if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { + vpci_dev->nvectors = dev->vdev.conf.num_queues + 1; + } + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + +static void virtio_blk_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); + dc->props = virtio_blk_pci_properties; + k->realize = virtio_blk_pci_realize; + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK; + pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; + pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI; +} + +static void virtio_blk_pci_instance_init(Object *obj) +{ + VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_BLK); + object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), + "bootindex", &error_abort); +} + +static const VirtioPCIDeviceTypeInfo virtio_blk_pci_info = { + .base_name = TYPE_VIRTIO_BLK_PCI, + .generic_name = "virtio-blk-pci", + .transitional_name = "virtio-blk-pci-transitional", + .non_transitional_name = "virtio-blk-pci-non-transitional", + .instance_size = sizeof(VirtIOBlkPCI), + .instance_init = virtio_blk_pci_instance_init, + .class_init = virtio_blk_pci_class_init, +}; + +static void virtio_blk_pci_register(void) +{ + virtio_pci_types_register(&virtio_blk_pci_info); +} + +type_init(virtio_blk_pci_register) diff --git a/hw/virtio/virtio-crypto-pci.c b/hw/virtio/virtio-crypto-pci.c index 8cc3fa3ef7..90a6e0dc2e 100644 --- a/hw/virtio/virtio-crypto-pci.c +++ b/hw/virtio/virtio-crypto-pci.c @@ -19,6 +19,20 @@ #include "hw/virtio/virtio-crypto.h" #include "qapi/error.h" +typedef struct VirtIOCryptoPCI VirtIOCryptoPCI; + +/* + * virtio-crypto-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VIRTIO_CRYPTO_PCI "virtio-crypto-pci" +#define VIRTIO_CRYPTO_PCI(obj) \ + OBJECT_CHECK(VirtIOCryptoPCI, (obj), TYPE_VIRTIO_CRYPTO_PCI) + +struct VirtIOCryptoPCI { + VirtIOPCIProxy parent_obj; + VirtIOCrypto vdev; +}; + static Property virtio_crypto_pci_properties[] = { DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), diff --git a/hw/virtio/virtio-input-host-pci.c b/hw/virtio/virtio-input-host-pci.c new file mode 100644 index 0000000000..725a51ad30 --- /dev/null +++ b/hw/virtio/virtio-input-host-pci.c @@ -0,0 +1,48 @@ +/* + * Virtio input host PCI Bindings + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#include "qemu/osdep.h" + +#include "virtio-pci.h" +#include "hw/virtio/virtio-input.h" + +typedef struct VirtIOInputHostPCI VirtIOInputHostPCI; + +#define TYPE_VIRTIO_INPUT_HOST_PCI "virtio-input-host-pci-base" +#define VIRTIO_INPUT_HOST_PCI(obj) \ + OBJECT_CHECK(VirtIOInputHostPCI, (obj), TYPE_VIRTIO_INPUT_HOST_PCI) + +struct VirtIOInputHostPCI { + VirtIOPCIProxy parent_obj; + VirtIOInputHost vdev; +}; + +static void virtio_host_initfn(Object *obj) +{ + VirtIOInputHostPCI *dev = VIRTIO_INPUT_HOST_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_INPUT_HOST); +} + +static const VirtioPCIDeviceTypeInfo virtio_input_host_pci_info = { + .base_name = TYPE_VIRTIO_INPUT_HOST_PCI, + .generic_name = "virtio-input-host-pci", + .transitional_name = "virtio-input-host-pci-transitional", + .non_transitional_name = "virtio-input-host-pci-non-transitional", + .parent = TYPE_VIRTIO_INPUT_PCI, + .instance_size = sizeof(VirtIOInputHostPCI), + .instance_init = virtio_host_initfn, +}; + +static void virtio_input_host_pci_register(void) +{ + virtio_pci_types_register(&virtio_input_host_pci_info); +} + +type_init(virtio_input_host_pci_register) diff --git a/hw/virtio/virtio-input-pci.c b/hw/virtio/virtio-input-pci.c new file mode 100644 index 0000000000..2c1397842b --- /dev/null +++ b/hw/virtio/virtio-input-pci.c @@ -0,0 +1,157 @@ +/* + * Virtio input PCI Bindings + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#include "qemu/osdep.h" + +#include "virtio-pci.h" +#include "hw/virtio/virtio-input.h" + +typedef struct VirtIOInputPCI VirtIOInputPCI; +typedef struct VirtIOInputHIDPCI VirtIOInputHIDPCI; + +/* + * virtio-input-pci: This extends VirtioPCIProxy. + */ +#define VIRTIO_INPUT_PCI(obj) \ + OBJECT_CHECK(VirtIOInputPCI, (obj), TYPE_VIRTIO_INPUT_PCI) + +struct VirtIOInputPCI { + VirtIOPCIProxy parent_obj; + VirtIOInput vdev; +}; + +#define TYPE_VIRTIO_INPUT_HID_PCI "virtio-input-hid-pci" +#define TYPE_VIRTIO_KEYBOARD_PCI "virtio-keyboard-pci" +#define TYPE_VIRTIO_MOUSE_PCI "virtio-mouse-pci" +#define TYPE_VIRTIO_TABLET_PCI "virtio-tablet-pci" +#define VIRTIO_INPUT_HID_PCI(obj) \ + OBJECT_CHECK(VirtIOInputHIDPCI, (obj), TYPE_VIRTIO_INPUT_HID_PCI) + +struct VirtIOInputHIDPCI { + VirtIOPCIProxy parent_obj; + VirtIOInputHID vdev; +}; + +static Property virtio_input_pci_properties[] = { + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_input_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VirtIOInputPCI *vinput = VIRTIO_INPUT_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&vinput->vdev); + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + virtio_pci_force_virtio_1(vpci_dev); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + +static void virtio_input_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + + dc->props = virtio_input_pci_properties; + k->realize = virtio_input_pci_realize; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); + + pcidev_k->class_id = PCI_CLASS_INPUT_OTHER; +} + +static void virtio_input_hid_kbd_pci_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + + pcidev_k->class_id = PCI_CLASS_INPUT_KEYBOARD; +} + +static void virtio_input_hid_mouse_pci_class_init(ObjectClass *klass, + void *data) +{ + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + + pcidev_k->class_id = PCI_CLASS_INPUT_MOUSE; +} + +static void virtio_keyboard_initfn(Object *obj) +{ + VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_KEYBOARD); +} + +static void virtio_mouse_initfn(Object *obj) +{ + VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_MOUSE); +} + +static void virtio_tablet_initfn(Object *obj) +{ + VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_TABLET); +} + +static const TypeInfo virtio_input_pci_info = { + .name = TYPE_VIRTIO_INPUT_PCI, + .parent = TYPE_VIRTIO_PCI, + .instance_size = sizeof(VirtIOInputPCI), + .class_init = virtio_input_pci_class_init, + .abstract = true, +}; + +static const TypeInfo virtio_input_hid_pci_info = { + .name = TYPE_VIRTIO_INPUT_HID_PCI, + .parent = TYPE_VIRTIO_INPUT_PCI, + .instance_size = sizeof(VirtIOInputHIDPCI), + .abstract = true, +}; + +static const VirtioPCIDeviceTypeInfo virtio_keyboard_pci_info = { + .generic_name = TYPE_VIRTIO_KEYBOARD_PCI, + .parent = TYPE_VIRTIO_INPUT_HID_PCI, + .class_init = virtio_input_hid_kbd_pci_class_init, + .instance_size = sizeof(VirtIOInputHIDPCI), + .instance_init = virtio_keyboard_initfn, +}; + +static const VirtioPCIDeviceTypeInfo virtio_mouse_pci_info = { + .generic_name = TYPE_VIRTIO_MOUSE_PCI, + .parent = TYPE_VIRTIO_INPUT_HID_PCI, + .class_init = virtio_input_hid_mouse_pci_class_init, + .instance_size = sizeof(VirtIOInputHIDPCI), + .instance_init = virtio_mouse_initfn, +}; + +static const VirtioPCIDeviceTypeInfo virtio_tablet_pci_info = { + .generic_name = TYPE_VIRTIO_TABLET_PCI, + .parent = TYPE_VIRTIO_INPUT_HID_PCI, + .instance_size = sizeof(VirtIOInputHIDPCI), + .instance_init = virtio_tablet_initfn, +}; + +static void virtio_pci_input_register(void) +{ + /* Base types: */ + type_register_static(&virtio_input_pci_info); + type_register_static(&virtio_input_hid_pci_info); + + /* Implementations: */ + virtio_pci_types_register(&virtio_keyboard_pci_info); + virtio_pci_types_register(&virtio_mouse_pci_info); + virtio_pci_types_register(&virtio_tablet_pci_info); +} + +type_init(virtio_pci_input_register) diff --git a/hw/virtio/virtio-net-pci.c b/hw/virtio/virtio-net-pci.c new file mode 100644 index 0000000000..db07ab9e21 --- /dev/null +++ b/hw/virtio/virtio-net-pci.c @@ -0,0 +1,98 @@ +/* + * Virtio net PCI Bindings + * + * Copyright IBM, Corp. 2007 + * Copyright (c) 2009 CodeSourcery + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * Paul Brook <paul@codesourcery.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "qemu/osdep.h" + +#include "hw/virtio/virtio-net.h" +#include "virtio-pci.h" +#include "qapi/error.h" + +typedef struct VirtIONetPCI VirtIONetPCI; + +/* + * virtio-net-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VIRTIO_NET_PCI "virtio-net-pci-base" +#define VIRTIO_NET_PCI(obj) \ + OBJECT_CHECK(VirtIONetPCI, (obj), TYPE_VIRTIO_NET_PCI) + +struct VirtIONetPCI { + VirtIOPCIProxy parent_obj; + VirtIONet vdev; +}; + +static Property virtio_net_properties[] = { + DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, + VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_net_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + DeviceState *qdev = DEVICE(vpci_dev); + VirtIONetPCI *dev = VIRTIO_NET_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + + virtio_net_set_netclient_name(&dev->vdev, qdev->id, + object_get_typename(OBJECT(qdev))); + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + +static void virtio_net_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass); + + k->romfile = "efi-virtio.rom"; + k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + k->device_id = PCI_DEVICE_ID_VIRTIO_NET; + k->revision = VIRTIO_PCI_ABI_VERSION; + k->class_id = PCI_CLASS_NETWORK_ETHERNET; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); + dc->props = virtio_net_properties; + vpciklass->realize = virtio_net_pci_realize; +} + +static void virtio_net_pci_instance_init(Object *obj) +{ + VirtIONetPCI *dev = VIRTIO_NET_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_NET); + object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), + "bootindex", &error_abort); +} + +static const VirtioPCIDeviceTypeInfo virtio_net_pci_info = { + .base_name = TYPE_VIRTIO_NET_PCI, + .generic_name = "virtio-net-pci", + .transitional_name = "virtio-net-pci-transitional", + .non_transitional_name = "virtio-net-pci-non-transitional", + .instance_size = sizeof(VirtIONetPCI), + .instance_init = virtio_net_pci_instance_init, + .class_init = virtio_net_pci_class_init, +}; + +static void virtio_net_pci_register(void) +{ + virtio_pci_types_register(&virtio_net_pci_info); +} + +type_init(virtio_net_pci_register) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index d05066deb8..b282109343 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -19,12 +19,6 @@ #include "standard-headers/linux/virtio_pci.h" #include "hw/virtio/virtio.h" -#include "hw/virtio/virtio-blk.h" -#include "hw/virtio/virtio-net.h" -#include "hw/virtio/virtio-serial.h" -#include "hw/virtio/virtio-scsi.h" -#include "hw/virtio/virtio-balloon.h" -#include "hw/virtio/virtio-input.h" #include "hw/pci/pci.h" #include "qapi/error.h" #include "qemu/error-report.h" @@ -1079,57 +1073,6 @@ static void virtio_pci_vmstate_change(DeviceState *d, bool running) } } -#ifdef CONFIG_VIRTFS -static void virtio_9p_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) -{ - V9fsPCIState *dev = VIRTIO_9P_PCI(vpci_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); -} - -static Property virtio_9p_pci_properties[] = { - DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, - VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), - DEFINE_PROP_END_OF_LIST(), -}; - -static void virtio_9p_pci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); - VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); - - k->realize = virtio_9p_pci_realize; - pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_9P; - pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; - pcidev_k->class_id = 0x2; - set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - dc->props = virtio_9p_pci_properties; -} - -static void virtio_9p_pci_instance_init(Object *obj) -{ - V9fsPCIState *dev = VIRTIO_9P_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VIRTIO_9P); -} - -static const VirtioPCIDeviceTypeInfo virtio_9p_pci_info = { - .base_name = TYPE_VIRTIO_9P_PCI, - .generic_name = "virtio-9p-pci", - .transitional_name = "virtio-9p-pci-transitional", - .non_transitional_name = "virtio-9p-pci-non-transitional", - .instance_size = sizeof(V9fsPCIState), - .instance_init = virtio_9p_pci_instance_init, - .class_init = virtio_9p_pci_class_init, -}; -#endif /* CONFIG_VIRTFS */ - /* * virtio-pci: This is the PCIDevice which has a virtio-pci-bus. */ @@ -2055,728 +1998,6 @@ void virtio_pci_types_register(const VirtioPCIDeviceTypeInfo *t) } } -/* virtio-blk-pci */ - -static Property virtio_blk_pci_properties[] = { - DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0), - DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, - VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, - DEV_NVECTORS_UNSPECIFIED), - DEFINE_PROP_END_OF_LIST(), -}; - -static void virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) -{ - VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - - if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { - vpci_dev->nvectors = dev->vdev.conf.num_queues + 1; - } - - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); -} - -static void virtio_blk_pci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); - PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); - - set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - dc->props = virtio_blk_pci_properties; - k->realize = virtio_blk_pci_realize; - pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK; - pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; - pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI; -} - -static void virtio_blk_pci_instance_init(Object *obj) -{ - VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VIRTIO_BLK); - object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), - "bootindex", &error_abort); -} - -static const VirtioPCIDeviceTypeInfo virtio_blk_pci_info = { - .base_name = TYPE_VIRTIO_BLK_PCI, - .generic_name = "virtio-blk-pci", - .transitional_name = "virtio-blk-pci-transitional", - .non_transitional_name = "virtio-blk-pci-non-transitional", - .instance_size = sizeof(VirtIOBlkPCI), - .instance_init = virtio_blk_pci_instance_init, - .class_init = virtio_blk_pci_class_init, -}; - -#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX) -/* vhost-user-blk */ - -static Property vhost_user_blk_pci_properties[] = { - DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0), - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, - DEV_NVECTORS_UNSPECIFIED), - DEFINE_PROP_END_OF_LIST(), -}; - -static void vhost_user_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) -{ - VHostUserBlkPCI *dev = VHOST_USER_BLK_PCI(vpci_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - - if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { - vpci_dev->nvectors = dev->vdev.num_queues + 1; - } - - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); -} - -static void vhost_user_blk_pci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); - PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); - - set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - dc->props = vhost_user_blk_pci_properties; - k->realize = vhost_user_blk_pci_realize; - pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK; - pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; - pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI; -} - -static void vhost_user_blk_pci_instance_init(Object *obj) -{ - VHostUserBlkPCI *dev = VHOST_USER_BLK_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VHOST_USER_BLK); - object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), - "bootindex", &error_abort); -} - -static const VirtioPCIDeviceTypeInfo vhost_user_blk_pci_info = { - .base_name = TYPE_VHOST_USER_BLK_PCI, - .generic_name = "vhost-user-blk-pci", - .transitional_name = "vhost-user-blk-pci-transitional", - .non_transitional_name = "vhost-user-blk-pci-non-transitional", - .instance_size = sizeof(VHostUserBlkPCI), - .instance_init = vhost_user_blk_pci_instance_init, - .class_init = vhost_user_blk_pci_class_init, -}; -#endif - -/* virtio-scsi-pci */ - -static Property virtio_scsi_pci_properties[] = { - DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, - VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, - DEV_NVECTORS_UNSPECIFIED), - DEFINE_PROP_END_OF_LIST(), -}; - -static void virtio_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) -{ - VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(vpci_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); - DeviceState *proxy = DEVICE(vpci_dev); - char *bus_name; - - if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { - vpci_dev->nvectors = vs->conf.num_queues + 3; - } - - /* - * For command line compatibility, this sets the virtio-scsi-device bus - * name as before. - */ - if (proxy->id) { - bus_name = g_strdup_printf("%s.0", proxy->id); - virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name); - g_free(bus_name); - } - - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); -} - -static void virtio_scsi_pci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); - PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); - - k->realize = virtio_scsi_pci_realize; - set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - dc->props = virtio_scsi_pci_properties; - pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI; - pcidev_k->revision = 0x00; - pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI; -} - -static void virtio_scsi_pci_instance_init(Object *obj) -{ - VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VIRTIO_SCSI); -} - -static const VirtioPCIDeviceTypeInfo virtio_scsi_pci_info = { - .base_name = TYPE_VIRTIO_SCSI_PCI, - .generic_name = "virtio-scsi-pci", - .transitional_name = "virtio-scsi-pci-transitional", - .non_transitional_name = "virtio-scsi-pci-non-transitional", - .instance_size = sizeof(VirtIOSCSIPCI), - .instance_init = virtio_scsi_pci_instance_init, - .class_init = virtio_scsi_pci_class_init, -}; - -/* vhost-scsi-pci */ - -#ifdef CONFIG_VHOST_SCSI -static Property vhost_scsi_pci_properties[] = { - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, - DEV_NVECTORS_UNSPECIFIED), - DEFINE_PROP_END_OF_LIST(), -}; - -static void vhost_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) -{ - VHostSCSIPCI *dev = VHOST_SCSI_PCI(vpci_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); - - if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { - vpci_dev->nvectors = vs->conf.num_queues + 3; - } - - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); -} - -static void vhost_scsi_pci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); - PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); - k->realize = vhost_scsi_pci_realize; - set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - dc->props = vhost_scsi_pci_properties; - pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI; - pcidev_k->revision = 0x00; - pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI; -} - -static void vhost_scsi_pci_instance_init(Object *obj) -{ - VHostSCSIPCI *dev = VHOST_SCSI_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VHOST_SCSI); - object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), - "bootindex", &error_abort); -} - -static const VirtioPCIDeviceTypeInfo vhost_scsi_pci_info = { - .base_name = TYPE_VHOST_SCSI_PCI, - .generic_name = "vhost-scsi-pci", - .transitional_name = "vhost-scsi-pci-transitional", - .non_transitional_name = "vhost-scsi-pci-non-transitional", - .instance_size = sizeof(VHostSCSIPCI), - .instance_init = vhost_scsi_pci_instance_init, - .class_init = vhost_scsi_pci_class_init, -}; -#endif - -#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX) -/* vhost-user-scsi-pci */ -static Property vhost_user_scsi_pci_properties[] = { - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, - DEV_NVECTORS_UNSPECIFIED), - DEFINE_PROP_END_OF_LIST(), -}; - -static void vhost_user_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) -{ - VHostUserSCSIPCI *dev = VHOST_USER_SCSI_PCI(vpci_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); - - if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { - vpci_dev->nvectors = vs->conf.num_queues + 3; - } - - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); -} - -static void vhost_user_scsi_pci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); - PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); - k->realize = vhost_user_scsi_pci_realize; - set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - dc->props = vhost_user_scsi_pci_properties; - pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI; - pcidev_k->revision = 0x00; - pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI; -} - -static void vhost_user_scsi_pci_instance_init(Object *obj) -{ - VHostUserSCSIPCI *dev = VHOST_USER_SCSI_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VHOST_USER_SCSI); - object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), - "bootindex", &error_abort); -} - -static const VirtioPCIDeviceTypeInfo vhost_user_scsi_pci_info = { - .base_name = TYPE_VHOST_USER_SCSI_PCI, - .generic_name = "vhost-user-scsi-pci", - .transitional_name = "vhost-user-scsi-pci-transitional", - .non_transitional_name = "vhost-user-scsi-pci-non-transitional", - .instance_size = sizeof(VHostUserSCSIPCI), - .instance_init = vhost_user_scsi_pci_instance_init, - .class_init = vhost_user_scsi_pci_class_init, -}; -#endif - -/* vhost-vsock-pci */ - -#ifdef CONFIG_VHOST_VSOCK -static Property vhost_vsock_pci_properties[] = { - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3), - DEFINE_PROP_END_OF_LIST(), -}; - -static void vhost_vsock_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) -{ - VHostVSockPCI *dev = VHOST_VSOCK_PCI(vpci_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); -} - -static void vhost_vsock_pci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); - PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); - k->realize = vhost_vsock_pci_realize; - set_bit(DEVICE_CATEGORY_MISC, dc->categories); - dc->props = vhost_vsock_pci_properties; - pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_VSOCK; - pcidev_k->revision = 0x00; - pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER; -} - -static void vhost_vsock_pci_instance_init(Object *obj) -{ - VHostVSockPCI *dev = VHOST_VSOCK_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VHOST_VSOCK); -} - -static const VirtioPCIDeviceTypeInfo vhost_vsock_pci_info = { - .base_name = TYPE_VHOST_VSOCK_PCI, - .generic_name = "vhost-vsock-pci", - .transitional_name = "vhost-vsock-pci-transitional", - .non_transitional_name = "vhost-vsock-pci-non-transitional", - .instance_size = sizeof(VHostVSockPCI), - .instance_init = vhost_vsock_pci_instance_init, - .class_init = vhost_vsock_pci_class_init, -}; -#endif - -/* virtio-balloon-pci */ - -static Property virtio_balloon_pci_properties[] = { - DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void virtio_balloon_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) -{ - VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(vpci_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - - if (vpci_dev->class_code != PCI_CLASS_OTHERS && - vpci_dev->class_code != PCI_CLASS_MEMORY_RAM) { /* qemu < 1.1 */ - vpci_dev->class_code = PCI_CLASS_OTHERS; - } - - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); -} - -static void virtio_balloon_pci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); - PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); - k->realize = virtio_balloon_pci_realize; - set_bit(DEVICE_CATEGORY_MISC, dc->categories); - dc->props = virtio_balloon_pci_properties; - pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON; - pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; - pcidev_k->class_id = PCI_CLASS_OTHERS; -} - -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_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 VirtioPCIDeviceTypeInfo virtio_balloon_pci_info = { - .base_name = TYPE_VIRTIO_BALLOON_PCI, - .generic_name = "virtio-balloon-pci", - .transitional_name = "virtio-balloon-pci-transitional", - .non_transitional_name = "virtio-balloon-pci-non-transitional", - .instance_size = sizeof(VirtIOBalloonPCI), - .instance_init = virtio_balloon_pci_instance_init, - .class_init = virtio_balloon_pci_class_init, -}; - -/* virtio-serial-pci */ - -static void virtio_serial_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) -{ - VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(vpci_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - DeviceState *proxy = DEVICE(vpci_dev); - char *bus_name; - - if (vpci_dev->class_code != PCI_CLASS_COMMUNICATION_OTHER && - vpci_dev->class_code != PCI_CLASS_DISPLAY_OTHER && /* qemu 0.10 */ - vpci_dev->class_code != PCI_CLASS_OTHERS) { /* qemu-kvm */ - vpci_dev->class_code = PCI_CLASS_COMMUNICATION_OTHER; - } - - /* backwards-compatibility with machines that were created with - DEV_NVECTORS_UNSPECIFIED */ - if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { - vpci_dev->nvectors = dev->vdev.serial.max_virtserial_ports + 1; - } - - /* - * For command line compatibility, this sets the virtio-serial-device bus - * name as before. - */ - if (proxy->id) { - bus_name = g_strdup_printf("%s.0", proxy->id); - virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name); - g_free(bus_name); - } - - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); -} - -static Property virtio_serial_pci_properties[] = { - DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, - VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), - DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void virtio_serial_pci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); - PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); - k->realize = virtio_serial_pci_realize; - set_bit(DEVICE_CATEGORY_INPUT, dc->categories); - dc->props = virtio_serial_pci_properties; - pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE; - pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; - pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER; -} - -static void virtio_serial_pci_instance_init(Object *obj) -{ - VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VIRTIO_SERIAL); -} - -static const VirtioPCIDeviceTypeInfo virtio_serial_pci_info = { - .base_name = TYPE_VIRTIO_SERIAL_PCI, - .generic_name = "virtio-serial-pci", - .transitional_name = "virtio-serial-pci-transitional", - .non_transitional_name = "virtio-serial-pci-non-transitional", - .instance_size = sizeof(VirtIOSerialPCI), - .instance_init = virtio_serial_pci_instance_init, - .class_init = virtio_serial_pci_class_init, -}; - -/* virtio-net-pci */ - -static Property virtio_net_properties[] = { - DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, - VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3), - DEFINE_PROP_END_OF_LIST(), -}; - -static void virtio_net_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) -{ - DeviceState *qdev = DEVICE(vpci_dev); - VirtIONetPCI *dev = VIRTIO_NET_PCI(vpci_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - - virtio_net_set_netclient_name(&dev->vdev, qdev->id, - object_get_typename(OBJECT(qdev))); - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); -} - -static void virtio_net_pci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass); - - k->romfile = "efi-virtio.rom"; - k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - k->device_id = PCI_DEVICE_ID_VIRTIO_NET; - k->revision = VIRTIO_PCI_ABI_VERSION; - k->class_id = PCI_CLASS_NETWORK_ETHERNET; - set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); - dc->props = virtio_net_properties; - vpciklass->realize = virtio_net_pci_realize; -} - -static void virtio_net_pci_instance_init(Object *obj) -{ - VirtIONetPCI *dev = VIRTIO_NET_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VIRTIO_NET); - object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), - "bootindex", &error_abort); -} - -static const VirtioPCIDeviceTypeInfo virtio_net_pci_info = { - .base_name = TYPE_VIRTIO_NET_PCI, - .generic_name = "virtio-net-pci", - .transitional_name = "virtio-net-pci-transitional", - .non_transitional_name = "virtio-net-pci-non-transitional", - .instance_size = sizeof(VirtIONetPCI), - .instance_init = virtio_net_pci_instance_init, - .class_init = virtio_net_pci_class_init, -}; - -/* virtio-rng-pci */ - -static void virtio_rng_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) -{ - VirtIORngPCI *vrng = VIRTIO_RNG_PCI(vpci_dev); - DeviceState *vdev = DEVICE(&vrng->vdev); - Error *err = NULL; - - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - object_property_set_link(OBJECT(vrng), - OBJECT(vrng->vdev.conf.rng), "rng", - NULL); -} - -static void virtio_rng_pci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); - PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); - - k->realize = virtio_rng_pci_realize; - set_bit(DEVICE_CATEGORY_MISC, dc->categories); - - pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_RNG; - pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; - pcidev_k->class_id = PCI_CLASS_OTHERS; -} - -static void virtio_rng_initfn(Object *obj) -{ - VirtIORngPCI *dev = VIRTIO_RNG_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VIRTIO_RNG); -} - -static const VirtioPCIDeviceTypeInfo virtio_rng_pci_info = { - .base_name = TYPE_VIRTIO_RNG_PCI, - .generic_name = "virtio-rng-pci", - .transitional_name = "virtio-rng-pci-transitional", - .non_transitional_name = "virtio-rng-pci-non-transitional", - .instance_size = sizeof(VirtIORngPCI), - .instance_init = virtio_rng_initfn, - .class_init = virtio_rng_pci_class_init, -}; - -/* virtio-input-pci */ - -static Property virtio_input_pci_properties[] = { - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), - DEFINE_PROP_END_OF_LIST(), -}; - -static void virtio_input_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) -{ - VirtIOInputPCI *vinput = VIRTIO_INPUT_PCI(vpci_dev); - DeviceState *vdev = DEVICE(&vinput->vdev); - - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - virtio_pci_force_virtio_1(vpci_dev); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); -} - -static void virtio_input_pci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); - PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); - - dc->props = virtio_input_pci_properties; - k->realize = virtio_input_pci_realize; - set_bit(DEVICE_CATEGORY_INPUT, dc->categories); - - pcidev_k->class_id = PCI_CLASS_INPUT_OTHER; -} - -static void virtio_input_hid_kbd_pci_class_init(ObjectClass *klass, void *data) -{ - PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); - - pcidev_k->class_id = PCI_CLASS_INPUT_KEYBOARD; -} - -static void virtio_input_hid_mouse_pci_class_init(ObjectClass *klass, - void *data) -{ - PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); - - pcidev_k->class_id = PCI_CLASS_INPUT_MOUSE; -} - -static void virtio_keyboard_initfn(Object *obj) -{ - VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VIRTIO_KEYBOARD); -} - -static void virtio_mouse_initfn(Object *obj) -{ - VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VIRTIO_MOUSE); -} - -static void virtio_tablet_initfn(Object *obj) -{ - VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VIRTIO_TABLET); -} - -static const TypeInfo virtio_input_pci_info = { - .name = TYPE_VIRTIO_INPUT_PCI, - .parent = TYPE_VIRTIO_PCI, - .instance_size = sizeof(VirtIOInputPCI), - .class_init = virtio_input_pci_class_init, - .abstract = true, -}; - -static const TypeInfo virtio_input_hid_pci_info = { - .name = TYPE_VIRTIO_INPUT_HID_PCI, - .parent = TYPE_VIRTIO_INPUT_PCI, - .instance_size = sizeof(VirtIOInputHIDPCI), - .abstract = true, -}; - -static const VirtioPCIDeviceTypeInfo virtio_keyboard_pci_info = { - .generic_name = TYPE_VIRTIO_KEYBOARD_PCI, - .parent = TYPE_VIRTIO_INPUT_HID_PCI, - .class_init = virtio_input_hid_kbd_pci_class_init, - .instance_size = sizeof(VirtIOInputHIDPCI), - .instance_init = virtio_keyboard_initfn, -}; - -static const VirtioPCIDeviceTypeInfo virtio_mouse_pci_info = { - .generic_name = TYPE_VIRTIO_MOUSE_PCI, - .parent = TYPE_VIRTIO_INPUT_HID_PCI, - .class_init = virtio_input_hid_mouse_pci_class_init, - .instance_size = sizeof(VirtIOInputHIDPCI), - .instance_init = virtio_mouse_initfn, -}; - -static const VirtioPCIDeviceTypeInfo virtio_tablet_pci_info = { - .generic_name = TYPE_VIRTIO_TABLET_PCI, - .parent = TYPE_VIRTIO_INPUT_HID_PCI, - .instance_size = sizeof(VirtIOInputHIDPCI), - .instance_init = virtio_tablet_initfn, -}; - -#ifdef CONFIG_LINUX -static void virtio_host_initfn(Object *obj) -{ - VirtIOInputHostPCI *dev = VIRTIO_INPUT_HOST_PCI(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VIRTIO_INPUT_HOST); -} - -static const VirtioPCIDeviceTypeInfo virtio_host_pci_info = { - .base_name = TYPE_VIRTIO_INPUT_HOST_PCI, - .generic_name = "virtio-input-host-pci", - .transitional_name = "virtio-input-host-pci-transitional", - .non_transitional_name = "virtio-input-host-pci-non-transitional", - .parent = TYPE_VIRTIO_INPUT_PCI, - .instance_size = sizeof(VirtIOInputHostPCI), - .instance_init = virtio_host_initfn, -}; -#endif - /* virtio-pci-bus */ static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size, @@ -2827,37 +2048,7 @@ static void virtio_pci_register_types(void) /* Base types: */ type_register_static(&virtio_pci_bus_info); type_register_static(&virtio_pci_info); - type_register_static(&virtio_input_pci_info); - type_register_static(&virtio_input_hid_pci_info); - - /* Implementations: */ - virtio_pci_types_register(&virtio_rng_pci_info); - virtio_pci_types_register(&virtio_keyboard_pci_info); - virtio_pci_types_register(&virtio_mouse_pci_info); - virtio_pci_types_register(&virtio_tablet_pci_info); -#ifdef CONFIG_LINUX - virtio_pci_types_register(&virtio_host_pci_info); -#endif -#ifdef CONFIG_VIRTFS - virtio_pci_types_register(&virtio_9p_pci_info); -#endif - virtio_pci_types_register(&virtio_blk_pci_info); -#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX) - virtio_pci_types_register(&vhost_user_blk_pci_info); -#endif - virtio_pci_types_register(&virtio_scsi_pci_info); - virtio_pci_types_register(&virtio_balloon_pci_info); - virtio_pci_types_register(&virtio_serial_pci_info); - virtio_pci_types_register(&virtio_net_pci_info); -#ifdef CONFIG_VHOST_SCSI - virtio_pci_types_register(&vhost_scsi_pci_info); -#endif -#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX) - virtio_pci_types_register(&vhost_user_scsi_pci_info); -#endif -#ifdef CONFIG_VHOST_VSOCK - virtio_pci_types_register(&vhost_vsock_pci_info); -#endif } type_init(virtio_pci_register_types) + diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index 29b4216107..bd223a6e3b 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -16,47 +16,9 @@ #define QEMU_VIRTIO_PCI_H #include "hw/pci/msi.h" -#include "hw/virtio/virtio-blk.h" -#include "hw/virtio/virtio-net.h" -#include "hw/virtio/virtio-rng.h" -#include "hw/virtio/virtio-serial.h" -#include "hw/virtio/virtio-scsi.h" -#include "hw/virtio/virtio-balloon.h" #include "hw/virtio/virtio-bus.h" -#include "hw/virtio/virtio-input.h" -#include "hw/virtio/virtio-gpu.h" -#include "hw/virtio/virtio-crypto.h" -#include "hw/virtio/vhost-user-scsi.h" -#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX) -#include "hw/virtio/vhost-user-blk.h" -#endif - -#ifdef CONFIG_VIRTFS -#include "hw/9pfs/virtio-9p.h" -#endif -#ifdef CONFIG_VHOST_SCSI -#include "hw/virtio/vhost-scsi.h" -#endif -#ifdef CONFIG_VHOST_VSOCK -#include "hw/virtio/vhost-vsock.h" -#endif typedef struct VirtIOPCIProxy VirtIOPCIProxy; -typedef struct VirtIOBlkPCI VirtIOBlkPCI; -typedef struct VirtIOSCSIPCI VirtIOSCSIPCI; -typedef struct VirtIOBalloonPCI VirtIOBalloonPCI; -typedef struct VirtIOSerialPCI VirtIOSerialPCI; -typedef struct VirtIONetPCI VirtIONetPCI; -typedef struct VHostSCSIPCI VHostSCSIPCI; -typedef struct VHostUserSCSIPCI VHostUserSCSIPCI; -typedef struct VHostUserBlkPCI VHostUserBlkPCI; -typedef struct VirtIORngPCI VirtIORngPCI; -typedef struct VirtIOInputPCI VirtIOInputPCI; -typedef struct VirtIOInputHIDPCI VirtIOInputHIDPCI; -typedef struct VirtIOInputHostPCI VirtIOInputHostPCI; -typedef struct VirtIOGPUPCI VirtIOGPUPCI; -typedef struct VHostVSockPCI VHostVSockPCI; -typedef struct VirtIOCryptoPCI VirtIOCryptoPCI; /* virtio-pci-bus */ @@ -214,205 +176,9 @@ static inline void virtio_pci_disable_modern(VirtIOPCIProxy *proxy) } /* - * virtio-scsi-pci: This extends VirtioPCIProxy. - */ -#define TYPE_VIRTIO_SCSI_PCI "virtio-scsi-pci-base" -#define VIRTIO_SCSI_PCI(obj) \ - OBJECT_CHECK(VirtIOSCSIPCI, (obj), TYPE_VIRTIO_SCSI_PCI) - -struct VirtIOSCSIPCI { - VirtIOPCIProxy parent_obj; - VirtIOSCSI vdev; -}; - -#ifdef CONFIG_VHOST_SCSI -/* - * vhost-scsi-pci: This extends VirtioPCIProxy. - */ -#define TYPE_VHOST_SCSI_PCI "vhost-scsi-pci-base" -#define VHOST_SCSI_PCI(obj) \ - OBJECT_CHECK(VHostSCSIPCI, (obj), TYPE_VHOST_SCSI_PCI) - -struct VHostSCSIPCI { - VirtIOPCIProxy parent_obj; - VHostSCSI vdev; -}; -#endif - -#define TYPE_VHOST_USER_SCSI_PCI "vhost-user-scsi-pci-base" -#define VHOST_USER_SCSI_PCI(obj) \ - OBJECT_CHECK(VHostUserSCSIPCI, (obj), TYPE_VHOST_USER_SCSI_PCI) - -struct VHostUserSCSIPCI { - VirtIOPCIProxy parent_obj; - VHostUserSCSI vdev; -}; - -#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX) -/* - * vhost-user-blk-pci: This extends VirtioPCIProxy. - */ -#define TYPE_VHOST_USER_BLK_PCI "vhost-user-blk-pci-base" -#define VHOST_USER_BLK_PCI(obj) \ - OBJECT_CHECK(VHostUserBlkPCI, (obj), TYPE_VHOST_USER_BLK_PCI) - -struct VHostUserBlkPCI { - VirtIOPCIProxy parent_obj; - VHostUserBlk vdev; -}; -#endif - -/* - * virtio-blk-pci: This extends VirtioPCIProxy. - */ -#define TYPE_VIRTIO_BLK_PCI "virtio-blk-pci-base" -#define VIRTIO_BLK_PCI(obj) \ - OBJECT_CHECK(VirtIOBlkPCI, (obj), TYPE_VIRTIO_BLK_PCI) - -struct VirtIOBlkPCI { - VirtIOPCIProxy parent_obj; - VirtIOBlock vdev; -}; - -/* - * virtio-balloon-pci: This extends VirtioPCIProxy. - */ -#define TYPE_VIRTIO_BALLOON_PCI "virtio-balloon-pci-base" -#define VIRTIO_BALLOON_PCI(obj) \ - OBJECT_CHECK(VirtIOBalloonPCI, (obj), TYPE_VIRTIO_BALLOON_PCI) - -struct VirtIOBalloonPCI { - VirtIOPCIProxy parent_obj; - VirtIOBalloon vdev; -}; - -/* - * virtio-serial-pci: This extends VirtioPCIProxy. - */ -#define TYPE_VIRTIO_SERIAL_PCI "virtio-serial-pci-base" -#define VIRTIO_SERIAL_PCI(obj) \ - OBJECT_CHECK(VirtIOSerialPCI, (obj), TYPE_VIRTIO_SERIAL_PCI) - -struct VirtIOSerialPCI { - VirtIOPCIProxy parent_obj; - VirtIOSerial vdev; -}; - -/* - * virtio-net-pci: This extends VirtioPCIProxy. - */ -#define TYPE_VIRTIO_NET_PCI "virtio-net-pci-base" -#define VIRTIO_NET_PCI(obj) \ - OBJECT_CHECK(VirtIONetPCI, (obj), TYPE_VIRTIO_NET_PCI) - -struct VirtIONetPCI { - VirtIOPCIProxy parent_obj; - VirtIONet vdev; -}; - -/* - * virtio-9p-pci: This extends VirtioPCIProxy. - */ - -#ifdef CONFIG_VIRTFS - -#define TYPE_VIRTIO_9P_PCI "virtio-9p-pci-base" -#define VIRTIO_9P_PCI(obj) \ - OBJECT_CHECK(V9fsPCIState, (obj), TYPE_VIRTIO_9P_PCI) - -typedef struct V9fsPCIState { - VirtIOPCIProxy parent_obj; - V9fsVirtioState vdev; -} V9fsPCIState; - -#endif - -/* - * virtio-rng-pci: This extends VirtioPCIProxy. - */ -#define TYPE_VIRTIO_RNG_PCI "virtio-rng-pci-base" -#define VIRTIO_RNG_PCI(obj) \ - OBJECT_CHECK(VirtIORngPCI, (obj), TYPE_VIRTIO_RNG_PCI) - -struct VirtIORngPCI { - VirtIOPCIProxy parent_obj; - VirtIORNG vdev; -}; - -/* * virtio-input-pci: This extends VirtioPCIProxy. */ #define TYPE_VIRTIO_INPUT_PCI "virtio-input-pci" -#define VIRTIO_INPUT_PCI(obj) \ - OBJECT_CHECK(VirtIOInputPCI, (obj), TYPE_VIRTIO_INPUT_PCI) - -struct VirtIOInputPCI { - VirtIOPCIProxy parent_obj; - VirtIOInput vdev; -}; - -#define TYPE_VIRTIO_INPUT_HID_PCI "virtio-input-hid-pci" -#define TYPE_VIRTIO_KEYBOARD_PCI "virtio-keyboard-pci" -#define TYPE_VIRTIO_MOUSE_PCI "virtio-mouse-pci" -#define TYPE_VIRTIO_TABLET_PCI "virtio-tablet-pci" -#define VIRTIO_INPUT_HID_PCI(obj) \ - OBJECT_CHECK(VirtIOInputHIDPCI, (obj), TYPE_VIRTIO_INPUT_HID_PCI) - -struct VirtIOInputHIDPCI { - VirtIOPCIProxy parent_obj; - VirtIOInputHID vdev; -}; - -#ifdef CONFIG_LINUX - -#define TYPE_VIRTIO_INPUT_HOST_PCI "virtio-input-host-pci-base" -#define VIRTIO_INPUT_HOST_PCI(obj) \ - OBJECT_CHECK(VirtIOInputHostPCI, (obj), TYPE_VIRTIO_INPUT_HOST_PCI) - -struct VirtIOInputHostPCI { - VirtIOPCIProxy parent_obj; - VirtIOInputHost vdev; -}; - -#endif - -/* - * virtio-gpu-pci: This extends VirtioPCIProxy. - */ -#define TYPE_VIRTIO_GPU_PCI "virtio-gpu-pci" -#define VIRTIO_GPU_PCI(obj) \ - OBJECT_CHECK(VirtIOGPUPCI, (obj), TYPE_VIRTIO_GPU_PCI) - -struct VirtIOGPUPCI { - VirtIOPCIProxy parent_obj; - VirtIOGPU vdev; -}; - -#ifdef CONFIG_VHOST_VSOCK -/* - * vhost-vsock-pci: This extends VirtioPCIProxy. - */ -#define TYPE_VHOST_VSOCK_PCI "vhost-vsock-pci-base" -#define VHOST_VSOCK_PCI(obj) \ - OBJECT_CHECK(VHostVSockPCI, (obj), TYPE_VHOST_VSOCK_PCI) - -struct VHostVSockPCI { - VirtIOPCIProxy parent_obj; - VHostVSock vdev; -}; -#endif - -/* - * virtio-crypto-pci: This extends VirtioPCIProxy. - */ -#define TYPE_VIRTIO_CRYPTO_PCI "virtio-crypto-pci" -#define VIRTIO_CRYPTO_PCI(obj) \ - OBJECT_CHECK(VirtIOCryptoPCI, (obj), TYPE_VIRTIO_CRYPTO_PCI) - -struct VirtIOCryptoPCI { - VirtIOPCIProxy parent_obj; - VirtIOCrypto vdev; -}; /* Virtio ABI version, if we increment this, we break the guest driver. */ #define VIRTIO_PCI_ABI_VERSION 0 diff --git a/hw/virtio/virtio-rng-pci.c b/hw/virtio/virtio-rng-pci.c new file mode 100644 index 0000000000..6cc6374289 --- /dev/null +++ b/hw/virtio/virtio-rng-pci.c @@ -0,0 +1,88 @@ +/* + * Virtio rng PCI Bindings + * + * Copyright 2012 Red Hat, Inc. + * Copyright 2012 Amit Shah <amit.shah@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#include "qemu/osdep.h" + +#include "virtio-pci.h" +#include "hw/virtio/virtio-rng.h" +#include "qapi/error.h" + +typedef struct VirtIORngPCI VirtIORngPCI; + +/* + * virtio-rng-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VIRTIO_RNG_PCI "virtio-rng-pci-base" +#define VIRTIO_RNG_PCI(obj) \ + OBJECT_CHECK(VirtIORngPCI, (obj), TYPE_VIRTIO_RNG_PCI) + +struct VirtIORngPCI { + VirtIOPCIProxy parent_obj; + VirtIORNG vdev; +}; + +static void virtio_rng_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VirtIORngPCI *vrng = VIRTIO_RNG_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&vrng->vdev); + Error *err = NULL; + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + object_property_set_link(OBJECT(vrng), + OBJECT(vrng->vdev.conf.rng), "rng", + NULL); +} + +static void virtio_rng_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + + k->realize = virtio_rng_pci_realize; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_RNG; + pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; + pcidev_k->class_id = PCI_CLASS_OTHERS; +} + +static void virtio_rng_initfn(Object *obj) +{ + VirtIORngPCI *dev = VIRTIO_RNG_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_RNG); +} + +static const VirtioPCIDeviceTypeInfo virtio_rng_pci_info = { + .base_name = TYPE_VIRTIO_RNG_PCI, + .generic_name = "virtio-rng-pci", + .transitional_name = "virtio-rng-pci-transitional", + .non_transitional_name = "virtio-rng-pci-non-transitional", + .instance_size = sizeof(VirtIORngPCI), + .instance_init = virtio_rng_initfn, + .class_init = virtio_rng_pci_class_init, +}; + +static void virtio_rng_pci_register(void) +{ + virtio_pci_types_register(&virtio_rng_pci_info); +} + +type_init(virtio_rng_pci_register) diff --git a/hw/virtio/virtio-scsi-pci.c b/hw/virtio/virtio-scsi-pci.c new file mode 100644 index 0000000000..2830849729 --- /dev/null +++ b/hw/virtio/virtio-scsi-pci.c @@ -0,0 +1,107 @@ +/* + * Virtio scsi PCI Bindings + * + * Copyright IBM, Corp. 2007 + * Copyright (c) 2009 CodeSourcery + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * Paul Brook <paul@codesourcery.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#include "qemu/osdep.h" + +#include "hw/virtio/virtio-scsi.h" +#include "virtio-pci.h" + +typedef struct VirtIOSCSIPCI VirtIOSCSIPCI; + +/* + * virtio-scsi-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VIRTIO_SCSI_PCI "virtio-scsi-pci-base" +#define VIRTIO_SCSI_PCI(obj) \ + OBJECT_CHECK(VirtIOSCSIPCI, (obj), TYPE_VIRTIO_SCSI_PCI) + +struct VirtIOSCSIPCI { + VirtIOPCIProxy parent_obj; + VirtIOSCSI vdev; +}; + +static Property virtio_scsi_pci_properties[] = { + DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, + VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, + DEV_NVECTORS_UNSPECIFIED), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); + DeviceState *proxy = DEVICE(vpci_dev); + char *bus_name; + + if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { + vpci_dev->nvectors = vs->conf.num_queues + 3; + } + + /* + * For command line compatibility, this sets the virtio-scsi-device bus + * name as before. + */ + if (proxy->id) { + bus_name = g_strdup_printf("%s.0", proxy->id); + virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name); + g_free(bus_name); + } + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + +static void virtio_scsi_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + + k->realize = virtio_scsi_pci_realize; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); + dc->props = virtio_scsi_pci_properties; + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI; + pcidev_k->revision = 0x00; + pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI; +} + +static void virtio_scsi_pci_instance_init(Object *obj) +{ + VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_SCSI); +} + +static const VirtioPCIDeviceTypeInfo virtio_scsi_pci_info = { + .base_name = TYPE_VIRTIO_SCSI_PCI, + .generic_name = "virtio-scsi-pci", + .transitional_name = "virtio-scsi-pci-transitional", + .non_transitional_name = "virtio-scsi-pci-non-transitional", + .instance_size = sizeof(VirtIOSCSIPCI), + .instance_init = virtio_scsi_pci_instance_init, + .class_init = virtio_scsi_pci_class_init, +}; + +static void virtio_scsi_pci_register(void) +{ + virtio_pci_types_register(&virtio_scsi_pci_info); +} + +type_init(virtio_scsi_pci_register) diff --git a/hw/virtio/virtio-serial-pci.c b/hw/virtio/virtio-serial-pci.c new file mode 100644 index 0000000000..971b2eb8d8 --- /dev/null +++ b/hw/virtio/virtio-serial-pci.c @@ -0,0 +1,115 @@ +/* + * Virtio serial PCI Bindings + * + * Copyright IBM, Corp. 2007 + * Copyright (c) 2009 CodeSourcery + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * Paul Brook <paul@codesourcery.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "qemu/osdep.h" + +#include "hw/virtio/virtio-serial.h" +#include "virtio-pci.h" + +typedef struct VirtIOSerialPCI VirtIOSerialPCI; + +/* + * virtio-serial-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VIRTIO_SERIAL_PCI "virtio-serial-pci-base" +#define VIRTIO_SERIAL_PCI(obj) \ + OBJECT_CHECK(VirtIOSerialPCI, (obj), TYPE_VIRTIO_SERIAL_PCI) + +struct VirtIOSerialPCI { + VirtIOPCIProxy parent_obj; + VirtIOSerial vdev; +}; + +static void virtio_serial_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + DeviceState *proxy = DEVICE(vpci_dev); + char *bus_name; + + if (vpci_dev->class_code != PCI_CLASS_COMMUNICATION_OTHER && + vpci_dev->class_code != PCI_CLASS_DISPLAY_OTHER && /* qemu 0.10 */ + vpci_dev->class_code != PCI_CLASS_OTHERS) { /* qemu-kvm */ + vpci_dev->class_code = PCI_CLASS_COMMUNICATION_OTHER; + } + + /* backwards-compatibility with machines that were created with + DEV_NVECTORS_UNSPECIFIED */ + if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { + vpci_dev->nvectors = dev->vdev.serial.max_virtserial_ports + 1; + } + + /* + * For command line compatibility, this sets the virtio-serial-device bus + * name as before. + */ + if (proxy->id) { + bus_name = g_strdup_printf("%s.0", proxy->id); + virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name); + g_free(bus_name); + } + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + +static Property virtio_serial_pci_properties[] = { + DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, + VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), + DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_serial_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + k->realize = virtio_serial_pci_realize; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); + dc->props = virtio_serial_pci_properties; + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE; + pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; + pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER; +} + +static void virtio_serial_pci_instance_init(Object *obj) +{ + VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_SERIAL); +} + +static const VirtioPCIDeviceTypeInfo virtio_serial_pci_info = { + .base_name = TYPE_VIRTIO_SERIAL_PCI, + .generic_name = "virtio-serial-pci", + .transitional_name = "virtio-serial-pci-transitional", + .non_transitional_name = "virtio-serial-pci-non-transitional", + .instance_size = sizeof(VirtIOSerialPCI), + .instance_init = virtio_serial_pci_instance_init, + .class_init = virtio_serial_pci_class_init, +}; + +static void virtio_serial_pci_register(void) +{ + virtio_pci_types_register(&virtio_serial_pci_info); +} + +type_init(virtio_serial_pci_register) |