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:
commit
51c1c13560
@ -1224,7 +1224,7 @@ static int find_vdi_name(BDRVSheepdogState *s, const char *filename,
|
||||
SheepdogVdiReq hdr;
|
||||
SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr;
|
||||
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);
|
||||
if (fd < 0) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
CONFIG_VHOST_USER_SCSI=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX))
|
||||
CONFIG_VHOST_USER_BLK=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX))
|
||||
CONFIG_VIRTIO=y
|
||||
CONFIG_VIRTIO_9P=y
|
||||
CONFIG_VIRTIO_9P=$(CONFIG_VIRTFS)
|
||||
CONFIG_VIRTIO_BALLOON=y
|
||||
CONFIG_VIRTIO_BLK=y
|
||||
CONFIG_VIRTIO_CRYPTO=y
|
||||
@ -12,3 +12,4 @@ CONFIG_VIRTIO_RNG=y
|
||||
CONFIG_SCSI=y
|
||||
CONFIG_VIRTIO_SCSI=y
|
||||
CONFIG_VIRTIO_SERIAL=y
|
||||
CONFIG_VIRTIO_INPUT_HOST=$(CONFIG_LINUX)
|
||||
|
@ -17,12 +17,16 @@ get interrupted by its peers.
|
||||
|
||||
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"
|
||||
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
|
||||
connects to the server's UNIX domain socket via character device
|
||||
|
@ -34,6 +34,25 @@ The CRB interface makes a memory mapped IO region in the area 0xfed40000 -
|
||||
QEMU files related to TPM CRB interface:
|
||||
- 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 =
|
||||
|
||||
@ -57,6 +76,91 @@ URL:
|
||||
|
||||
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:
|
||||
- hw/i386/acpi-build.c
|
||||
|
@ -11,6 +11,7 @@ common-obj-$(call lnot,$(CONFIG_ACPI_X86)) += acpi-stub.o
|
||||
common-obj-y += acpi_interface.o
|
||||
common-obj-y += bios-linker-loader.o
|
||||
common-obj-y += aml-build.o
|
||||
common-obj-$(CONFIG_TPM) += tpm.o
|
||||
|
||||
common-obj-$(CONFIG_IPMI) += ipmi.o
|
||||
common-obj-$(call lnot,$(CONFIG_IPMI)) += ipmi-stub.o
|
||||
|
@ -35,14 +35,18 @@
|
||||
struct acpi_table_header {
|
||||
uint16_t _length; /* our length, not actual part of the hdr */
|
||||
/* allows easier parsing for fw_cfg clients */
|
||||
char sig[4]; /* ACPI signature (4 ASCII characters) */
|
||||
char sig[4]
|
||||
QEMU_NONSTRING; /* ACPI signature (4 ASCII characters) */
|
||||
uint32_t length; /* Length of table, in bytes, including header */
|
||||
uint8_t revision; /* ACPI Specification minor version # */
|
||||
uint8_t checksum; /* To make sum of entire table == 0 */
|
||||
char oem_id[6]; /* OEM identification */
|
||||
char oem_table_id[8]; /* OEM table identification */
|
||||
char oem_id[6]
|
||||
QEMU_NONSTRING; /* OEM identification */
|
||||
char oem_table_id[8]
|
||||
QEMU_NONSTRING; /* OEM table identification */
|
||||
uint32_t oem_revision; /* OEM revision number */
|
||||
char asl_compiler_id[4]; /* ASL compiler vendor ID */
|
||||
char asl_compiler_id[4]
|
||||
QEMU_NONSTRING; /* ASL compiler vendor ID */
|
||||
uint32_t asl_compiler_revision; /* ASL compiler revision number */
|
||||
} QEMU_PACKED;
|
||||
|
||||
|
@ -686,15 +686,15 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem,
|
||||
|
||||
method = aml_method("_OST", 3, AML_NOTSERIALIZED);
|
||||
s = MEMORY_SLOT_OST_METHOD;
|
||||
aml_append(method, aml_return(aml_call4(
|
||||
s, aml_name("_UID"), aml_arg(0), aml_arg(1), aml_arg(2)
|
||||
)));
|
||||
aml_append(method,
|
||||
aml_call4(s, aml_name("_UID"), aml_arg(0),
|
||||
aml_arg(1), aml_arg(2)));
|
||||
aml_append(dev, method);
|
||||
|
||||
method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
|
||||
s = MEMORY_SLOT_EJECT_METHOD;
|
||||
aml_append(method, aml_return(aml_call2(
|
||||
s, aml_name("_UID"), aml_arg(0))));
|
||||
aml_append(method,
|
||||
aml_call2(s, aml_name("_UID"), aml_arg(0)));
|
||||
aml_append(dev, method);
|
||||
|
||||
aml_append(dev_container, dev);
|
||||
|
459
hw/acpi/tpm.c
Normal file
459
hw/acpi/tpm.c
Normal 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);
|
||||
}
|
@ -250,6 +250,7 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
||||
VHostUserBlk *s = VHOST_USER_BLK(vdev);
|
||||
VhostUserState *user;
|
||||
struct vhost_virtqueue *vqs = NULL;
|
||||
int i, ret;
|
||||
|
||||
if (!s->chardev.chr) {
|
||||
@ -288,6 +289,7 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
|
||||
s->dev.vqs = g_new(struct vhost_virtqueue, s->dev.nvqs);
|
||||
s->dev.vq_index = 0;
|
||||
s->dev.backend_features = 0;
|
||||
vqs = s->dev.vqs;
|
||||
|
||||
vhost_dev_set_config_notifier(&s->dev, &blk_ops);
|
||||
|
||||
@ -314,7 +316,7 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
|
||||
vhost_err:
|
||||
vhost_dev_cleanup(&s->dev);
|
||||
virtio_err:
|
||||
g_free(s->dev.vqs);
|
||||
g_free(vqs);
|
||||
virtio_cleanup(vdev);
|
||||
|
||||
vhost_user_cleanup(user);
|
||||
@ -326,10 +328,11 @@ static void vhost_user_blk_device_unrealize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
||||
VHostUserBlk *s = VHOST_USER_BLK(dev);
|
||||
struct vhost_virtqueue *vqs = s->dev.vqs;
|
||||
|
||||
vhost_user_blk_set_status(vdev, 0);
|
||||
vhost_dev_cleanup(&s->dev);
|
||||
g_free(s->dev.vqs);
|
||||
g_free(vqs);
|
||||
virtio_cleanup(vdev);
|
||||
|
||||
if (s->vhost_user) {
|
||||
|
@ -28,6 +28,8 @@ GlobalProperty hw_compat_3_1[] = {
|
||||
{ "pcie-root-port", "x-width", "1" },
|
||||
{ "memory-backend-file", "x-use-canonical-path-for-ramblock-id", "true" },
|
||||
{ "memory-backend-memfd", "x-use-canonical-path-for-ramblock-id", "true" },
|
||||
{ "tpm-crb", "ppi", "false" },
|
||||
{ "tpm-tis", "ppi", "false" },
|
||||
};
|
||||
const size_t hw_compat_3_1_len = G_N_ELEMENTS(hw_compat_3_1);
|
||||
|
||||
@ -91,8 +93,9 @@ const size_t hw_compat_2_7_len = G_N_ELEMENTS(hw_compat_2_7);
|
||||
|
||||
GlobalProperty hw_compat_2_6[] = {
|
||||
{ "virtio-mmio", "format_transport_address", "off" },
|
||||
{ "virtio-pci", "disable-modern", "on" },
|
||||
{ "virtio-pci", "disable-legacy", "off" },
|
||||
/* Optional because not all virtio-pci devices support legacy mode */
|
||||
{ "virtio-pci", "disable-modern", "on", .optional = true },
|
||||
{ "virtio-pci", "disable-legacy", "off", .optional = true },
|
||||
};
|
||||
const size_t hw_compat_2_6_len = G_N_ELEMENTS(hw_compat_2_6);
|
||||
|
||||
|
@ -19,6 +19,20 @@
|
||||
#include "hw/virtio/virtio-pci.h"
|
||||
#include "hw/virtio/virtio-gpu.h"
|
||||
|
||||
typedef struct VirtIOGPUPCI VirtIOGPUPCI;
|
||||
|
||||
/*
|
||||
* virtio-gpu-pci: This extends VirtioPCIProxy.
|
||||
*/
|
||||
#define TYPE_VIRTIO_GPU_PCI "virtio-gpu-pci"
|
||||
#define VIRTIO_GPU_PCI(obj) \
|
||||
OBJECT_CHECK(VirtIOGPUPCI, (obj), TYPE_VIRTIO_GPU_PCI)
|
||||
|
||||
struct VirtIOGPUPCI {
|
||||
VirtIOPCIProxy parent_obj;
|
||||
VirtIOGPU vdev;
|
||||
};
|
||||
|
||||
static Property virtio_gpu_pci_properties[] = {
|
||||
DEFINE_VIRTIO_GPU_PCI_PROPERTIES(VirtIOPCIProxy),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "hw/pci/pci.h"
|
||||
#include "vga_int.h"
|
||||
#include "hw/virtio/virtio-pci.h"
|
||||
#include "hw/virtio/virtio-gpu.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
/*
|
||||
|
@ -119,6 +119,12 @@ typedef struct AcpiBuildPciBusHotplugState {
|
||||
bool pcihp_bridge_en;
|
||||
} AcpiBuildPciBusHotplugState;
|
||||
|
||||
typedef struct FwCfgTPMConfig {
|
||||
uint32_t tpmppi_address;
|
||||
uint8_t tpm_version;
|
||||
uint8_t tpmppi_version;
|
||||
} QEMU_PACKED FwCfgTPMConfig;
|
||||
|
||||
static void init_common_fadt_data(Object *o, AcpiFadtData *data)
|
||||
{
|
||||
uint32_t io = object_property_get_uint(o, ACPI_PM_PROP_PM_IO_BASE, NULL);
|
||||
@ -1796,6 +1802,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
||||
uint32_t nr_mem = machine->ram_slots;
|
||||
int root_bus_limit = 0xFF;
|
||||
PCIBus *bus = NULL;
|
||||
TPMIf *tpm = tpm_find();
|
||||
int i;
|
||||
|
||||
dsdt = init_aml_allocator();
|
||||
@ -2133,7 +2140,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
||||
/* Scan all PCI buses. Generate tables to support hotplug. */
|
||||
build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en);
|
||||
|
||||
if (TPM_IS_TIS(tpm_find())) {
|
||||
if (TPM_IS_TIS(tpm)) {
|
||||
dev = aml_device("ISA.TPM");
|
||||
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C31")));
|
||||
aml_append(dev, aml_name_decl("_STA", aml_int(0xF)));
|
||||
@ -2147,6 +2154,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
||||
*/
|
||||
/* aml_append(crs, aml_irq_no_flags(TPM_TIS_IRQ)); */
|
||||
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||
|
||||
tpm_build_ppi_acpi(tpm, dev);
|
||||
|
||||
aml_append(scope, dev);
|
||||
}
|
||||
|
||||
@ -2154,7 +2164,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
||||
}
|
||||
}
|
||||
|
||||
if (TPM_IS_CRB(tpm_find())) {
|
||||
if (TPM_IS_CRB(tpm)) {
|
||||
dev = aml_device("TPM");
|
||||
aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101")));
|
||||
crs = aml_resource_template();
|
||||
@ -2166,6 +2176,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
||||
aml_append(method, aml_return(aml_int(0x0f)));
|
||||
aml_append(dev, method);
|
||||
|
||||
tpm_build_ppi_acpi(tpm, dev);
|
||||
|
||||
aml_append(sb_scope, dev);
|
||||
}
|
||||
|
||||
@ -2847,6 +2859,8 @@ void acpi_setup(void)
|
||||
AcpiBuildTables tables;
|
||||
AcpiBuildState *build_state;
|
||||
Object *vmgenid_dev;
|
||||
TPMIf *tpm;
|
||||
static FwCfgTPMConfig tpm_config;
|
||||
|
||||
if (!pcms->fw_cfg) {
|
||||
ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n");
|
||||
@ -2881,6 +2895,17 @@ void acpi_setup(void)
|
||||
fw_cfg_add_file(pcms->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
|
||||
tables.tcpalog->data, acpi_data_len(tables.tcpalog));
|
||||
|
||||
tpm = tpm_find();
|
||||
if (tpm && object_property_get_bool(OBJECT(tpm), "ppi", &error_abort)) {
|
||||
tpm_config = (FwCfgTPMConfig) {
|
||||
.tpmppi_address = cpu_to_le32(TPM_PPI_ADDR_BASE),
|
||||
.tpm_version = tpm_get_version(tpm),
|
||||
.tpmppi_version = TPM_PPI_VERSION_1_30
|
||||
};
|
||||
fw_cfg_add_file(pcms->fw_cfg, "etc/tpm/config",
|
||||
&tpm_config, sizeof tpm_config);
|
||||
}
|
||||
|
||||
vmgenid_dev = find_vmgenid_dev();
|
||||
if (vmgenid_dev) {
|
||||
vmgenid_add_fw_cfg(VMGENID(vmgenid_dev), pcms->fw_cfg,
|
||||
|
@ -715,7 +715,6 @@ static void pc_i440fx_1_2_machine_options(MachineClass *m)
|
||||
PC_CPU_MODEL_IDS("1.2.0")
|
||||
{ "nec-usb-xhci", "msi", "off" },
|
||||
{ "nec-usb-xhci", "msix", "off" },
|
||||
{ "ivshmem", "use64", "0" },
|
||||
{ "qxl", "revision", "3" },
|
||||
{ "qxl-vga", "revision", "3" },
|
||||
{ "VGA", "mmio", "off" },
|
||||
|
@ -377,6 +377,7 @@ static void pci_edu_uninit(PCIDevice *pdev)
|
||||
qemu_mutex_destroy(&edu->thr_mutex);
|
||||
|
||||
timer_del(&edu->dma_timer);
|
||||
msi_uninit(pdev);
|
||||
}
|
||||
|
||||
static void edu_obj_uint64(Object *obj, Visitor *v, const char *name,
|
||||
|
@ -112,13 +112,6 @@ typedef struct IVShmemState {
|
||||
/* migration stuff */
|
||||
OnOffAuto master;
|
||||
Error *migration_blocker;
|
||||
|
||||
/* legacy cruft */
|
||||
char *role;
|
||||
char *shmobj;
|
||||
char *sizearg;
|
||||
size_t legacy_size;
|
||||
uint32_t not_legacy_32bit;
|
||||
} IVShmemState;
|
||||
|
||||
/* registers for the Inter-VM shared memory device */
|
||||
@ -529,17 +522,6 @@ static void process_msg_shmem(IVShmemState *s, int fd, Error **errp)
|
||||
|
||||
size = buf.st_size;
|
||||
|
||||
/* Legacy cruft */
|
||||
if (s->legacy_size != SIZE_MAX) {
|
||||
if (size < s->legacy_size) {
|
||||
error_setg(errp, "server sent only %zd bytes of shared memory",
|
||||
(size_t)buf.st_size);
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
size = s->legacy_size;
|
||||
}
|
||||
|
||||
/* mmap the region and map into the BAR2 */
|
||||
memory_region_init_ram_from_fd(&s->server_bar2, OBJECT(s),
|
||||
"ivshmem.bar2", size, true, fd, &local_err);
|
||||
@ -882,8 +864,6 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
|
||||
IVShmemState *s = IVSHMEM_COMMON(dev);
|
||||
Error *err = NULL;
|
||||
uint8_t *pci_conf;
|
||||
uint8_t attr = PCI_BASE_ADDRESS_SPACE_MEMORY |
|
||||
PCI_BASE_ADDRESS_MEM_PREFETCH;
|
||||
Error *local_err = NULL;
|
||||
|
||||
/* IRQFD requires MSI */
|
||||
@ -903,10 +883,6 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
|
||||
pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
|
||||
&s->ivshmem_mmio);
|
||||
|
||||
if (s->not_legacy_32bit) {
|
||||
attr |= PCI_BASE_ADDRESS_MEM_TYPE_64;
|
||||
}
|
||||
|
||||
if (s->hostmem != NULL) {
|
||||
IVSHMEM_DPRINTF("using hostmem\n");
|
||||
|
||||
@ -964,7 +940,11 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
|
||||
}
|
||||
|
||||
vmstate_register_ram(s->ivshmem_bar2, DEVICE(s));
|
||||
pci_register_bar(PCI_DEVICE(s), 2, attr, s->ivshmem_bar2);
|
||||
pci_register_bar(PCI_DEVICE(s), 2,
|
||||
PCI_BASE_ADDRESS_SPACE_MEMORY |
|
||||
PCI_BASE_ADDRESS_MEM_PREFETCH |
|
||||
PCI_BASE_ADDRESS_MEM_TYPE_64,
|
||||
s->ivshmem_bar2);
|
||||
}
|
||||
|
||||
static void ivshmem_exit(PCIDevice *dev)
|
||||
@ -1084,13 +1064,6 @@ static Property ivshmem_plain_properties[] = {
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void ivshmem_plain_init(Object *obj)
|
||||
{
|
||||
IVShmemState *s = IVSHMEM_PLAIN(obj);
|
||||
|
||||
s->not_legacy_32bit = 1;
|
||||
}
|
||||
|
||||
static void ivshmem_plain_realize(PCIDevice *dev, Error **errp)
|
||||
{
|
||||
IVShmemState *s = IVSHMEM_COMMON(dev);
|
||||
@ -1122,7 +1095,6 @@ static const TypeInfo ivshmem_plain_info = {
|
||||
.name = TYPE_IVSHMEM_PLAIN,
|
||||
.parent = TYPE_IVSHMEM_COMMON,
|
||||
.instance_size = sizeof(IVShmemState),
|
||||
.instance_init = ivshmem_plain_init,
|
||||
.class_init = ivshmem_plain_class_init,
|
||||
};
|
||||
|
||||
@ -1155,8 +1127,6 @@ static void ivshmem_doorbell_init(Object *obj)
|
||||
IVShmemState *s = IVSHMEM_DOORBELL(obj);
|
||||
|
||||
s->features |= (1 << IVSHMEM_MSI);
|
||||
s->legacy_size = SIZE_MAX; /* whatever the server sends */
|
||||
s->not_legacy_32bit = 1;
|
||||
}
|
||||
|
||||
static void ivshmem_doorbell_realize(PCIDevice *dev, Error **errp)
|
||||
@ -1189,181 +1159,11 @@ static const TypeInfo ivshmem_doorbell_info = {
|
||||
.class_init = ivshmem_doorbell_class_init,
|
||||
};
|
||||
|
||||
static int ivshmem_load_old(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
IVShmemState *s = opaque;
|
||||
PCIDevice *pdev = PCI_DEVICE(s);
|
||||
int ret;
|
||||
|
||||
IVSHMEM_DPRINTF("ivshmem_load_old\n");
|
||||
|
||||
if (version_id != 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = ivshmem_pre_load(s);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = pci_device_load(pdev, f);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
|
||||
msix_load(pdev, f);
|
||||
ivshmem_msix_vector_use(s);
|
||||
} else {
|
||||
s->intrstatus = qemu_get_be32(f);
|
||||
s->intrmask = qemu_get_be32(f);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool test_msix(void *opaque, int version_id)
|
||||
{
|
||||
IVShmemState *s = opaque;
|
||||
|
||||
return ivshmem_has_feature(s, IVSHMEM_MSI);
|
||||
}
|
||||
|
||||
static bool test_no_msix(void *opaque, int version_id)
|
||||
{
|
||||
return !test_msix(opaque, version_id);
|
||||
}
|
||||
|
||||
static const VMStateDescription ivshmem_vmsd = {
|
||||
.name = "ivshmem",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.pre_load = ivshmem_pre_load,
|
||||
.post_load = ivshmem_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_PCI_DEVICE(parent_obj, IVShmemState),
|
||||
|
||||
VMSTATE_MSIX_TEST(parent_obj, IVShmemState, test_msix),
|
||||
VMSTATE_UINT32_TEST(intrstatus, IVShmemState, test_no_msix),
|
||||
VMSTATE_UINT32_TEST(intrmask, IVShmemState, test_no_msix),
|
||||
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
.load_state_old = ivshmem_load_old,
|
||||
.minimum_version_id_old = 0
|
||||
};
|
||||
|
||||
static Property ivshmem_properties[] = {
|
||||
DEFINE_PROP_CHR("chardev", IVShmemState, server_chr),
|
||||
DEFINE_PROP_STRING("size", IVShmemState, sizearg),
|
||||
DEFINE_PROP_UINT32("vectors", IVShmemState, vectors, 1),
|
||||
DEFINE_PROP_BIT("ioeventfd", IVShmemState, features, IVSHMEM_IOEVENTFD,
|
||||
false),
|
||||
DEFINE_PROP_BIT("msi", IVShmemState, features, IVSHMEM_MSI, true),
|
||||
DEFINE_PROP_STRING("shm", IVShmemState, shmobj),
|
||||
DEFINE_PROP_STRING("role", IVShmemState, role),
|
||||
DEFINE_PROP_UINT32("use64", IVShmemState, not_legacy_32bit, 1),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void desugar_shm(IVShmemState *s)
|
||||
{
|
||||
Object *obj;
|
||||
char *path;
|
||||
|
||||
obj = object_new("memory-backend-file");
|
||||
path = g_strdup_printf("/dev/shm/%s", s->shmobj);
|
||||
object_property_set_str(obj, path, "mem-path", &error_abort);
|
||||
g_free(path);
|
||||
object_property_set_int(obj, s->legacy_size, "size", &error_abort);
|
||||
object_property_set_bool(obj, true, "share", &error_abort);
|
||||
object_property_add_child(OBJECT(s), "internal-shm-backend", obj,
|
||||
&error_abort);
|
||||
object_unref(obj);
|
||||
user_creatable_complete(USER_CREATABLE(obj), &error_abort);
|
||||
s->hostmem = MEMORY_BACKEND(obj);
|
||||
}
|
||||
|
||||
static void ivshmem_realize(PCIDevice *dev, Error **errp)
|
||||
{
|
||||
IVShmemState *s = IVSHMEM_COMMON(dev);
|
||||
|
||||
if (!qtest_enabled()) {
|
||||
warn_report("ivshmem is deprecated, please use ivshmem-plain"
|
||||
" or ivshmem-doorbell instead");
|
||||
}
|
||||
|
||||
if (qemu_chr_fe_backend_connected(&s->server_chr) + !!s->shmobj != 1) {
|
||||
error_setg(errp, "You must specify either 'shm' or 'chardev'");
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->sizearg == NULL) {
|
||||
s->legacy_size = 4 * MiB; /* 4 MB default */
|
||||
} else {
|
||||
int ret;
|
||||
uint64_t size;
|
||||
|
||||
ret = qemu_strtosz_MiB(s->sizearg, NULL, &size);
|
||||
if (ret < 0 || (size_t)size != size || !is_power_of_2(size)) {
|
||||
error_setg(errp, "Invalid size %s", s->sizearg);
|
||||
return;
|
||||
}
|
||||
s->legacy_size = size;
|
||||
}
|
||||
|
||||
/* check that role is reasonable */
|
||||
if (s->role) {
|
||||
if (strncmp(s->role, "peer", 5) == 0) {
|
||||
s->master = ON_OFF_AUTO_OFF;
|
||||
} else if (strncmp(s->role, "master", 7) == 0) {
|
||||
s->master = ON_OFF_AUTO_ON;
|
||||
} else {
|
||||
error_setg(errp, "'role' must be 'peer' or 'master'");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
s->master = ON_OFF_AUTO_AUTO;
|
||||
}
|
||||
|
||||
if (s->shmobj) {
|
||||
desugar_shm(s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: we don't use INTx with IVSHMEM_MSI at all, so this is a
|
||||
* bald-faced lie then. But it's a backwards compatible lie.
|
||||
*/
|
||||
pci_config_set_interrupt_pin(dev->config, 1);
|
||||
|
||||
ivshmem_common_realize(dev, errp);
|
||||
}
|
||||
|
||||
static void ivshmem_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||
|
||||
k->realize = ivshmem_realize;
|
||||
k->revision = 0;
|
||||
dc->desc = "Inter-VM shared memory (legacy)";
|
||||
dc->props = ivshmem_properties;
|
||||
dc->vmsd = &ivshmem_vmsd;
|
||||
}
|
||||
|
||||
static const TypeInfo ivshmem_info = {
|
||||
.name = TYPE_IVSHMEM,
|
||||
.parent = TYPE_IVSHMEM_COMMON,
|
||||
.instance_size = sizeof(IVShmemState),
|
||||
.class_init = ivshmem_class_init,
|
||||
};
|
||||
|
||||
static void ivshmem_register_types(void)
|
||||
{
|
||||
type_register_static(&ivshmem_common_info);
|
||||
type_register_static(&ivshmem_plain_info);
|
||||
type_register_static(&ivshmem_doorbell_info);
|
||||
type_register_static(&ivshmem_info);
|
||||
}
|
||||
|
||||
type_init(ivshmem_register_types)
|
||||
|
@ -41,6 +41,47 @@
|
||||
#define VIRTIO_NET_RX_QUEUE_MIN_SIZE VIRTIO_NET_RX_QUEUE_DEFAULT_SIZE
|
||||
#define VIRTIO_NET_TX_QUEUE_MIN_SIZE VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE
|
||||
|
||||
#define VIRTIO_NET_IP4_ADDR_SIZE 8 /* ipv4 saddr + daddr */
|
||||
|
||||
#define VIRTIO_NET_TCP_FLAG 0x3F
|
||||
#define VIRTIO_NET_TCP_HDR_LENGTH 0xF000
|
||||
|
||||
/* IPv4 max payload, 16 bits in the header */
|
||||
#define VIRTIO_NET_MAX_IP4_PAYLOAD (65535 - sizeof(struct ip_header))
|
||||
#define VIRTIO_NET_MAX_TCP_PAYLOAD 65535
|
||||
|
||||
/* header length value in ip header without option */
|
||||
#define VIRTIO_NET_IP4_HEADER_LENGTH 5
|
||||
|
||||
#define VIRTIO_NET_IP6_ADDR_SIZE 32 /* ipv6 saddr + daddr */
|
||||
#define VIRTIO_NET_MAX_IP6_PAYLOAD VIRTIO_NET_MAX_TCP_PAYLOAD
|
||||
|
||||
/* Purge coalesced packets timer interval, This value affects the performance
|
||||
a lot, and should be tuned carefully, '300000'(300us) is the recommended
|
||||
value to pass the WHQL test, '50000' can gain 2x netperf throughput with
|
||||
tso/gso/gro 'off'. */
|
||||
#define VIRTIO_NET_RSC_DEFAULT_INTERVAL 300000
|
||||
|
||||
/* temporary until standard header include it */
|
||||
#if !defined(VIRTIO_NET_HDR_F_RSC_INFO)
|
||||
|
||||
#define VIRTIO_NET_HDR_F_RSC_INFO 4 /* rsc_ext data in csum_ fields */
|
||||
#define VIRTIO_NET_F_RSC_EXT 61
|
||||
|
||||
static inline __virtio16 *virtio_net_rsc_ext_num_packets(
|
||||
struct virtio_net_hdr *hdr)
|
||||
{
|
||||
return &hdr->csum_start;
|
||||
}
|
||||
|
||||
static inline __virtio16 *virtio_net_rsc_ext_num_dupacks(
|
||||
struct virtio_net_hdr *hdr)
|
||||
{
|
||||
return &hdr->csum_offset;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Calculate the number of bytes up to and including the given 'field' of
|
||||
* 'container'.
|
||||
@ -628,6 +669,7 @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features,
|
||||
if (!get_vhost_net(nc->peer)) {
|
||||
return features;
|
||||
}
|
||||
|
||||
features = vhost_net_get_features(get_vhost_net(nc->peer), features);
|
||||
vdev->backend_features = features;
|
||||
|
||||
@ -701,6 +743,11 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features)
|
||||
virtio_has_feature(features,
|
||||
VIRTIO_F_VERSION_1));
|
||||
|
||||
n->rsc4_enabled = virtio_has_feature(features, VIRTIO_NET_F_RSC_EXT) &&
|
||||
virtio_has_feature(features, VIRTIO_NET_F_GUEST_TSO4);
|
||||
n->rsc6_enabled = virtio_has_feature(features, VIRTIO_NET_F_RSC_EXT) &&
|
||||
virtio_has_feature(features, VIRTIO_NET_F_GUEST_TSO6);
|
||||
|
||||
if (n->has_vnet_hdr) {
|
||||
n->curr_guest_offloads =
|
||||
virtio_net_guest_offloads_by_features(features);
|
||||
@ -781,6 +828,12 @@ static int virtio_net_handle_offloads(VirtIONet *n, uint8_t cmd,
|
||||
return VIRTIO_NET_ERR;
|
||||
}
|
||||
|
||||
n->rsc4_enabled = virtio_has_feature(offloads, VIRTIO_NET_F_RSC_EXT) &&
|
||||
virtio_has_feature(offloads, VIRTIO_NET_F_GUEST_TSO4);
|
||||
n->rsc6_enabled = virtio_has_feature(offloads, VIRTIO_NET_F_RSC_EXT) &&
|
||||
virtio_has_feature(offloads, VIRTIO_NET_F_GUEST_TSO6);
|
||||
virtio_clear_feature(&offloads, VIRTIO_NET_F_RSC_EXT);
|
||||
|
||||
supported_offloads = virtio_net_supported_guest_offloads(n);
|
||||
if (offloads & ~supported_offloads) {
|
||||
return VIRTIO_NET_ERR;
|
||||
@ -1292,7 +1345,7 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf,
|
||||
static ssize_t virtio_net_do_receive(NetClientState *nc, const uint8_t *buf,
|
||||
size_t size)
|
||||
{
|
||||
ssize_t r;
|
||||
@ -1303,6 +1356,612 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf,
|
||||
return r;
|
||||
}
|
||||
|
||||
static void virtio_net_rsc_extract_unit4(VirtioNetRscChain *chain,
|
||||
const uint8_t *buf,
|
||||
VirtioNetRscUnit *unit)
|
||||
{
|
||||
uint16_t ip_hdrlen;
|
||||
struct ip_header *ip;
|
||||
|
||||
ip = (struct ip_header *)(buf + chain->n->guest_hdr_len
|
||||
+ sizeof(struct eth_header));
|
||||
unit->ip = (void *)ip;
|
||||
ip_hdrlen = (ip->ip_ver_len & 0xF) << 2;
|
||||
unit->ip_plen = &ip->ip_len;
|
||||
unit->tcp = (struct tcp_header *)(((uint8_t *)unit->ip) + ip_hdrlen);
|
||||
unit->tcp_hdrlen = (htons(unit->tcp->th_offset_flags) & 0xF000) >> 10;
|
||||
unit->payload = htons(*unit->ip_plen) - ip_hdrlen - unit->tcp_hdrlen;
|
||||
}
|
||||
|
||||
static void virtio_net_rsc_extract_unit6(VirtioNetRscChain *chain,
|
||||
const uint8_t *buf,
|
||||
VirtioNetRscUnit *unit)
|
||||
{
|
||||
struct ip6_header *ip6;
|
||||
|
||||
ip6 = (struct ip6_header *)(buf + chain->n->guest_hdr_len
|
||||
+ sizeof(struct eth_header));
|
||||
unit->ip = ip6;
|
||||
unit->ip_plen = &(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen);
|
||||
unit->tcp = (struct tcp_header *)(((uint8_t *)unit->ip)\
|
||||
+ sizeof(struct ip6_header));
|
||||
unit->tcp_hdrlen = (htons(unit->tcp->th_offset_flags) & 0xF000) >> 10;
|
||||
|
||||
/* There is a difference between payload lenght in ipv4 and v6,
|
||||
ip header is excluded in ipv6 */
|
||||
unit->payload = htons(*unit->ip_plen) - unit->tcp_hdrlen;
|
||||
}
|
||||
|
||||
static size_t virtio_net_rsc_drain_seg(VirtioNetRscChain *chain,
|
||||
VirtioNetRscSeg *seg)
|
||||
{
|
||||
int ret;
|
||||
struct virtio_net_hdr *h;
|
||||
|
||||
h = (struct virtio_net_hdr *)seg->buf;
|
||||
h->flags = 0;
|
||||
h->gso_type = VIRTIO_NET_HDR_GSO_NONE;
|
||||
|
||||
if (seg->is_coalesced) {
|
||||
*virtio_net_rsc_ext_num_packets(h) = seg->packets;
|
||||
*virtio_net_rsc_ext_num_dupacks(h) = seg->dup_ack;
|
||||
h->flags = VIRTIO_NET_HDR_F_RSC_INFO;
|
||||
if (chain->proto == ETH_P_IP) {
|
||||
h->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
|
||||
} else {
|
||||
h->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
|
||||
}
|
||||
}
|
||||
|
||||
ret = virtio_net_do_receive(seg->nc, seg->buf, seg->size);
|
||||
QTAILQ_REMOVE(&chain->buffers, seg, next);
|
||||
g_free(seg->buf);
|
||||
g_free(seg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void virtio_net_rsc_purge(void *opq)
|
||||
{
|
||||
VirtioNetRscSeg *seg, *rn;
|
||||
VirtioNetRscChain *chain = (VirtioNetRscChain *)opq;
|
||||
|
||||
QTAILQ_FOREACH_SAFE(seg, &chain->buffers, next, rn) {
|
||||
if (virtio_net_rsc_drain_seg(chain, seg) == 0) {
|
||||
chain->stat.purge_failed++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
chain->stat.timer++;
|
||||
if (!QTAILQ_EMPTY(&chain->buffers)) {
|
||||
timer_mod(chain->drain_timer,
|
||||
qemu_clock_get_ns(QEMU_CLOCK_HOST) + chain->n->rsc_timeout);
|
||||
}
|
||||
}
|
||||
|
||||
static void virtio_net_rsc_cleanup(VirtIONet *n)
|
||||
{
|
||||
VirtioNetRscChain *chain, *rn_chain;
|
||||
VirtioNetRscSeg *seg, *rn_seg;
|
||||
|
||||
QTAILQ_FOREACH_SAFE(chain, &n->rsc_chains, next, rn_chain) {
|
||||
QTAILQ_FOREACH_SAFE(seg, &chain->buffers, next, rn_seg) {
|
||||
QTAILQ_REMOVE(&chain->buffers, seg, next);
|
||||
g_free(seg->buf);
|
||||
g_free(seg);
|
||||
}
|
||||
|
||||
timer_del(chain->drain_timer);
|
||||
timer_free(chain->drain_timer);
|
||||
QTAILQ_REMOVE(&n->rsc_chains, chain, next);
|
||||
g_free(chain);
|
||||
}
|
||||
}
|
||||
|
||||
static void virtio_net_rsc_cache_buf(VirtioNetRscChain *chain,
|
||||
NetClientState *nc,
|
||||
const uint8_t *buf, size_t size)
|
||||
{
|
||||
uint16_t hdr_len;
|
||||
VirtioNetRscSeg *seg;
|
||||
|
||||
hdr_len = chain->n->guest_hdr_len;
|
||||
seg = g_malloc(sizeof(VirtioNetRscSeg));
|
||||
seg->buf = g_malloc(hdr_len + sizeof(struct eth_header)
|
||||
+ sizeof(struct ip6_header) + VIRTIO_NET_MAX_TCP_PAYLOAD);
|
||||
memcpy(seg->buf, buf, size);
|
||||
seg->size = size;
|
||||
seg->packets = 1;
|
||||
seg->dup_ack = 0;
|
||||
seg->is_coalesced = 0;
|
||||
seg->nc = nc;
|
||||
|
||||
QTAILQ_INSERT_TAIL(&chain->buffers, seg, next);
|
||||
chain->stat.cache++;
|
||||
|
||||
switch (chain->proto) {
|
||||
case ETH_P_IP:
|
||||
virtio_net_rsc_extract_unit4(chain, seg->buf, &seg->unit);
|
||||
break;
|
||||
case ETH_P_IPV6:
|
||||
virtio_net_rsc_extract_unit6(chain, seg->buf, &seg->unit);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t virtio_net_rsc_handle_ack(VirtioNetRscChain *chain,
|
||||
VirtioNetRscSeg *seg,
|
||||
const uint8_t *buf,
|
||||
struct tcp_header *n_tcp,
|
||||
struct tcp_header *o_tcp)
|
||||
{
|
||||
uint32_t nack, oack;
|
||||
uint16_t nwin, owin;
|
||||
|
||||
nack = htonl(n_tcp->th_ack);
|
||||
nwin = htons(n_tcp->th_win);
|
||||
oack = htonl(o_tcp->th_ack);
|
||||
owin = htons(o_tcp->th_win);
|
||||
|
||||
if ((nack - oack) >= VIRTIO_NET_MAX_TCP_PAYLOAD) {
|
||||
chain->stat.ack_out_of_win++;
|
||||
return RSC_FINAL;
|
||||
} else if (nack == oack) {
|
||||
/* duplicated ack or window probe */
|
||||
if (nwin == owin) {
|
||||
/* duplicated ack, add dup ack count due to whql test up to 1 */
|
||||
chain->stat.dup_ack++;
|
||||
return RSC_FINAL;
|
||||
} else {
|
||||
/* Coalesce window update */
|
||||
o_tcp->th_win = n_tcp->th_win;
|
||||
chain->stat.win_update++;
|
||||
return RSC_COALESCE;
|
||||
}
|
||||
} else {
|
||||
/* pure ack, go to 'C', finalize*/
|
||||
chain->stat.pure_ack++;
|
||||
return RSC_FINAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t virtio_net_rsc_coalesce_data(VirtioNetRscChain *chain,
|
||||
VirtioNetRscSeg *seg,
|
||||
const uint8_t *buf,
|
||||
VirtioNetRscUnit *n_unit)
|
||||
{
|
||||
void *data;
|
||||
uint16_t o_ip_len;
|
||||
uint32_t nseq, oseq;
|
||||
VirtioNetRscUnit *o_unit;
|
||||
|
||||
o_unit = &seg->unit;
|
||||
o_ip_len = htons(*o_unit->ip_plen);
|
||||
nseq = htonl(n_unit->tcp->th_seq);
|
||||
oseq = htonl(o_unit->tcp->th_seq);
|
||||
|
||||
/* out of order or retransmitted. */
|
||||
if ((nseq - oseq) > VIRTIO_NET_MAX_TCP_PAYLOAD) {
|
||||
chain->stat.data_out_of_win++;
|
||||
return RSC_FINAL;
|
||||
}
|
||||
|
||||
data = ((uint8_t *)n_unit->tcp) + n_unit->tcp_hdrlen;
|
||||
if (nseq == oseq) {
|
||||
if ((o_unit->payload == 0) && n_unit->payload) {
|
||||
/* From no payload to payload, normal case, not a dup ack or etc */
|
||||
chain->stat.data_after_pure_ack++;
|
||||
goto coalesce;
|
||||
} else {
|
||||
return virtio_net_rsc_handle_ack(chain, seg, buf,
|
||||
n_unit->tcp, o_unit->tcp);
|
||||
}
|
||||
} else if ((nseq - oseq) != o_unit->payload) {
|
||||
/* Not a consistent packet, out of order */
|
||||
chain->stat.data_out_of_order++;
|
||||
return RSC_FINAL;
|
||||
} else {
|
||||
coalesce:
|
||||
if ((o_ip_len + n_unit->payload) > chain->max_payload) {
|
||||
chain->stat.over_size++;
|
||||
return RSC_FINAL;
|
||||
}
|
||||
|
||||
/* Here comes the right data, the payload length in v4/v6 is different,
|
||||
so use the field value to update and record the new data len */
|
||||
o_unit->payload += n_unit->payload; /* update new data len */
|
||||
|
||||
/* update field in ip header */
|
||||
*o_unit->ip_plen = htons(o_ip_len + n_unit->payload);
|
||||
|
||||
/* Bring 'PUSH' big, the whql test guide says 'PUSH' can be coalesced
|
||||
for windows guest, while this may change the behavior for linux
|
||||
guest (only if it uses RSC feature). */
|
||||
o_unit->tcp->th_offset_flags = n_unit->tcp->th_offset_flags;
|
||||
|
||||
o_unit->tcp->th_ack = n_unit->tcp->th_ack;
|
||||
o_unit->tcp->th_win = n_unit->tcp->th_win;
|
||||
|
||||
memmove(seg->buf + seg->size, data, n_unit->payload);
|
||||
seg->size += n_unit->payload;
|
||||
seg->packets++;
|
||||
chain->stat.coalesced++;
|
||||
return RSC_COALESCE;
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t virtio_net_rsc_coalesce4(VirtioNetRscChain *chain,
|
||||
VirtioNetRscSeg *seg,
|
||||
const uint8_t *buf, size_t size,
|
||||
VirtioNetRscUnit *unit)
|
||||
{
|
||||
struct ip_header *ip1, *ip2;
|
||||
|
||||
ip1 = (struct ip_header *)(unit->ip);
|
||||
ip2 = (struct ip_header *)(seg->unit.ip);
|
||||
if ((ip1->ip_src ^ ip2->ip_src) || (ip1->ip_dst ^ ip2->ip_dst)
|
||||
|| (unit->tcp->th_sport ^ seg->unit.tcp->th_sport)
|
||||
|| (unit->tcp->th_dport ^ seg->unit.tcp->th_dport)) {
|
||||
chain->stat.no_match++;
|
||||
return RSC_NO_MATCH;
|
||||
}
|
||||
|
||||
return virtio_net_rsc_coalesce_data(chain, seg, buf, unit);
|
||||
}
|
||||
|
||||
static int32_t virtio_net_rsc_coalesce6(VirtioNetRscChain *chain,
|
||||
VirtioNetRscSeg *seg,
|
||||
const uint8_t *buf, size_t size,
|
||||
VirtioNetRscUnit *unit)
|
||||
{
|
||||
struct ip6_header *ip1, *ip2;
|
||||
|
||||
ip1 = (struct ip6_header *)(unit->ip);
|
||||
ip2 = (struct ip6_header *)(seg->unit.ip);
|
||||
if (memcmp(&ip1->ip6_src, &ip2->ip6_src, sizeof(struct in6_address))
|
||||
|| memcmp(&ip1->ip6_dst, &ip2->ip6_dst, sizeof(struct in6_address))
|
||||
|| (unit->tcp->th_sport ^ seg->unit.tcp->th_sport)
|
||||
|| (unit->tcp->th_dport ^ seg->unit.tcp->th_dport)) {
|
||||
chain->stat.no_match++;
|
||||
return RSC_NO_MATCH;
|
||||
}
|
||||
|
||||
return virtio_net_rsc_coalesce_data(chain, seg, buf, unit);
|
||||
}
|
||||
|
||||
/* Packets with 'SYN' should bypass, other flag should be sent after drain
|
||||
* to prevent out of order */
|
||||
static int virtio_net_rsc_tcp_ctrl_check(VirtioNetRscChain *chain,
|
||||
struct tcp_header *tcp)
|
||||
{
|
||||
uint16_t tcp_hdr;
|
||||
uint16_t tcp_flag;
|
||||
|
||||
tcp_flag = htons(tcp->th_offset_flags);
|
||||
tcp_hdr = (tcp_flag & VIRTIO_NET_TCP_HDR_LENGTH) >> 10;
|
||||
tcp_flag &= VIRTIO_NET_TCP_FLAG;
|
||||
tcp_flag = htons(tcp->th_offset_flags) & 0x3F;
|
||||
if (tcp_flag & TH_SYN) {
|
||||
chain->stat.tcp_syn++;
|
||||
return RSC_BYPASS;
|
||||
}
|
||||
|
||||
if (tcp_flag & (TH_FIN | TH_URG | TH_RST | TH_ECE | TH_CWR)) {
|
||||
chain->stat.tcp_ctrl_drain++;
|
||||
return RSC_FINAL;
|
||||
}
|
||||
|
||||
if (tcp_hdr > sizeof(struct tcp_header)) {
|
||||
chain->stat.tcp_all_opt++;
|
||||
return RSC_FINAL;
|
||||
}
|
||||
|
||||
return RSC_CANDIDATE;
|
||||
}
|
||||
|
||||
static size_t virtio_net_rsc_do_coalesce(VirtioNetRscChain *chain,
|
||||
NetClientState *nc,
|
||||
const uint8_t *buf, size_t size,
|
||||
VirtioNetRscUnit *unit)
|
||||
{
|
||||
int ret;
|
||||
VirtioNetRscSeg *seg, *nseg;
|
||||
|
||||
if (QTAILQ_EMPTY(&chain->buffers)) {
|
||||
chain->stat.empty_cache++;
|
||||
virtio_net_rsc_cache_buf(chain, nc, buf, size);
|
||||
timer_mod(chain->drain_timer,
|
||||
qemu_clock_get_ns(QEMU_CLOCK_HOST) + chain->n->rsc_timeout);
|
||||
return size;
|
||||
}
|
||||
|
||||
QTAILQ_FOREACH_SAFE(seg, &chain->buffers, next, nseg) {
|
||||
if (chain->proto == ETH_P_IP) {
|
||||
ret = virtio_net_rsc_coalesce4(chain, seg, buf, size, unit);
|
||||
} else {
|
||||
ret = virtio_net_rsc_coalesce6(chain, seg, buf, size, unit);
|
||||
}
|
||||
|
||||
if (ret == RSC_FINAL) {
|
||||
if (virtio_net_rsc_drain_seg(chain, seg) == 0) {
|
||||
/* Send failed */
|
||||
chain->stat.final_failed++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Send current packet */
|
||||
return virtio_net_do_receive(nc, buf, size);
|
||||
} else if (ret == RSC_NO_MATCH) {
|
||||
continue;
|
||||
} else {
|
||||
/* Coalesced, mark coalesced flag to tell calc cksum for ipv4 */
|
||||
seg->is_coalesced = 1;
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
chain->stat.no_match_cache++;
|
||||
virtio_net_rsc_cache_buf(chain, nc, buf, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
/* Drain a connection data, this is to avoid out of order segments */
|
||||
static size_t virtio_net_rsc_drain_flow(VirtioNetRscChain *chain,
|
||||
NetClientState *nc,
|
||||
const uint8_t *buf, size_t size,
|
||||
uint16_t ip_start, uint16_t ip_size,
|
||||
uint16_t tcp_port)
|
||||
{
|
||||
VirtioNetRscSeg *seg, *nseg;
|
||||
uint32_t ppair1, ppair2;
|
||||
|
||||
ppair1 = *(uint32_t *)(buf + tcp_port);
|
||||
QTAILQ_FOREACH_SAFE(seg, &chain->buffers, next, nseg) {
|
||||
ppair2 = *(uint32_t *)(seg->buf + tcp_port);
|
||||
if (memcmp(buf + ip_start, seg->buf + ip_start, ip_size)
|
||||
|| (ppair1 != ppair2)) {
|
||||
continue;
|
||||
}
|
||||
if (virtio_net_rsc_drain_seg(chain, seg) == 0) {
|
||||
chain->stat.drain_failed++;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return virtio_net_do_receive(nc, buf, size);
|
||||
}
|
||||
|
||||
static int32_t virtio_net_rsc_sanity_check4(VirtioNetRscChain *chain,
|
||||
struct ip_header *ip,
|
||||
const uint8_t *buf, size_t size)
|
||||
{
|
||||
uint16_t ip_len;
|
||||
|
||||
/* Not an ipv4 packet */
|
||||
if (((ip->ip_ver_len & 0xF0) >> 4) != IP_HEADER_VERSION_4) {
|
||||
chain->stat.ip_option++;
|
||||
return RSC_BYPASS;
|
||||
}
|
||||
|
||||
/* Don't handle packets with ip option */
|
||||
if ((ip->ip_ver_len & 0xF) != VIRTIO_NET_IP4_HEADER_LENGTH) {
|
||||
chain->stat.ip_option++;
|
||||
return RSC_BYPASS;
|
||||
}
|
||||
|
||||
if (ip->ip_p != IPPROTO_TCP) {
|
||||
chain->stat.bypass_not_tcp++;
|
||||
return RSC_BYPASS;
|
||||
}
|
||||
|
||||
/* Don't handle packets with ip fragment */
|
||||
if (!(htons(ip->ip_off) & IP_DF)) {
|
||||
chain->stat.ip_frag++;
|
||||
return RSC_BYPASS;
|
||||
}
|
||||
|
||||
/* Don't handle packets with ecn flag */
|
||||
if (IPTOS_ECN(ip->ip_tos)) {
|
||||
chain->stat.ip_ecn++;
|
||||
return RSC_BYPASS;
|
||||
}
|
||||
|
||||
ip_len = htons(ip->ip_len);
|
||||
if (ip_len < (sizeof(struct ip_header) + sizeof(struct tcp_header))
|
||||
|| ip_len > (size - chain->n->guest_hdr_len -
|
||||
sizeof(struct eth_header))) {
|
||||
chain->stat.ip_hacked++;
|
||||
return RSC_BYPASS;
|
||||
}
|
||||
|
||||
return RSC_CANDIDATE;
|
||||
}
|
||||
|
||||
static size_t virtio_net_rsc_receive4(VirtioNetRscChain *chain,
|
||||
NetClientState *nc,
|
||||
const uint8_t *buf, size_t size)
|
||||
{
|
||||
int32_t ret;
|
||||
uint16_t hdr_len;
|
||||
VirtioNetRscUnit unit;
|
||||
|
||||
hdr_len = ((VirtIONet *)(chain->n))->guest_hdr_len;
|
||||
|
||||
if (size < (hdr_len + sizeof(struct eth_header) + sizeof(struct ip_header)
|
||||
+ sizeof(struct tcp_header))) {
|
||||
chain->stat.bypass_not_tcp++;
|
||||
return virtio_net_do_receive(nc, buf, size);
|
||||
}
|
||||
|
||||
virtio_net_rsc_extract_unit4(chain, buf, &unit);
|
||||
if (virtio_net_rsc_sanity_check4(chain, unit.ip, buf, size)
|
||||
!= RSC_CANDIDATE) {
|
||||
return virtio_net_do_receive(nc, buf, size);
|
||||
}
|
||||
|
||||
ret = virtio_net_rsc_tcp_ctrl_check(chain, unit.tcp);
|
||||
if (ret == RSC_BYPASS) {
|
||||
return virtio_net_do_receive(nc, buf, size);
|
||||
} else if (ret == RSC_FINAL) {
|
||||
return virtio_net_rsc_drain_flow(chain, nc, buf, size,
|
||||
((hdr_len + sizeof(struct eth_header)) + 12),
|
||||
VIRTIO_NET_IP4_ADDR_SIZE,
|
||||
hdr_len + sizeof(struct eth_header) + sizeof(struct ip_header));
|
||||
}
|
||||
|
||||
return virtio_net_rsc_do_coalesce(chain, nc, buf, size, &unit);
|
||||
}
|
||||
|
||||
static int32_t virtio_net_rsc_sanity_check6(VirtioNetRscChain *chain,
|
||||
struct ip6_header *ip6,
|
||||
const uint8_t *buf, size_t size)
|
||||
{
|
||||
uint16_t ip_len;
|
||||
|
||||
if (((ip6->ip6_ctlun.ip6_un1.ip6_un1_flow & 0xF0) >> 4)
|
||||
!= IP_HEADER_VERSION_6) {
|
||||
return RSC_BYPASS;
|
||||
}
|
||||
|
||||
/* Both option and protocol is checked in this */
|
||||
if (ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt != IPPROTO_TCP) {
|
||||
chain->stat.bypass_not_tcp++;
|
||||
return RSC_BYPASS;
|
||||
}
|
||||
|
||||
ip_len = htons(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen);
|
||||
if (ip_len < sizeof(struct tcp_header) ||
|
||||
ip_len > (size - chain->n->guest_hdr_len - sizeof(struct eth_header)
|
||||
- sizeof(struct ip6_header))) {
|
||||
chain->stat.ip_hacked++;
|
||||
return RSC_BYPASS;
|
||||
}
|
||||
|
||||
/* Don't handle packets with ecn flag */
|
||||
if (IP6_ECN(ip6->ip6_ctlun.ip6_un3.ip6_un3_ecn)) {
|
||||
chain->stat.ip_ecn++;
|
||||
return RSC_BYPASS;
|
||||
}
|
||||
|
||||
return RSC_CANDIDATE;
|
||||
}
|
||||
|
||||
static size_t virtio_net_rsc_receive6(void *opq, NetClientState *nc,
|
||||
const uint8_t *buf, size_t size)
|
||||
{
|
||||
int32_t ret;
|
||||
uint16_t hdr_len;
|
||||
VirtioNetRscChain *chain;
|
||||
VirtioNetRscUnit unit;
|
||||
|
||||
chain = (VirtioNetRscChain *)opq;
|
||||
hdr_len = ((VirtIONet *)(chain->n))->guest_hdr_len;
|
||||
|
||||
if (size < (hdr_len + sizeof(struct eth_header) + sizeof(struct ip6_header)
|
||||
+ sizeof(tcp_header))) {
|
||||
return virtio_net_do_receive(nc, buf, size);
|
||||
}
|
||||
|
||||
virtio_net_rsc_extract_unit6(chain, buf, &unit);
|
||||
if (RSC_CANDIDATE != virtio_net_rsc_sanity_check6(chain,
|
||||
unit.ip, buf, size)) {
|
||||
return virtio_net_do_receive(nc, buf, size);
|
||||
}
|
||||
|
||||
ret = virtio_net_rsc_tcp_ctrl_check(chain, unit.tcp);
|
||||
if (ret == RSC_BYPASS) {
|
||||
return virtio_net_do_receive(nc, buf, size);
|
||||
} else if (ret == RSC_FINAL) {
|
||||
return virtio_net_rsc_drain_flow(chain, nc, buf, size,
|
||||
((hdr_len + sizeof(struct eth_header)) + 8),
|
||||
VIRTIO_NET_IP6_ADDR_SIZE,
|
||||
hdr_len + sizeof(struct eth_header)
|
||||
+ sizeof(struct ip6_header));
|
||||
}
|
||||
|
||||
return virtio_net_rsc_do_coalesce(chain, nc, buf, size, &unit);
|
||||
}
|
||||
|
||||
static VirtioNetRscChain *virtio_net_rsc_lookup_chain(VirtIONet *n,
|
||||
NetClientState *nc,
|
||||
uint16_t proto)
|
||||
{
|
||||
VirtioNetRscChain *chain;
|
||||
|
||||
if ((proto != (uint16_t)ETH_P_IP) && (proto != (uint16_t)ETH_P_IPV6)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QTAILQ_FOREACH(chain, &n->rsc_chains, next) {
|
||||
if (chain->proto == proto) {
|
||||
return chain;
|
||||
}
|
||||
}
|
||||
|
||||
chain = g_malloc(sizeof(*chain));
|
||||
chain->n = n;
|
||||
chain->proto = proto;
|
||||
if (proto == (uint16_t)ETH_P_IP) {
|
||||
chain->max_payload = VIRTIO_NET_MAX_IP4_PAYLOAD;
|
||||
chain->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
|
||||
} else {
|
||||
chain->max_payload = VIRTIO_NET_MAX_IP6_PAYLOAD;
|
||||
chain->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
|
||||
}
|
||||
chain->drain_timer = timer_new_ns(QEMU_CLOCK_HOST,
|
||||
virtio_net_rsc_purge, chain);
|
||||
memset(&chain->stat, 0, sizeof(chain->stat));
|
||||
|
||||
QTAILQ_INIT(&chain->buffers);
|
||||
QTAILQ_INSERT_TAIL(&n->rsc_chains, chain, next);
|
||||
|
||||
return chain;
|
||||
}
|
||||
|
||||
static ssize_t virtio_net_rsc_receive(NetClientState *nc,
|
||||
const uint8_t *buf,
|
||||
size_t size)
|
||||
{
|
||||
uint16_t proto;
|
||||
VirtioNetRscChain *chain;
|
||||
struct eth_header *eth;
|
||||
VirtIONet *n;
|
||||
|
||||
n = qemu_get_nic_opaque(nc);
|
||||
if (size < (n->host_hdr_len + sizeof(struct eth_header))) {
|
||||
return virtio_net_do_receive(nc, buf, size);
|
||||
}
|
||||
|
||||
eth = (struct eth_header *)(buf + n->guest_hdr_len);
|
||||
proto = htons(eth->h_proto);
|
||||
|
||||
chain = virtio_net_rsc_lookup_chain(n, nc, proto);
|
||||
if (chain) {
|
||||
chain->stat.received++;
|
||||
if (proto == (uint16_t)ETH_P_IP && n->rsc4_enabled) {
|
||||
return virtio_net_rsc_receive4(chain, nc, buf, size);
|
||||
} else if (proto == (uint16_t)ETH_P_IPV6 && n->rsc6_enabled) {
|
||||
return virtio_net_rsc_receive6(chain, nc, buf, size);
|
||||
}
|
||||
}
|
||||
return virtio_net_do_receive(nc, buf, size);
|
||||
}
|
||||
|
||||
static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf,
|
||||
size_t size)
|
||||
{
|
||||
VirtIONet *n = qemu_get_nic_opaque(nc);
|
||||
if ((n->rsc4_enabled || n->rsc6_enabled)) {
|
||||
return virtio_net_rsc_receive(nc, buf, size);
|
||||
} else {
|
||||
return virtio_net_do_receive(nc, buf, size);
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t virtio_net_flush_tx(VirtIONetQueue *q);
|
||||
|
||||
static void virtio_net_tx_complete(NetClientState *nc, ssize_t len)
|
||||
@ -2075,6 +2734,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
|
||||
nc = qemu_get_queue(n->nic);
|
||||
nc->rxfilter_notify_enabled = 1;
|
||||
|
||||
QTAILQ_INIT(&n->rsc_chains);
|
||||
n->qdev = dev;
|
||||
}
|
||||
|
||||
@ -2104,6 +2764,7 @@ static void virtio_net_device_unrealize(DeviceState *dev, Error **errp)
|
||||
timer_free(n->announce_timer);
|
||||
g_free(n->vqs);
|
||||
qemu_del_nic(n->nic);
|
||||
virtio_net_rsc_cleanup(n);
|
||||
virtio_cleanup(vdev);
|
||||
}
|
||||
|
||||
@ -2184,6 +2845,10 @@ static Property virtio_net_properties[] = {
|
||||
DEFINE_PROP_BIT64("ctrl_guest_offloads", VirtIONet, host_features,
|
||||
VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, true),
|
||||
DEFINE_PROP_BIT64("mq", VirtIONet, host_features, VIRTIO_NET_F_MQ, false),
|
||||
DEFINE_PROP_BIT64("guest_rsc_ext", VirtIONet, host_features,
|
||||
VIRTIO_NET_F_RSC_EXT, false),
|
||||
DEFINE_PROP_UINT32("rsc_interval", VirtIONet, rsc_timeout,
|
||||
VIRTIO_NET_RSC_DEFAULT_INTERVAL),
|
||||
DEFINE_NIC_PROPERTIES(VirtIONet, nic_conf),
|
||||
DEFINE_PROP_UINT32("x-txtimer", VirtIONet, net_conf.txtimer,
|
||||
TX_TIMER_INTERVAL),
|
||||
|
@ -345,7 +345,7 @@ int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries,
|
||||
char *name;
|
||||
uint32_t bar_size = 4096;
|
||||
uint32_t bar_pba_offset = bar_size / 2;
|
||||
uint32_t bar_pba_size = (nentries / 8 + 1) * 8;
|
||||
uint32_t bar_pba_size = QEMU_ALIGN_UP(nentries, 64) / 8;
|
||||
|
||||
/*
|
||||
* Migration compatibility dictates that this remains a 4k
|
||||
|
@ -391,10 +391,10 @@ static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event)
|
||||
}
|
||||
|
||||
static void pcie_cap_slot_plug_common(PCIDevice *hotplug_dev, DeviceState *dev,
|
||||
uint8_t **exp_cap, Error **errp)
|
||||
Error **errp)
|
||||
{
|
||||
*exp_cap = hotplug_dev->config + hotplug_dev->exp.exp_cap;
|
||||
uint16_t sltsta = pci_get_word(*exp_cap + PCI_EXP_SLTSTA);
|
||||
uint8_t *exp_cap = hotplug_dev->config + hotplug_dev->exp.exp_cap;
|
||||
uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
|
||||
|
||||
PCIE_DEV_PRINTF(PCI_DEVICE(dev), "hotplug state: 0x%x\n", sltsta);
|
||||
if (sltsta & PCI_EXP_SLTSTA_EIS) {
|
||||
@ -405,14 +405,19 @@ static void pcie_cap_slot_plug_common(PCIDevice *hotplug_dev, DeviceState *dev,
|
||||
}
|
||||
}
|
||||
|
||||
void pcie_cap_slot_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||
Error **errp)
|
||||
{
|
||||
pcie_cap_slot_plug_common(PCI_DEVICE(hotplug_dev), dev, errp);
|
||||
}
|
||||
|
||||
void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||
Error **errp)
|
||||
{
|
||||
uint8_t *exp_cap;
|
||||
PCIDevice *hotplug_pdev = PCI_DEVICE(hotplug_dev);
|
||||
uint8_t *exp_cap = hotplug_pdev->config + hotplug_pdev->exp.exp_cap;
|
||||
PCIDevice *pci_dev = PCI_DEVICE(dev);
|
||||
|
||||
pcie_cap_slot_plug_common(PCI_DEVICE(hotplug_dev), dev, &exp_cap, errp);
|
||||
|
||||
/* Don't send event when device is enabled during qemu machine creation:
|
||||
* it is present on boot, no hotplug event is necessary. We do send an
|
||||
* event when the device is disabled later. */
|
||||
@ -458,11 +463,15 @@ static void pcie_unplug_device(PCIBus *bus, PCIDevice *dev, void *opaque)
|
||||
void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
uint8_t *exp_cap;
|
||||
Error *local_err = NULL;
|
||||
PCIDevice *pci_dev = PCI_DEVICE(dev);
|
||||
PCIBus *bus = pci_get_bus(pci_dev);
|
||||
|
||||
pcie_cap_slot_plug_common(PCI_DEVICE(hotplug_dev), dev, &exp_cap, errp);
|
||||
pcie_cap_slot_plug_common(PCI_DEVICE(hotplug_dev), dev, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* In case user cancel the operation of multi-function hot-add,
|
||||
* remove the function that is unexposed to guest individually,
|
||||
|
@ -154,6 +154,7 @@ static void pcie_slot_class_init(ObjectClass *oc, void *data)
|
||||
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
|
||||
|
||||
dc->props = pcie_slot_props;
|
||||
hc->pre_plug = pcie_cap_slot_pre_plug_cb;
|
||||
hc->plug = pcie_cap_slot_plug_cb;
|
||||
hc->unplug = pcie_cap_slot_unplug_cb;
|
||||
hc->unplug_request = pcie_cap_slot_unplug_request_cb;
|
||||
|
@ -215,6 +215,7 @@ static void vhost_scsi_unrealize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
||||
VHostSCSICommon *vsc = VHOST_SCSI_COMMON(dev);
|
||||
struct vhost_virtqueue *vqs = vsc->dev.vqs;
|
||||
|
||||
migrate_del_blocker(vsc->migration_blocker);
|
||||
error_free(vsc->migration_blocker);
|
||||
@ -223,7 +224,7 @@ static void vhost_scsi_unrealize(DeviceState *dev, Error **errp)
|
||||
vhost_scsi_set_status(vdev, 0);
|
||||
|
||||
vhost_dev_cleanup(&vsc->dev);
|
||||
g_free(vsc->dev.vqs);
|
||||
g_free(vqs);
|
||||
|
||||
virtio_scsi_common_unrealize(dev, errp);
|
||||
}
|
||||
|
@ -121,12 +121,13 @@ static void vhost_user_scsi_unrealize(DeviceState *dev, Error **errp)
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
||||
VHostUserSCSI *s = VHOST_USER_SCSI(dev);
|
||||
VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
|
||||
struct vhost_virtqueue *vqs = vsc->dev.vqs;
|
||||
|
||||
/* This will stop the vhost backend. */
|
||||
vhost_user_scsi_set_status(vdev, 0);
|
||||
|
||||
vhost_dev_cleanup(&vsc->dev);
|
||||
g_free(vsc->dev.vqs);
|
||||
g_free(vqs);
|
||||
|
||||
virtio_scsi_common_unrealize(dev, errp);
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
common-obj-y += tpm_util.o
|
||||
obj-y += tpm_ppi.o
|
||||
common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
|
||||
common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o
|
||||
common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "sysemu/reset.h"
|
||||
#include "tpm_int.h"
|
||||
#include "tpm_util.h"
|
||||
#include "tpm_ppi.h"
|
||||
#include "trace.h"
|
||||
|
||||
typedef struct CRBState {
|
||||
@ -41,6 +42,9 @@ typedef struct CRBState {
|
||||
MemoryRegion cmdmem;
|
||||
|
||||
size_t be_buffer_size;
|
||||
|
||||
bool ppi_enabled;
|
||||
TPMPPI ppi;
|
||||
} CRBState;
|
||||
|
||||
#define CRB(obj) OBJECT_CHECK(CRBState, (obj), TYPE_TPM_CRB)
|
||||
@ -221,6 +225,7 @@ static const VMStateDescription vmstate_tpm_crb = {
|
||||
|
||||
static Property tpm_crb_properties[] = {
|
||||
DEFINE_PROP_TPMBE("tpmdev", CRBState, tpmbe),
|
||||
DEFINE_PROP_BOOL("ppi", CRBState, ppi_enabled, true),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@ -228,6 +233,9 @@ static void tpm_crb_reset(void *dev)
|
||||
{
|
||||
CRBState *s = CRB(dev);
|
||||
|
||||
if (s->ppi_enabled) {
|
||||
tpm_ppi_reset(&s->ppi);
|
||||
}
|
||||
tpm_backend_reset(s->tpmbe);
|
||||
|
||||
memset(s->regs, 0, sizeof(s->regs));
|
||||
@ -291,6 +299,11 @@ static void tpm_crb_realize(DeviceState *dev, Error **errp)
|
||||
memory_region_add_subregion(get_system_memory(),
|
||||
TPM_CRB_ADDR_BASE + sizeof(s->regs), &s->cmdmem);
|
||||
|
||||
if (s->ppi_enabled) {
|
||||
tpm_ppi_init(&s->ppi, get_system_memory(),
|
||||
TPM_PPI_ADDR_BASE, OBJECT(s));
|
||||
}
|
||||
|
||||
qemu_register_reset(tpm_crb_reset, dev);
|
||||
}
|
||||
|
||||
|
53
hw/tpm/tpm_ppi.c
Normal file
53
hw/tpm/tpm_ppi.c
Normal 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
46
hw/tpm/tpm_ppi.h
Normal 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 */
|
@ -31,6 +31,7 @@
|
||||
#include "sysemu/tpm_backend.h"
|
||||
#include "tpm_int.h"
|
||||
#include "tpm_util.h"
|
||||
#include "tpm_ppi.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define TPM_TIS_NUM_LOCALITIES 5 /* per spec */
|
||||
@ -81,6 +82,9 @@ typedef struct TPMState {
|
||||
TPMVersion be_tpm_version;
|
||||
|
||||
size_t be_buffer_size;
|
||||
|
||||
bool ppi_enabled;
|
||||
TPMPPI ppi;
|
||||
} TPMState;
|
||||
|
||||
#define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS)
|
||||
@ -868,6 +872,9 @@ static void tpm_tis_reset(DeviceState *dev)
|
||||
s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->be_driver),
|
||||
TPM_TIS_BUFFER_MAX);
|
||||
|
||||
if (s->ppi_enabled) {
|
||||
tpm_ppi_reset(&s->ppi);
|
||||
}
|
||||
tpm_backend_reset(s->be_driver);
|
||||
|
||||
s->active_locty = TPM_TIS_NO_LOCALITY;
|
||||
@ -954,6 +961,7 @@ static const VMStateDescription vmstate_tpm_tis = {
|
||||
static Property tpm_tis_properties[] = {
|
||||
DEFINE_PROP_UINT32("irq", TPMState, irq_num, TPM_TIS_IRQ),
|
||||
DEFINE_PROP_TPMBE("tpmdev", TPMState, be_driver),
|
||||
DEFINE_PROP_BOOL("ppi", TPMState, ppi_enabled, true),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@ -980,6 +988,11 @@ static void tpm_tis_realizefn(DeviceState *dev, Error **errp)
|
||||
|
||||
memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)),
|
||||
TPM_TIS_ADDR_BASE, &s->mmio);
|
||||
|
||||
if (s->ppi_enabled) {
|
||||
tpm_ppi_init(&s->ppi, isa_address_space(ISA_DEVICE(dev)),
|
||||
TPM_PPI_ADDR_BASE, OBJECT(s));
|
||||
}
|
||||
}
|
||||
|
||||
static void tpm_tis_initfn(Object *obj)
|
||||
|
@ -51,3 +51,6 @@ tpm_tis_mmio_write_init_abort(void) "Initiating abort"
|
||||
tpm_tis_mmio_write_lowering_irq(void) "Lowering IRQ"
|
||||
tpm_tis_mmio_write_data2send(uint32_t value, unsigned size) "Data to send to TPM: 0x%08x (size=%d)"
|
||||
tpm_tis_pre_save(uint8_t locty, uint32_t rw_offset) "locty: %d, rw_offset = %u"
|
||||
|
||||
# hw/tpm/tpm_ppi.c
|
||||
tpm_ppi_memset(uint8_t *ptr, size_t size) "memset: %p %zu"
|
||||
|
@ -11,6 +11,21 @@ obj-$(call land,$(CONFIG_VIRTIO_CRYPTO),$(CONFIG_VIRTIO_PCI)) += virtio-crypto-p
|
||||
|
||||
obj-$(CONFIG_LINUX) += vhost.o vhost-backend.o vhost-user.o
|
||||
obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock.o
|
||||
ifeq ($(CONFIG_PCI),y)
|
||||
obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock-pci.o
|
||||
obj-$(CONFIG_VHOST_USER_BLK) += vhost-user-blk-pci.o
|
||||
obj-$(CONFIG_VHOST_USER_SCSI) += vhost-user-scsi-pci.o
|
||||
obj-$(CONFIG_VHOST_SCSI) += vhost-scsi-pci.o
|
||||
obj-$(CONFIG_VIRTIO_INPUT_HOST) += virtio-input-host-pci.o
|
||||
obj-$(CONFIG_VIRTIO_INPUT) += virtio-input-pci.o
|
||||
obj-$(CONFIG_VIRTIO_RNG) += virtio-rng-pci.o
|
||||
obj-$(CONFIG_VIRTIO_BALLOON) += virtio-balloon-pci.o
|
||||
obj-$(CONFIG_VIRTIO_9P) += virtio-9p-pci.o
|
||||
obj-$(CONFIG_VIRTIO_SCSI) += virtio-scsi-pci.o
|
||||
obj-$(CONFIG_VIRTIO_BLK) += virtio-blk-pci.o
|
||||
obj-$(CONFIG_VIRTIO_NET) += virtio-net-pci.o
|
||||
obj-$(CONFIG_VIRTIO_SERIAL) += virtio-serial-pci.o
|
||||
endif
|
||||
endif
|
||||
|
||||
common-obj-$(call lnot,$(call land,$(CONFIG_VIRTIO),$(CONFIG_LINUX))) += vhost-stub.o
|
||||
|
97
hw/virtio/vhost-scsi-pci.c
Normal file
97
hw/virtio/vhost-scsi-pci.c
Normal 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)
|
103
hw/virtio/vhost-user-blk-pci.c
Normal file
103
hw/virtio/vhost-user-blk-pci.c
Normal 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)
|
103
hw/virtio/vhost-user-scsi-pci.c
Normal file
103
hw/virtio/vhost-user-scsi-pci.c
Normal 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)
|
@ -207,7 +207,7 @@ struct vhost_user {
|
||||
|
||||
static bool ioeventfd_enabled(void)
|
||||
{
|
||||
return kvm_enabled() && kvm_eventfds_enabled();
|
||||
return !kvm_enabled() || kvm_eventfds_enabled();
|
||||
}
|
||||
|
||||
static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg)
|
||||
|
86
hw/virtio/vhost-vsock-pci.c
Normal file
86
hw/virtio/vhost-vsock-pci.c
Normal 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
88
hw/virtio/virtio-9p-pci.c
Normal 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)
|
95
hw/virtio/virtio-balloon-pci.c
Normal file
95
hw/virtio/virtio-balloon-pci.c
Normal 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
100
hw/virtio/virtio-blk-pci.c
Normal 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)
|
@ -19,6 +19,20 @@
|
||||
#include "hw/virtio/virtio-crypto.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
typedef struct VirtIOCryptoPCI VirtIOCryptoPCI;
|
||||
|
||||
/*
|
||||
* virtio-crypto-pci: This extends VirtioPCIProxy.
|
||||
*/
|
||||
#define TYPE_VIRTIO_CRYPTO_PCI "virtio-crypto-pci"
|
||||
#define VIRTIO_CRYPTO_PCI(obj) \
|
||||
OBJECT_CHECK(VirtIOCryptoPCI, (obj), TYPE_VIRTIO_CRYPTO_PCI)
|
||||
|
||||
struct VirtIOCryptoPCI {
|
||||
VirtIOPCIProxy parent_obj;
|
||||
VirtIOCrypto vdev;
|
||||
};
|
||||
|
||||
static Property virtio_crypto_pci_properties[] = {
|
||||
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
|
||||
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
|
||||
|
48
hw/virtio/virtio-input-host-pci.c
Normal file
48
hw/virtio/virtio-input-host-pci.c
Normal 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)
|
157
hw/virtio/virtio-input-pci.c
Normal file
157
hw/virtio/virtio-input-pci.c
Normal 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)
|
98
hw/virtio/virtio-net-pci.c
Normal file
98
hw/virtio/virtio-net-pci.c
Normal 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)
|
@ -19,12 +19,6 @@
|
||||
|
||||
#include "standard-headers/linux/virtio_pci.h"
|
||||
#include "hw/virtio/virtio.h"
|
||||
#include "hw/virtio/virtio-blk.h"
|
||||
#include "hw/virtio/virtio-net.h"
|
||||
#include "hw/virtio/virtio-serial.h"
|
||||
#include "hw/virtio/virtio-scsi.h"
|
||||
#include "hw/virtio/virtio-balloon.h"
|
||||
#include "hw/virtio/virtio-input.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
@ -1079,57 +1073,6 @@ static void virtio_pci_vmstate_change(DeviceState *d, bool running)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VIRTFS
|
||||
static void virtio_9p_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
||||
{
|
||||
V9fsPCIState *dev = VIRTIO_9P_PCI(vpci_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
|
||||
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", errp);
|
||||
}
|
||||
|
||||
static Property virtio_9p_pci_properties[] = {
|
||||
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
|
||||
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
|
||||
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void virtio_9p_pci_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
|
||||
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
|
||||
|
||||
k->realize = virtio_9p_pci_realize;
|
||||
pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
|
||||
pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_9P;
|
||||
pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
|
||||
pcidev_k->class_id = 0x2;
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
||||
dc->props = virtio_9p_pci_properties;
|
||||
}
|
||||
|
||||
static void virtio_9p_pci_instance_init(Object *obj)
|
||||
{
|
||||
V9fsPCIState *dev = VIRTIO_9P_PCI(obj);
|
||||
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VIRTIO_9P);
|
||||
}
|
||||
|
||||
static const VirtioPCIDeviceTypeInfo virtio_9p_pci_info = {
|
||||
.base_name = TYPE_VIRTIO_9P_PCI,
|
||||
.generic_name = "virtio-9p-pci",
|
||||
.transitional_name = "virtio-9p-pci-transitional",
|
||||
.non_transitional_name = "virtio-9p-pci-non-transitional",
|
||||
.instance_size = sizeof(V9fsPCIState),
|
||||
.instance_init = virtio_9p_pci_instance_init,
|
||||
.class_init = virtio_9p_pci_class_init,
|
||||
};
|
||||
#endif /* CONFIG_VIRTFS */
|
||||
|
||||
/*
|
||||
* virtio-pci: This is the PCIDevice which has a virtio-pci-bus.
|
||||
*/
|
||||
@ -2055,728 +1998,6 @@ void virtio_pci_types_register(const VirtioPCIDeviceTypeInfo *t)
|
||||
}
|
||||
}
|
||||
|
||||
/* virtio-blk-pci */
|
||||
|
||||
static Property virtio_blk_pci_properties[] = {
|
||||
DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
|
||||
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
|
||||
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
|
||||
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
|
||||
DEV_NVECTORS_UNSPECIFIED),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
||||
{
|
||||
VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
|
||||
if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
|
||||
vpci_dev->nvectors = dev->vdev.conf.num_queues + 1;
|
||||
}
|
||||
|
||||
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", errp);
|
||||
}
|
||||
|
||||
static void virtio_blk_pci_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
|
||||
PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
|
||||
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
||||
dc->props = virtio_blk_pci_properties;
|
||||
k->realize = virtio_blk_pci_realize;
|
||||
pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
|
||||
pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK;
|
||||
pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
|
||||
pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
|
||||
}
|
||||
|
||||
static void virtio_blk_pci_instance_init(Object *obj)
|
||||
{
|
||||
VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj);
|
||||
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VIRTIO_BLK);
|
||||
object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
|
||||
"bootindex", &error_abort);
|
||||
}
|
||||
|
||||
static const VirtioPCIDeviceTypeInfo virtio_blk_pci_info = {
|
||||
.base_name = TYPE_VIRTIO_BLK_PCI,
|
||||
.generic_name = "virtio-blk-pci",
|
||||
.transitional_name = "virtio-blk-pci-transitional",
|
||||
.non_transitional_name = "virtio-blk-pci-non-transitional",
|
||||
.instance_size = sizeof(VirtIOBlkPCI),
|
||||
.instance_init = virtio_blk_pci_instance_init,
|
||||
.class_init = virtio_blk_pci_class_init,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX)
|
||||
/* vhost-user-blk */
|
||||
|
||||
static Property vhost_user_blk_pci_properties[] = {
|
||||
DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
|
||||
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
|
||||
DEV_NVECTORS_UNSPECIFIED),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void vhost_user_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
||||
{
|
||||
VHostUserBlkPCI *dev = VHOST_USER_BLK_PCI(vpci_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
|
||||
if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
|
||||
vpci_dev->nvectors = dev->vdev.num_queues + 1;
|
||||
}
|
||||
|
||||
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", errp);
|
||||
}
|
||||
|
||||
static void vhost_user_blk_pci_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
|
||||
PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
|
||||
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
||||
dc->props = vhost_user_blk_pci_properties;
|
||||
k->realize = vhost_user_blk_pci_realize;
|
||||
pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
|
||||
pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK;
|
||||
pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
|
||||
pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
|
||||
}
|
||||
|
||||
static void vhost_user_blk_pci_instance_init(Object *obj)
|
||||
{
|
||||
VHostUserBlkPCI *dev = VHOST_USER_BLK_PCI(obj);
|
||||
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VHOST_USER_BLK);
|
||||
object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
|
||||
"bootindex", &error_abort);
|
||||
}
|
||||
|
||||
static const VirtioPCIDeviceTypeInfo vhost_user_blk_pci_info = {
|
||||
.base_name = TYPE_VHOST_USER_BLK_PCI,
|
||||
.generic_name = "vhost-user-blk-pci",
|
||||
.transitional_name = "vhost-user-blk-pci-transitional",
|
||||
.non_transitional_name = "vhost-user-blk-pci-non-transitional",
|
||||
.instance_size = sizeof(VHostUserBlkPCI),
|
||||
.instance_init = vhost_user_blk_pci_instance_init,
|
||||
.class_init = vhost_user_blk_pci_class_init,
|
||||
};
|
||||
#endif
|
||||
|
||||
/* virtio-scsi-pci */
|
||||
|
||||
static Property virtio_scsi_pci_properties[] = {
|
||||
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
|
||||
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
|
||||
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
|
||||
DEV_NVECTORS_UNSPECIFIED),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void virtio_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
||||
{
|
||||
VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(vpci_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
|
||||
DeviceState *proxy = DEVICE(vpci_dev);
|
||||
char *bus_name;
|
||||
|
||||
if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
|
||||
vpci_dev->nvectors = vs->conf.num_queues + 3;
|
||||
}
|
||||
|
||||
/*
|
||||
* For command line compatibility, this sets the virtio-scsi-device bus
|
||||
* name as before.
|
||||
*/
|
||||
if (proxy->id) {
|
||||
bus_name = g_strdup_printf("%s.0", proxy->id);
|
||||
virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name);
|
||||
g_free(bus_name);
|
||||
}
|
||||
|
||||
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", errp);
|
||||
}
|
||||
|
||||
static void virtio_scsi_pci_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
|
||||
PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
|
||||
|
||||
k->realize = virtio_scsi_pci_realize;
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
||||
dc->props = virtio_scsi_pci_properties;
|
||||
pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
|
||||
pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
|
||||
pcidev_k->revision = 0x00;
|
||||
pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
|
||||
}
|
||||
|
||||
static void virtio_scsi_pci_instance_init(Object *obj)
|
||||
{
|
||||
VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(obj);
|
||||
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VIRTIO_SCSI);
|
||||
}
|
||||
|
||||
static const VirtioPCIDeviceTypeInfo virtio_scsi_pci_info = {
|
||||
.base_name = TYPE_VIRTIO_SCSI_PCI,
|
||||
.generic_name = "virtio-scsi-pci",
|
||||
.transitional_name = "virtio-scsi-pci-transitional",
|
||||
.non_transitional_name = "virtio-scsi-pci-non-transitional",
|
||||
.instance_size = sizeof(VirtIOSCSIPCI),
|
||||
.instance_init = virtio_scsi_pci_instance_init,
|
||||
.class_init = virtio_scsi_pci_class_init,
|
||||
};
|
||||
|
||||
/* vhost-scsi-pci */
|
||||
|
||||
#ifdef CONFIG_VHOST_SCSI
|
||||
static Property vhost_scsi_pci_properties[] = {
|
||||
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
|
||||
DEV_NVECTORS_UNSPECIFIED),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void vhost_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
||||
{
|
||||
VHostSCSIPCI *dev = VHOST_SCSI_PCI(vpci_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
|
||||
|
||||
if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
|
||||
vpci_dev->nvectors = vs->conf.num_queues + 3;
|
||||
}
|
||||
|
||||
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", errp);
|
||||
}
|
||||
|
||||
static void vhost_scsi_pci_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
|
||||
PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
|
||||
k->realize = vhost_scsi_pci_realize;
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
||||
dc->props = vhost_scsi_pci_properties;
|
||||
pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
|
||||
pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
|
||||
pcidev_k->revision = 0x00;
|
||||
pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
|
||||
}
|
||||
|
||||
static void vhost_scsi_pci_instance_init(Object *obj)
|
||||
{
|
||||
VHostSCSIPCI *dev = VHOST_SCSI_PCI(obj);
|
||||
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VHOST_SCSI);
|
||||
object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
|
||||
"bootindex", &error_abort);
|
||||
}
|
||||
|
||||
static const VirtioPCIDeviceTypeInfo vhost_scsi_pci_info = {
|
||||
.base_name = TYPE_VHOST_SCSI_PCI,
|
||||
.generic_name = "vhost-scsi-pci",
|
||||
.transitional_name = "vhost-scsi-pci-transitional",
|
||||
.non_transitional_name = "vhost-scsi-pci-non-transitional",
|
||||
.instance_size = sizeof(VHostSCSIPCI),
|
||||
.instance_init = vhost_scsi_pci_instance_init,
|
||||
.class_init = vhost_scsi_pci_class_init,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX)
|
||||
/* vhost-user-scsi-pci */
|
||||
static Property vhost_user_scsi_pci_properties[] = {
|
||||
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
|
||||
DEV_NVECTORS_UNSPECIFIED),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void vhost_user_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
||||
{
|
||||
VHostUserSCSIPCI *dev = VHOST_USER_SCSI_PCI(vpci_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
|
||||
|
||||
if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
|
||||
vpci_dev->nvectors = vs->conf.num_queues + 3;
|
||||
}
|
||||
|
||||
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", errp);
|
||||
}
|
||||
|
||||
static void vhost_user_scsi_pci_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
|
||||
PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
|
||||
k->realize = vhost_user_scsi_pci_realize;
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
||||
dc->props = vhost_user_scsi_pci_properties;
|
||||
pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
|
||||
pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
|
||||
pcidev_k->revision = 0x00;
|
||||
pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
|
||||
}
|
||||
|
||||
static void vhost_user_scsi_pci_instance_init(Object *obj)
|
||||
{
|
||||
VHostUserSCSIPCI *dev = VHOST_USER_SCSI_PCI(obj);
|
||||
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VHOST_USER_SCSI);
|
||||
object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
|
||||
"bootindex", &error_abort);
|
||||
}
|
||||
|
||||
static const VirtioPCIDeviceTypeInfo vhost_user_scsi_pci_info = {
|
||||
.base_name = TYPE_VHOST_USER_SCSI_PCI,
|
||||
.generic_name = "vhost-user-scsi-pci",
|
||||
.transitional_name = "vhost-user-scsi-pci-transitional",
|
||||
.non_transitional_name = "vhost-user-scsi-pci-non-transitional",
|
||||
.instance_size = sizeof(VHostUserSCSIPCI),
|
||||
.instance_init = vhost_user_scsi_pci_instance_init,
|
||||
.class_init = vhost_user_scsi_pci_class_init,
|
||||
};
|
||||
#endif
|
||||
|
||||
/* vhost-vsock-pci */
|
||||
|
||||
#ifdef CONFIG_VHOST_VSOCK
|
||||
static Property vhost_vsock_pci_properties[] = {
|
||||
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void vhost_vsock_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
||||
{
|
||||
VHostVSockPCI *dev = VHOST_VSOCK_PCI(vpci_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
|
||||
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", errp);
|
||||
}
|
||||
|
||||
static void vhost_vsock_pci_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
|
||||
PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
|
||||
k->realize = vhost_vsock_pci_realize;
|
||||
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||
dc->props = vhost_vsock_pci_properties;
|
||||
pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
|
||||
pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_VSOCK;
|
||||
pcidev_k->revision = 0x00;
|
||||
pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
|
||||
}
|
||||
|
||||
static void vhost_vsock_pci_instance_init(Object *obj)
|
||||
{
|
||||
VHostVSockPCI *dev = VHOST_VSOCK_PCI(obj);
|
||||
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VHOST_VSOCK);
|
||||
}
|
||||
|
||||
static const VirtioPCIDeviceTypeInfo vhost_vsock_pci_info = {
|
||||
.base_name = TYPE_VHOST_VSOCK_PCI,
|
||||
.generic_name = "vhost-vsock-pci",
|
||||
.transitional_name = "vhost-vsock-pci-transitional",
|
||||
.non_transitional_name = "vhost-vsock-pci-non-transitional",
|
||||
.instance_size = sizeof(VHostVSockPCI),
|
||||
.instance_init = vhost_vsock_pci_instance_init,
|
||||
.class_init = vhost_vsock_pci_class_init,
|
||||
};
|
||||
#endif
|
||||
|
||||
/* virtio-balloon-pci */
|
||||
|
||||
static Property virtio_balloon_pci_properties[] = {
|
||||
DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void virtio_balloon_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
||||
{
|
||||
VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(vpci_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
|
||||
if (vpci_dev->class_code != PCI_CLASS_OTHERS &&
|
||||
vpci_dev->class_code != PCI_CLASS_MEMORY_RAM) { /* qemu < 1.1 */
|
||||
vpci_dev->class_code = PCI_CLASS_OTHERS;
|
||||
}
|
||||
|
||||
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", errp);
|
||||
}
|
||||
|
||||
static void virtio_balloon_pci_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
|
||||
PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
|
||||
k->realize = virtio_balloon_pci_realize;
|
||||
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||
dc->props = virtio_balloon_pci_properties;
|
||||
pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
|
||||
pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON;
|
||||
pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
|
||||
pcidev_k->class_id = PCI_CLASS_OTHERS;
|
||||
}
|
||||
|
||||
static void virtio_balloon_pci_instance_init(Object *obj)
|
||||
{
|
||||
VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(obj);
|
||||
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VIRTIO_BALLOON);
|
||||
object_property_add_alias(obj, "guest-stats", OBJECT(&dev->vdev),
|
||||
"guest-stats", &error_abort);
|
||||
object_property_add_alias(obj, "guest-stats-polling-interval",
|
||||
OBJECT(&dev->vdev),
|
||||
"guest-stats-polling-interval", &error_abort);
|
||||
}
|
||||
|
||||
static const VirtioPCIDeviceTypeInfo virtio_balloon_pci_info = {
|
||||
.base_name = TYPE_VIRTIO_BALLOON_PCI,
|
||||
.generic_name = "virtio-balloon-pci",
|
||||
.transitional_name = "virtio-balloon-pci-transitional",
|
||||
.non_transitional_name = "virtio-balloon-pci-non-transitional",
|
||||
.instance_size = sizeof(VirtIOBalloonPCI),
|
||||
.instance_init = virtio_balloon_pci_instance_init,
|
||||
.class_init = virtio_balloon_pci_class_init,
|
||||
};
|
||||
|
||||
/* virtio-serial-pci */
|
||||
|
||||
static void virtio_serial_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
||||
{
|
||||
VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(vpci_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
DeviceState *proxy = DEVICE(vpci_dev);
|
||||
char *bus_name;
|
||||
|
||||
if (vpci_dev->class_code != PCI_CLASS_COMMUNICATION_OTHER &&
|
||||
vpci_dev->class_code != PCI_CLASS_DISPLAY_OTHER && /* qemu 0.10 */
|
||||
vpci_dev->class_code != PCI_CLASS_OTHERS) { /* qemu-kvm */
|
||||
vpci_dev->class_code = PCI_CLASS_COMMUNICATION_OTHER;
|
||||
}
|
||||
|
||||
/* backwards-compatibility with machines that were created with
|
||||
DEV_NVECTORS_UNSPECIFIED */
|
||||
if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
|
||||
vpci_dev->nvectors = dev->vdev.serial.max_virtserial_ports + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* For command line compatibility, this sets the virtio-serial-device bus
|
||||
* name as before.
|
||||
*/
|
||||
if (proxy->id) {
|
||||
bus_name = g_strdup_printf("%s.0", proxy->id);
|
||||
virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name);
|
||||
g_free(bus_name);
|
||||
}
|
||||
|
||||
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", errp);
|
||||
}
|
||||
|
||||
static Property virtio_serial_pci_properties[] = {
|
||||
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
|
||||
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
|
||||
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
|
||||
DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void virtio_serial_pci_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
|
||||
PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
|
||||
k->realize = virtio_serial_pci_realize;
|
||||
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
|
||||
dc->props = virtio_serial_pci_properties;
|
||||
pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
|
||||
pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE;
|
||||
pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
|
||||
pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
|
||||
}
|
||||
|
||||
static void virtio_serial_pci_instance_init(Object *obj)
|
||||
{
|
||||
VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(obj);
|
||||
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VIRTIO_SERIAL);
|
||||
}
|
||||
|
||||
static const VirtioPCIDeviceTypeInfo virtio_serial_pci_info = {
|
||||
.base_name = TYPE_VIRTIO_SERIAL_PCI,
|
||||
.generic_name = "virtio-serial-pci",
|
||||
.transitional_name = "virtio-serial-pci-transitional",
|
||||
.non_transitional_name = "virtio-serial-pci-non-transitional",
|
||||
.instance_size = sizeof(VirtIOSerialPCI),
|
||||
.instance_init = virtio_serial_pci_instance_init,
|
||||
.class_init = virtio_serial_pci_class_init,
|
||||
};
|
||||
|
||||
/* virtio-net-pci */
|
||||
|
||||
static Property virtio_net_properties[] = {
|
||||
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
|
||||
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
|
||||
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void virtio_net_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
||||
{
|
||||
DeviceState *qdev = DEVICE(vpci_dev);
|
||||
VirtIONetPCI *dev = VIRTIO_NET_PCI(vpci_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
|
||||
virtio_net_set_netclient_name(&dev->vdev, qdev->id,
|
||||
object_get_typename(OBJECT(qdev)));
|
||||
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", errp);
|
||||
}
|
||||
|
||||
static void virtio_net_pci_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||
VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass);
|
||||
|
||||
k->romfile = "efi-virtio.rom";
|
||||
k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
|
||||
k->device_id = PCI_DEVICE_ID_VIRTIO_NET;
|
||||
k->revision = VIRTIO_PCI_ABI_VERSION;
|
||||
k->class_id = PCI_CLASS_NETWORK_ETHERNET;
|
||||
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
|
||||
dc->props = virtio_net_properties;
|
||||
vpciklass->realize = virtio_net_pci_realize;
|
||||
}
|
||||
|
||||
static void virtio_net_pci_instance_init(Object *obj)
|
||||
{
|
||||
VirtIONetPCI *dev = VIRTIO_NET_PCI(obj);
|
||||
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VIRTIO_NET);
|
||||
object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
|
||||
"bootindex", &error_abort);
|
||||
}
|
||||
|
||||
static const VirtioPCIDeviceTypeInfo virtio_net_pci_info = {
|
||||
.base_name = TYPE_VIRTIO_NET_PCI,
|
||||
.generic_name = "virtio-net-pci",
|
||||
.transitional_name = "virtio-net-pci-transitional",
|
||||
.non_transitional_name = "virtio-net-pci-non-transitional",
|
||||
.instance_size = sizeof(VirtIONetPCI),
|
||||
.instance_init = virtio_net_pci_instance_init,
|
||||
.class_init = virtio_net_pci_class_init,
|
||||
};
|
||||
|
||||
/* virtio-rng-pci */
|
||||
|
||||
static void virtio_rng_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
||||
{
|
||||
VirtIORngPCI *vrng = VIRTIO_RNG_PCI(vpci_dev);
|
||||
DeviceState *vdev = DEVICE(&vrng->vdev);
|
||||
Error *err = NULL;
|
||||
|
||||
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
object_property_set_link(OBJECT(vrng),
|
||||
OBJECT(vrng->vdev.conf.rng), "rng",
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void virtio_rng_pci_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
|
||||
PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
|
||||
|
||||
k->realize = virtio_rng_pci_realize;
|
||||
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||
|
||||
pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
|
||||
pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_RNG;
|
||||
pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
|
||||
pcidev_k->class_id = PCI_CLASS_OTHERS;
|
||||
}
|
||||
|
||||
static void virtio_rng_initfn(Object *obj)
|
||||
{
|
||||
VirtIORngPCI *dev = VIRTIO_RNG_PCI(obj);
|
||||
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VIRTIO_RNG);
|
||||
}
|
||||
|
||||
static const VirtioPCIDeviceTypeInfo virtio_rng_pci_info = {
|
||||
.base_name = TYPE_VIRTIO_RNG_PCI,
|
||||
.generic_name = "virtio-rng-pci",
|
||||
.transitional_name = "virtio-rng-pci-transitional",
|
||||
.non_transitional_name = "virtio-rng-pci-non-transitional",
|
||||
.instance_size = sizeof(VirtIORngPCI),
|
||||
.instance_init = virtio_rng_initfn,
|
||||
.class_init = virtio_rng_pci_class_init,
|
||||
};
|
||||
|
||||
/* virtio-input-pci */
|
||||
|
||||
static Property virtio_input_pci_properties[] = {
|
||||
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void virtio_input_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
||||
{
|
||||
VirtIOInputPCI *vinput = VIRTIO_INPUT_PCI(vpci_dev);
|
||||
DeviceState *vdev = DEVICE(&vinput->vdev);
|
||||
|
||||
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
|
||||
virtio_pci_force_virtio_1(vpci_dev);
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", errp);
|
||||
}
|
||||
|
||||
static void virtio_input_pci_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
|
||||
PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
|
||||
|
||||
dc->props = virtio_input_pci_properties;
|
||||
k->realize = virtio_input_pci_realize;
|
||||
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
|
||||
|
||||
pcidev_k->class_id = PCI_CLASS_INPUT_OTHER;
|
||||
}
|
||||
|
||||
static void virtio_input_hid_kbd_pci_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
|
||||
|
||||
pcidev_k->class_id = PCI_CLASS_INPUT_KEYBOARD;
|
||||
}
|
||||
|
||||
static void virtio_input_hid_mouse_pci_class_init(ObjectClass *klass,
|
||||
void *data)
|
||||
{
|
||||
PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
|
||||
|
||||
pcidev_k->class_id = PCI_CLASS_INPUT_MOUSE;
|
||||
}
|
||||
|
||||
static void virtio_keyboard_initfn(Object *obj)
|
||||
{
|
||||
VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
|
||||
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VIRTIO_KEYBOARD);
|
||||
}
|
||||
|
||||
static void virtio_mouse_initfn(Object *obj)
|
||||
{
|
||||
VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
|
||||
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VIRTIO_MOUSE);
|
||||
}
|
||||
|
||||
static void virtio_tablet_initfn(Object *obj)
|
||||
{
|
||||
VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
|
||||
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VIRTIO_TABLET);
|
||||
}
|
||||
|
||||
static const TypeInfo virtio_input_pci_info = {
|
||||
.name = TYPE_VIRTIO_INPUT_PCI,
|
||||
.parent = TYPE_VIRTIO_PCI,
|
||||
.instance_size = sizeof(VirtIOInputPCI),
|
||||
.class_init = virtio_input_pci_class_init,
|
||||
.abstract = true,
|
||||
};
|
||||
|
||||
static const TypeInfo virtio_input_hid_pci_info = {
|
||||
.name = TYPE_VIRTIO_INPUT_HID_PCI,
|
||||
.parent = TYPE_VIRTIO_INPUT_PCI,
|
||||
.instance_size = sizeof(VirtIOInputHIDPCI),
|
||||
.abstract = true,
|
||||
};
|
||||
|
||||
static const VirtioPCIDeviceTypeInfo virtio_keyboard_pci_info = {
|
||||
.generic_name = TYPE_VIRTIO_KEYBOARD_PCI,
|
||||
.parent = TYPE_VIRTIO_INPUT_HID_PCI,
|
||||
.class_init = virtio_input_hid_kbd_pci_class_init,
|
||||
.instance_size = sizeof(VirtIOInputHIDPCI),
|
||||
.instance_init = virtio_keyboard_initfn,
|
||||
};
|
||||
|
||||
static const VirtioPCIDeviceTypeInfo virtio_mouse_pci_info = {
|
||||
.generic_name = TYPE_VIRTIO_MOUSE_PCI,
|
||||
.parent = TYPE_VIRTIO_INPUT_HID_PCI,
|
||||
.class_init = virtio_input_hid_mouse_pci_class_init,
|
||||
.instance_size = sizeof(VirtIOInputHIDPCI),
|
||||
.instance_init = virtio_mouse_initfn,
|
||||
};
|
||||
|
||||
static const VirtioPCIDeviceTypeInfo virtio_tablet_pci_info = {
|
||||
.generic_name = TYPE_VIRTIO_TABLET_PCI,
|
||||
.parent = TYPE_VIRTIO_INPUT_HID_PCI,
|
||||
.instance_size = sizeof(VirtIOInputHIDPCI),
|
||||
.instance_init = virtio_tablet_initfn,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_LINUX
|
||||
static void virtio_host_initfn(Object *obj)
|
||||
{
|
||||
VirtIOInputHostPCI *dev = VIRTIO_INPUT_HOST_PCI(obj);
|
||||
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VIRTIO_INPUT_HOST);
|
||||
}
|
||||
|
||||
static const VirtioPCIDeviceTypeInfo virtio_host_pci_info = {
|
||||
.base_name = TYPE_VIRTIO_INPUT_HOST_PCI,
|
||||
.generic_name = "virtio-input-host-pci",
|
||||
.transitional_name = "virtio-input-host-pci-transitional",
|
||||
.non_transitional_name = "virtio-input-host-pci-non-transitional",
|
||||
.parent = TYPE_VIRTIO_INPUT_PCI,
|
||||
.instance_size = sizeof(VirtIOInputHostPCI),
|
||||
.instance_init = virtio_host_initfn,
|
||||
};
|
||||
#endif
|
||||
|
||||
/* virtio-pci-bus */
|
||||
|
||||
static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
|
||||
@ -2827,37 +2048,7 @@ static void virtio_pci_register_types(void)
|
||||
/* Base types: */
|
||||
type_register_static(&virtio_pci_bus_info);
|
||||
type_register_static(&virtio_pci_info);
|
||||
type_register_static(&virtio_input_pci_info);
|
||||
type_register_static(&virtio_input_hid_pci_info);
|
||||
|
||||
/* Implementations: */
|
||||
virtio_pci_types_register(&virtio_rng_pci_info);
|
||||
virtio_pci_types_register(&virtio_keyboard_pci_info);
|
||||
virtio_pci_types_register(&virtio_mouse_pci_info);
|
||||
virtio_pci_types_register(&virtio_tablet_pci_info);
|
||||
#ifdef CONFIG_LINUX
|
||||
virtio_pci_types_register(&virtio_host_pci_info);
|
||||
#endif
|
||||
#ifdef CONFIG_VIRTFS
|
||||
virtio_pci_types_register(&virtio_9p_pci_info);
|
||||
#endif
|
||||
virtio_pci_types_register(&virtio_blk_pci_info);
|
||||
#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX)
|
||||
virtio_pci_types_register(&vhost_user_blk_pci_info);
|
||||
#endif
|
||||
virtio_pci_types_register(&virtio_scsi_pci_info);
|
||||
virtio_pci_types_register(&virtio_balloon_pci_info);
|
||||
virtio_pci_types_register(&virtio_serial_pci_info);
|
||||
virtio_pci_types_register(&virtio_net_pci_info);
|
||||
#ifdef CONFIG_VHOST_SCSI
|
||||
virtio_pci_types_register(&vhost_scsi_pci_info);
|
||||
#endif
|
||||
#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX)
|
||||
virtio_pci_types_register(&vhost_user_scsi_pci_info);
|
||||
#endif
|
||||
#ifdef CONFIG_VHOST_VSOCK
|
||||
virtio_pci_types_register(&vhost_vsock_pci_info);
|
||||
#endif
|
||||
}
|
||||
|
||||
type_init(virtio_pci_register_types)
|
||||
|
||||
|
@ -16,47 +16,9 @@
|
||||
#define QEMU_VIRTIO_PCI_H
|
||||
|
||||
#include "hw/pci/msi.h"
|
||||
#include "hw/virtio/virtio-blk.h"
|
||||
#include "hw/virtio/virtio-net.h"
|
||||
#include "hw/virtio/virtio-rng.h"
|
||||
#include "hw/virtio/virtio-serial.h"
|
||||
#include "hw/virtio/virtio-scsi.h"
|
||||
#include "hw/virtio/virtio-balloon.h"
|
||||
#include "hw/virtio/virtio-bus.h"
|
||||
#include "hw/virtio/virtio-input.h"
|
||||
#include "hw/virtio/virtio-gpu.h"
|
||||
#include "hw/virtio/virtio-crypto.h"
|
||||
#include "hw/virtio/vhost-user-scsi.h"
|
||||
#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX)
|
||||
#include "hw/virtio/vhost-user-blk.h"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_VIRTFS
|
||||
#include "hw/9pfs/virtio-9p.h"
|
||||
#endif
|
||||
#ifdef CONFIG_VHOST_SCSI
|
||||
#include "hw/virtio/vhost-scsi.h"
|
||||
#endif
|
||||
#ifdef CONFIG_VHOST_VSOCK
|
||||
#include "hw/virtio/vhost-vsock.h"
|
||||
#endif
|
||||
|
||||
typedef struct VirtIOPCIProxy VirtIOPCIProxy;
|
||||
typedef struct VirtIOBlkPCI VirtIOBlkPCI;
|
||||
typedef struct VirtIOSCSIPCI VirtIOSCSIPCI;
|
||||
typedef struct VirtIOBalloonPCI VirtIOBalloonPCI;
|
||||
typedef struct VirtIOSerialPCI VirtIOSerialPCI;
|
||||
typedef struct VirtIONetPCI VirtIONetPCI;
|
||||
typedef struct VHostSCSIPCI VHostSCSIPCI;
|
||||
typedef struct VHostUserSCSIPCI VHostUserSCSIPCI;
|
||||
typedef struct VHostUserBlkPCI VHostUserBlkPCI;
|
||||
typedef struct VirtIORngPCI VirtIORngPCI;
|
||||
typedef struct VirtIOInputPCI VirtIOInputPCI;
|
||||
typedef struct VirtIOInputHIDPCI VirtIOInputHIDPCI;
|
||||
typedef struct VirtIOInputHostPCI VirtIOInputHostPCI;
|
||||
typedef struct VirtIOGPUPCI VirtIOGPUPCI;
|
||||
typedef struct VHostVSockPCI VHostVSockPCI;
|
||||
typedef struct VirtIOCryptoPCI VirtIOCryptoPCI;
|
||||
|
||||
/* virtio-pci-bus */
|
||||
|
||||
@ -213,206 +175,10 @@ static inline void virtio_pci_disable_modern(VirtIOPCIProxy *proxy)
|
||||
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.
|
||||
*/
|
||||
#define TYPE_VIRTIO_INPUT_PCI "virtio-input-pci"
|
||||
#define VIRTIO_INPUT_PCI(obj) \
|
||||
OBJECT_CHECK(VirtIOInputPCI, (obj), TYPE_VIRTIO_INPUT_PCI)
|
||||
|
||||
struct VirtIOInputPCI {
|
||||
VirtIOPCIProxy parent_obj;
|
||||
VirtIOInput vdev;
|
||||
};
|
||||
|
||||
#define TYPE_VIRTIO_INPUT_HID_PCI "virtio-input-hid-pci"
|
||||
#define TYPE_VIRTIO_KEYBOARD_PCI "virtio-keyboard-pci"
|
||||
#define TYPE_VIRTIO_MOUSE_PCI "virtio-mouse-pci"
|
||||
#define TYPE_VIRTIO_TABLET_PCI "virtio-tablet-pci"
|
||||
#define VIRTIO_INPUT_HID_PCI(obj) \
|
||||
OBJECT_CHECK(VirtIOInputHIDPCI, (obj), TYPE_VIRTIO_INPUT_HID_PCI)
|
||||
|
||||
struct VirtIOInputHIDPCI {
|
||||
VirtIOPCIProxy parent_obj;
|
||||
VirtIOInputHID vdev;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_LINUX
|
||||
|
||||
#define TYPE_VIRTIO_INPUT_HOST_PCI "virtio-input-host-pci-base"
|
||||
#define VIRTIO_INPUT_HOST_PCI(obj) \
|
||||
OBJECT_CHECK(VirtIOInputHostPCI, (obj), TYPE_VIRTIO_INPUT_HOST_PCI)
|
||||
|
||||
struct VirtIOInputHostPCI {
|
||||
VirtIOPCIProxy parent_obj;
|
||||
VirtIOInputHost vdev;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* virtio-gpu-pci: This extends VirtioPCIProxy.
|
||||
*/
|
||||
#define TYPE_VIRTIO_GPU_PCI "virtio-gpu-pci"
|
||||
#define VIRTIO_GPU_PCI(obj) \
|
||||
OBJECT_CHECK(VirtIOGPUPCI, (obj), TYPE_VIRTIO_GPU_PCI)
|
||||
|
||||
struct VirtIOGPUPCI {
|
||||
VirtIOPCIProxy parent_obj;
|
||||
VirtIOGPU vdev;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_VHOST_VSOCK
|
||||
/*
|
||||
* vhost-vsock-pci: This extends VirtioPCIProxy.
|
||||
*/
|
||||
#define TYPE_VHOST_VSOCK_PCI "vhost-vsock-pci-base"
|
||||
#define VHOST_VSOCK_PCI(obj) \
|
||||
OBJECT_CHECK(VHostVSockPCI, (obj), TYPE_VHOST_VSOCK_PCI)
|
||||
|
||||
struct VHostVSockPCI {
|
||||
VirtIOPCIProxy parent_obj;
|
||||
VHostVSock vdev;
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* virtio-crypto-pci: This extends VirtioPCIProxy.
|
||||
*/
|
||||
#define TYPE_VIRTIO_CRYPTO_PCI "virtio-crypto-pci"
|
||||
#define VIRTIO_CRYPTO_PCI(obj) \
|
||||
OBJECT_CHECK(VirtIOCryptoPCI, (obj), TYPE_VIRTIO_CRYPTO_PCI)
|
||||
|
||||
struct VirtIOCryptoPCI {
|
||||
VirtIOPCIProxy parent_obj;
|
||||
VirtIOCrypto vdev;
|
||||
};
|
||||
|
||||
/* Virtio ABI version, if we increment this, we break the guest driver. */
|
||||
#define VIRTIO_PCI_ABI_VERSION 0
|
||||
|
88
hw/virtio/virtio-rng-pci.c
Normal file
88
hw/virtio/virtio-rng-pci.c
Normal 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
107
hw/virtio/virtio-scsi-pci.c
Normal 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)
|
115
hw/virtio/virtio-serial-pci.c
Normal file
115
hw/virtio/virtio-serial-pci.c
Normal 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)
|
@ -41,8 +41,8 @@ enum {
|
||||
};
|
||||
|
||||
typedef struct AcpiRsdpData {
|
||||
uint8_t oem_id[6]; /* OEM identification */
|
||||
uint8_t revision; /* Must be 0 for 1.0, 2 for 2.0 */
|
||||
uint8_t oem_id[6] QEMU_NONSTRING; /* OEM identification */
|
||||
uint8_t revision; /* Must be 0 for 1.0, 2 for 2.0 */
|
||||
|
||||
unsigned *rsdt_tbl_offset;
|
||||
unsigned *xsdt_tbl_offset;
|
||||
@ -57,10 +57,13 @@ typedef struct AcpiRsdpData {
|
||||
uint32_t length; /* Length of table, in bytes, including header */ \
|
||||
uint8_t revision; /* ACPI Specification minor version # */ \
|
||||
uint8_t checksum; /* To make sum of entire table == 0 */ \
|
||||
uint8_t oem_id [6]; /* OEM identification */ \
|
||||
uint8_t oem_table_id [8]; /* OEM table identification */ \
|
||||
uint8_t oem_id[6] \
|
||||
QEMU_NONSTRING; /* OEM identification */ \
|
||||
uint8_t oem_table_id[8] \
|
||||
QEMU_NONSTRING; /* OEM table identification */ \
|
||||
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 */
|
||||
|
||||
|
||||
|
@ -18,6 +18,8 @@
|
||||
|
||||
#include "qemu/units.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_SIZE 0x5000
|
||||
@ -188,4 +190,23 @@ REG32(CRB_DATA_BUFFER, 0x80)
|
||||
#define TPM2_START_METHOD_MMIO 6
|
||||
#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 */
|
||||
|
@ -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_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,
|
||||
Error **errp);
|
||||
void pcie_cap_slot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||
|
@ -250,6 +250,8 @@ struct PropertyInfo {
|
||||
/**
|
||||
* GlobalProperty:
|
||||
* @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.
|
||||
*/
|
||||
@ -258,6 +260,7 @@ typedef struct GlobalProperty {
|
||||
const char *property;
|
||||
const char *value;
|
||||
bool used;
|
||||
bool optional;
|
||||
} GlobalProperty;
|
||||
|
||||
static inline void
|
||||
|
@ -44,6 +44,83 @@ typedef struct virtio_net_conf
|
||||
uint8_t duplex;
|
||||
} 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 */
|
||||
#define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 * KiB))
|
||||
|
||||
@ -66,12 +143,18 @@ typedef struct VirtIONet {
|
||||
VirtIONetQueue *vqs;
|
||||
VirtQueue *ctrl_vq;
|
||||
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;
|
||||
int32_t tx_burst;
|
||||
uint32_t has_vnet_hdr;
|
||||
size_t host_hdr_len;
|
||||
size_t guest_hdr_len;
|
||||
uint64_t host_features;
|
||||
uint32_t rsc_timeout;
|
||||
uint8_t rsc4_enabled;
|
||||
uint8_t rsc6_enabled;
|
||||
uint8_t has_ufo;
|
||||
uint32_t mergeable_rx_bufs;
|
||||
uint8_t promisc;
|
||||
|
@ -177,6 +177,8 @@ struct tcp_hdr {
|
||||
#define TH_PUSH 0x08
|
||||
#define TH_ACK 0x10
|
||||
#define TH_URG 0x20
|
||||
#define TH_ECE 0x40
|
||||
#define TH_CWR 0x80
|
||||
u_short th_win; /* window */
|
||||
u_short th_sum; /* checksum */
|
||||
u_short th_urp; /* urgent pointer */
|
||||
|
@ -151,6 +151,21 @@
|
||||
# define QEMU_ERROR(X)
|
||||
#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:
|
||||
*
|
||||
* QEMU_GENERIC(x, (float, sinf), (long double, sinl), sin) (x)
|
||||
|
@ -42,6 +42,7 @@ int global_state_store(void)
|
||||
void global_state_store_running(void)
|
||||
{
|
||||
const char *state = RunState_str(RUN_STATE_RUNNING);
|
||||
assert(strlen(state) < sizeof(global_state.runstate));
|
||||
strncpy((char *)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;
|
||||
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);
|
||||
|
||||
if (r == -1) {
|
||||
@ -106,7 +118,8 @@ static int global_state_pre_save(void *opaque)
|
||||
GlobalState *s = opaque;
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -126,11 +126,6 @@ documentation of ``query-hotpluggable-cpus'' for additional details.
|
||||
|
||||
@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)
|
||||
|
||||
The bluetooth subsystem is unmaintained since many years and likely bitrotten
|
||||
|
@ -385,6 +385,9 @@ void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp
|
||||
if (object_dynamic_cast(obj, p->driver) == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (p->optional && !object_property_find(obj, p->property, NULL)) {
|
||||
continue;
|
||||
}
|
||||
p->used = true;
|
||||
object_property_parse(obj, p->value, p->property, &err);
|
||||
if (err != NULL) {
|
||||
|
@ -83,7 +83,6 @@ ERROR_WHITELIST = [
|
||||
{'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-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-plain', 'expected':True}, # You must specify a 'memdev'
|
||||
{'device':'loader', 'expected':True}, # please include valid arguments
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/qapi-commands-tpm.h"
|
||||
#include "sysemu/tpm.h"
|
||||
#include "hw/acpi/tpm.h"
|
||||
|
||||
void tpm_init(void)
|
||||
{
|
||||
@ -31,3 +32,7 @@ TpmModelList *qmp_query_tpm_models(Error **errp)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void tpm_build_ppi_acpi(TPMIf *tpm, Aml *dev)
|
||||
{
|
||||
}
|
||||
|
@ -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-tlssession$(EXESUF)
|
||||
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
|
||||
check-unit-y += tests/test-timed-average$(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-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-y += tests/virtio-balloon-test$(EXESUF)
|
||||
check-qtest-virtio-y += tests/virtio-blk-test$(EXESUF)
|
||||
check-qtest-virtio-y += tests/virtio-rng-test$(EXESUF)
|
||||
check-qtest-virtio-y += tests/virtio-scsi-test$(EXESUF)
|
||||
check-qtest-virtio-$(CONFIG_VIRTIO_NET) += tests/virtio-net-test$(EXESUF)
|
||||
check-qtest-virtio-$(CONFIG_VIRTIO_BALLOON) += tests/virtio-balloon-test$(EXESUF)
|
||||
check-qtest-virtio-$(CONFIG_VIRTIO_BLK) += tests/virtio-blk-test$(EXESUF)
|
||||
check-qtest-virtio-$(CONFIG_VIRTIO_RNG) += tests/virtio-rng-test$(EXESUF)
|
||||
check-qtest-virtio-$(CONFIG_VIRTIO_SCSI) += tests/virtio-scsi-test$(EXESUF)
|
||||
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
|
||||
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-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/microbit-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/boot-serial-test$(EXESUF)
|
||||
check-qtest-arm-$(CONFIG_SDHCI) += tests/sdhci-test$(EXESUF)
|
||||
|
@ -51,14 +51,6 @@ uint32_t acpi_find_rsdp_address(QTestState *qts)
|
||||
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 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_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));
|
||||
}
|
||||
}
|
||||
|
@ -13,14 +13,12 @@
|
||||
#ifndef TEST_ACPI_UTILS_H
|
||||
#define TEST_ACPI_UTILS_H
|
||||
|
||||
#include "hw/acpi/acpi-defs.h"
|
||||
#include "libqtest.h"
|
||||
|
||||
/* DSDT and SSDTs format */
|
||||
typedef struct {
|
||||
AcpiTableHeader header;
|
||||
gchar *aml; /* aml bytecode from guest */
|
||||
gsize aml_len;
|
||||
uint8_t *aml; /* aml bytecode from guest */
|
||||
uint32_t aml_len;
|
||||
gchar *aml_file;
|
||||
gchar *asl; /* asl code generated from aml */
|
||||
gsize asl_len;
|
||||
@ -28,36 +26,6 @@ typedef struct {
|
||||
bool tmp_files_retain; /* do not delete the temp asl/aml */
|
||||
} 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 { \
|
||||
char ACPI_ASSERT_CMP_str[5] = {}; \
|
||||
memcpy(ACPI_ASSERT_CMP_str, &actual, 4); \
|
||||
@ -71,11 +39,17 @@ typedef struct {
|
||||
} 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);
|
||||
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);
|
||||
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 */
|
||||
|
@ -28,12 +28,6 @@ typedef struct {
|
||||
const char *variant;
|
||||
uint32_t rsdp_addr;
|
||||
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;
|
||||
uint32_t smbios_ep_addr;
|
||||
struct smbios_21_entry_point smbios_ep_table;
|
||||
@ -50,28 +44,34 @@ static const char *iasl = stringify(CONFIG_IASL);
|
||||
static const char *iasl;
|
||||
#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)
|
||||
{
|
||||
AcpiSdtTable *temp;
|
||||
int i;
|
||||
|
||||
g_free(data->rsdt_tables_addr);
|
||||
|
||||
for (i = 0; i < data->tables->len; ++i) {
|
||||
temp = &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);
|
||||
cleanup_table_descriptor(&g_array_index(data->tables, AcpiSdtTable, i));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
AcpiRsdtDescriptorRev1 *rsdt_table = &data->rsdt_table;
|
||||
uint32_t addr = acpi_get_rsdt_address(data->rsdp_table);
|
||||
uint32_t *tables;
|
||||
int tables_nr;
|
||||
uint8_t checksum;
|
||||
uint32_t rsdt_table_length;
|
||||
AcpiSdtTable rsdt = {};
|
||||
uint8_t *ent;
|
||||
|
||||
/* read the header */
|
||||
ACPI_READ_TABLE_HEADER(data->qts, rsdt_table, addr);
|
||||
ACPI_ASSERT_CMP(rsdt_table->signature, "RSDT");
|
||||
/* read RSDT table */
|
||||
acpi_fetch_table(data->qts, &rsdt.aml, &rsdt.aml_len,
|
||||
&data->rsdp_table[16 /* RsdtAddress */], "RSDT", true);
|
||||
|
||||
rsdt_table_length = le32_to_cpu(rsdt_table->length);
|
||||
|
||||
/* compute the table entries in rsdt */
|
||||
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);
|
||||
/* 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 */) {
|
||||
AcpiSdtTable ssdt_table = {};
|
||||
|
||||
acpi_fetch_table(data->qts, &ssdt_table.aml, &ssdt_table.aml_len, ent,
|
||||
NULL, true);
|
||||
/* Add table to ASL test tables list */
|
||||
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)
|
||||
@ -275,7 +174,7 @@ static void dump_aml_files(test_data *data, bool rebuild)
|
||||
|
||||
if (rebuild) {
|
||||
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,
|
||||
S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
|
||||
} else {
|
||||
@ -284,8 +183,6 @@ static void dump_aml_files(test_data *data, bool rebuild)
|
||||
}
|
||||
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);
|
||||
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)
|
||||
{
|
||||
AcpiSdtTable *temp;
|
||||
@ -382,6 +274,7 @@ static GArray *load_expected_aml(test_data *data)
|
||||
AcpiSdtTable *sdt;
|
||||
GError *error = NULL;
|
||||
gboolean ret;
|
||||
gsize aml_len;
|
||||
|
||||
GArray *exp_tables = g_array_new(false, true, sizeof(AcpiSdtTable));
|
||||
if (getenv("V")) {
|
||||
@ -395,11 +288,10 @@ static GArray *load_expected_aml(test_data *data)
|
||||
sdt = &g_array_index(data->tables, AcpiSdtTable, i);
|
||||
|
||||
memset(&exp_sdt, 0, sizeof(exp_sdt));
|
||||
exp_sdt.header.signature = sdt->header.signature;
|
||||
|
||||
try_again:
|
||||
aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, data->machine,
|
||||
(gchar *)&sdt->header.signature, ext);
|
||||
sdt->aml, ext);
|
||||
if (getenv("V")) {
|
||||
fprintf(stderr, "Looking for expected file '%s'\n", aml_file);
|
||||
}
|
||||
@ -415,8 +307,9 @@ try_again:
|
||||
if (getenv("V")) {
|
||||
fprintf(stderr, "Using expected file '%s'\n", aml_file);
|
||||
}
|
||||
ret = g_file_get_contents(aml_file, &exp_sdt.aml,
|
||||
&exp_sdt.aml_len, &error);
|
||||
ret = g_file_get_contents(aml_file, (gchar **)&exp_sdt.aml,
|
||||
&aml_len, &error);
|
||||
exp_sdt.aml_len = aml_len;
|
||||
g_assert(ret);
|
||||
g_assert_no_error(error);
|
||||
g_assert(exp_sdt.aml);
|
||||
@ -459,14 +352,12 @@ static void test_acpi_asl(test_data *data)
|
||||
fprintf(stderr,
|
||||
"Warning! iasl couldn't parse the expected aml\n");
|
||||
} else {
|
||||
uint32_t signature = cpu_to_le32(exp_sdt->header.signature);
|
||||
sdt->tmp_files_retain = true;
|
||||
exp_sdt->tmp_files_retain = true;
|
||||
fprintf(stderr,
|
||||
"acpi-test: Warning! %.4s mismatch. "
|
||||
"Actual [asl:%s, aml:%s], Expected [asl:%s, aml:%s].\n",
|
||||
(gchar *)&signature,
|
||||
sdt->asl_file, sdt->aml_file,
|
||||
exp_sdt->aml, sdt->asl_file, sdt->aml_file,
|
||||
exp_sdt->asl_file, exp_sdt->aml_file);
|
||||
if (getenv("V")) {
|
||||
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;
|
||||
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)) {
|
||||
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)) {
|
||||
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) {
|
||||
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) {
|
||||
return false;
|
||||
}
|
||||
ACPI_READ_FIELD(data->qts, ep_table->smbios_bcd_revision, addr);
|
||||
if (acpi_calc_checksum((uint8_t *)ep_table, sizeof *ep_table) ||
|
||||
acpi_calc_checksum((uint8_t *)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_table(data);
|
||||
test_acpi_rsdt_table(data);
|
||||
fadt_fetch_facs_and_dsdt_ptrs(data);
|
||||
test_acpi_facs_table(data);
|
||||
test_acpi_dsdt_table(data);
|
||||
fetch_rsdt_referenced_tables(data);
|
||||
|
||||
sanitize_fadt_ptrs(data);
|
||||
test_acpi_fadt_table(data);
|
||||
|
||||
if (iasl) {
|
||||
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.
@ -291,20 +291,20 @@ static void *server_thread(void *data)
|
||||
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 "
|
||||
"-device ivshmem%s,chardev=chr0,vectors=%d",
|
||||
tmpserver,
|
||||
msi ? "-doorbell" : ",size=1M,msi=off",
|
||||
nvectors);
|
||||
char *cmd;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void test_ivshmem_server(bool msi)
|
||||
static void test_ivshmem_server(void)
|
||||
{
|
||||
IVState state1, state2, *s1, *s2;
|
||||
ServerThread thread;
|
||||
@ -327,9 +327,9 @@ static void test_ivshmem_server(bool msi)
|
||||
thread.thread = g_thread_new("ivshmem-server", server_thread, &thread);
|
||||
g_assert(thread.thread != NULL);
|
||||
|
||||
setup_vm_with_server(&state1, nvectors, msi);
|
||||
setup_vm_with_server(&state1, nvectors);
|
||||
s1 = &state1;
|
||||
setup_vm_with_server(&state2, nvectors, msi);
|
||||
setup_vm_with_server(&state2, nvectors);
|
||||
s2 = &state2;
|
||||
|
||||
/* check got different VM ids */
|
||||
@ -340,38 +340,28 @@ static void test_ivshmem_server(bool msi)
|
||||
g_assert_cmpint(vm1, !=, vm2);
|
||||
|
||||
/* check number of MSI-X vectors */
|
||||
if (msi) {
|
||||
ret = qpci_msix_table_size(s1->dev);
|
||||
g_assert_cmpuint(ret, ==, nvectors);
|
||||
}
|
||||
ret = qpci_msix_table_size(s1->dev);
|
||||
g_assert_cmpuint(ret, ==, nvectors);
|
||||
|
||||
/* TODO test behavior before MSI-X is enabled */
|
||||
|
||||
/* ping vm2 -> vm1 on vector 0 */
|
||||
if (msi) {
|
||||
ret = qpci_msix_pending(s1->dev, 0);
|
||||
g_assert_cmpuint(ret, ==, 0);
|
||||
} else {
|
||||
g_assert_cmpuint(in_reg(s1, INTRSTATUS), ==, 0);
|
||||
}
|
||||
ret = qpci_msix_pending(s1->dev, 0);
|
||||
g_assert_cmpuint(ret, ==, 0);
|
||||
out_reg(s2, DOORBELL, vm1 << 16);
|
||||
do {
|
||||
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);
|
||||
g_assert_cmpuint(ret, !=, 0);
|
||||
|
||||
/* ping vm1 -> vm2 on vector 1 */
|
||||
if (msi) {
|
||||
ret = qpci_msix_pending(s2->dev, 1);
|
||||
g_assert_cmpuint(ret, ==, 0);
|
||||
} else {
|
||||
g_assert_cmpuint(in_reg(s2, INTRSTATUS), ==, 0);
|
||||
}
|
||||
ret = qpci_msix_pending(s2->dev, 1);
|
||||
g_assert_cmpuint(ret, ==, 0);
|
||||
out_reg(s1, DOORBELL, vm2 << 16 | 1);
|
||||
do {
|
||||
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);
|
||||
g_assert_cmpuint(ret, !=, 0);
|
||||
|
||||
@ -389,27 +379,17 @@ static void test_ivshmem_server(bool msi)
|
||||
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
|
||||
|
||||
static void test_ivshmem_hotplug(void)
|
||||
{
|
||||
const char *arch = qtest_get_arch();
|
||||
|
||||
qtest_start("");
|
||||
qtest_start("-object memory-backend-ram,size=1M,id=mb1");
|
||||
|
||||
qtest_qmp_device_add("ivshmem",
|
||||
"iv1", "{'addr': %s, 'shm': %s, 'size': '1M'}",
|
||||
stringify(PCI_SLOT_HP), tmpshm);
|
||||
qtest_qmp_device_add("ivshmem-plain", "iv1",
|
||||
"{'addr': %s, 'memdev': 'mb1'}",
|
||||
stringify(PCI_SLOT_HP));
|
||||
if (strcmp(arch, "ppc64") != 0) {
|
||||
qpci_unplug_acpi_device_test("iv1", PCI_SLOT_HP);
|
||||
}
|
||||
@ -509,8 +489,7 @@ int main(int argc, char **argv)
|
||||
if (g_test_slow()) {
|
||||
qtest_add_func("/ivshmem/pair", test_ivshmem_pair);
|
||||
if (strcmp(arch, "ppc64") != 0) {
|
||||
qtest_add_func("/ivshmem/server-msi", test_ivshmem_server_msi);
|
||||
qtest_add_func("/ivshmem/server-irq", test_ivshmem_server_irq);
|
||||
qtest_add_func("/ivshmem/server", test_ivshmem_server);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -309,7 +309,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
|
||||
CharBackend *chr = &s->chr;
|
||||
VhostUserMsg msg;
|
||||
uint8_t *p = (uint8_t *) &msg;
|
||||
int fd;
|
||||
int fd = -1;
|
||||
|
||||
if (s->test_fail) {
|
||||
qemu_chr_fe_disconnect(chr);
|
||||
|
@ -23,26 +23,13 @@
|
||||
*/
|
||||
#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)
|
||||
{
|
||||
uint32_t rsdp_offset;
|
||||
uint32_t guid_offset = 0;
|
||||
uint8_t rsdp_table[36 /* ACPI 2.0+ RSDP size */];
|
||||
uint32_t rsdt, rsdt_table_length;
|
||||
AcpiRsdtDescriptorRev1 rsdt_table;
|
||||
size_t tables_nr;
|
||||
uint32_t *tables;
|
||||
AcpiTableHeader ssdt_table;
|
||||
VgidTable vgid_table;
|
||||
int i;
|
||||
uint32_t rsdt_len, table_length;
|
||||
uint8_t *rsdt, *ent;
|
||||
|
||||
/* Wait for guest firmware to finish and start the payload. */
|
||||
boot_sector_test(qts);
|
||||
@ -52,48 +39,37 @@ static uint32_t acpi_find_vgia(QTestState *qts)
|
||||
|
||||
g_assert_cmphex(rsdp_offset, <, RSDP_ADDR_INVALID);
|
||||
|
||||
|
||||
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);
|
||||
g_assert(rsdt);
|
||||
ACPI_FOREACH_RSDT_ENTRY(rsdt, rsdt_len, ent, 4 /* Entry size */) {
|
||||
uint8_t *table_aml;
|
||||
|
||||
/* read the header */
|
||||
ACPI_READ_TABLE_HEADER(qts, &rsdt_table, rsdt);
|
||||
ACPI_ASSERT_CMP(rsdt_table.signature, "RSDT");
|
||||
rsdt_table_length = le32_to_cpu(rsdt_table.length);
|
||||
|
||||
/* 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)) {
|
||||
acpi_fetch_table(qts, &table_aml, &table_length, ent, NULL, true);
|
||||
if (!memcmp(table_aml + 16 /* OEM Table ID */, "VMGENID", 7)) {
|
||||
uint32_t vgia_val;
|
||||
uint8_t *aml = &table_aml[36 /* AML byte-code start */];
|
||||
/* the first entry in the table should be VGIA
|
||||
* That's all we need
|
||||
*/
|
||||
ACPI_READ_FIELD(qts, vgid_table.name_op, addr);
|
||||
g_assert(vgid_table.name_op == 0x08); /* name */
|
||||
ACPI_READ_ARRAY(qts, vgid_table.vgia, addr);
|
||||
g_assert(memcmp(vgid_table.vgia, "VGIA", 4) == 0);
|
||||
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);
|
||||
g_assert(aml[0 /* name_op*/] == 0x08);
|
||||
g_assert(memcmp(&aml[1 /* name */], "VGIA", 4) == 0);
|
||||
g_assert(aml[5 /* value op */] == 0x0C /* dword */);
|
||||
memcpy(&vgia_val, &aml[6 /* value */], 4);
|
||||
|
||||
/* The GUID is written at a fixed offset into the fw_cfg file
|
||||
* in order to implement the "OVMF SDT Header probe suppressor"
|
||||
* 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;
|
||||
}
|
||||
g_free(table_aml);
|
||||
}
|
||||
g_free(tables);
|
||||
g_free(rsdt);
|
||||
return guid_offset;
|
||||
}
|
||||
|
||||
|
@ -233,14 +233,18 @@ void qemu_set_block(int fd)
|
||||
{
|
||||
int f;
|
||||
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)
|
||||
{
|
||||
int f;
|
||||
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)
|
||||
|
Loading…
Reference in New Issue
Block a user