mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging
pc, pci, virtio: features, fixes, cleanups A bunch of fixes, cleanus and new features all over the place. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # gpg: Signature made Thu 18 Jan 2018 20:41:03 GMT # gpg: using RSA key 0x281F0DB8D28D5469 # 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: (29 commits) vhost: remove assertion to prevent crash vhost-user: fix misaligned access to payload vhost-user: factor out msg head and payload tests: acpi: add comments to fetch_rsdt_referenced_tables/data->tables usage tests: acpi: rename test_acpi_tables()/test_dst_table() to reflect its usage tests: acpi: init table descriptor in test_dst_table() tests: acpi: move tested tables array allocation outside of test_acpi_dsdt_table() x86_iommu: check if machine has PCI bus x86_iommu: Move machine check to x86_iommu_realize() vhost-user-test: use init_virtio_dev in multiqueue test vhost-user-test: make features mask an init_virtio_dev() argument vhost-user-test: setup virtqueues in all tests vhost-user-test: extract read-guest-mem test from main loop vhost-user-test: fix features mask hw/acpi-build: Make next_base easy to follow ACPI/unit-test: Add a testcase for RAM allocation in numa node hw/pci-bridge: fix QEMU crash because of pcie-root-port intel-iommu: Extend address width to 48 bits intel-iommu: Redefine macros to enable supporting 48 bit address width vhost-user: fix multiple queue specification ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -54,6 +54,7 @@
|
||||
/module_block.h
|
||||
/scsi/qemu-pr-helper
|
||||
/vhost-user-scsi
|
||||
/vhost-user-blk
|
||||
/fsdev/virtfs-proxy-helper
|
||||
*.tmp
|
||||
*.[1-9]
|
||||
|
||||
@@ -852,6 +852,7 @@ X86 Machines
|
||||
------------
|
||||
PC
|
||||
M: Michael S. Tsirkin <mst@redhat.com>
|
||||
M: Marcel Apfelbaum <marcel@redhat.com>
|
||||
S: Supported
|
||||
F: include/hw/i386/
|
||||
F: hw/i386/
|
||||
|
||||
@@ -334,6 +334,7 @@ dummy := $(call unnest-vars,, \
|
||||
ivshmem-server-obj-y \
|
||||
libvhost-user-obj-y \
|
||||
vhost-user-scsi-obj-y \
|
||||
vhost-user-blk-obj-y \
|
||||
qga-vss-dll-obj-y \
|
||||
block-obj-y \
|
||||
block-obj-m \
|
||||
@@ -565,6 +566,8 @@ ivshmem-server$(EXESUF): $(ivshmem-server-obj-y) $(COMMON_LDADDS)
|
||||
endif
|
||||
vhost-user-scsi$(EXESUF): $(vhost-user-scsi-obj-y) libvhost-user.a
|
||||
$(call LINK, $^)
|
||||
vhost-user-blk$(EXESUF): $(vhost-user-blk-obj-y) libvhost-user.a
|
||||
$(call LINK, $^)
|
||||
|
||||
module_block.h: $(SRC_PATH)/scripts/modules/module_block.py config-host.mak
|
||||
$(call quiet-command,$(PYTHON) $< $@ \
|
||||
|
||||
@@ -115,6 +115,7 @@ libvhost-user-obj-y = contrib/libvhost-user/
|
||||
vhost-user-scsi.o-cflags := $(LIBISCSI_CFLAGS)
|
||||
vhost-user-scsi.o-libs := $(LIBISCSI_LIBS)
|
||||
vhost-user-scsi-obj-y = contrib/vhost-user-scsi/
|
||||
vhost-user-blk-obj-y = contrib/vhost-user-blk/
|
||||
|
||||
######################################################################
|
||||
trace-events-subdirs =
|
||||
|
||||
@@ -812,6 +812,10 @@ static void kvm_mem_ioeventfd_del(MemoryListener *listener,
|
||||
if (r < 0) {
|
||||
abort();
|
||||
}
|
||||
|
||||
if (e->cleanup) {
|
||||
e->cleanup(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void kvm_io_ioeventfd_add(MemoryListener *listener,
|
||||
|
||||
@@ -84,6 +84,8 @@ vu_request_to_string(unsigned int req)
|
||||
REQ(VHOST_USER_SET_SLAVE_REQ_FD),
|
||||
REQ(VHOST_USER_IOTLB_MSG),
|
||||
REQ(VHOST_USER_SET_VRING_ENDIAN),
|
||||
REQ(VHOST_USER_GET_CONFIG),
|
||||
REQ(VHOST_USER_SET_CONFIG),
|
||||
REQ(VHOST_USER_MAX),
|
||||
};
|
||||
#undef REQ
|
||||
@@ -797,6 +799,42 @@ vu_set_slave_req_fd(VuDev *dev, VhostUserMsg *vmsg)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
vu_get_config(VuDev *dev, VhostUserMsg *vmsg)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (dev->iface->get_config) {
|
||||
ret = dev->iface->get_config(dev, vmsg->payload.config.region,
|
||||
vmsg->payload.config.size);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
/* resize to zero to indicate an error to master */
|
||||
vmsg->size = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
vu_set_config(VuDev *dev, VhostUserMsg *vmsg)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (dev->iface->set_config) {
|
||||
ret = dev->iface->set_config(dev, vmsg->payload.config.region,
|
||||
vmsg->payload.config.offset,
|
||||
vmsg->payload.config.size,
|
||||
vmsg->payload.config.flags);
|
||||
if (ret) {
|
||||
vu_panic(dev, "Set virtio configuration space failed");
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
vu_process_message(VuDev *dev, VhostUserMsg *vmsg)
|
||||
{
|
||||
@@ -862,6 +900,10 @@ vu_process_message(VuDev *dev, VhostUserMsg *vmsg)
|
||||
return vu_set_vring_enable_exec(dev, vmsg);
|
||||
case VHOST_USER_SET_SLAVE_REQ_FD:
|
||||
return vu_set_slave_req_fd(dev, vmsg);
|
||||
case VHOST_USER_GET_CONFIG:
|
||||
return vu_get_config(dev, vmsg);
|
||||
case VHOST_USER_SET_CONFIG:
|
||||
return vu_set_config(dev, vmsg);
|
||||
case VHOST_USER_NONE:
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -30,6 +30,16 @@
|
||||
|
||||
#define VHOST_MEMORY_MAX_NREGIONS 8
|
||||
|
||||
typedef enum VhostSetConfigType {
|
||||
VHOST_SET_CONFIG_TYPE_MASTER = 0,
|
||||
VHOST_SET_CONFIG_TYPE_MIGRATION = 1,
|
||||
} VhostSetConfigType;
|
||||
|
||||
/*
|
||||
* Maximum size of virtio device config space
|
||||
*/
|
||||
#define VHOST_USER_MAX_CONFIG_SIZE 256
|
||||
|
||||
enum VhostUserProtocolFeature {
|
||||
VHOST_USER_PROTOCOL_F_MQ = 0,
|
||||
VHOST_USER_PROTOCOL_F_LOG_SHMFD = 1,
|
||||
@@ -69,6 +79,8 @@ typedef enum VhostUserRequest {
|
||||
VHOST_USER_SET_SLAVE_REQ_FD = 21,
|
||||
VHOST_USER_IOTLB_MSG = 22,
|
||||
VHOST_USER_SET_VRING_ENDIAN = 23,
|
||||
VHOST_USER_GET_CONFIG = 24,
|
||||
VHOST_USER_SET_CONFIG = 25,
|
||||
VHOST_USER_MAX
|
||||
} VhostUserRequest;
|
||||
|
||||
@@ -90,6 +102,18 @@ typedef struct VhostUserLog {
|
||||
uint64_t mmap_offset;
|
||||
} VhostUserLog;
|
||||
|
||||
typedef struct VhostUserConfig {
|
||||
uint32_t offset;
|
||||
uint32_t size;
|
||||
uint32_t flags;
|
||||
uint8_t region[VHOST_USER_MAX_CONFIG_SIZE];
|
||||
} VhostUserConfig;
|
||||
|
||||
static VhostUserConfig c __attribute__ ((unused));
|
||||
#define VHOST_USER_CONFIG_HDR_SIZE (sizeof(c.offset) \
|
||||
+ sizeof(c.size) \
|
||||
+ sizeof(c.flags))
|
||||
|
||||
#if defined(_WIN32)
|
||||
# define VU_PACKED __attribute__((gcc_struct, packed))
|
||||
#else
|
||||
@@ -112,6 +136,7 @@ typedef struct VhostUserMsg {
|
||||
struct vhost_vring_addr addr;
|
||||
VhostUserMemory memory;
|
||||
VhostUserLog log;
|
||||
VhostUserConfig config;
|
||||
} payload;
|
||||
|
||||
int fds[VHOST_MEMORY_MAX_NREGIONS];
|
||||
@@ -140,6 +165,10 @@ typedef int (*vu_process_msg_cb) (VuDev *dev, VhostUserMsg *vmsg,
|
||||
int *do_reply);
|
||||
typedef void (*vu_queue_set_started_cb) (VuDev *dev, int qidx, bool started);
|
||||
typedef bool (*vu_queue_is_processed_in_order_cb) (VuDev *dev, int qidx);
|
||||
typedef int (*vu_get_config_cb) (VuDev *dev, uint8_t *config, uint32_t len);
|
||||
typedef int (*vu_set_config_cb) (VuDev *dev, const uint8_t *data,
|
||||
uint32_t offset, uint32_t size,
|
||||
uint32_t flags);
|
||||
|
||||
typedef struct VuDevIface {
|
||||
/* called by VHOST_USER_GET_FEATURES to get the features bitmask */
|
||||
@@ -162,6 +191,10 @@ typedef struct VuDevIface {
|
||||
* on unmanaged exit/crash.
|
||||
*/
|
||||
vu_queue_is_processed_in_order_cb queue_is_processed_in_order;
|
||||
/* get the config space of the device */
|
||||
vu_get_config_cb get_config;
|
||||
/* set the config space of the device */
|
||||
vu_set_config_cb set_config;
|
||||
} VuDevIface;
|
||||
|
||||
typedef void (*vu_queue_handler_cb) (VuDev *dev, int qidx);
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
vhost-user-blk-obj-y = vhost-user-blk.o
|
||||
File diff suppressed because it is too large
Load Diff
@@ -43,3 +43,4 @@ CONFIG_VGA_PCI=y
|
||||
CONFIG_IVSHMEM_DEVICE=$(CONFIG_IVSHMEM)
|
||||
CONFIG_ROCKER=y
|
||||
CONFIG_VHOST_USER_SCSI=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX))
|
||||
CONFIG_VHOST_USER_BLK=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
CONFIG_PCI=y
|
||||
CONFIG_VIRTIO_PCI=$(CONFIG_PCI)
|
||||
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_SCLPCONSOLE=y
|
||||
CONFIG_TERMINAL3270=y
|
||||
|
||||
@@ -119,6 +119,19 @@ Depending on the request type, payload can be:
|
||||
- 3: IOTLB invalidate
|
||||
- 4: IOTLB access fail
|
||||
|
||||
* Virtio device config space
|
||||
-----------------------------------
|
||||
| offset | size | flags | payload |
|
||||
-----------------------------------
|
||||
|
||||
Offset: a 32-bit offset of virtio device's configuration space
|
||||
Size: a 32-bit configuration space access size in bytes
|
||||
Flags: a 32-bit value:
|
||||
- 0: Vhost master messages used for writeable fields
|
||||
- 1: Vhost master messages used for live migration
|
||||
Payload: Size bytes array holding the contents of the virtio
|
||||
device's configuration space
|
||||
|
||||
In QEMU the vhost-user message is implemented with the following struct:
|
||||
|
||||
typedef struct VhostUserMsg {
|
||||
@@ -132,6 +145,7 @@ typedef struct VhostUserMsg {
|
||||
VhostUserMemory memory;
|
||||
VhostUserLog log;
|
||||
struct vhost_iotlb_msg iotlb;
|
||||
VhostUserConfig config;
|
||||
};
|
||||
} QEMU_PACKED VhostUserMsg;
|
||||
|
||||
@@ -214,8 +228,8 @@ Multiple queue is treated as a protocol extension, hence the slave has to
|
||||
implement protocol features first. The multiple queues feature is supported
|
||||
only when the protocol feature VHOST_USER_PROTOCOL_F_MQ (bit 0) is set.
|
||||
|
||||
The max number of queues the slave supports can be queried with message
|
||||
VHOST_USER_GET_PROTOCOL_FEATURES. Master should stop when the number of
|
||||
The max number of queue pairs the slave supports can be queried with message
|
||||
VHOST_USER_GET_QUEUE_NUM. Master should stop when the number of
|
||||
requested queues is bigger than that.
|
||||
|
||||
As all queues share one connection, the master uses a unique index for each
|
||||
@@ -623,6 +637,32 @@ Master message types
|
||||
and expect this message once (per VQ) during device configuration
|
||||
(ie. before the master starts the VQ).
|
||||
|
||||
* VHOST_USER_GET_CONFIG
|
||||
|
||||
Id: 24
|
||||
Equivalent ioctl: N/A
|
||||
Master payload: virtio device config space
|
||||
Slave payload: virtio device config space
|
||||
|
||||
Submitted by the vhost-user master to fetch the contents of the virtio
|
||||
device configuration space, vhost-user slave's payload size MUST match
|
||||
master's request, vhost-user slave uses zero length of payload to
|
||||
indicate an error to vhost-user master. The vhost-user master may
|
||||
cache the contents to avoid repeated VHOST_USER_GET_CONFIG calls.
|
||||
|
||||
* VHOST_USER_SET_CONFIG
|
||||
|
||||
Id: 25
|
||||
Equivalent ioctl: N/A
|
||||
Master payload: virtio device config space
|
||||
Slave payload: N/A
|
||||
|
||||
Submitted by the vhost-user master when the Guest changes the virtio
|
||||
device configuration space and also can be used for live migration
|
||||
on the destination host. The vhost-user slave must check the flags
|
||||
field, and slaves MUST NOT accept SET_CONFIG for read-only
|
||||
configuration space fields unless the live migration bit is set.
|
||||
|
||||
Slave message types
|
||||
-------------------
|
||||
|
||||
@@ -641,6 +681,21 @@ Slave message types
|
||||
This request should be send only when VIRTIO_F_IOMMU_PLATFORM feature
|
||||
has been successfully negotiated.
|
||||
|
||||
* VHOST_USER_SLAVE_CONFIG_CHANGE_MSG
|
||||
|
||||
Id: 2
|
||||
Equivalent ioctl: N/A
|
||||
Slave payload: N/A
|
||||
Master payload: N/A
|
||||
|
||||
Vhost-user slave sends such messages to notify that the virtio device's
|
||||
configuration space has changed, for those host devices which can support
|
||||
such feature, host driver can send VHOST_USER_GET_CONFIG message to slave
|
||||
to get the latest content. If VHOST_USER_PROTOCOL_F_REPLY_ACK is
|
||||
negotiated, and slave set the VHOST_USER_NEED_REPLY flag, master must
|
||||
respond with zero when operation is successfully completed, or non-zero
|
||||
otherwise.
|
||||
|
||||
VHOST_USER_PROTOCOL_F_REPLY_ACK:
|
||||
-------------------------------
|
||||
The original vhost-user specification only demands replies for certain
|
||||
|
||||
@@ -13,3 +13,6 @@ obj-$(CONFIG_SH4) += tc58128.o
|
||||
|
||||
obj-$(CONFIG_VIRTIO) += virtio-blk.o
|
||||
obj-$(CONFIG_VIRTIO) += dataplane/
|
||||
ifeq ($(CONFIG_VIRTIO),y)
|
||||
obj-$(CONFIG_VHOST_USER_BLK) += vhost-user-blk.o
|
||||
endif
|
||||
|
||||
@@ -0,0 +1,359 @@
|
||||
/*
|
||||
* vhost-user-blk host device
|
||||
*
|
||||
* 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 "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/typedefs.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qom/object.h"
|
||||
#include "hw/qdev-core.h"
|
||||
#include "hw/virtio/vhost.h"
|
||||
#include "hw/virtio/vhost-user-blk.h"
|
||||
#include "hw/virtio/virtio.h"
|
||||
#include "hw/virtio/virtio-bus.h"
|
||||
#include "hw/virtio/virtio-access.h"
|
||||
|
||||
static const int user_feature_bits[] = {
|
||||
VIRTIO_BLK_F_SIZE_MAX,
|
||||
VIRTIO_BLK_F_SEG_MAX,
|
||||
VIRTIO_BLK_F_GEOMETRY,
|
||||
VIRTIO_BLK_F_BLK_SIZE,
|
||||
VIRTIO_BLK_F_TOPOLOGY,
|
||||
VIRTIO_BLK_F_MQ,
|
||||
VIRTIO_BLK_F_RO,
|
||||
VIRTIO_BLK_F_FLUSH,
|
||||
VIRTIO_BLK_F_CONFIG_WCE,
|
||||
VIRTIO_F_VERSION_1,
|
||||
VIRTIO_RING_F_INDIRECT_DESC,
|
||||
VIRTIO_RING_F_EVENT_IDX,
|
||||
VIRTIO_F_NOTIFY_ON_EMPTY,
|
||||
VHOST_INVALID_FEATURE_BIT
|
||||
};
|
||||
|
||||
static void vhost_user_blk_update_config(VirtIODevice *vdev, uint8_t *config)
|
||||
{
|
||||
VHostUserBlk *s = VHOST_USER_BLK(vdev);
|
||||
|
||||
memcpy(config, &s->blkcfg, sizeof(struct virtio_blk_config));
|
||||
}
|
||||
|
||||
static void vhost_user_blk_set_config(VirtIODevice *vdev, const uint8_t *config)
|
||||
{
|
||||
VHostUserBlk *s = VHOST_USER_BLK(vdev);
|
||||
struct virtio_blk_config *blkcfg = (struct virtio_blk_config *)config;
|
||||
int ret;
|
||||
|
||||
if (blkcfg->wce == s->blkcfg.wce) {
|
||||
return;
|
||||
}
|
||||
|
||||
ret = vhost_dev_set_config(&s->dev, &blkcfg->wce,
|
||||
offsetof(struct virtio_blk_config, wce),
|
||||
sizeof(blkcfg->wce),
|
||||
VHOST_SET_CONFIG_TYPE_MASTER);
|
||||
if (ret) {
|
||||
error_report("set device config space failed");
|
||||
return;
|
||||
}
|
||||
|
||||
s->blkcfg.wce = blkcfg->wce;
|
||||
}
|
||||
|
||||
static int vhost_user_blk_handle_config_change(struct vhost_dev *dev)
|
||||
{
|
||||
int ret;
|
||||
struct virtio_blk_config blkcfg;
|
||||
VHostUserBlk *s = VHOST_USER_BLK(dev->vdev);
|
||||
|
||||
ret = vhost_dev_get_config(dev, (uint8_t *)&blkcfg,
|
||||
sizeof(struct virtio_blk_config));
|
||||
if (ret < 0) {
|
||||
error_report("get config space failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* valid for resize only */
|
||||
if (blkcfg.capacity != s->blkcfg.capacity) {
|
||||
s->blkcfg.capacity = blkcfg.capacity;
|
||||
memcpy(dev->vdev->config, &s->blkcfg, sizeof(struct virtio_blk_config));
|
||||
virtio_notify_config(dev->vdev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const VhostDevConfigOps blk_ops = {
|
||||
.vhost_dev_config_notifier = vhost_user_blk_handle_config_change,
|
||||
};
|
||||
|
||||
static void vhost_user_blk_start(VirtIODevice *vdev)
|
||||
{
|
||||
VHostUserBlk *s = VHOST_USER_BLK(vdev);
|
||||
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
|
||||
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
|
||||
int i, ret;
|
||||
|
||||
if (!k->set_guest_notifiers) {
|
||||
error_report("binding does not support guest notifiers");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = vhost_dev_enable_notifiers(&s->dev, vdev);
|
||||
if (ret < 0) {
|
||||
error_report("Error enabling host notifiers: %d", -ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, true);
|
||||
if (ret < 0) {
|
||||
error_report("Error binding guest notifier: %d", -ret);
|
||||
goto err_host_notifiers;
|
||||
}
|
||||
|
||||
s->dev.acked_features = vdev->guest_features;
|
||||
ret = vhost_dev_start(&s->dev, vdev);
|
||||
if (ret < 0) {
|
||||
error_report("Error starting vhost: %d", -ret);
|
||||
goto err_guest_notifiers;
|
||||
}
|
||||
|
||||
/* guest_notifier_mask/pending not used yet, so just unmask
|
||||
* everything here. virtio-pci will do the right thing by
|
||||
* enabling/disabling irqfd.
|
||||
*/
|
||||
for (i = 0; i < s->dev.nvqs; i++) {
|
||||
vhost_virtqueue_mask(&s->dev, vdev, i, false);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
err_guest_notifiers:
|
||||
k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false);
|
||||
err_host_notifiers:
|
||||
vhost_dev_disable_notifiers(&s->dev, vdev);
|
||||
}
|
||||
|
||||
static void vhost_user_blk_stop(VirtIODevice *vdev)
|
||||
{
|
||||
VHostUserBlk *s = VHOST_USER_BLK(vdev);
|
||||
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
|
||||
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
|
||||
int ret;
|
||||
|
||||
if (!k->set_guest_notifiers) {
|
||||
return;
|
||||
}
|
||||
|
||||
vhost_dev_stop(&s->dev, vdev);
|
||||
|
||||
ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false);
|
||||
if (ret < 0) {
|
||||
error_report("vhost guest notifier cleanup failed: %d", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
vhost_dev_disable_notifiers(&s->dev, vdev);
|
||||
}
|
||||
|
||||
static void vhost_user_blk_set_status(VirtIODevice *vdev, uint8_t status)
|
||||
{
|
||||
VHostUserBlk *s = VHOST_USER_BLK(vdev);
|
||||
bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK;
|
||||
|
||||
if (!vdev->vm_running) {
|
||||
should_start = false;
|
||||
}
|
||||
|
||||
if (s->dev.started == should_start) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (should_start) {
|
||||
vhost_user_blk_start(vdev);
|
||||
} else {
|
||||
vhost_user_blk_stop(vdev);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static uint64_t vhost_user_blk_get_features(VirtIODevice *vdev,
|
||||
uint64_t features,
|
||||
Error **errp)
|
||||
{
|
||||
VHostUserBlk *s = VHOST_USER_BLK(vdev);
|
||||
uint64_t get_features;
|
||||
|
||||
/* Turn on pre-defined features */
|
||||
virtio_add_feature(&features, VIRTIO_BLK_F_SEG_MAX);
|
||||
virtio_add_feature(&features, VIRTIO_BLK_F_GEOMETRY);
|
||||
virtio_add_feature(&features, VIRTIO_BLK_F_TOPOLOGY);
|
||||
virtio_add_feature(&features, VIRTIO_BLK_F_BLK_SIZE);
|
||||
virtio_add_feature(&features, VIRTIO_BLK_F_FLUSH);
|
||||
|
||||
if (s->config_wce) {
|
||||
virtio_add_feature(&features, VIRTIO_BLK_F_CONFIG_WCE);
|
||||
}
|
||||
if (s->config_ro) {
|
||||
virtio_add_feature(&features, VIRTIO_BLK_F_RO);
|
||||
}
|
||||
if (s->num_queues > 1) {
|
||||
virtio_add_feature(&features, VIRTIO_BLK_F_MQ);
|
||||
}
|
||||
|
||||
get_features = vhost_get_features(&s->dev, user_feature_bits, features);
|
||||
|
||||
return get_features;
|
||||
}
|
||||
|
||||
static void vhost_user_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
||||
VHostUserBlk *s = VHOST_USER_BLK(vdev);
|
||||
int i, ret;
|
||||
|
||||
if (!s->chardev.chr) {
|
||||
error_setg(errp, "vhost-user-blk: chardev is mandatory");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s->num_queues || s->num_queues > VIRTIO_QUEUE_MAX) {
|
||||
error_setg(errp, "vhost-user-blk: invalid number of IO queues");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s->queue_size) {
|
||||
error_setg(errp, "vhost-user-blk: queue size must be non-zero");
|
||||
return;
|
||||
}
|
||||
|
||||
virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK,
|
||||
sizeof(struct virtio_blk_config));
|
||||
|
||||
for (i = 0; i < s->num_queues; i++) {
|
||||
virtio_add_queue(vdev, s->queue_size,
|
||||
vhost_user_blk_handle_output);
|
||||
}
|
||||
|
||||
s->dev.nvqs = s->num_queues;
|
||||
s->dev.vqs = g_new(struct vhost_virtqueue, s->dev.nvqs);
|
||||
s->dev.vq_index = 0;
|
||||
s->dev.backend_features = 0;
|
||||
|
||||
ret = vhost_dev_init(&s->dev, &s->chardev, VHOST_BACKEND_TYPE_USER, 0);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "vhost-user-blk: vhost initialization failed: %s",
|
||||
strerror(-ret));
|
||||
goto virtio_err;
|
||||
}
|
||||
|
||||
ret = vhost_dev_get_config(&s->dev, (uint8_t *)&s->blkcfg,
|
||||
sizeof(struct virtio_blk_config));
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "vhost-user-blk: get block config failed");
|
||||
goto vhost_err;
|
||||
}
|
||||
|
||||
if (s->blkcfg.num_queues != s->num_queues) {
|
||||
s->blkcfg.num_queues = s->num_queues;
|
||||
}
|
||||
|
||||
vhost_dev_set_config_notifier(&s->dev, &blk_ops);
|
||||
|
||||
return;
|
||||
|
||||
vhost_err:
|
||||
vhost_dev_cleanup(&s->dev);
|
||||
virtio_err:
|
||||
g_free(s->dev.vqs);
|
||||
virtio_cleanup(vdev);
|
||||
}
|
||||
|
||||
static void vhost_user_blk_device_unrealize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
||||
VHostUserBlk *s = VHOST_USER_BLK(dev);
|
||||
|
||||
vhost_user_blk_set_status(vdev, 0);
|
||||
vhost_dev_cleanup(&s->dev);
|
||||
g_free(s->dev.vqs);
|
||||
virtio_cleanup(vdev);
|
||||
}
|
||||
|
||||
static void vhost_user_blk_instance_init(Object *obj)
|
||||
{
|
||||
VHostUserBlk *s = VHOST_USER_BLK(obj);
|
||||
|
||||
device_add_bootindex_property(obj, &s->bootindex, "bootindex",
|
||||
"/disk@0,0", DEVICE(obj), NULL);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_vhost_user_blk = {
|
||||
.name = "vhost-user-blk",
|
||||
.minimum_version_id = 1,
|
||||
.version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_VIRTIO_DEVICE,
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
|
||||
static Property vhost_user_blk_properties[] = {
|
||||
DEFINE_PROP_CHR("chardev", VHostUserBlk, chardev),
|
||||
DEFINE_PROP_UINT16("num-queues", VHostUserBlk, num_queues, 1),
|
||||
DEFINE_PROP_UINT32("queue-size", VHostUserBlk, queue_size, 128),
|
||||
DEFINE_PROP_BIT("config-wce", VHostUserBlk, config_wce, 0, true),
|
||||
DEFINE_PROP_BIT("config-ro", VHostUserBlk, config_ro, 0, false),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void vhost_user_blk_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
|
||||
|
||||
dc->props = vhost_user_blk_properties;
|
||||
dc->vmsd = &vmstate_vhost_user_blk;
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
||||
vdc->realize = vhost_user_blk_device_realize;
|
||||
vdc->unrealize = vhost_user_blk_device_unrealize;
|
||||
vdc->get_config = vhost_user_blk_update_config;
|
||||
vdc->set_config = vhost_user_blk_set_config;
|
||||
vdc->get_features = vhost_user_blk_get_features;
|
||||
vdc->set_status = vhost_user_blk_set_status;
|
||||
}
|
||||
|
||||
static const TypeInfo vhost_user_blk_info = {
|
||||
.name = TYPE_VHOST_USER_BLK,
|
||||
.parent = TYPE_VIRTIO_DEVICE,
|
||||
.instance_size = sizeof(VHostUserBlk),
|
||||
.instance_init = vhost_user_blk_instance_init,
|
||||
.class_init = vhost_user_blk_class_init,
|
||||
};
|
||||
|
||||
static void virtio_register_types(void)
|
||||
{
|
||||
type_register_static(&vhost_user_blk_info);
|
||||
}
|
||||
|
||||
type_init(virtio_register_types)
|
||||
@@ -2394,7 +2394,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
|
||||
}
|
||||
mem_base = 1ULL << 32;
|
||||
mem_len = next_base - pcms->below_4g_mem_size;
|
||||
next_base += (1ULL << 32) - pcms->below_4g_mem_size;
|
||||
next_base = mem_base + mem_len;
|
||||
}
|
||||
numamem = acpi_data_push(table_data, sizeof *numamem);
|
||||
build_srat_memory(numamem, mem_base, mem_len, i - 1,
|
||||
@@ -2473,6 +2473,7 @@ build_dmar_q35(GArray *table_data, BIOSLinker *linker)
|
||||
AcpiDmarDeviceScope *scope = NULL;
|
||||
/* Root complex IOAPIC use one path[0] only */
|
||||
size_t ioapic_scope_size = sizeof(*scope) + sizeof(scope->path[0]);
|
||||
IntelIOMMUState *intel_iommu = INTEL_IOMMU_DEVICE(iommu);
|
||||
|
||||
assert(iommu);
|
||||
if (iommu->intr_supported) {
|
||||
@@ -2480,7 +2481,7 @@ build_dmar_q35(GArray *table_data, BIOSLinker *linker)
|
||||
}
|
||||
|
||||
dmar = acpi_data_push(table_data, sizeof(*dmar));
|
||||
dmar->host_address_width = VTD_HOST_ADDRESS_WIDTH - 1;
|
||||
dmar->host_address_width = intel_iommu->aw_bits - 1;
|
||||
dmar->flags = dmar_flags;
|
||||
|
||||
/* DMAR Remapping Hardware Unit Definition structure */
|
||||
|
||||
+2
-11
@@ -1144,18 +1144,9 @@ static void amdvi_realize(DeviceState *dev, Error **err)
|
||||
AMDVIState *s = AMD_IOMMU_DEVICE(dev);
|
||||
X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(dev);
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
||||
PCMachineState *pcms =
|
||||
PC_MACHINE(object_dynamic_cast(OBJECT(ms), TYPE_PC_MACHINE));
|
||||
PCIBus *bus;
|
||||
PCMachineState *pcms = PC_MACHINE(ms);
|
||||
PCIBus *bus = pcms->bus;
|
||||
|
||||
if (!pcms) {
|
||||
error_setg(err, "Machine-type '%s' not supported by amd-iommu",
|
||||
mc->name);
|
||||
return;
|
||||
}
|
||||
|
||||
bus = pcms->bus;
|
||||
s->iotlb = g_hash_table_new_full(amdvi_uint64_hash,
|
||||
amdvi_uint64_equal, g_free, g_free);
|
||||
|
||||
|
||||
+74
-58
@@ -521,9 +521,9 @@ static inline dma_addr_t vtd_ce_get_slpt_base(VTDContextEntry *ce)
|
||||
return ce->lo & VTD_CONTEXT_ENTRY_SLPTPTR;
|
||||
}
|
||||
|
||||
static inline uint64_t vtd_get_slpte_addr(uint64_t slpte)
|
||||
static inline uint64_t vtd_get_slpte_addr(uint64_t slpte, uint8_t aw)
|
||||
{
|
||||
return slpte & VTD_SL_PT_BASE_ADDR_MASK;
|
||||
return slpte & VTD_SL_PT_BASE_ADDR_MASK(aw);
|
||||
}
|
||||
|
||||
/* Whether the pte indicates the address of the page frame */
|
||||
@@ -608,35 +608,29 @@ static inline bool vtd_ce_type_check(X86IOMMUState *x86_iommu,
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline uint64_t vtd_iova_limit(VTDContextEntry *ce)
|
||||
static inline uint64_t vtd_iova_limit(VTDContextEntry *ce, uint8_t aw)
|
||||
{
|
||||
uint32_t ce_agaw = vtd_ce_get_agaw(ce);
|
||||
return 1ULL << MIN(ce_agaw, VTD_MGAW);
|
||||
return 1ULL << MIN(ce_agaw, aw);
|
||||
}
|
||||
|
||||
/* Return true if IOVA passes range check, otherwise false. */
|
||||
static inline bool vtd_iova_range_check(uint64_t iova, VTDContextEntry *ce)
|
||||
static inline bool vtd_iova_range_check(uint64_t iova, VTDContextEntry *ce,
|
||||
uint8_t aw)
|
||||
{
|
||||
/*
|
||||
* Check if @iova is above 2^X-1, where X is the minimum of MGAW
|
||||
* in CAP_REG and AW in context-entry.
|
||||
*/
|
||||
return !(iova & ~(vtd_iova_limit(ce) - 1));
|
||||
return !(iova & ~(vtd_iova_limit(ce, aw) - 1));
|
||||
}
|
||||
|
||||
static const uint64_t vtd_paging_entry_rsvd_field[] = {
|
||||
[0] = ~0ULL,
|
||||
/* For not large page */
|
||||
[1] = 0x800ULL | ~(VTD_HAW_MASK | VTD_SL_IGN_COM),
|
||||
[2] = 0x800ULL | ~(VTD_HAW_MASK | VTD_SL_IGN_COM),
|
||||
[3] = 0x800ULL | ~(VTD_HAW_MASK | VTD_SL_IGN_COM),
|
||||
[4] = 0x880ULL | ~(VTD_HAW_MASK | VTD_SL_IGN_COM),
|
||||
/* For large page */
|
||||
[5] = 0x800ULL | ~(VTD_HAW_MASK | VTD_SL_IGN_COM),
|
||||
[6] = 0x1ff800ULL | ~(VTD_HAW_MASK | VTD_SL_IGN_COM),
|
||||
[7] = 0x3ffff800ULL | ~(VTD_HAW_MASK | VTD_SL_IGN_COM),
|
||||
[8] = 0x880ULL | ~(VTD_HAW_MASK | VTD_SL_IGN_COM),
|
||||
};
|
||||
/*
|
||||
* Rsvd field masks for spte:
|
||||
* Index [1] to [4] 4k pages
|
||||
* Index [5] to [8] large pages
|
||||
*/
|
||||
static uint64_t vtd_paging_entry_rsvd_field[9];
|
||||
|
||||
static bool vtd_slpte_nonzero_rsvd(uint64_t slpte, uint32_t level)
|
||||
{
|
||||
@@ -676,7 +670,7 @@ static VTDBus *vtd_find_as_from_bus_num(IntelIOMMUState *s, uint8_t bus_num)
|
||||
*/
|
||||
static int vtd_iova_to_slpte(VTDContextEntry *ce, uint64_t iova, bool is_write,
|
||||
uint64_t *slptep, uint32_t *slpte_level,
|
||||
bool *reads, bool *writes)
|
||||
bool *reads, bool *writes, uint8_t aw_bits)
|
||||
{
|
||||
dma_addr_t addr = vtd_ce_get_slpt_base(ce);
|
||||
uint32_t level = vtd_ce_get_level(ce);
|
||||
@@ -684,7 +678,7 @@ static int vtd_iova_to_slpte(VTDContextEntry *ce, uint64_t iova, bool is_write,
|
||||
uint64_t slpte;
|
||||
uint64_t access_right_check;
|
||||
|
||||
if (!vtd_iova_range_check(iova, ce)) {
|
||||
if (!vtd_iova_range_check(iova, ce, aw_bits)) {
|
||||
trace_vtd_err_dmar_iova_overflow(iova);
|
||||
return -VTD_FR_ADDR_BEYOND_MGAW;
|
||||
}
|
||||
@@ -721,7 +715,7 @@ static int vtd_iova_to_slpte(VTDContextEntry *ce, uint64_t iova, bool is_write,
|
||||
*slpte_level = level;
|
||||
return 0;
|
||||
}
|
||||
addr = vtd_get_slpte_addr(slpte);
|
||||
addr = vtd_get_slpte_addr(slpte, aw_bits);
|
||||
level--;
|
||||
}
|
||||
}
|
||||
@@ -739,11 +733,12 @@ typedef int (*vtd_page_walk_hook)(IOMMUTLBEntry *entry, void *private);
|
||||
* @read: whether parent level has read permission
|
||||
* @write: whether parent level has write permission
|
||||
* @notify_unmap: whether we should notify invalid entries
|
||||
* @aw: maximum address width
|
||||
*/
|
||||
static int vtd_page_walk_level(dma_addr_t addr, uint64_t start,
|
||||
uint64_t end, vtd_page_walk_hook hook_fn,
|
||||
void *private, uint32_t level,
|
||||
bool read, bool write, bool notify_unmap)
|
||||
void *private, uint32_t level, bool read,
|
||||
bool write, bool notify_unmap, uint8_t aw)
|
||||
{
|
||||
bool read_cur, write_cur, entry_valid;
|
||||
uint32_t offset;
|
||||
@@ -790,7 +785,7 @@ static int vtd_page_walk_level(dma_addr_t addr, uint64_t start,
|
||||
entry.target_as = &address_space_memory;
|
||||
entry.iova = iova & subpage_mask;
|
||||
/* NOTE: this is only meaningful if entry_valid == true */
|
||||
entry.translated_addr = vtd_get_slpte_addr(slpte);
|
||||
entry.translated_addr = vtd_get_slpte_addr(slpte, aw);
|
||||
entry.addr_mask = ~subpage_mask;
|
||||
entry.perm = IOMMU_ACCESS_FLAG(read_cur, write_cur);
|
||||
if (!entry_valid && !notify_unmap) {
|
||||
@@ -810,10 +805,10 @@ static int vtd_page_walk_level(dma_addr_t addr, uint64_t start,
|
||||
trace_vtd_page_walk_skip_perm(iova, iova_next);
|
||||
goto next;
|
||||
}
|
||||
ret = vtd_page_walk_level(vtd_get_slpte_addr(slpte), iova,
|
||||
ret = vtd_page_walk_level(vtd_get_slpte_addr(slpte, aw), iova,
|
||||
MIN(iova_next, end), hook_fn, private,
|
||||
level - 1, read_cur, write_cur,
|
||||
notify_unmap);
|
||||
notify_unmap, aw);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@@ -834,25 +829,26 @@ next:
|
||||
* @end: IOVA range end address (start <= addr < end)
|
||||
* @hook_fn: the hook that to be called for each detected area
|
||||
* @private: private data for the hook function
|
||||
* @aw: maximum address width
|
||||
*/
|
||||
static int vtd_page_walk(VTDContextEntry *ce, uint64_t start, uint64_t end,
|
||||
vtd_page_walk_hook hook_fn, void *private,
|
||||
bool notify_unmap)
|
||||
bool notify_unmap, uint8_t aw)
|
||||
{
|
||||
dma_addr_t addr = vtd_ce_get_slpt_base(ce);
|
||||
uint32_t level = vtd_ce_get_level(ce);
|
||||
|
||||
if (!vtd_iova_range_check(start, ce)) {
|
||||
if (!vtd_iova_range_check(start, ce, aw)) {
|
||||
return -VTD_FR_ADDR_BEYOND_MGAW;
|
||||
}
|
||||
|
||||
if (!vtd_iova_range_check(end, ce)) {
|
||||
if (!vtd_iova_range_check(end, ce, aw)) {
|
||||
/* Fix end so that it reaches the maximum */
|
||||
end = vtd_iova_limit(ce);
|
||||
end = vtd_iova_limit(ce, aw);
|
||||
}
|
||||
|
||||
return vtd_page_walk_level(addr, start, end, hook_fn, private,
|
||||
level, true, true, notify_unmap);
|
||||
level, true, true, notify_unmap, aw);
|
||||
}
|
||||
|
||||
/* Map a device to its corresponding domain (context-entry) */
|
||||
@@ -874,7 +870,7 @@ static int vtd_dev_to_context_entry(IntelIOMMUState *s, uint8_t bus_num,
|
||||
return -VTD_FR_ROOT_ENTRY_P;
|
||||
}
|
||||
|
||||
if (re.rsvd || (re.val & VTD_ROOT_ENTRY_RSVD)) {
|
||||
if (re.rsvd || (re.val & VTD_ROOT_ENTRY_RSVD(s->aw_bits))) {
|
||||
trace_vtd_re_invalid(re.rsvd, re.val);
|
||||
return -VTD_FR_ROOT_ENTRY_RSVD;
|
||||
}
|
||||
@@ -891,7 +887,7 @@ static int vtd_dev_to_context_entry(IntelIOMMUState *s, uint8_t bus_num,
|
||||
}
|
||||
|
||||
if ((ce->hi & VTD_CONTEXT_ENTRY_RSVD_HI) ||
|
||||
(ce->lo & VTD_CONTEXT_ENTRY_RSVD_LO)) {
|
||||
(ce->lo & VTD_CONTEXT_ENTRY_RSVD_LO(s->aw_bits))) {
|
||||
trace_vtd_ce_invalid(ce->hi, ce->lo);
|
||||
return -VTD_FR_CONTEXT_ENTRY_RSVD;
|
||||
}
|
||||
@@ -1173,7 +1169,7 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
|
||||
}
|
||||
|
||||
ret_fr = vtd_iova_to_slpte(&ce, addr, is_write, &slpte, &level,
|
||||
&reads, &writes);
|
||||
&reads, &writes, s->aw_bits);
|
||||
if (ret_fr) {
|
||||
ret_fr = -ret_fr;
|
||||
if (is_fpd_set && vtd_is_qualified_fault(ret_fr)) {
|
||||
@@ -1190,7 +1186,7 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
|
||||
access_flags, level);
|
||||
out:
|
||||
entry->iova = addr & page_mask;
|
||||
entry->translated_addr = vtd_get_slpte_addr(slpte) & page_mask;
|
||||
entry->translated_addr = vtd_get_slpte_addr(slpte, s->aw_bits) & page_mask;
|
||||
entry->addr_mask = ~page_mask;
|
||||
entry->perm = access_flags;
|
||||
return true;
|
||||
@@ -1207,7 +1203,7 @@ static void vtd_root_table_setup(IntelIOMMUState *s)
|
||||
{
|
||||
s->root = vtd_get_quad_raw(s, DMAR_RTADDR_REG);
|
||||
s->root_extended = s->root & VTD_RTADDR_RTT;
|
||||
s->root &= VTD_RTADDR_ADDR_MASK;
|
||||
s->root &= VTD_RTADDR_ADDR_MASK(s->aw_bits);
|
||||
|
||||
trace_vtd_reg_dmar_root(s->root, s->root_extended);
|
||||
}
|
||||
@@ -1223,7 +1219,7 @@ static void vtd_interrupt_remap_table_setup(IntelIOMMUState *s)
|
||||
uint64_t value = 0;
|
||||
value = vtd_get_quad_raw(s, DMAR_IRTA_REG);
|
||||
s->intr_size = 1UL << ((value & VTD_IRTA_SIZE_MASK) + 1);
|
||||
s->intr_root = value & VTD_IRTA_ADDR_MASK;
|
||||
s->intr_root = value & VTD_IRTA_ADDR_MASK(s->aw_bits);
|
||||
s->intr_eime = value & VTD_IRTA_EIME;
|
||||
|
||||
/* Notify global invalidation */
|
||||
@@ -1399,7 +1395,7 @@ static void vtd_iotlb_page_invalidate_notify(IntelIOMMUState *s,
|
||||
if (!ret && domain_id == VTD_CONTEXT_ENTRY_DID(ce.hi)) {
|
||||
vtd_page_walk(&ce, addr, addr + (1 << am) * VTD_PAGE_SIZE,
|
||||
vtd_page_invalidate_notify_hook,
|
||||
(void *)&vtd_as->iommu, true);
|
||||
(void *)&vtd_as->iommu, true, s->aw_bits);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1479,7 +1475,7 @@ static void vtd_handle_gcmd_qie(IntelIOMMUState *s, bool en)
|
||||
trace_vtd_inv_qi_enable(en);
|
||||
|
||||
if (en) {
|
||||
s->iq = iqa_val & VTD_IQA_IQA_MASK;
|
||||
s->iq = iqa_val & VTD_IQA_IQA_MASK(s->aw_bits);
|
||||
/* 2^(x+8) entries */
|
||||
s->iq_size = 1UL << ((iqa_val & VTD_IQA_QS) + 8);
|
||||
s->qi_enabled = true;
|
||||
@@ -2410,6 +2406,8 @@ static Property vtd_properties[] = {
|
||||
DEFINE_PROP_ON_OFF_AUTO("eim", IntelIOMMUState, intr_eim,
|
||||
ON_OFF_AUTO_AUTO),
|
||||
DEFINE_PROP_BOOL("x-buggy-eim", IntelIOMMUState, buggy_eim, false),
|
||||
DEFINE_PROP_UINT8("x-aw-bits", IntelIOMMUState, aw_bits,
|
||||
VTD_HOST_ADDRESS_WIDTH),
|
||||
DEFINE_PROP_BOOL("caching-mode", IntelIOMMUState, caching_mode, FALSE),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
@@ -2765,6 +2763,7 @@ static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n)
|
||||
hwaddr size;
|
||||
hwaddr start = n->start;
|
||||
hwaddr end = n->end;
|
||||
IntelIOMMUState *s = as->iommu_state;
|
||||
|
||||
/*
|
||||
* Note: all the codes in this function has a assumption that IOVA
|
||||
@@ -2772,12 +2771,12 @@ static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n)
|
||||
* VT-d spec), otherwise we need to consider overflow of 64 bits.
|
||||
*/
|
||||
|
||||
if (end > VTD_ADDRESS_SIZE) {
|
||||
if (end > VTD_ADDRESS_SIZE(s->aw_bits)) {
|
||||
/*
|
||||
* Don't need to unmap regions that is bigger than the whole
|
||||
* VT-d supported address space size
|
||||
*/
|
||||
end = VTD_ADDRESS_SIZE;
|
||||
end = VTD_ADDRESS_SIZE(s->aw_bits);
|
||||
}
|
||||
|
||||
assert(start <= end);
|
||||
@@ -2789,9 +2788,9 @@ static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n)
|
||||
* suite the minimum available mask.
|
||||
*/
|
||||
int n = 64 - clz64(size);
|
||||
if (n > VTD_MGAW) {
|
||||
if (n > s->aw_bits) {
|
||||
/* should not happen, but in case it happens, limit it */
|
||||
n = VTD_MGAW;
|
||||
n = s->aw_bits;
|
||||
}
|
||||
size = 1ULL << n;
|
||||
}
|
||||
@@ -2851,7 +2850,8 @@ static void vtd_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n)
|
||||
PCI_FUNC(vtd_as->devfn),
|
||||
VTD_CONTEXT_ENTRY_DID(ce.hi),
|
||||
ce.hi, ce.lo);
|
||||
vtd_page_walk(&ce, 0, ~0ULL, vtd_replay_hook, (void *)n, false);
|
||||
vtd_page_walk(&ce, 0, ~0ULL, vtd_replay_hook, (void *)n, false,
|
||||
s->aw_bits);
|
||||
} else {
|
||||
trace_vtd_replay_ce_invalid(bus_n, PCI_SLOT(vtd_as->devfn),
|
||||
PCI_FUNC(vtd_as->devfn));
|
||||
@@ -2882,10 +2882,27 @@ static void vtd_init(IntelIOMMUState *s)
|
||||
s->qi_enabled = false;
|
||||
s->iq_last_desc_type = VTD_INV_DESC_NONE;
|
||||
s->next_frcd_reg = 0;
|
||||
s->cap = VTD_CAP_FRO | VTD_CAP_NFR | VTD_CAP_ND | VTD_CAP_MGAW |
|
||||
VTD_CAP_SAGAW | VTD_CAP_MAMV | VTD_CAP_PSI | VTD_CAP_SLLPS;
|
||||
s->cap = VTD_CAP_FRO | VTD_CAP_NFR | VTD_CAP_ND |
|
||||
VTD_CAP_MAMV | VTD_CAP_PSI | VTD_CAP_SLLPS |
|
||||
VTD_CAP_SAGAW_39bit | VTD_CAP_MGAW(s->aw_bits);
|
||||
if (s->aw_bits == VTD_HOST_AW_48BIT) {
|
||||
s->cap |= VTD_CAP_SAGAW_48bit;
|
||||
}
|
||||
s->ecap = VTD_ECAP_QI | VTD_ECAP_IRO;
|
||||
|
||||
/*
|
||||
* Rsvd field masks for spte
|
||||
*/
|
||||
vtd_paging_entry_rsvd_field[0] = ~0ULL;
|
||||
vtd_paging_entry_rsvd_field[1] = VTD_SPTE_PAGE_L1_RSVD_MASK(s->aw_bits);
|
||||
vtd_paging_entry_rsvd_field[2] = VTD_SPTE_PAGE_L2_RSVD_MASK(s->aw_bits);
|
||||
vtd_paging_entry_rsvd_field[3] = VTD_SPTE_PAGE_L3_RSVD_MASK(s->aw_bits);
|
||||
vtd_paging_entry_rsvd_field[4] = VTD_SPTE_PAGE_L4_RSVD_MASK(s->aw_bits);
|
||||
vtd_paging_entry_rsvd_field[5] = VTD_SPTE_LPAGE_L1_RSVD_MASK(s->aw_bits);
|
||||
vtd_paging_entry_rsvd_field[6] = VTD_SPTE_LPAGE_L2_RSVD_MASK(s->aw_bits);
|
||||
vtd_paging_entry_rsvd_field[7] = VTD_SPTE_LPAGE_L3_RSVD_MASK(s->aw_bits);
|
||||
vtd_paging_entry_rsvd_field[8] = VTD_SPTE_LPAGE_L4_RSVD_MASK(s->aw_bits);
|
||||
|
||||
if (x86_iommu->intr_supported) {
|
||||
s->ecap |= VTD_ECAP_IR | VTD_ECAP_MHMV;
|
||||
if (s->intr_eim == ON_OFF_AUTO_ON) {
|
||||
@@ -3021,26 +3038,25 @@ static bool vtd_decide_config(IntelIOMMUState *s, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
/* Currently only address widths supported are 39 and 48 bits */
|
||||
if ((s->aw_bits != VTD_HOST_AW_39BIT) &&
|
||||
(s->aw_bits != VTD_HOST_AW_48BIT)) {
|
||||
error_setg(errp, "Supported values for x-aw-bits are: %d, %d",
|
||||
VTD_HOST_AW_39BIT, VTD_HOST_AW_48BIT);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void vtd_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
||||
PCMachineState *pcms =
|
||||
PC_MACHINE(object_dynamic_cast(OBJECT(ms), TYPE_PC_MACHINE));
|
||||
PCIBus *bus;
|
||||
PCMachineState *pcms = PC_MACHINE(ms);
|
||||
PCIBus *bus = pcms->bus;
|
||||
IntelIOMMUState *s = INTEL_IOMMU_DEVICE(dev);
|
||||
X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(dev);
|
||||
|
||||
if (!pcms) {
|
||||
error_setg(errp, "Machine-type '%s' not supported by intel-iommu",
|
||||
mc->name);
|
||||
return;
|
||||
}
|
||||
|
||||
bus = pcms->bus;
|
||||
x86_iommu->type = TYPE_INTEL;
|
||||
|
||||
if (!vtd_decide_config(s, errp)) {
|
||||
|
||||
@@ -131,7 +131,7 @@
|
||||
#define VTD_TLB_DID(val) (((val) >> 32) & VTD_DOMAIN_ID_MASK)
|
||||
|
||||
/* IVA_REG */
|
||||
#define VTD_IVA_ADDR(val) ((val) & ~0xfffULL & ((1ULL << VTD_MGAW) - 1))
|
||||
#define VTD_IVA_ADDR(val) ((val) & ~0xfffULL)
|
||||
#define VTD_IVA_AM(val) ((val) & 0x3fULL)
|
||||
|
||||
/* GCMD_REG */
|
||||
@@ -172,10 +172,10 @@
|
||||
|
||||
/* RTADDR_REG */
|
||||
#define VTD_RTADDR_RTT (1ULL << 11)
|
||||
#define VTD_RTADDR_ADDR_MASK (VTD_HAW_MASK ^ 0xfffULL)
|
||||
#define VTD_RTADDR_ADDR_MASK(aw) (VTD_HAW_MASK(aw) ^ 0xfffULL)
|
||||
|
||||
/* IRTA_REG */
|
||||
#define VTD_IRTA_ADDR_MASK (VTD_HAW_MASK ^ 0xfffULL)
|
||||
#define VTD_IRTA_ADDR_MASK(aw) (VTD_HAW_MASK(aw) ^ 0xfffULL)
|
||||
#define VTD_IRTA_EIME (1ULL << 11)
|
||||
#define VTD_IRTA_SIZE_MASK (0xfULL)
|
||||
|
||||
@@ -197,9 +197,8 @@
|
||||
#define VTD_DOMAIN_ID_SHIFT 16 /* 16-bit domain id for 64K domains */
|
||||
#define VTD_DOMAIN_ID_MASK ((1UL << VTD_DOMAIN_ID_SHIFT) - 1)
|
||||
#define VTD_CAP_ND (((VTD_DOMAIN_ID_SHIFT - 4) / 2) & 7ULL)
|
||||
#define VTD_MGAW 39 /* Maximum Guest Address Width */
|
||||
#define VTD_ADDRESS_SIZE (1ULL << VTD_MGAW)
|
||||
#define VTD_CAP_MGAW (((VTD_MGAW - 1) & 0x3fULL) << 16)
|
||||
#define VTD_ADDRESS_SIZE(aw) (1ULL << (aw))
|
||||
#define VTD_CAP_MGAW(aw) ((((aw) - 1) & 0x3fULL) << 16)
|
||||
#define VTD_MAMV 18ULL
|
||||
#define VTD_CAP_MAMV (VTD_MAMV << 48)
|
||||
#define VTD_CAP_PSI (1ULL << 39)
|
||||
@@ -213,13 +212,12 @@
|
||||
#define VTD_CAP_SAGAW_39bit (0x2ULL << VTD_CAP_SAGAW_SHIFT)
|
||||
/* 48-bit AGAW, 4-level page-table */
|
||||
#define VTD_CAP_SAGAW_48bit (0x4ULL << VTD_CAP_SAGAW_SHIFT)
|
||||
#define VTD_CAP_SAGAW VTD_CAP_SAGAW_39bit
|
||||
|
||||
/* IQT_REG */
|
||||
#define VTD_IQT_QT(val) (((val) >> 4) & 0x7fffULL)
|
||||
|
||||
/* IQA_REG */
|
||||
#define VTD_IQA_IQA_MASK (VTD_HAW_MASK ^ 0xfffULL)
|
||||
#define VTD_IQA_IQA_MASK(aw) (VTD_HAW_MASK(aw) ^ 0xfffULL)
|
||||
#define VTD_IQA_QS 0x7ULL
|
||||
|
||||
/* IQH_REG */
|
||||
@@ -252,7 +250,7 @@
|
||||
#define VTD_FRCD_SID_MASK 0xffffULL
|
||||
#define VTD_FRCD_SID(val) ((val) & VTD_FRCD_SID_MASK)
|
||||
/* For the low 64-bit of 128-bit */
|
||||
#define VTD_FRCD_FI(val) ((val) & (((1ULL << VTD_MGAW) - 1) ^ 0xfffULL))
|
||||
#define VTD_FRCD_FI(val) ((val) & ~0xfffULL)
|
||||
|
||||
/* DMA Remapping Fault Conditions */
|
||||
typedef enum VTDFaultReason {
|
||||
@@ -360,8 +358,7 @@ typedef union VTDInvDesc VTDInvDesc;
|
||||
#define VTD_INV_DESC_IOTLB_DOMAIN (2ULL << 4)
|
||||
#define VTD_INV_DESC_IOTLB_PAGE (3ULL << 4)
|
||||
#define VTD_INV_DESC_IOTLB_DID(val) (((val) >> 16) & VTD_DOMAIN_ID_MASK)
|
||||
#define VTD_INV_DESC_IOTLB_ADDR(val) ((val) & ~0xfffULL & \
|
||||
((1ULL << VTD_MGAW) - 1))
|
||||
#define VTD_INV_DESC_IOTLB_ADDR(val) ((val) & ~0xfffULL)
|
||||
#define VTD_INV_DESC_IOTLB_AM(val) ((val) & 0x3fULL)
|
||||
#define VTD_INV_DESC_IOTLB_RSVD_LO 0xffffffff0000ff00ULL
|
||||
#define VTD_INV_DESC_IOTLB_RSVD_HI 0xf80ULL
|
||||
@@ -373,6 +370,24 @@ typedef union VTDInvDesc VTDInvDesc;
|
||||
#define VTD_INV_DESC_DEVICE_IOTLB_RSVD_HI 0xffeULL
|
||||
#define VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO 0xffff0000ffe0fff8
|
||||
|
||||
/* Rsvd field masks for spte */
|
||||
#define VTD_SPTE_PAGE_L1_RSVD_MASK(aw) \
|
||||
(0x800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM))
|
||||
#define VTD_SPTE_PAGE_L2_RSVD_MASK(aw) \
|
||||
(0x800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM))
|
||||
#define VTD_SPTE_PAGE_L3_RSVD_MASK(aw) \
|
||||
(0x800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM))
|
||||
#define VTD_SPTE_PAGE_L4_RSVD_MASK(aw) \
|
||||
(0x880ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM))
|
||||
#define VTD_SPTE_LPAGE_L1_RSVD_MASK(aw) \
|
||||
(0x800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM))
|
||||
#define VTD_SPTE_LPAGE_L2_RSVD_MASK(aw) \
|
||||
(0x1ff800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM))
|
||||
#define VTD_SPTE_LPAGE_L3_RSVD_MASK(aw) \
|
||||
(0x3ffff800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM))
|
||||
#define VTD_SPTE_LPAGE_L4_RSVD_MASK(aw) \
|
||||
(0x880ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM))
|
||||
|
||||
/* Information about page-selective IOTLB invalidate */
|
||||
struct VTDIOTLBPageInvInfo {
|
||||
uint16_t domain_id;
|
||||
@@ -403,7 +418,7 @@ typedef struct VTDRootEntry VTDRootEntry;
|
||||
#define VTD_ROOT_ENTRY_CTP (~0xfffULL)
|
||||
|
||||
#define VTD_ROOT_ENTRY_NR (VTD_PAGE_SIZE / sizeof(VTDRootEntry))
|
||||
#define VTD_ROOT_ENTRY_RSVD (0xffeULL | ~VTD_HAW_MASK)
|
||||
#define VTD_ROOT_ENTRY_RSVD(aw) (0xffeULL | ~VTD_HAW_MASK(aw))
|
||||
|
||||
/* Masks for struct VTDContextEntry */
|
||||
/* lo */
|
||||
@@ -415,7 +430,7 @@ typedef struct VTDRootEntry VTDRootEntry;
|
||||
#define VTD_CONTEXT_TT_PASS_THROUGH (2ULL << 2)
|
||||
/* Second Level Page Translation Pointer*/
|
||||
#define VTD_CONTEXT_ENTRY_SLPTPTR (~0xfffULL)
|
||||
#define VTD_CONTEXT_ENTRY_RSVD_LO (0xff0ULL | ~VTD_HAW_MASK)
|
||||
#define VTD_CONTEXT_ENTRY_RSVD_LO(aw) (0xff0ULL | ~VTD_HAW_MASK(aw))
|
||||
/* hi */
|
||||
#define VTD_CONTEXT_ENTRY_AW 7ULL /* Adjusted guest-address-width */
|
||||
#define VTD_CONTEXT_ENTRY_DID(val) (((val) >> 8) & VTD_DOMAIN_ID_MASK)
|
||||
@@ -439,7 +454,7 @@ typedef struct VTDRootEntry VTDRootEntry;
|
||||
#define VTD_SL_RW_MASK 3ULL
|
||||
#define VTD_SL_R 1ULL
|
||||
#define VTD_SL_W (1ULL << 1)
|
||||
#define VTD_SL_PT_BASE_ADDR_MASK (~(VTD_PAGE_SIZE - 1) & VTD_HAW_MASK)
|
||||
#define VTD_SL_PT_BASE_ADDR_MASK(aw) (~(VTD_PAGE_SIZE - 1) & VTD_HAW_MASK(aw))
|
||||
#define VTD_SL_IGN_COM 0xbff0000000000000ULL
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/i386/x86-iommu.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "trace.h"
|
||||
|
||||
@@ -80,7 +82,18 @@ static void x86_iommu_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(dev);
|
||||
X86IOMMUClass *x86_class = X86_IOMMU_GET_CLASS(dev);
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
||||
PCMachineState *pcms =
|
||||
PC_MACHINE(object_dynamic_cast(OBJECT(ms), TYPE_PC_MACHINE));
|
||||
QLIST_INIT(&x86_iommu->iec_notifiers);
|
||||
|
||||
if (!pcms || !pcms->bus) {
|
||||
error_setg(errp, "Machine-type '%s' not supported by IOMMU",
|
||||
mc->name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (x86_class->realize) {
|
||||
x86_class->realize(dev, errp);
|
||||
}
|
||||
|
||||
@@ -74,8 +74,13 @@ static void gen_rp_realize(DeviceState *dev, Error **errp)
|
||||
PCIDevice *d = PCI_DEVICE(dev);
|
||||
GenPCIERootPort *grp = GEN_PCIE_ROOT_PORT(d);
|
||||
PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(d);
|
||||
Error *local_err = NULL;
|
||||
|
||||
rpc->parent_realize(dev, errp);
|
||||
rpc->parent_realize(dev, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
int rc = pci_bridge_qemu_reserve_cap_init(d, 0, grp->bus_reserve,
|
||||
grp->io_reserve, grp->mem_reserve, grp->pref32_reserve,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user