pci, pc, virtio: fixes, features

tpm physical presence interface
 rsc support in virtio net
 ivshmem is removed
 misc cleanups and fixes all over the place
 
 Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iQEcBAABAgAGBQJcQTW/AAoJECgfDbjSjVRpY34H/0wniUqht3CVVihAfC9qnL7N
 jgAJ41OGgrrCmXLrwa5P5iWxIKRjp2Odo7DQ2dl+9sqYshe6WoBBXmqEa8bDeldE
 69EJ3xSnZjkpScqXKoSaDO3dtibUGpdvlTKpjuh7q2FFBOvNvf3hQubhyt/vINsO
 qoDMqycjXJkHSaZLfdNb3P/LAkAuHI4veNk8KEbog3XTijSUbZlb2GYc8vT/agka
 0SldiEVi9CTIh7co0L2BkcLVeTMVrF3OZuWDek3tVHXPxPaNbQM3GMvHZaxqZusU
 SZinnNhcnI++kgLZVHuurxo7e1S9d8Oy0QuHGX8CZ1sfeqy3vzxer0Hbb7BdLIY=
 =GhIM
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging

pci, pc, virtio: fixes, features

tpm physical presence interface
rsc support in virtio net
ivshmem is removed
misc cleanups and fixes all over the place

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

# gpg: Signature made Fri 18 Jan 2019 02:11:11 GMT
# gpg:                using RSA key 281F0DB8D28D5469
# gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>"
# gpg:                 aka "Michael S. Tsirkin <mst@redhat.com>"
# Primary key fingerprint: 0270 606B 6F3C DF3D 0B17  0970 C350 3912 AFBE 8E67
#      Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA  8A0D 281F 0DB8 D28D 5469

* remotes/mst/tags/for_upstream: (49 commits)
  migration: Use strnlen() for fixed-size string
  migration: Fix stringop-truncation warning
  hw/acpi: Use QEMU_NONSTRING for non NUL-terminated arrays
  block/sheepdog: Use QEMU_NONSTRING for non NUL-terminated arrays
  qemu/compiler: Define QEMU_NONSTRING
  acpi: update expected files
  hw: acpi: Fix memory hotplug AML generation error
  tpm: clear RAM when "memory overwrite" requested
  acpi: add ACPI memory clear interface
  acpi: build TPM Physical Presence interface
  acpi: expose TPM/PPI configuration parameters to firmware via fw_cfg
  tpm: allocate/map buffer for TPM Physical Presence interface
  tpm: add a "ppi" boolean property
  hw/misc/edu: add msi_uninit() for pci_edu_uninit()
  virtio: Make disable-legacy/disable-modern compat properties optional
  globals: Allow global properties to be optional
  virtio: virtio 9p really requires CONFIG_VIRTFS to work
  virtio: split virtio crypto bits from virtio-pci.h
  virtio: split virtio gpu bits from virtio-pci.h
  virtio: split virtio serial bits from virtio-pci
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2019-01-18 14:58:57 +00:00
commit 51c1c13560
71 changed files with 3103 additions and 1638 deletions

View File

@ -1224,7 +1224,7 @@ static int find_vdi_name(BDRVSheepdogState *s, const char *filename,
SheepdogVdiReq hdr; SheepdogVdiReq hdr;
SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr; SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr;
unsigned int wlen, rlen = 0; unsigned int wlen, rlen = 0;
char buf[SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN]; char buf[SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN] QEMU_NONSTRING;
fd = connect_to_sdog(s, errp); fd = connect_to_sdog(s, errp);
if (fd < 0) { if (fd < 0) {

View File

@ -1,7 +1,7 @@
CONFIG_VHOST_USER_SCSI=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) CONFIG_VHOST_USER_SCSI=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX))
CONFIG_VHOST_USER_BLK=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) CONFIG_VHOST_USER_BLK=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX))
CONFIG_VIRTIO=y CONFIG_VIRTIO=y
CONFIG_VIRTIO_9P=y CONFIG_VIRTIO_9P=$(CONFIG_VIRTFS)
CONFIG_VIRTIO_BALLOON=y CONFIG_VIRTIO_BALLOON=y
CONFIG_VIRTIO_BLK=y CONFIG_VIRTIO_BLK=y
CONFIG_VIRTIO_CRYPTO=y CONFIG_VIRTIO_CRYPTO=y
@ -12,3 +12,4 @@ CONFIG_VIRTIO_RNG=y
CONFIG_SCSI=y CONFIG_SCSI=y
CONFIG_VIRTIO_SCSI=y CONFIG_VIRTIO_SCSI=y
CONFIG_VIRTIO_SERIAL=y CONFIG_VIRTIO_SERIAL=y
CONFIG_VIRTIO_INPUT_HOST=$(CONFIG_LINUX)

View File

@ -17,12 +17,16 @@ get interrupted by its peers.
There are two basic configurations: There are two basic configurations:
- Just shared memory: -device ivshmem-plain,memdev=HMB,... - Just shared memory:
-device ivshmem-plain,memdev=HMB,...
This uses host memory backend HMB. It should have option "share" This uses host memory backend HMB. It should have option "share"
set. set.
- Shared memory plus interrupts: -device ivshmem,chardev=CHR,vectors=N,... - Shared memory plus interrupts:
-device ivshmem-doorbell,chardev=CHR,vectors=N,...
An ivshmem server must already be running on the host. The device An ivshmem server must already be running on the host. The device
connects to the server's UNIX domain socket via character device connects to the server's UNIX domain socket via character device

View File

@ -34,6 +34,25 @@ The CRB interface makes a memory mapped IO region in the area 0xfed40000 -
QEMU files related to TPM CRB interface: QEMU files related to TPM CRB interface:
- hw/tpm/tpm_crb.c - hw/tpm/tpm_crb.c
= fw_cfg interface =
The bios/firmware may read the "etc/tpm/config" fw_cfg entry for
configuring the guest appropriately.
The entry of 6 bytes has the following content, in little-endian:
#define TPM_VERSION_UNSPEC 0
#define TPM_VERSION_1_2 1
#define TPM_VERSION_2_0 2
#define TPM_PPI_VERSION_NONE 0
#define TPM_PPI_VERSION_1_30 1
struct FwCfgTPMConfig {
uint32_t tpmppi_address; /* PPI memory location */
uint8_t tpm_version; /* TPM version */
uint8_t tpmppi_version; /* PPI version */
};
= ACPI Interface = = ACPI Interface =
@ -57,6 +76,91 @@ URL:
https://trustedcomputinggroup.org/tcg-acpi-specification/ https://trustedcomputinggroup.org/tcg-acpi-specification/
== ACPI PPI Interface ==
QEMU supports the Physical Presence Interface (PPI) for TPM 1.2 and TPM 2. This
interface requires ACPI and firmware support. The specification can be found at
the following URL:
https://trustedcomputinggroup.org/resource/tcg-physical-presence-interface-specification/
PPI enables a system administrator (root) to request a modification to the
TPM upon reboot. The PPI specification defines the operation requests and the
actions the firmware has to take. The system administrator passes the operation
request number to the firmware through an ACPI interface which writes this
number to a memory location that the firmware knows. Upon reboot, the firmware
finds the number and sends commands to the the TPM. The firmware writes the TPM
result code and the operation request number to a memory location that ACPI can
read from and pass the result on to the administrator.
The PPI specification defines a set of mandatory and optional operations for
the firmware to implement. The ACPI interface also allows an administrator to
list the supported operations. In QEMU the ACPI code is generated by QEMU, yet
the firmware needs to implement support on a per-operations basis, and
different firmwares may support a different subset. Therefore, QEMU introduces
the virtual memory device for PPI where the firmware can indicate which
operations it supports and ACPI can enable the ones that are supported and
disable all others. This interface lies in main memory and has the following
layout:
+----------+--------+--------+-------------------------------------------+
| Field | Length | Offset | Description |
+----------+--------+--------+-------------------------------------------+
| func | 0x100 | 0x000 | Firmware sets values for each supported |
| | | | operation. See defined values below. |
+----------+--------+--------+-------------------------------------------+
| ppin | 0x1 | 0x100 | SMI interrupt to use. Set by firmware. |
| | | | Not supported. |
+----------+--------+--------+-------------------------------------------+
| ppip | 0x4 | 0x101 | ACPI function index to pass to SMM code. |
| | | | Set by ACPI. Not supported. |
+----------+--------+--------+-------------------------------------------+
| pprp | 0x4 | 0x105 | Result of last executed operation. Set by |
| | | | firmware. See function index 5 for values.|
+----------+--------+--------+-------------------------------------------+
| pprq | 0x4 | 0x109 | Operation request number to execute. See |
| | | | 'Physical Presence Interface Operation |
| | | | Summary' tables in specs. Set by ACPI. |
+----------+--------+--------+-------------------------------------------+
| pprm | 0x4 | 0x10d | Operation request optional parameter. |
| | | | Values depend on operation. Set by ACPI. |
+----------+--------+--------+-------------------------------------------+
| lppr | 0x4 | 0x111 | Last executed operation request number. |
| | | | Copied from pprq field by firmware. |
+----------+--------+--------+-------------------------------------------+
| fret | 0x4 | 0x115 | Result code from SMM function. |
| | | | Not supported. |
+----------+--------+--------+-------------------------------------------+
| res1 | 0x40 | 0x119 | Reserved for future use |
+----------+--------+--------+-------------------------------------------+
| next_step| 0x1 | 0x159 | Operation to execute after reboot by |
| | | | firmware. Used by firmware. |
+----------+--------+--------+-------------------------------------------+
| movv | 0x1 | 0x15a | Memory overwrite variable |
+----------+--------+--------+-------------------------------------------+
The following values are supported for the 'func' field. They correspond
to the values used by ACPI function index 8.
+----------+-------------------------------------------------------------+
| value | Description |
+----------+-------------------------------------------------------------+
| 0 | Operation is not implemented. |
+----------+-------------------------------------------------------------+
| 1 | Operation is only accessible through firmware. |
+----------+-------------------------------------------------------------+
| 2 | Operation is blocked for OS by firmware configuration. |
+----------+-------------------------------------------------------------+
| 3 | Operation is allowed and physically present user required. |
+----------+-------------------------------------------------------------+
| 4 | Operation is allowed and physically present user is not |
| | required. |
+----------+-------------------------------------------------------------+
The location of the table is given by the fw_cfg tpmppi_address field.
The PPI memory region size is 0x400 (TPM_PPI_ADDR_SIZE) to leave
enough room for future updates.
QEMU files related to TPM ACPI tables: QEMU files related to TPM ACPI tables:
- hw/i386/acpi-build.c - hw/i386/acpi-build.c

View File

@ -11,6 +11,7 @@ common-obj-$(call lnot,$(CONFIG_ACPI_X86)) += acpi-stub.o
common-obj-y += acpi_interface.o common-obj-y += acpi_interface.o
common-obj-y += bios-linker-loader.o common-obj-y += bios-linker-loader.o
common-obj-y += aml-build.o common-obj-y += aml-build.o
common-obj-$(CONFIG_TPM) += tpm.o
common-obj-$(CONFIG_IPMI) += ipmi.o common-obj-$(CONFIG_IPMI) += ipmi.o
common-obj-$(call lnot,$(CONFIG_IPMI)) += ipmi-stub.o common-obj-$(call lnot,$(CONFIG_IPMI)) += ipmi-stub.o

View File

@ -35,14 +35,18 @@
struct acpi_table_header { struct acpi_table_header {
uint16_t _length; /* our length, not actual part of the hdr */ uint16_t _length; /* our length, not actual part of the hdr */
/* allows easier parsing for fw_cfg clients */ /* 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 */ uint32_t length; /* Length of table, in bytes, including header */
uint8_t revision; /* ACPI Specification minor version # */ uint8_t revision; /* ACPI Specification minor version # */
uint8_t checksum; /* To make sum of entire table == 0 */ uint8_t checksum; /* To make sum of entire table == 0 */
char oem_id[6]; /* OEM identification */ char oem_id[6]
char oem_table_id[8]; /* OEM table identification */ QEMU_NONSTRING; /* OEM identification */
char oem_table_id[8]
QEMU_NONSTRING; /* OEM table identification */
uint32_t oem_revision; /* OEM revision number */ 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 */ uint32_t asl_compiler_revision; /* ASL compiler revision number */
} QEMU_PACKED; } QEMU_PACKED;

View File

@ -686,15 +686,15 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem,
method = aml_method("_OST", 3, AML_NOTSERIALIZED); method = aml_method("_OST", 3, AML_NOTSERIALIZED);
s = MEMORY_SLOT_OST_METHOD; s = MEMORY_SLOT_OST_METHOD;
aml_append(method, aml_return(aml_call4( aml_append(method,
s, aml_name("_UID"), aml_arg(0), aml_arg(1), aml_arg(2) aml_call4(s, aml_name("_UID"), aml_arg(0),
))); aml_arg(1), aml_arg(2)));
aml_append(dev, method); aml_append(dev, method);
method = aml_method("_EJ0", 1, AML_NOTSERIALIZED); method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
s = MEMORY_SLOT_EJECT_METHOD; s = MEMORY_SLOT_EJECT_METHOD;
aml_append(method, aml_return(aml_call2( aml_append(method,
s, aml_name("_UID"), aml_arg(0)))); aml_call2(s, aml_name("_UID"), aml_arg(0)));
aml_append(dev, method); aml_append(dev, method);
aml_append(dev_container, dev); aml_append(dev_container, dev);

459
hw/acpi/tpm.c Normal file
View File

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

View File

@ -250,6 +250,7 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserBlk *s = VHOST_USER_BLK(vdev); VHostUserBlk *s = VHOST_USER_BLK(vdev);
VhostUserState *user; VhostUserState *user;
struct vhost_virtqueue *vqs = NULL;
int i, ret; int i, ret;
if (!s->chardev.chr) { 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.vqs = g_new(struct vhost_virtqueue, s->dev.nvqs);
s->dev.vq_index = 0; s->dev.vq_index = 0;
s->dev.backend_features = 0; s->dev.backend_features = 0;
vqs = s->dev.vqs;
vhost_dev_set_config_notifier(&s->dev, &blk_ops); 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_err:
vhost_dev_cleanup(&s->dev); vhost_dev_cleanup(&s->dev);
virtio_err: virtio_err:
g_free(s->dev.vqs); g_free(vqs);
virtio_cleanup(vdev); virtio_cleanup(vdev);
vhost_user_cleanup(user); vhost_user_cleanup(user);
@ -326,10 +328,11 @@ static void vhost_user_blk_device_unrealize(DeviceState *dev, Error **errp)
{ {
VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserBlk *s = VHOST_USER_BLK(dev); VHostUserBlk *s = VHOST_USER_BLK(dev);
struct vhost_virtqueue *vqs = s->dev.vqs;
vhost_user_blk_set_status(vdev, 0); vhost_user_blk_set_status(vdev, 0);
vhost_dev_cleanup(&s->dev); vhost_dev_cleanup(&s->dev);
g_free(s->dev.vqs); g_free(vqs);
virtio_cleanup(vdev); virtio_cleanup(vdev);
if (s->vhost_user) { if (s->vhost_user) {

View File

@ -28,6 +28,8 @@ GlobalProperty hw_compat_3_1[] = {
{ "pcie-root-port", "x-width", "1" }, { "pcie-root-port", "x-width", "1" },
{ "memory-backend-file", "x-use-canonical-path-for-ramblock-id", "true" }, { "memory-backend-file", "x-use-canonical-path-for-ramblock-id", "true" },
{ "memory-backend-memfd", "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); 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[] = { GlobalProperty hw_compat_2_6[] = {
{ "virtio-mmio", "format_transport_address", "off" }, { "virtio-mmio", "format_transport_address", "off" },
{ "virtio-pci", "disable-modern", "on" }, /* Optional because not all virtio-pci devices support legacy mode */
{ "virtio-pci", "disable-legacy", "off" }, { "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); const size_t hw_compat_2_6_len = G_N_ELEMENTS(hw_compat_2_6);

View File

@ -19,6 +19,20 @@
#include "hw/virtio/virtio-pci.h" #include "hw/virtio/virtio-pci.h"
#include "hw/virtio/virtio-gpu.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[] = { static Property virtio_gpu_pci_properties[] = {
DEFINE_VIRTIO_GPU_PCI_PROPERTIES(VirtIOPCIProxy), DEFINE_VIRTIO_GPU_PCI_PROPERTIES(VirtIOPCIProxy),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),

View File

@ -3,6 +3,7 @@
#include "hw/pci/pci.h" #include "hw/pci/pci.h"
#include "vga_int.h" #include "vga_int.h"
#include "hw/virtio/virtio-pci.h" #include "hw/virtio/virtio-pci.h"
#include "hw/virtio/virtio-gpu.h"
#include "qapi/error.h" #include "qapi/error.h"
/* /*

View File

@ -119,6 +119,12 @@ typedef struct AcpiBuildPciBusHotplugState {
bool pcihp_bridge_en; bool pcihp_bridge_en;
} AcpiBuildPciBusHotplugState; } 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) 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); 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; uint32_t nr_mem = machine->ram_slots;
int root_bus_limit = 0xFF; int root_bus_limit = 0xFF;
PCIBus *bus = NULL; PCIBus *bus = NULL;
TPMIf *tpm = tpm_find();
int i; int i;
dsdt = init_aml_allocator(); dsdt = init_aml_allocator();
@ -2133,7 +2140,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
/* Scan all PCI buses. Generate tables to support hotplug. */ /* Scan all PCI buses. Generate tables to support hotplug. */
build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en); 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"); dev = aml_device("ISA.TPM");
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C31"))); aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C31")));
aml_append(dev, aml_name_decl("_STA", aml_int(0xF))); 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(crs, aml_irq_no_flags(TPM_TIS_IRQ)); */
aml_append(dev, aml_name_decl("_CRS", crs)); aml_append(dev, aml_name_decl("_CRS", crs));
tpm_build_ppi_acpi(tpm, dev);
aml_append(scope, 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"); dev = aml_device("TPM");
aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101"))); aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101")));
crs = aml_resource_template(); 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(method, aml_return(aml_int(0x0f)));
aml_append(dev, method); aml_append(dev, method);
tpm_build_ppi_acpi(tpm, dev);
aml_append(sb_scope, dev); aml_append(sb_scope, dev);
} }
@ -2847,6 +2859,8 @@ void acpi_setup(void)
AcpiBuildTables tables; AcpiBuildTables tables;
AcpiBuildState *build_state; AcpiBuildState *build_state;
Object *vmgenid_dev; Object *vmgenid_dev;
TPMIf *tpm;
static FwCfgTPMConfig tpm_config;
if (!pcms->fw_cfg) { if (!pcms->fw_cfg) {
ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n"); 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, fw_cfg_add_file(pcms->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
tables.tcpalog->data, acpi_data_len(tables.tcpalog)); 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(); vmgenid_dev = find_vmgenid_dev();
if (vmgenid_dev) { if (vmgenid_dev) {
vmgenid_add_fw_cfg(VMGENID(vmgenid_dev), pcms->fw_cfg, vmgenid_add_fw_cfg(VMGENID(vmgenid_dev), pcms->fw_cfg,

View File

@ -715,7 +715,6 @@ static void pc_i440fx_1_2_machine_options(MachineClass *m)
PC_CPU_MODEL_IDS("1.2.0") PC_CPU_MODEL_IDS("1.2.0")
{ "nec-usb-xhci", "msi", "off" }, { "nec-usb-xhci", "msi", "off" },
{ "nec-usb-xhci", "msix", "off" }, { "nec-usb-xhci", "msix", "off" },
{ "ivshmem", "use64", "0" },
{ "qxl", "revision", "3" }, { "qxl", "revision", "3" },
{ "qxl-vga", "revision", "3" }, { "qxl-vga", "revision", "3" },
{ "VGA", "mmio", "off" }, { "VGA", "mmio", "off" },

View File

@ -377,6 +377,7 @@ static void pci_edu_uninit(PCIDevice *pdev)
qemu_mutex_destroy(&edu->thr_mutex); qemu_mutex_destroy(&edu->thr_mutex);
timer_del(&edu->dma_timer); timer_del(&edu->dma_timer);
msi_uninit(pdev);
} }
static void edu_obj_uint64(Object *obj, Visitor *v, const char *name, static void edu_obj_uint64(Object *obj, Visitor *v, const char *name,

View File

@ -112,13 +112,6 @@ typedef struct IVShmemState {
/* migration stuff */ /* migration stuff */
OnOffAuto master; OnOffAuto master;
Error *migration_blocker; Error *migration_blocker;
/* legacy cruft */
char *role;
char *shmobj;
char *sizearg;
size_t legacy_size;
uint32_t not_legacy_32bit;
} IVShmemState; } IVShmemState;
/* registers for the Inter-VM shared memory device */ /* 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; 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 */ /* mmap the region and map into the BAR2 */
memory_region_init_ram_from_fd(&s->server_bar2, OBJECT(s), memory_region_init_ram_from_fd(&s->server_bar2, OBJECT(s),
"ivshmem.bar2", size, true, fd, &local_err); "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); IVShmemState *s = IVSHMEM_COMMON(dev);
Error *err = NULL; Error *err = NULL;
uint8_t *pci_conf; uint8_t *pci_conf;
uint8_t attr = PCI_BASE_ADDRESS_SPACE_MEMORY |
PCI_BASE_ADDRESS_MEM_PREFETCH;
Error *local_err = NULL; Error *local_err = NULL;
/* IRQFD requires MSI */ /* 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, pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
&s->ivshmem_mmio); &s->ivshmem_mmio);
if (s->not_legacy_32bit) {
attr |= PCI_BASE_ADDRESS_MEM_TYPE_64;
}
if (s->hostmem != NULL) { if (s->hostmem != NULL) {
IVSHMEM_DPRINTF("using hostmem\n"); 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)); 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) static void ivshmem_exit(PCIDevice *dev)
@ -1084,13 +1064,6 @@ static Property ivshmem_plain_properties[] = {
DEFINE_PROP_END_OF_LIST(), 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) static void ivshmem_plain_realize(PCIDevice *dev, Error **errp)
{ {
IVShmemState *s = IVSHMEM_COMMON(dev); IVShmemState *s = IVSHMEM_COMMON(dev);
@ -1122,7 +1095,6 @@ static const TypeInfo ivshmem_plain_info = {
.name = TYPE_IVSHMEM_PLAIN, .name = TYPE_IVSHMEM_PLAIN,
.parent = TYPE_IVSHMEM_COMMON, .parent = TYPE_IVSHMEM_COMMON,
.instance_size = sizeof(IVShmemState), .instance_size = sizeof(IVShmemState),
.instance_init = ivshmem_plain_init,
.class_init = ivshmem_plain_class_init, .class_init = ivshmem_plain_class_init,
}; };
@ -1155,8 +1127,6 @@ static void ivshmem_doorbell_init(Object *obj)
IVShmemState *s = IVSHMEM_DOORBELL(obj); IVShmemState *s = IVSHMEM_DOORBELL(obj);
s->features |= (1 << IVSHMEM_MSI); 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) 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, .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) static void ivshmem_register_types(void)
{ {
type_register_static(&ivshmem_common_info); type_register_static(&ivshmem_common_info);
type_register_static(&ivshmem_plain_info); type_register_static(&ivshmem_plain_info);
type_register_static(&ivshmem_doorbell_info); type_register_static(&ivshmem_doorbell_info);
type_register_static(&ivshmem_info);
} }
type_init(ivshmem_register_types) type_init(ivshmem_register_types)

View File

@ -41,6 +41,47 @@
#define VIRTIO_NET_RX_QUEUE_MIN_SIZE VIRTIO_NET_RX_QUEUE_DEFAULT_SIZE #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_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 * Calculate the number of bytes up to and including the given 'field' of
* 'container'. * 'container'.
@ -628,6 +669,7 @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features,
if (!get_vhost_net(nc->peer)) { if (!get_vhost_net(nc->peer)) {
return features; return features;
} }
features = vhost_net_get_features(get_vhost_net(nc->peer), features); features = vhost_net_get_features(get_vhost_net(nc->peer), features);
vdev->backend_features = 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_has_feature(features,
VIRTIO_F_VERSION_1)); 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) { if (n->has_vnet_hdr) {
n->curr_guest_offloads = n->curr_guest_offloads =
virtio_net_guest_offloads_by_features(features); 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; 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); supported_offloads = virtio_net_supported_guest_offloads(n);
if (offloads & ~supported_offloads) { if (offloads & ~supported_offloads) {
return VIRTIO_NET_ERR; return VIRTIO_NET_ERR;
@ -1292,7 +1345,7 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
return size; 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) size_t size)
{ {
ssize_t r; ssize_t r;
@ -1303,6 +1356,612 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf,
return r; 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 int32_t virtio_net_flush_tx(VirtIONetQueue *q);
static void virtio_net_tx_complete(NetClientState *nc, ssize_t len) 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 = qemu_get_queue(n->nic);
nc->rxfilter_notify_enabled = 1; nc->rxfilter_notify_enabled = 1;
QTAILQ_INIT(&n->rsc_chains);
n->qdev = dev; n->qdev = dev;
} }
@ -2104,6 +2764,7 @@ static void virtio_net_device_unrealize(DeviceState *dev, Error **errp)
timer_free(n->announce_timer); timer_free(n->announce_timer);
g_free(n->vqs); g_free(n->vqs);
qemu_del_nic(n->nic); qemu_del_nic(n->nic);
virtio_net_rsc_cleanup(n);
virtio_cleanup(vdev); virtio_cleanup(vdev);
} }
@ -2184,6 +2845,10 @@ static Property virtio_net_properties[] = {
DEFINE_PROP_BIT64("ctrl_guest_offloads", VirtIONet, host_features, DEFINE_PROP_BIT64("ctrl_guest_offloads", VirtIONet, host_features,
VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, true), VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, true),
DEFINE_PROP_BIT64("mq", VirtIONet, host_features, VIRTIO_NET_F_MQ, false), 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_NIC_PROPERTIES(VirtIONet, nic_conf),
DEFINE_PROP_UINT32("x-txtimer", VirtIONet, net_conf.txtimer, DEFINE_PROP_UINT32("x-txtimer", VirtIONet, net_conf.txtimer,
TX_TIMER_INTERVAL), TX_TIMER_INTERVAL),

View File

@ -345,7 +345,7 @@ int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries,
char *name; char *name;
uint32_t bar_size = 4096; uint32_t bar_size = 4096;
uint32_t bar_pba_offset = bar_size / 2; 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 * Migration compatibility dictates that this remains a 4k

View File

@ -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, 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; uint8_t *exp_cap = hotplug_dev->config + hotplug_dev->exp.exp_cap;
uint16_t sltsta = pci_get_word(*exp_cap + PCI_EXP_SLTSTA); uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
PCIE_DEV_PRINTF(PCI_DEVICE(dev), "hotplug state: 0x%x\n", sltsta); PCIE_DEV_PRINTF(PCI_DEVICE(dev), "hotplug state: 0x%x\n", sltsta);
if (sltsta & PCI_EXP_SLTSTA_EIS) { 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, void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp) 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); 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: /* 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 * it is present on boot, no hotplug event is necessary. We do send an
* event when the device is disabled later. */ * 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, void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp) DeviceState *dev, Error **errp)
{ {
uint8_t *exp_cap; Error *local_err = NULL;
PCIDevice *pci_dev = PCI_DEVICE(dev); PCIDevice *pci_dev = PCI_DEVICE(dev);
PCIBus *bus = pci_get_bus(pci_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, /* In case user cancel the operation of multi-function hot-add,
* remove the function that is unexposed to guest individually, * remove the function that is unexposed to guest individually,

View File

@ -154,6 +154,7 @@ static void pcie_slot_class_init(ObjectClass *oc, void *data)
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
dc->props = pcie_slot_props; dc->props = pcie_slot_props;
hc->pre_plug = pcie_cap_slot_pre_plug_cb;
hc->plug = pcie_cap_slot_plug_cb; hc->plug = pcie_cap_slot_plug_cb;
hc->unplug = pcie_cap_slot_unplug_cb; hc->unplug = pcie_cap_slot_unplug_cb;
hc->unplug_request = pcie_cap_slot_unplug_request_cb; hc->unplug_request = pcie_cap_slot_unplug_request_cb;

View File

@ -215,6 +215,7 @@ static void vhost_scsi_unrealize(DeviceState *dev, Error **errp)
{ {
VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostSCSICommon *vsc = VHOST_SCSI_COMMON(dev); VHostSCSICommon *vsc = VHOST_SCSI_COMMON(dev);
struct vhost_virtqueue *vqs = vsc->dev.vqs;
migrate_del_blocker(vsc->migration_blocker); migrate_del_blocker(vsc->migration_blocker);
error_free(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_scsi_set_status(vdev, 0);
vhost_dev_cleanup(&vsc->dev); vhost_dev_cleanup(&vsc->dev);
g_free(vsc->dev.vqs); g_free(vqs);
virtio_scsi_common_unrealize(dev, errp); virtio_scsi_common_unrealize(dev, errp);
} }

View File

@ -121,12 +121,13 @@ static void vhost_user_scsi_unrealize(DeviceState *dev, Error **errp)
VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserSCSI *s = VHOST_USER_SCSI(dev); VHostUserSCSI *s = VHOST_USER_SCSI(dev);
VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
struct vhost_virtqueue *vqs = vsc->dev.vqs;
/* This will stop the vhost backend. */ /* This will stop the vhost backend. */
vhost_user_scsi_set_status(vdev, 0); vhost_user_scsi_set_status(vdev, 0);
vhost_dev_cleanup(&vsc->dev); vhost_dev_cleanup(&vsc->dev);
g_free(vsc->dev.vqs); g_free(vqs);
virtio_scsi_common_unrealize(dev, errp); virtio_scsi_common_unrealize(dev, errp);

View File

@ -1,4 +1,5 @@
common-obj-y += tpm_util.o common-obj-y += tpm_util.o
obj-y += tpm_ppi.o
common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o
common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o

View File

@ -29,6 +29,7 @@
#include "sysemu/reset.h" #include "sysemu/reset.h"
#include "tpm_int.h" #include "tpm_int.h"
#include "tpm_util.h" #include "tpm_util.h"
#include "tpm_ppi.h"
#include "trace.h" #include "trace.h"
typedef struct CRBState { typedef struct CRBState {
@ -41,6 +42,9 @@ typedef struct CRBState {
MemoryRegion cmdmem; MemoryRegion cmdmem;
size_t be_buffer_size; size_t be_buffer_size;
bool ppi_enabled;
TPMPPI ppi;
} CRBState; } CRBState;
#define CRB(obj) OBJECT_CHECK(CRBState, (obj), TYPE_TPM_CRB) #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[] = { static Property tpm_crb_properties[] = {
DEFINE_PROP_TPMBE("tpmdev", CRBState, tpmbe), DEFINE_PROP_TPMBE("tpmdev", CRBState, tpmbe),
DEFINE_PROP_BOOL("ppi", CRBState, ppi_enabled, true),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };
@ -228,6 +233,9 @@ static void tpm_crb_reset(void *dev)
{ {
CRBState *s = CRB(dev); CRBState *s = CRB(dev);
if (s->ppi_enabled) {
tpm_ppi_reset(&s->ppi);
}
tpm_backend_reset(s->tpmbe); tpm_backend_reset(s->tpmbe);
memset(s->regs, 0, sizeof(s->regs)); 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(), memory_region_add_subregion(get_system_memory(),
TPM_CRB_ADDR_BASE + sizeof(s->regs), &s->cmdmem); 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); qemu_register_reset(tpm_crb_reset, dev);
} }

53
hw/tpm/tpm_ppi.c Normal file
View File

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

46
hw/tpm/tpm_ppi.h Normal file
View File

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

View File

@ -31,6 +31,7 @@
#include "sysemu/tpm_backend.h" #include "sysemu/tpm_backend.h"
#include "tpm_int.h" #include "tpm_int.h"
#include "tpm_util.h" #include "tpm_util.h"
#include "tpm_ppi.h"
#include "trace.h" #include "trace.h"
#define TPM_TIS_NUM_LOCALITIES 5 /* per spec */ #define TPM_TIS_NUM_LOCALITIES 5 /* per spec */
@ -81,6 +82,9 @@ typedef struct TPMState {
TPMVersion be_tpm_version; TPMVersion be_tpm_version;
size_t be_buffer_size; size_t be_buffer_size;
bool ppi_enabled;
TPMPPI ppi;
} TPMState; } TPMState;
#define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS) #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), s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->be_driver),
TPM_TIS_BUFFER_MAX); TPM_TIS_BUFFER_MAX);
if (s->ppi_enabled) {
tpm_ppi_reset(&s->ppi);
}
tpm_backend_reset(s->be_driver); tpm_backend_reset(s->be_driver);
s->active_locty = TPM_TIS_NO_LOCALITY; s->active_locty = TPM_TIS_NO_LOCALITY;
@ -954,6 +961,7 @@ static const VMStateDescription vmstate_tpm_tis = {
static Property tpm_tis_properties[] = { static Property tpm_tis_properties[] = {
DEFINE_PROP_UINT32("irq", TPMState, irq_num, TPM_TIS_IRQ), DEFINE_PROP_UINT32("irq", TPMState, irq_num, TPM_TIS_IRQ),
DEFINE_PROP_TPMBE("tpmdev", TPMState, be_driver), DEFINE_PROP_TPMBE("tpmdev", TPMState, be_driver),
DEFINE_PROP_BOOL("ppi", TPMState, ppi_enabled, true),
DEFINE_PROP_END_OF_LIST(), 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)), memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)),
TPM_TIS_ADDR_BASE, &s->mmio); 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) static void tpm_tis_initfn(Object *obj)

View File

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

View File

@ -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_LINUX) += vhost.o vhost-backend.o vhost-user.o
obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock.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 endif
common-obj-$(call lnot,$(call land,$(CONFIG_VIRTIO),$(CONFIG_LINUX))) += vhost-stub.o common-obj-$(call lnot,$(call land,$(CONFIG_VIRTIO),$(CONFIG_LINUX))) += vhost-stub.o

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -207,7 +207,7 @@ struct vhost_user {
static bool ioeventfd_enabled(void) 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) static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg)

View File

@ -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)

88
hw/virtio/virtio-9p-pci.c Normal file
View File

@ -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)

View File

@ -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)

100
hw/virtio/virtio-blk-pci.c Normal file
View File

@ -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)

View File

@ -19,6 +19,20 @@
#include "hw/virtio/virtio-crypto.h" #include "hw/virtio/virtio-crypto.h"
#include "qapi/error.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[] = { static Property virtio_crypto_pci_properties[] = {
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -19,12 +19,6 @@
#include "standard-headers/linux/virtio_pci.h" #include "standard-headers/linux/virtio_pci.h"
#include "hw/virtio/virtio.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 "hw/pci/pci.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qemu/error-report.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. * 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 */ /* virtio-pci-bus */
static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size, 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: */ /* Base types: */
type_register_static(&virtio_pci_bus_info); type_register_static(&virtio_pci_bus_info);
type_register_static(&virtio_pci_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) type_init(virtio_pci_register_types)

View File

@ -16,47 +16,9 @@
#define QEMU_VIRTIO_PCI_H #define QEMU_VIRTIO_PCI_H
#include "hw/pci/msi.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-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 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 */ /* virtio-pci-bus */
@ -213,206 +175,10 @@ static inline void virtio_pci_disable_modern(VirtIOPCIProxy *proxy)
proxy->disable_modern = true; proxy->disable_modern = true;
} }
/*
* 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. * virtio-input-pci: This extends VirtioPCIProxy.
*/ */
#define TYPE_VIRTIO_INPUT_PCI "virtio-input-pci" #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. */ /* Virtio ABI version, if we increment this, we break the guest driver. */
#define VIRTIO_PCI_ABI_VERSION 0 #define VIRTIO_PCI_ABI_VERSION 0

View File

@ -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)

107
hw/virtio/virtio-scsi-pci.c Normal file
View File

@ -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)

View File

@ -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)

View File

@ -41,8 +41,8 @@ enum {
}; };
typedef struct AcpiRsdpData { typedef struct AcpiRsdpData {
uint8_t oem_id[6]; /* OEM identification */ uint8_t oem_id[6] QEMU_NONSTRING; /* OEM identification */
uint8_t revision; /* Must be 0 for 1.0, 2 for 2.0 */ uint8_t revision; /* Must be 0 for 1.0, 2 for 2.0 */
unsigned *rsdt_tbl_offset; unsigned *rsdt_tbl_offset;
unsigned *xsdt_tbl_offset; unsigned *xsdt_tbl_offset;
@ -57,10 +57,13 @@ typedef struct AcpiRsdpData {
uint32_t length; /* Length of table, in bytes, including header */ \ uint32_t length; /* Length of table, in bytes, including header */ \
uint8_t revision; /* ACPI Specification minor version # */ \ uint8_t revision; /* ACPI Specification minor version # */ \
uint8_t checksum; /* To make sum of entire table == 0 */ \ uint8_t checksum; /* To make sum of entire table == 0 */ \
uint8_t oem_id [6]; /* OEM identification */ \ uint8_t oem_id[6] \
uint8_t oem_table_id [8]; /* OEM table identification */ \ QEMU_NONSTRING; /* OEM identification */ \
uint8_t oem_table_id[8] \
QEMU_NONSTRING; /* OEM table identification */ \
uint32_t oem_revision; /* OEM revision number */ \ uint32_t oem_revision; /* OEM revision number */ \
uint8_t asl_compiler_id [4]; /* ASL compiler vendor ID */ \ uint8_t asl_compiler_id[4] \
QEMU_NONSTRING; /* ASL compiler vendor ID */ \
uint32_t asl_compiler_revision; /* ASL compiler revision number */ uint32_t asl_compiler_revision; /* ASL compiler revision number */

View File

@ -18,6 +18,8 @@
#include "qemu/units.h" #include "qemu/units.h"
#include "hw/registerfields.h" #include "hw/registerfields.h"
#include "hw/acpi/aml-build.h"
#include "sysemu/tpm.h"
#define TPM_TIS_ADDR_BASE 0xFED40000 #define TPM_TIS_ADDR_BASE 0xFED40000
#define TPM_TIS_ADDR_SIZE 0x5000 #define TPM_TIS_ADDR_SIZE 0x5000
@ -188,4 +190,23 @@ REG32(CRB_DATA_BUFFER, 0x80)
#define TPM2_START_METHOD_MMIO 6 #define TPM2_START_METHOD_MMIO 6
#define TPM2_START_METHOD_CRB 7 #define TPM2_START_METHOD_CRB 7
/*
* Physical Presence Interface
*/
#define TPM_PPI_ADDR_SIZE 0x400
#define TPM_PPI_ADDR_BASE 0xFED45000
#define TPM_PPI_VERSION_NONE 0
#define TPM_PPI_VERSION_1_30 1
/* whether function is blocked by BIOS settings; bits 0, 1, 2 */
#define TPM_PPI_FUNC_NOT_IMPLEMENTED (0 << 0)
#define TPM_PPI_FUNC_BIOS_ONLY (1 << 0)
#define TPM_PPI_FUNC_BLOCKED (2 << 0)
#define TPM_PPI_FUNC_ALLOWED_USR_REQ (3 << 0)
#define TPM_PPI_FUNC_ALLOWED_USR_NOT_REQ (4 << 0)
#define TPM_PPI_FUNC_MASK (7 << 0)
void tpm_build_ppi_acpi(TPMIf *tpm, Aml *dev);
#endif /* HW_ACPI_TPM_H */ #endif /* HW_ACPI_TPM_H */

View File

@ -132,6 +132,8 @@ void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn);
void pcie_dev_ser_num_init(PCIDevice *dev, uint16_t offset, uint64_t ser_num); void pcie_dev_ser_num_init(PCIDevice *dev, uint16_t offset, uint64_t ser_num);
void pcie_ats_init(PCIDevice *dev, uint16_t offset); void pcie_ats_init(PCIDevice *dev, uint16_t offset);
void pcie_cap_slot_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp);
void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp); Error **errp);
void pcie_cap_slot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, void pcie_cap_slot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,

View File

@ -250,6 +250,8 @@ struct PropertyInfo {
/** /**
* GlobalProperty: * GlobalProperty:
* @used: Set to true if property was used when initializing a device. * @used: Set to true if property was used when initializing a device.
* @optional: If set to true, GlobalProperty will be skipped without errors
* if the property doesn't exist.
* *
* An error is fatal for non-hotplugged devices, when the global is applied. * An error is fatal for non-hotplugged devices, when the global is applied.
*/ */
@ -258,6 +260,7 @@ typedef struct GlobalProperty {
const char *property; const char *property;
const char *value; const char *value;
bool used; bool used;
bool optional;
} GlobalProperty; } GlobalProperty;
static inline void static inline void

View File

@ -44,6 +44,83 @@ typedef struct virtio_net_conf
uint8_t duplex; uint8_t duplex;
} virtio_net_conf; } virtio_net_conf;
/* Coalesced packets type & status */
typedef enum {
RSC_COALESCE, /* Data been coalesced */
RSC_FINAL, /* Will terminate current connection */
RSC_NO_MATCH, /* No matched in the buffer pool */
RSC_BYPASS, /* Packet to be bypass, not tcp, tcp ctrl, etc */
RSC_CANDIDATE /* Data want to be coalesced */
} CoalesceStatus;
typedef struct VirtioNetRscStat {
uint32_t received;
uint32_t coalesced;
uint32_t over_size;
uint32_t cache;
uint32_t empty_cache;
uint32_t no_match_cache;
uint32_t win_update;
uint32_t no_match;
uint32_t tcp_syn;
uint32_t tcp_ctrl_drain;
uint32_t dup_ack;
uint32_t dup_ack1;
uint32_t dup_ack2;
uint32_t pure_ack;
uint32_t ack_out_of_win;
uint32_t data_out_of_win;
uint32_t data_out_of_order;
uint32_t data_after_pure_ack;
uint32_t bypass_not_tcp;
uint32_t tcp_option;
uint32_t tcp_all_opt;
uint32_t ip_frag;
uint32_t ip_ecn;
uint32_t ip_hacked;
uint32_t ip_option;
uint32_t purge_failed;
uint32_t drain_failed;
uint32_t final_failed;
int64_t timer;
} VirtioNetRscStat;
/* Rsc unit general info used to checking if can coalescing */
typedef struct VirtioNetRscUnit {
void *ip; /* ip header */
uint16_t *ip_plen; /* data len pointer in ip header field */
struct tcp_header *tcp; /* tcp header */
uint16_t tcp_hdrlen; /* tcp header len */
uint16_t payload; /* pure payload without virtio/eth/ip/tcp */
} VirtioNetRscUnit;
/* Coalesced segmant */
typedef struct VirtioNetRscSeg {
QTAILQ_ENTRY(VirtioNetRscSeg) next;
void *buf;
size_t size;
uint16_t packets;
uint16_t dup_ack;
bool is_coalesced; /* need recal ipv4 header checksum, mark here */
VirtioNetRscUnit unit;
NetClientState *nc;
} VirtioNetRscSeg;
struct VirtIONet;
typedef struct VirtIONet VirtIONet;
/* Chain is divided by protocol(ipv4/v6) and NetClientInfo */
typedef struct VirtioNetRscChain {
QTAILQ_ENTRY(VirtioNetRscChain) next;
VirtIONet *n; /* VirtIONet */
uint16_t proto;
uint8_t gso_type;
uint16_t max_payload;
QEMUTimer *drain_timer;
QTAILQ_HEAD(, VirtioNetRscSeg) buffers;
VirtioNetRscStat stat;
} VirtioNetRscChain;
/* Maximum packet size we can receive from tap device: header + 64k */ /* Maximum packet size we can receive from tap device: header + 64k */
#define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 * KiB)) #define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 * KiB))
@ -66,12 +143,18 @@ typedef struct VirtIONet {
VirtIONetQueue *vqs; VirtIONetQueue *vqs;
VirtQueue *ctrl_vq; VirtQueue *ctrl_vq;
NICState *nic; NICState *nic;
/* RSC Chains - temporary storage of coalesced data,
all these data are lost in case of migration */
QTAILQ_HEAD(, VirtioNetRscChain) rsc_chains;
uint32_t tx_timeout; uint32_t tx_timeout;
int32_t tx_burst; int32_t tx_burst;
uint32_t has_vnet_hdr; uint32_t has_vnet_hdr;
size_t host_hdr_len; size_t host_hdr_len;
size_t guest_hdr_len; size_t guest_hdr_len;
uint64_t host_features; uint64_t host_features;
uint32_t rsc_timeout;
uint8_t rsc4_enabled;
uint8_t rsc6_enabled;
uint8_t has_ufo; uint8_t has_ufo;
uint32_t mergeable_rx_bufs; uint32_t mergeable_rx_bufs;
uint8_t promisc; uint8_t promisc;

View File

@ -177,6 +177,8 @@ struct tcp_hdr {
#define TH_PUSH 0x08 #define TH_PUSH 0x08
#define TH_ACK 0x10 #define TH_ACK 0x10
#define TH_URG 0x20 #define TH_URG 0x20
#define TH_ECE 0x40
#define TH_CWR 0x80
u_short th_win; /* window */ u_short th_win; /* window */
u_short th_sum; /* checksum */ u_short th_sum; /* checksum */
u_short th_urp; /* urgent pointer */ u_short th_urp; /* urgent pointer */

View File

@ -151,6 +151,21 @@
# define QEMU_ERROR(X) # define QEMU_ERROR(X)
#endif #endif
/*
* The nonstring variable attribute specifies that an object or member
* declaration with type array of char or pointer to char is intended
* to store character arrays that do not necessarily contain a terminating
* NUL character. This is useful in detecting uses of such arrays or pointers
* with functions that expect NUL-terminated strings, and to avoid warnings
* when such an array or pointer is used as an argument to a bounded string
* manipulation function such as strncpy.
*/
#if __has_attribute(nonstring)
# define QEMU_NONSTRING __attribute__((nonstring))
#else
# define QEMU_NONSTRING
#endif
/* Implement C11 _Generic via GCC builtins. Example: /* Implement C11 _Generic via GCC builtins. Example:
* *
* QEMU_GENERIC(x, (float, sinf), (long double, sinl), sin) (x) * QEMU_GENERIC(x, (float, sinf), (long double, sinl), sin) (x)

View File

@ -42,6 +42,7 @@ int global_state_store(void)
void global_state_store_running(void) void global_state_store_running(void)
{ {
const char *state = RunState_str(RUN_STATE_RUNNING); const char *state = RunState_str(RUN_STATE_RUNNING);
assert(strlen(state) < sizeof(global_state.runstate));
strncpy((char *)global_state.runstate, strncpy((char *)global_state.runstate,
state, sizeof(global_state.runstate)); state, sizeof(global_state.runstate));
} }
@ -88,6 +89,17 @@ static int global_state_post_load(void *opaque, int version_id)
s->received = true; s->received = true;
trace_migrate_global_state_post_load(runstate); trace_migrate_global_state_post_load(runstate);
if (strnlen((char *)s->runstate,
sizeof(s->runstate)) == sizeof(s->runstate)) {
/*
* This condition should never happen during migration, because
* all runstate names are shorter than 100 bytes (the size of
* s->runstate). However, a malicious stream could overflow
* the qapi_enum_parse() call, so we force the last character
* to a NUL byte.
*/
s->runstate[sizeof(s->runstate) - 1] = '\0';
}
r = qapi_enum_parse(&RunState_lookup, runstate, -1, &local_err); r = qapi_enum_parse(&RunState_lookup, runstate, -1, &local_err);
if (r == -1) { if (r == -1) {
@ -106,7 +118,8 @@ static int global_state_pre_save(void *opaque)
GlobalState *s = opaque; GlobalState *s = opaque;
trace_migrate_global_state_pre_save((char *)s->runstate); trace_migrate_global_state_pre_save((char *)s->runstate);
s->size = strlen((char *)s->runstate) + 1; s->size = strnlen((char *)s->runstate, sizeof(s->runstate)) + 1;
assert(s->size <= sizeof(s->runstate));
return 0; return 0;
} }

View File

@ -126,11 +126,6 @@ documentation of ``query-hotpluggable-cpus'' for additional details.
@section System emulator devices @section System emulator devices
@subsection ivshmem (since 2.6.0)
The ``ivshmem'' device type is replaced by either the ``ivshmem-plain''
or ``ivshmem-doorbell`` device types.
@subsection bluetooth (since 3.1) @subsection bluetooth (since 3.1)
The bluetooth subsystem is unmaintained since many years and likely bitrotten The bluetooth subsystem is unmaintained since many years and likely bitrotten

View File

@ -385,6 +385,9 @@ void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp
if (object_dynamic_cast(obj, p->driver) == NULL) { if (object_dynamic_cast(obj, p->driver) == NULL) {
continue; continue;
} }
if (p->optional && !object_property_find(obj, p->property, NULL)) {
continue;
}
p->used = true; p->used = true;
object_property_parse(obj, p->value, p->property, &err); object_property_parse(obj, p->value, p->property, &err);
if (err != NULL) { if (err != NULL) {

View File

@ -83,7 +83,6 @@ ERROR_WHITELIST = [
{'device':'isa-ipmi-bt', 'expected':True}, # IPMI device requires a bmc attribute to be set {'device':'isa-ipmi-bt', 'expected':True}, # IPMI device requires a bmc attribute to be set
{'device':'isa-ipmi-kcs', 'expected':True}, # IPMI device requires a bmc attribute to be set {'device':'isa-ipmi-kcs', 'expected':True}, # IPMI device requires a bmc attribute to be set
{'device':'isa-parallel', 'expected':True}, # Can't create serial device, empty char device {'device':'isa-parallel', 'expected':True}, # Can't create serial device, empty char device
{'device':'ivshmem', 'expected':True}, # You must specify either 'shm' or 'chardev'
{'device':'ivshmem-doorbell', 'expected':True}, # You must specify a 'chardev' {'device':'ivshmem-doorbell', 'expected':True}, # You must specify a 'chardev'
{'device':'ivshmem-plain', 'expected':True}, # You must specify a 'memdev' {'device':'ivshmem-plain', 'expected':True}, # You must specify a 'memdev'
{'device':'loader', 'expected':True}, # please include valid arguments {'device':'loader', 'expected':True}, # please include valid arguments

View File

@ -8,6 +8,7 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qapi/qapi-commands-tpm.h" #include "qapi/qapi-commands-tpm.h"
#include "sysemu/tpm.h" #include "sysemu/tpm.h"
#include "hw/acpi/tpm.h"
void tpm_init(void) void tpm_init(void)
{ {
@ -31,3 +32,7 @@ TpmModelList *qmp_query_tpm_models(Error **errp)
{ {
return NULL; return NULL;
} }
void tpm_build_ppi_acpi(TPMIf *tpm, Aml *dev)
{
}

View File

@ -107,7 +107,7 @@ check-unit-y += tests/test-crypto-secret$(EXESUF)
check-unit-$(CONFIG_GNUTLS) += tests/test-crypto-tlscredsx509$(EXESUF) check-unit-$(CONFIG_GNUTLS) += tests/test-crypto-tlscredsx509$(EXESUF)
check-unit-$(CONFIG_GNUTLS) += tests/test-crypto-tlssession$(EXESUF) check-unit-$(CONFIG_GNUTLS) += tests/test-crypto-tlssession$(EXESUF)
ifneq (,$(findstring qemu-ga,$(TOOLS))) ifneq (,$(findstring qemu-ga,$(TOOLS)))
check-unit-$(CONFIG_LINUX) += tests/test-qga$(EXESUF) check-unit-$(land,$(CONFIG_LINUX),$(CONFIG_VIRTIO_SERIAL)) += tests/test-qga$(EXESUF)
endif endif
check-unit-y += tests/test-timed-average$(EXESUF) check-unit-y += tests/test-timed-average$(EXESUF)
check-unit-y += tests/test-util-sockets$(EXESUF) check-unit-y += tests/test-util-sockets$(EXESUF)
@ -143,17 +143,17 @@ check-qtest-generic-y += tests/cdrom-test$(EXESUF)
check-qtest-ipack-y += tests/ipoctal232-test$(EXESUF) check-qtest-ipack-y += tests/ipoctal232-test$(EXESUF)
check-qtest-virtioserial-y += tests/virtio-console-test$(EXESUF) check-qtest-virtioserial-$(CONFIG_VIRTIO_SERIAL) += tests/virtio-console-test$(EXESUF)
check-qtest-virtio-y += tests/virtio-net-test$(EXESUF) check-qtest-virtio-$(CONFIG_VIRTIO_NET) += tests/virtio-net-test$(EXESUF)
check-qtest-virtio-y += tests/virtio-balloon-test$(EXESUF) check-qtest-virtio-$(CONFIG_VIRTIO_BALLOON) += tests/virtio-balloon-test$(EXESUF)
check-qtest-virtio-y += tests/virtio-blk-test$(EXESUF) check-qtest-virtio-$(CONFIG_VIRTIO_BLK) += tests/virtio-blk-test$(EXESUF)
check-qtest-virtio-y += tests/virtio-rng-test$(EXESUF) check-qtest-virtio-$(CONFIG_VIRTIO_RNG) += tests/virtio-rng-test$(EXESUF)
check-qtest-virtio-y += tests/virtio-scsi-test$(EXESUF) check-qtest-virtio-$(CONFIG_VIRTIO_SCSI) += tests/virtio-scsi-test$(EXESUF)
ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy) ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy)
check-qtest-virtio-y += tests/virtio-9p-test$(EXESUF) check-qtest-virtio-$(CONFIG_VIRTIO_9P) += tests/virtio-9p-test$(EXESUF)
endif endif
check-qtest-virtio-y += tests/virtio-serial-test$(EXESUF) check-qtest-virtio-$(CONFIG_VIRTIO_SERIAL) += tests/virtio-serial-test$(EXESUF)
check-qtest-virtio-y += $(check-qtest-virtioserial-y) check-qtest-virtio-y += $(check-qtest-virtioserial-y)
check-qtest-pci-y += tests/e1000-test$(EXESUF) check-qtest-pci-y += tests/e1000-test$(EXESUF)
@ -284,7 +284,7 @@ check-qtest-arm-y += tests/pca9552-test$(EXESUF)
check-qtest-arm-y += tests/ds1338-test$(EXESUF) check-qtest-arm-y += tests/ds1338-test$(EXESUF)
check-qtest-arm-y += tests/microbit-test$(EXESUF) check-qtest-arm-y += tests/microbit-test$(EXESUF)
check-qtest-arm-y += tests/m25p80-test$(EXESUF) check-qtest-arm-y += tests/m25p80-test$(EXESUF)
check-qtest-arm-y += tests/virtio-blk-test$(EXESUF) check-qtest-arm-$(CONFIG_VIRTIO_BLK) += tests/virtio-blk-test$(EXESUF)
check-qtest-arm-y += tests/test-arm-mptimer$(EXESUF) check-qtest-arm-y += tests/test-arm-mptimer$(EXESUF)
check-qtest-arm-y += tests/boot-serial-test$(EXESUF) check-qtest-arm-y += tests/boot-serial-test$(EXESUF)
check-qtest-arm-$(CONFIG_SDHCI) += tests/sdhci-test$(EXESUF) check-qtest-arm-$(CONFIG_SDHCI) += tests/sdhci-test$(EXESUF)

View File

@ -51,14 +51,6 @@ uint32_t acpi_find_rsdp_address(QTestState *qts)
return off; return off;
} }
uint32_t acpi_get_rsdt_address(uint8_t *rsdp_table)
{
uint32_t rsdt_physical_address;
memcpy(&rsdt_physical_address, &rsdp_table[16 /* RsdtAddress offset */], 4);
return le32_to_cpu(rsdt_physical_address);
}
uint64_t acpi_get_xsdt_address(uint8_t *rsdp_table) uint64_t acpi_get_xsdt_address(uint8_t *rsdp_table)
{ {
uint64_t xsdt_physical_address; uint64_t xsdt_physical_address;
@ -92,3 +84,30 @@ void acpi_parse_rsdp_table(QTestState *qts, uint32_t addr, uint8_t *rsdp_table)
ACPI_ASSERT_CMP64(*((uint64_t *)(rsdp_table)), "RSD PTR "); ACPI_ASSERT_CMP64(*((uint64_t *)(rsdp_table)), "RSD PTR ");
} }
/** acpi_fetch_table
* load ACPI table at @addr_ptr offset pointer into buffer and return it in
* @aml, its length in @aml_len and check that signature/checksum matches
* actual one.
*/
void acpi_fetch_table(QTestState *qts, uint8_t **aml, uint32_t *aml_len,
const uint8_t *addr_ptr, const char *sig,
bool verify_checksum)
{
uint32_t addr, len;
memcpy(&addr, addr_ptr , sizeof(addr));
addr = le32_to_cpu(addr);
qtest_memread(qts, addr + 4, &len, 4); /* Length of ACPI table */
*aml_len = le32_to_cpu(len);
*aml = g_malloc0(*aml_len);
/* get whole table */
qtest_memread(qts, addr, *aml, *aml_len);
if (sig) {
ACPI_ASSERT_CMP(**aml, sig);
}
if (verify_checksum) {
g_assert(!acpi_calc_checksum(*aml, *aml_len));
}
}

View File

@ -13,14 +13,12 @@
#ifndef TEST_ACPI_UTILS_H #ifndef TEST_ACPI_UTILS_H
#define TEST_ACPI_UTILS_H #define TEST_ACPI_UTILS_H
#include "hw/acpi/acpi-defs.h"
#include "libqtest.h" #include "libqtest.h"
/* DSDT and SSDTs format */ /* DSDT and SSDTs format */
typedef struct { typedef struct {
AcpiTableHeader header; uint8_t *aml; /* aml bytecode from guest */
gchar *aml; /* aml bytecode from guest */ uint32_t aml_len;
gsize aml_len;
gchar *aml_file; gchar *aml_file;
gchar *asl; /* asl code generated from aml */ gchar *asl; /* asl code generated from aml */
gsize asl_len; gsize asl_len;
@ -28,36 +26,6 @@ typedef struct {
bool tmp_files_retain; /* do not delete the temp asl/aml */ bool tmp_files_retain; /* do not delete the temp asl/aml */
} AcpiSdtTable; } AcpiSdtTable;
#define ACPI_READ_FIELD(qts, field, addr) \
do { \
qtest_memread(qts, addr, &field, sizeof(field)); \
addr += sizeof(field); \
} while (0)
#define ACPI_READ_ARRAY_PTR(qts, arr, length, addr) \
do { \
int idx; \
for (idx = 0; idx < length; ++idx) { \
ACPI_READ_FIELD(qts, arr[idx], addr); \
} \
} while (0)
#define ACPI_READ_ARRAY(qts, arr, addr) \
ACPI_READ_ARRAY_PTR(qts, arr, sizeof(arr) / sizeof(arr[0]), addr)
#define ACPI_READ_TABLE_HEADER(qts, table, addr) \
do { \
ACPI_READ_FIELD(qts, (table)->signature, addr); \
ACPI_READ_FIELD(qts, (table)->length, addr); \
ACPI_READ_FIELD(qts, (table)->revision, addr); \
ACPI_READ_FIELD(qts, (table)->checksum, addr); \
ACPI_READ_ARRAY(qts, (table)->oem_id, addr); \
ACPI_READ_ARRAY(qts, (table)->oem_table_id, addr); \
ACPI_READ_FIELD(qts, (table)->oem_revision, addr); \
ACPI_READ_ARRAY(qts, (table)->asl_compiler_id, addr); \
ACPI_READ_FIELD(qts, (table)->asl_compiler_revision, addr); \
} while (0)
#define ACPI_ASSERT_CMP(actual, expected) do { \ #define ACPI_ASSERT_CMP(actual, expected) do { \
char ACPI_ASSERT_CMP_str[5] = {}; \ char ACPI_ASSERT_CMP_str[5] = {}; \
memcpy(ACPI_ASSERT_CMP_str, &actual, 4); \ memcpy(ACPI_ASSERT_CMP_str, &actual, 4); \
@ -71,11 +39,17 @@ typedef struct {
} while (0) } while (0)
#define ACPI_FOREACH_RSDT_ENTRY(table, table_len, entry_ptr, entry_size) \
for (entry_ptr = table + 36 /* 1st Entry */; \
entry_ptr < table + table_len; \
entry_ptr += entry_size)
uint8_t acpi_calc_checksum(const uint8_t *data, int len); uint8_t acpi_calc_checksum(const uint8_t *data, int len);
uint32_t acpi_find_rsdp_address(QTestState *qts); uint32_t acpi_find_rsdp_address(QTestState *qts);
uint32_t acpi_get_rsdt_address(uint8_t *rsdp_table);
uint64_t acpi_get_xsdt_address(uint8_t *rsdp_table); uint64_t acpi_get_xsdt_address(uint8_t *rsdp_table);
void acpi_parse_rsdp_table(QTestState *qts, uint32_t addr, uint8_t *rsdp_table); void acpi_parse_rsdp_table(QTestState *qts, uint32_t addr, uint8_t *rsdp_table);
void acpi_fetch_table(QTestState *qts, uint8_t **aml, uint32_t *aml_len,
const uint8_t *addr_ptr, const char *sig,
bool verify_checksum);
#endif /* TEST_ACPI_UTILS_H */ #endif /* TEST_ACPI_UTILS_H */

View File

@ -28,12 +28,6 @@ typedef struct {
const char *variant; const char *variant;
uint32_t rsdp_addr; uint32_t rsdp_addr;
uint8_t rsdp_table[36 /* ACPI 2.0+ RSDP size */]; uint8_t rsdp_table[36 /* ACPI 2.0+ RSDP size */];
AcpiRsdtDescriptorRev1 rsdt_table;
uint32_t dsdt_addr;
uint32_t facs_addr;
AcpiFacsDescriptorRev1 facs_table;
uint32_t *rsdt_tables_addr;
int rsdt_tables_nr;
GArray *tables; GArray *tables;
uint32_t smbios_ep_addr; uint32_t smbios_ep_addr;
struct smbios_21_entry_point smbios_ep_table; struct smbios_21_entry_point smbios_ep_table;
@ -50,28 +44,34 @@ static const char *iasl = stringify(CONFIG_IASL);
static const char *iasl; static const char *iasl;
#endif #endif
static bool compare_signature(const AcpiSdtTable *sdt, const char *signature)
{
return !memcmp(sdt->aml, signature, 4);
}
static void cleanup_table_descriptor(AcpiSdtTable *table)
{
g_free(table->aml);
if (table->aml_file &&
!table->tmp_files_retain &&
g_strstr_len(table->aml_file, -1, "aml-")) {
unlink(table->aml_file);
}
g_free(table->aml_file);
g_free(table->asl);
if (table->asl_file &&
!table->tmp_files_retain) {
unlink(table->asl_file);
}
g_free(table->asl_file);
}
static void free_test_data(test_data *data) static void free_test_data(test_data *data)
{ {
AcpiSdtTable *temp;
int i; int i;
g_free(data->rsdt_tables_addr);
for (i = 0; i < data->tables->len; ++i) { for (i = 0; i < data->tables->len; ++i) {
temp = &g_array_index(data->tables, AcpiSdtTable, i); cleanup_table_descriptor(&g_array_index(data->tables, AcpiSdtTable, i));
g_free(temp->aml);
if (temp->aml_file &&
!temp->tmp_files_retain &&
g_strstr_len(temp->aml_file, -1, "aml-")) {
unlink(temp->aml_file);
}
g_free(temp->aml_file);
g_free(temp->asl);
if (temp->asl_file &&
!temp->tmp_files_retain) {
unlink(temp->asl_file);
}
g_free(temp->asl_file);
} }
g_array_free(data->tables, true); g_array_free(data->tables, true);
@ -109,154 +109,53 @@ static void test_acpi_rsdp_table(test_data *data)
static void test_acpi_rsdt_table(test_data *data) static void test_acpi_rsdt_table(test_data *data)
{ {
AcpiRsdtDescriptorRev1 *rsdt_table = &data->rsdt_table; AcpiSdtTable rsdt = {};
uint32_t addr = acpi_get_rsdt_address(data->rsdp_table); uint8_t *ent;
uint32_t *tables;
int tables_nr;
uint8_t checksum;
uint32_t rsdt_table_length;
/* read the header */ /* read RSDT table */
ACPI_READ_TABLE_HEADER(data->qts, rsdt_table, addr); acpi_fetch_table(data->qts, &rsdt.aml, &rsdt.aml_len,
ACPI_ASSERT_CMP(rsdt_table->signature, "RSDT"); &data->rsdp_table[16 /* RsdtAddress */], "RSDT", true);
rsdt_table_length = le32_to_cpu(rsdt_table->length); /* Load all tables and add to test list directly RSDT referenced tables */
ACPI_FOREACH_RSDT_ENTRY(rsdt.aml, rsdt.aml_len, ent, 4 /* Entry size */) {
/* compute the table entries in rsdt */ AcpiSdtTable ssdt_table = {};
tables_nr = (rsdt_table_length - sizeof(AcpiRsdtDescriptorRev1)) /
sizeof(uint32_t);
g_assert(tables_nr > 0);
/* get the addresses of the tables pointed by rsdt */
tables = g_new0(uint32_t, tables_nr);
ACPI_READ_ARRAY_PTR(data->qts, tables, tables_nr, addr);
checksum = acpi_calc_checksum((uint8_t *)rsdt_table, rsdt_table_length) +
acpi_calc_checksum((uint8_t *)tables,
tables_nr * sizeof(uint32_t));
g_assert(!checksum);
/* SSDT tables after FADT */
data->rsdt_tables_addr = tables;
data->rsdt_tables_nr = tables_nr;
}
static void fadt_fetch_facs_and_dsdt_ptrs(test_data *data)
{
uint32_t addr;
AcpiTableHeader hdr;
/* FADT table comes first */
addr = le32_to_cpu(data->rsdt_tables_addr[0]);
ACPI_READ_TABLE_HEADER(data->qts, &hdr, addr);
ACPI_ASSERT_CMP(hdr.signature, "FACP");
ACPI_READ_FIELD(data->qts, data->facs_addr, addr);
ACPI_READ_FIELD(data->qts, data->dsdt_addr, addr);
}
static void sanitize_fadt_ptrs(test_data *data)
{
/* fixup pointers in FADT */
int i;
for (i = 0; i < data->tables->len; i++) {
AcpiSdtTable *sdt = &g_array_index(data->tables, AcpiSdtTable, i);
if (memcmp(&sdt->header.signature, "FACP", 4)) {
continue;
}
/* check original FADT checksum before sanitizing table */
g_assert(!(uint8_t)(
acpi_calc_checksum((uint8_t *)sdt, sizeof(AcpiTableHeader)) +
acpi_calc_checksum((uint8_t *)sdt->aml, sdt->aml_len)
));
/* sdt->aml field offset := spec offset - header size */
memset(sdt->aml + 0, 0, 4); /* sanitize FIRMWARE_CTRL(36) ptr */
memset(sdt->aml + 4, 0, 4); /* sanitize DSDT(40) ptr */
if (sdt->header.revision >= 3) {
memset(sdt->aml + 96, 0, 8); /* sanitize X_FIRMWARE_CTRL(132) ptr */
memset(sdt->aml + 104, 0, 8); /* sanitize X_DSDT(140) ptr */
}
/* update checksum */
sdt->header.checksum = 0;
sdt->header.checksum -=
acpi_calc_checksum((uint8_t *)sdt, sizeof(AcpiTableHeader)) +
acpi_calc_checksum((uint8_t *)sdt->aml, sdt->aml_len);
break;
}
}
static void test_acpi_facs_table(test_data *data)
{
AcpiFacsDescriptorRev1 *facs_table = &data->facs_table;
uint32_t addr = le32_to_cpu(data->facs_addr);
ACPI_READ_FIELD(data->qts, facs_table->signature, addr);
ACPI_READ_FIELD(data->qts, facs_table->length, addr);
ACPI_READ_FIELD(data->qts, facs_table->hardware_signature, addr);
ACPI_READ_FIELD(data->qts, facs_table->firmware_waking_vector, addr);
ACPI_READ_FIELD(data->qts, facs_table->global_lock, addr);
ACPI_READ_FIELD(data->qts, facs_table->flags, addr);
ACPI_READ_ARRAY(data->qts, facs_table->resverved3, addr);
ACPI_ASSERT_CMP(facs_table->signature, "FACS");
}
/** fetch_table
* load ACPI table at @addr into table descriptor @sdt_table
* and check that header checksum matches actual one.
*/
static void fetch_table(QTestState *qts, AcpiSdtTable *sdt_table, uint32_t addr)
{
uint8_t checksum;
memset(sdt_table, 0, sizeof(*sdt_table));
ACPI_READ_TABLE_HEADER(qts, &sdt_table->header, addr);
sdt_table->aml_len = le32_to_cpu(sdt_table->header.length)
- sizeof(AcpiTableHeader);
sdt_table->aml = g_malloc0(sdt_table->aml_len);
ACPI_READ_ARRAY_PTR(qts, sdt_table->aml, sdt_table->aml_len, addr);
checksum = acpi_calc_checksum((uint8_t *)sdt_table,
sizeof(AcpiTableHeader)) +
acpi_calc_checksum((uint8_t *)sdt_table->aml,
sdt_table->aml_len);
g_assert(!checksum);
}
static void test_acpi_dsdt_table(test_data *data)
{
AcpiSdtTable dsdt_table;
uint32_t addr = le32_to_cpu(data->dsdt_addr);
fetch_table(data->qts, &dsdt_table, addr);
ACPI_ASSERT_CMP(dsdt_table.header.signature, "DSDT");
/* Since DSDT isn't in RSDT, add DSDT to ASL test tables list manually */
g_array_append_val(data->tables, dsdt_table);
}
/* Load all tables and add to test list directly RSDT referenced tables */
static void fetch_rsdt_referenced_tables(test_data *data)
{
int tables_nr = data->rsdt_tables_nr;
int i;
for (i = 0; i < tables_nr; i++) {
AcpiSdtTable ssdt_table;
uint32_t addr;
addr = le32_to_cpu(data->rsdt_tables_addr[i]);
fetch_table(data->qts, &ssdt_table, addr);
acpi_fetch_table(data->qts, &ssdt_table.aml, &ssdt_table.aml_len, ent,
NULL, true);
/* Add table to ASL test tables list */ /* Add table to ASL test tables list */
g_array_append_val(data->tables, ssdt_table); g_array_append_val(data->tables, ssdt_table);
} }
cleanup_table_descriptor(&rsdt);
}
static void test_acpi_fadt_table(test_data *data)
{
/* FADT table is 1st */
AcpiSdtTable table = g_array_index(data->tables, typeof(table), 0);
uint8_t *fadt_aml = table.aml;
uint32_t fadt_len = table.aml_len;
g_assert(compare_signature(&table, "FACP"));
/* Since DSDT/FACS isn't in RSDT, add them to ASL test list manually */
acpi_fetch_table(data->qts, &table.aml, &table.aml_len,
fadt_aml + 36 /* FIRMWARE_CTRL */, "FACS", false);
g_array_append_val(data->tables, table);
acpi_fetch_table(data->qts, &table.aml, &table.aml_len,
fadt_aml + 40 /* DSDT */, "DSDT", true);
g_array_append_val(data->tables, table);
memset(fadt_aml + 36, 0, 4); /* sanitize FIRMWARE_CTRL ptr */
memset(fadt_aml + 40, 0, 4); /* sanitize DSDT ptr */
if (fadt_aml[8 /* FADT Major Version */] >= 3) {
memset(fadt_aml + 132, 0, 8); /* sanitize X_FIRMWARE_CTRL ptr */
memset(fadt_aml + 140, 0, 8); /* sanitize X_DSDT ptr */
}
/* update checksum */
fadt_aml[9 /* Checksum */] = 0;
fadt_aml[9 /* Checksum */] -= acpi_calc_checksum(fadt_aml, fadt_len);
} }
static void dump_aml_files(test_data *data, bool rebuild) static void dump_aml_files(test_data *data, bool rebuild)
@ -275,7 +174,7 @@ static void dump_aml_files(test_data *data, bool rebuild)
if (rebuild) { if (rebuild) {
aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, data->machine, aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, data->machine,
(gchar *)&sdt->header.signature, ext); sdt->aml, ext);
fd = g_open(aml_file, O_WRONLY|O_TRUNC|O_CREAT, fd = g_open(aml_file, O_WRONLY|O_TRUNC|O_CREAT,
S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH); S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
} else { } else {
@ -284,8 +183,6 @@ static void dump_aml_files(test_data *data, bool rebuild)
} }
g_assert(fd >= 0); g_assert(fd >= 0);
ret = qemu_write_full(fd, sdt, sizeof(AcpiTableHeader));
g_assert(ret == sizeof(AcpiTableHeader));
ret = qemu_write_full(fd, sdt->aml, sdt->aml_len); ret = qemu_write_full(fd, sdt->aml, sdt->aml_len);
g_assert(ret == sdt->aml_len); g_assert(ret == sdt->aml_len);
@ -295,11 +192,6 @@ static void dump_aml_files(test_data *data, bool rebuild)
} }
} }
static bool compare_signature(AcpiSdtTable *sdt, const char *signature)
{
return !memcmp(&sdt->header.signature, signature, 4);
}
static bool load_asl(GArray *sdts, AcpiSdtTable *sdt) static bool load_asl(GArray *sdts, AcpiSdtTable *sdt)
{ {
AcpiSdtTable *temp; AcpiSdtTable *temp;
@ -382,6 +274,7 @@ static GArray *load_expected_aml(test_data *data)
AcpiSdtTable *sdt; AcpiSdtTable *sdt;
GError *error = NULL; GError *error = NULL;
gboolean ret; gboolean ret;
gsize aml_len;
GArray *exp_tables = g_array_new(false, true, sizeof(AcpiSdtTable)); GArray *exp_tables = g_array_new(false, true, sizeof(AcpiSdtTable));
if (getenv("V")) { if (getenv("V")) {
@ -395,11 +288,10 @@ static GArray *load_expected_aml(test_data *data)
sdt = &g_array_index(data->tables, AcpiSdtTable, i); sdt = &g_array_index(data->tables, AcpiSdtTable, i);
memset(&exp_sdt, 0, sizeof(exp_sdt)); memset(&exp_sdt, 0, sizeof(exp_sdt));
exp_sdt.header.signature = sdt->header.signature;
try_again: try_again:
aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, data->machine, aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, data->machine,
(gchar *)&sdt->header.signature, ext); sdt->aml, ext);
if (getenv("V")) { if (getenv("V")) {
fprintf(stderr, "Looking for expected file '%s'\n", aml_file); fprintf(stderr, "Looking for expected file '%s'\n", aml_file);
} }
@ -415,8 +307,9 @@ try_again:
if (getenv("V")) { if (getenv("V")) {
fprintf(stderr, "Using expected file '%s'\n", aml_file); fprintf(stderr, "Using expected file '%s'\n", aml_file);
} }
ret = g_file_get_contents(aml_file, &exp_sdt.aml, ret = g_file_get_contents(aml_file, (gchar **)&exp_sdt.aml,
&exp_sdt.aml_len, &error); &aml_len, &error);
exp_sdt.aml_len = aml_len;
g_assert(ret); g_assert(ret);
g_assert_no_error(error); g_assert_no_error(error);
g_assert(exp_sdt.aml); g_assert(exp_sdt.aml);
@ -459,14 +352,12 @@ static void test_acpi_asl(test_data *data)
fprintf(stderr, fprintf(stderr,
"Warning! iasl couldn't parse the expected aml\n"); "Warning! iasl couldn't parse the expected aml\n");
} else { } else {
uint32_t signature = cpu_to_le32(exp_sdt->header.signature);
sdt->tmp_files_retain = true; sdt->tmp_files_retain = true;
exp_sdt->tmp_files_retain = true; exp_sdt->tmp_files_retain = true;
fprintf(stderr, fprintf(stderr,
"acpi-test: Warning! %.4s mismatch. " "acpi-test: Warning! %.4s mismatch. "
"Actual [asl:%s, aml:%s], Expected [asl:%s, aml:%s].\n", "Actual [asl:%s, aml:%s], Expected [asl:%s, aml:%s].\n",
(gchar *)&signature, exp_sdt->aml, sdt->asl_file, sdt->aml_file,
sdt->asl_file, sdt->aml_file,
exp_sdt->asl_file, exp_sdt->aml_file); exp_sdt->asl_file, exp_sdt->aml_file);
if (getenv("V")) { if (getenv("V")) {
const char *diff_cmd = getenv("DIFF"); const char *diff_cmd = getenv("DIFF");
@ -498,32 +389,19 @@ static bool smbios_ep_table_ok(test_data *data)
struct smbios_21_entry_point *ep_table = &data->smbios_ep_table; struct smbios_21_entry_point *ep_table = &data->smbios_ep_table;
uint32_t addr = data->smbios_ep_addr; uint32_t addr = data->smbios_ep_addr;
ACPI_READ_ARRAY(data->qts, ep_table->anchor_string, addr); qtest_memread(data->qts, addr, ep_table, sizeof(*ep_table));
if (memcmp(ep_table->anchor_string, "_SM_", 4)) { if (memcmp(ep_table->anchor_string, "_SM_", 4)) {
return false; return false;
} }
ACPI_READ_FIELD(data->qts, ep_table->checksum, addr);
ACPI_READ_FIELD(data->qts, ep_table->length, addr);
ACPI_READ_FIELD(data->qts, ep_table->smbios_major_version, addr);
ACPI_READ_FIELD(data->qts, ep_table->smbios_minor_version, addr);
ACPI_READ_FIELD(data->qts, ep_table->max_structure_size, addr);
ACPI_READ_FIELD(data->qts, ep_table->entry_point_revision, addr);
ACPI_READ_ARRAY(data->qts, ep_table->formatted_area, addr);
ACPI_READ_ARRAY(data->qts, ep_table->intermediate_anchor_string, addr);
if (memcmp(ep_table->intermediate_anchor_string, "_DMI_", 5)) { if (memcmp(ep_table->intermediate_anchor_string, "_DMI_", 5)) {
return false; return false;
} }
ACPI_READ_FIELD(data->qts, ep_table->intermediate_checksum, addr);
ACPI_READ_FIELD(data->qts, ep_table->structure_table_length, addr);
if (ep_table->structure_table_length == 0) { if (ep_table->structure_table_length == 0) {
return false; return false;
} }
ACPI_READ_FIELD(data->qts, ep_table->structure_table_address, addr);
ACPI_READ_FIELD(data->qts, ep_table->number_of_structures, addr);
if (ep_table->number_of_structures == 0) { if (ep_table->number_of_structures == 0) {
return false; return false;
} }
ACPI_READ_FIELD(data->qts, ep_table->smbios_bcd_revision, addr);
if (acpi_calc_checksum((uint8_t *)ep_table, sizeof *ep_table) || if (acpi_calc_checksum((uint8_t *)ep_table, sizeof *ep_table) ||
acpi_calc_checksum((uint8_t *)ep_table + 0x10, acpi_calc_checksum((uint8_t *)ep_table + 0x10,
sizeof *ep_table - 0x10)) { sizeof *ep_table - 0x10)) {
@ -644,12 +522,7 @@ static void test_acpi_one(const char *params, test_data *data)
test_acpi_rsdp_address(data); test_acpi_rsdp_address(data);
test_acpi_rsdp_table(data); test_acpi_rsdp_table(data);
test_acpi_rsdt_table(data); test_acpi_rsdt_table(data);
fadt_fetch_facs_and_dsdt_ptrs(data); test_acpi_fadt_table(data);
test_acpi_facs_table(data);
test_acpi_dsdt_table(data);
fetch_rsdt_referenced_tables(data);
sanitize_fadt_ptrs(data);
if (iasl) { if (iasl) {
if (getenv(ACPI_REBUILD_EXPECTED_AML)) { if (getenv(ACPI_REBUILD_EXPECTED_AML)) {

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -291,20 +291,20 @@ static void *server_thread(void *data)
return NULL; return NULL;
} }
static void setup_vm_with_server(IVState *s, int nvectors, bool msi) static void setup_vm_with_server(IVState *s, int nvectors)
{ {
char *cmd = g_strdup_printf("-chardev socket,id=chr0,path=%s,nowait " char *cmd;
"-device ivshmem%s,chardev=chr0,vectors=%d",
tmpserver,
msi ? "-doorbell" : ",size=1M,msi=off",
nvectors);
setup_vm_cmd(s, cmd, msi); cmd = g_strdup_printf("-chardev socket,id=chr0,path=%s,nowait "
"-device ivshmem-doorbell,chardev=chr0,vectors=%d",
tmpserver, nvectors);
setup_vm_cmd(s, cmd, true);
g_free(cmd); g_free(cmd);
} }
static void test_ivshmem_server(bool msi) static void test_ivshmem_server(void)
{ {
IVState state1, state2, *s1, *s2; IVState state1, state2, *s1, *s2;
ServerThread thread; ServerThread thread;
@ -327,9 +327,9 @@ static void test_ivshmem_server(bool msi)
thread.thread = g_thread_new("ivshmem-server", server_thread, &thread); thread.thread = g_thread_new("ivshmem-server", server_thread, &thread);
g_assert(thread.thread != NULL); g_assert(thread.thread != NULL);
setup_vm_with_server(&state1, nvectors, msi); setup_vm_with_server(&state1, nvectors);
s1 = &state1; s1 = &state1;
setup_vm_with_server(&state2, nvectors, msi); setup_vm_with_server(&state2, nvectors);
s2 = &state2; s2 = &state2;
/* check got different VM ids */ /* check got different VM ids */
@ -340,38 +340,28 @@ static void test_ivshmem_server(bool msi)
g_assert_cmpint(vm1, !=, vm2); g_assert_cmpint(vm1, !=, vm2);
/* check number of MSI-X vectors */ /* check number of MSI-X vectors */
if (msi) { ret = qpci_msix_table_size(s1->dev);
ret = qpci_msix_table_size(s1->dev); g_assert_cmpuint(ret, ==, nvectors);
g_assert_cmpuint(ret, ==, nvectors);
}
/* TODO test behavior before MSI-X is enabled */ /* TODO test behavior before MSI-X is enabled */
/* ping vm2 -> vm1 on vector 0 */ /* ping vm2 -> vm1 on vector 0 */
if (msi) { ret = qpci_msix_pending(s1->dev, 0);
ret = qpci_msix_pending(s1->dev, 0); g_assert_cmpuint(ret, ==, 0);
g_assert_cmpuint(ret, ==, 0);
} else {
g_assert_cmpuint(in_reg(s1, INTRSTATUS), ==, 0);
}
out_reg(s2, DOORBELL, vm1 << 16); out_reg(s2, DOORBELL, vm1 << 16);
do { do {
g_usleep(10000); g_usleep(10000);
ret = msi ? qpci_msix_pending(s1->dev, 0) : in_reg(s1, INTRSTATUS); ret = qpci_msix_pending(s1->dev, 0);
} while (ret == 0 && g_get_monotonic_time() < end_time); } while (ret == 0 && g_get_monotonic_time() < end_time);
g_assert_cmpuint(ret, !=, 0); g_assert_cmpuint(ret, !=, 0);
/* ping vm1 -> vm2 on vector 1 */ /* ping vm1 -> vm2 on vector 1 */
if (msi) { ret = qpci_msix_pending(s2->dev, 1);
ret = qpci_msix_pending(s2->dev, 1); g_assert_cmpuint(ret, ==, 0);
g_assert_cmpuint(ret, ==, 0);
} else {
g_assert_cmpuint(in_reg(s2, INTRSTATUS), ==, 0);
}
out_reg(s1, DOORBELL, vm2 << 16 | 1); out_reg(s1, DOORBELL, vm2 << 16 | 1);
do { do {
g_usleep(10000); g_usleep(10000);
ret = msi ? qpci_msix_pending(s2->dev, 1) : in_reg(s2, INTRSTATUS); ret = qpci_msix_pending(s2->dev, 1);
} while (ret == 0 && g_get_monotonic_time() < end_time); } while (ret == 0 && g_get_monotonic_time() < end_time);
g_assert_cmpuint(ret, !=, 0); g_assert_cmpuint(ret, !=, 0);
@ -389,27 +379,17 @@ static void test_ivshmem_server(bool msi)
close(thread.pipe[0]); close(thread.pipe[0]);
} }
static void test_ivshmem_server_msi(void)
{
test_ivshmem_server(true);
}
static void test_ivshmem_server_irq(void)
{
test_ivshmem_server(false);
}
#define PCI_SLOT_HP 0x06 #define PCI_SLOT_HP 0x06
static void test_ivshmem_hotplug(void) static void test_ivshmem_hotplug(void)
{ {
const char *arch = qtest_get_arch(); const char *arch = qtest_get_arch();
qtest_start(""); qtest_start("-object memory-backend-ram,size=1M,id=mb1");
qtest_qmp_device_add("ivshmem", qtest_qmp_device_add("ivshmem-plain", "iv1",
"iv1", "{'addr': %s, 'shm': %s, 'size': '1M'}", "{'addr': %s, 'memdev': 'mb1'}",
stringify(PCI_SLOT_HP), tmpshm); stringify(PCI_SLOT_HP));
if (strcmp(arch, "ppc64") != 0) { if (strcmp(arch, "ppc64") != 0) {
qpci_unplug_acpi_device_test("iv1", PCI_SLOT_HP); qpci_unplug_acpi_device_test("iv1", PCI_SLOT_HP);
} }
@ -509,8 +489,7 @@ int main(int argc, char **argv)
if (g_test_slow()) { if (g_test_slow()) {
qtest_add_func("/ivshmem/pair", test_ivshmem_pair); qtest_add_func("/ivshmem/pair", test_ivshmem_pair);
if (strcmp(arch, "ppc64") != 0) { if (strcmp(arch, "ppc64") != 0) {
qtest_add_func("/ivshmem/server-msi", test_ivshmem_server_msi); qtest_add_func("/ivshmem/server", test_ivshmem_server);
qtest_add_func("/ivshmem/server-irq", test_ivshmem_server_irq);
} }
} }

View File

@ -309,7 +309,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
CharBackend *chr = &s->chr; CharBackend *chr = &s->chr;
VhostUserMsg msg; VhostUserMsg msg;
uint8_t *p = (uint8_t *) &msg; uint8_t *p = (uint8_t *) &msg;
int fd; int fd = -1;
if (s->test_fail) { if (s->test_fail) {
qemu_chr_fe_disconnect(chr); qemu_chr_fe_disconnect(chr);

View File

@ -23,26 +23,13 @@
*/ */
#define RSDP_ADDR_INVALID 0x100000 /* RSDP must be below this address */ #define RSDP_ADDR_INVALID 0x100000 /* RSDP must be below this address */
typedef struct {
AcpiTableHeader header;
gchar name_op;
gchar vgia[4];
gchar val_op;
uint32_t vgia_val;
} QEMU_PACKED VgidTable;
static uint32_t acpi_find_vgia(QTestState *qts) static uint32_t acpi_find_vgia(QTestState *qts)
{ {
uint32_t rsdp_offset; uint32_t rsdp_offset;
uint32_t guid_offset = 0; uint32_t guid_offset = 0;
uint8_t rsdp_table[36 /* ACPI 2.0+ RSDP size */]; uint8_t rsdp_table[36 /* ACPI 2.0+ RSDP size */];
uint32_t rsdt, rsdt_table_length; uint32_t rsdt_len, table_length;
AcpiRsdtDescriptorRev1 rsdt_table; uint8_t *rsdt, *ent;
size_t tables_nr;
uint32_t *tables;
AcpiTableHeader ssdt_table;
VgidTable vgid_table;
int i;
/* Wait for guest firmware to finish and start the payload. */ /* Wait for guest firmware to finish and start the payload. */
boot_sector_test(qts); boot_sector_test(qts);
@ -52,48 +39,37 @@ static uint32_t acpi_find_vgia(QTestState *qts)
g_assert_cmphex(rsdp_offset, <, RSDP_ADDR_INVALID); g_assert_cmphex(rsdp_offset, <, RSDP_ADDR_INVALID);
acpi_parse_rsdp_table(qts, rsdp_offset, rsdp_table); acpi_parse_rsdp_table(qts, rsdp_offset, rsdp_table);
acpi_fetch_table(qts, &rsdt, &rsdt_len, &rsdp_table[16 /* RsdtAddress */],
"RSDT", true);
rsdt = acpi_get_rsdt_address(rsdp_table); ACPI_FOREACH_RSDT_ENTRY(rsdt, rsdt_len, ent, 4 /* Entry size */) {
g_assert(rsdt); uint8_t *table_aml;
/* read the header */ acpi_fetch_table(qts, &table_aml, &table_length, ent, NULL, true);
ACPI_READ_TABLE_HEADER(qts, &rsdt_table, rsdt); if (!memcmp(table_aml + 16 /* OEM Table ID */, "VMGENID", 7)) {
ACPI_ASSERT_CMP(rsdt_table.signature, "RSDT"); uint32_t vgia_val;
rsdt_table_length = le32_to_cpu(rsdt_table.length); uint8_t *aml = &table_aml[36 /* AML byte-code start */];
/* compute the table entries in rsdt */
g_assert_cmpint(rsdt_table_length, >, sizeof(AcpiRsdtDescriptorRev1));
tables_nr = (rsdt_table_length - sizeof(AcpiRsdtDescriptorRev1)) /
sizeof(uint32_t);
/* get the addresses of the tables pointed by rsdt */
tables = g_new0(uint32_t, tables_nr);
ACPI_READ_ARRAY_PTR(qts, tables, tables_nr, rsdt);
for (i = 0; i < tables_nr; i++) {
uint32_t addr = le32_to_cpu(tables[i]);
ACPI_READ_TABLE_HEADER(qts, &ssdt_table, addr);
if (!strncmp((char *)ssdt_table.oem_table_id, "VMGENID", 7)) {
/* the first entry in the table should be VGIA /* the first entry in the table should be VGIA
* That's all we need * That's all we need
*/ */
ACPI_READ_FIELD(qts, vgid_table.name_op, addr); g_assert(aml[0 /* name_op*/] == 0x08);
g_assert(vgid_table.name_op == 0x08); /* name */ g_assert(memcmp(&aml[1 /* name */], "VGIA", 4) == 0);
ACPI_READ_ARRAY(qts, vgid_table.vgia, addr); g_assert(aml[5 /* value op */] == 0x0C /* dword */);
g_assert(memcmp(vgid_table.vgia, "VGIA", 4) == 0); memcpy(&vgia_val, &aml[6 /* value */], 4);
ACPI_READ_FIELD(qts, vgid_table.val_op, addr);
g_assert(vgid_table.val_op == 0x0C); /* dword */
ACPI_READ_FIELD(qts, vgid_table.vgia_val, addr);
/* The GUID is written at a fixed offset into the fw_cfg file /* The GUID is written at a fixed offset into the fw_cfg file
* in order to implement the "OVMF SDT Header probe suppressor" * in order to implement the "OVMF SDT Header probe suppressor"
* see docs/specs/vmgenid.txt for more details * see docs/specs/vmgenid.txt for more details
*/ */
guid_offset = le32_to_cpu(vgid_table.vgia_val) + VMGENID_GUID_OFFSET; guid_offset = le32_to_cpu(vgia_val) + VMGENID_GUID_OFFSET;
g_free(table_aml);
break; break;
} }
g_free(table_aml);
} }
g_free(tables); g_free(rsdt);
return guid_offset; return guid_offset;
} }

View File

@ -233,14 +233,18 @@ void qemu_set_block(int fd)
{ {
int f; int f;
f = fcntl(fd, F_GETFL); f = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, f & ~O_NONBLOCK); assert(f != -1);
f = fcntl(fd, F_SETFL, f & ~O_NONBLOCK);
assert(f != -1);
} }
void qemu_set_nonblock(int fd) void qemu_set_nonblock(int fd)
{ {
int f; int f;
f = fcntl(fd, F_GETFL); f = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, f | O_NONBLOCK); assert(f != -1);
f = fcntl(fd, F_SETFL, f | O_NONBLOCK);
assert(f != -1);
} }
int socket_set_fast_reuse(int fd) int socket_set_fast_reuse(int fd)