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
vhost, pc, virtio features, fixes, cleanups
New features:
VT-d support for devices behind a bridge
vhost-user migration support
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
# gpg: Signature made Thu 22 Oct 2015 12:39:19 BST using RSA key ID D28D5469
# gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>"
# gpg: aka "Michael S. Tsirkin <mst@redhat.com>"
* remotes/mst/tags/for_upstream: (37 commits)
hw/isa/lpc_ich9: inject the SMI on the VCPU that is writing to APM_CNT
i386: keep cpu_model field in MachineState uptodate
vhost: set the correct queue index in case of migration with multiqueue
piix: fix resource leak reported by Coverity
seccomp: add memfd_create to whitelist
vhost-user-test: check ownership during migration
vhost-user-test: add live-migration test
vhost-user-test: learn to tweak various qemu arguments
vhost-user-test: wrap server in TestServer struct
vhost-user-test: remove useless static check
vhost-user-test: move wait_for_fds() out
vhost: add migration block if memfd failed
vhost-user: use an enum helper for features mask
vhost user: add rarp sending after live migration for legacy guest
vhost user: add support of live migration
net: add trace_vhost_user_event
vhost-user: document migration log
vhost: use a function for each call
vhost-user: add a migration blocker
vhost-user: send log shm fd along with log_base
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -3491,6 +3491,22 @@ if compile_prog "" "" ; then
|
||||
eventfd=yes
|
||||
fi
|
||||
|
||||
# check if memfd is supported
|
||||
memfd=no
|
||||
cat > $TMPC << EOF
|
||||
#include <sys/memfd.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return memfd_create("foo", MFD_ALLOW_SEALING);
|
||||
}
|
||||
EOF
|
||||
if compile_prog "" "" ; then
|
||||
memfd=yes
|
||||
fi
|
||||
|
||||
|
||||
|
||||
# check for fallocate
|
||||
fallocate=no
|
||||
cat > $TMPC << EOF
|
||||
@@ -4885,6 +4901,9 @@ fi
|
||||
if test "$eventfd" = "yes" ; then
|
||||
echo "CONFIG_EVENTFD=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$memfd" = "yes" ; then
|
||||
echo "CONFIG_MEMFD=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$fallocate" = "yes" ; then
|
||||
echo "CONFIG_FALLOCATE=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
@@ -115,11 +115,13 @@ the ones that do:
|
||||
* VHOST_GET_FEATURES
|
||||
* VHOST_GET_PROTOCOL_FEATURES
|
||||
* VHOST_GET_VRING_BASE
|
||||
* VHOST_SET_LOG_BASE (if VHOST_USER_PROTOCOL_F_LOG_SHMFD)
|
||||
|
||||
There are several messages that the master sends with file descriptors passed
|
||||
in the ancillary data:
|
||||
|
||||
* VHOST_SET_MEM_TABLE
|
||||
* VHOST_SET_LOG_BASE (if VHOST_USER_PROTOCOL_F_LOG_SHMFD)
|
||||
* VHOST_SET_LOG_FD
|
||||
* VHOST_SET_VRING_KICK
|
||||
* VHOST_SET_VRING_CALL
|
||||
@@ -140,8 +142,7 @@ Multiple queue support
|
||||
|
||||
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:
|
||||
#define VHOST_USER_PROTOCOL_F_MQ 0
|
||||
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
|
||||
@@ -152,6 +153,49 @@ queue in the sent message to identify a specified queue. One queue pair
|
||||
is enabled initially. More queues are enabled dynamically, by sending
|
||||
message VHOST_USER_SET_VRING_ENABLE.
|
||||
|
||||
Migration
|
||||
---------
|
||||
|
||||
During live migration, the master may need to track the modifications
|
||||
the slave makes to the memory mapped regions. The client should mark
|
||||
the dirty pages in a log. Once it complies to this logging, it may
|
||||
declare the VHOST_F_LOG_ALL vhost feature.
|
||||
|
||||
All the modifications to memory pointed by vring "descriptor" should
|
||||
be marked. Modifications to "used" vring should be marked if
|
||||
VHOST_VRING_F_LOG is part of ring's features.
|
||||
|
||||
Dirty pages are of size:
|
||||
#define VHOST_LOG_PAGE 0x1000
|
||||
|
||||
The log memory fd is provided in the ancillary data of
|
||||
VHOST_USER_SET_LOG_BASE message when the slave has
|
||||
VHOST_USER_PROTOCOL_F_LOG_SHMFD protocol feature.
|
||||
|
||||
The size of the log may be computed by using all the known guest
|
||||
addresses. The log covers from address 0 to the maximum of guest
|
||||
regions. In pseudo-code, to mark page at "addr" as dirty:
|
||||
|
||||
page = addr / VHOST_LOG_PAGE
|
||||
log[page / 8] |= 1 << page % 8
|
||||
|
||||
Use atomic operations, as the log may be concurrently manipulated.
|
||||
|
||||
VHOST_USER_SET_LOG_FD is an optional message with an eventfd in
|
||||
ancillary data, it may be used to inform the master that the log has
|
||||
been modified.
|
||||
|
||||
Once the source has finished migration, VHOST_USER_RESET_OWNER message
|
||||
will be sent by the source. No further update must be done before the
|
||||
destination takes over with new regions & rings.
|
||||
|
||||
Protocol features
|
||||
-----------------
|
||||
|
||||
#define VHOST_USER_PROTOCOL_F_MQ 0
|
||||
#define VHOST_USER_PROTOCOL_F_LOG_SHMFD 1
|
||||
#define VHOST_USER_PROTOCOL_F_RARP 2
|
||||
|
||||
Message types
|
||||
-------------
|
||||
|
||||
@@ -236,6 +280,7 @@ Message types
|
||||
Id: 6
|
||||
Equivalent ioctl: VHOST_SET_LOG_BASE
|
||||
Master payload: u64
|
||||
Slave payload: N/A
|
||||
|
||||
Sets the logging base address.
|
||||
|
||||
@@ -337,3 +382,17 @@ Message types
|
||||
Master payload: vring state description
|
||||
|
||||
Signal slave to enable or disable corresponding vring.
|
||||
|
||||
* VHOST_USER_SEND_RARP
|
||||
|
||||
Id: 19
|
||||
Equivalent ioctl: N/A
|
||||
Master payload: u64
|
||||
|
||||
Ask vhost user backend to broadcast a fake RARP to notify the migration
|
||||
is terminated for guest that does not support GUEST_ANNOUNCE.
|
||||
Only legal if feature bit VHOST_USER_F_PROTOCOL_FEATURES is present in
|
||||
VHOST_USER_GET_FEATURES and protocol feature bit VHOST_USER_PROTOCOL_F_RARP
|
||||
is present in VHOST_USER_GET_PROTOCOL_FEATURES.
|
||||
The first 6 bytes of the payload contain the mac address of the guest to
|
||||
allow the vhost user backend to construct and broadcast the fake RARP.
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
Virtio devices and migration
|
||||
============================
|
||||
|
||||
Copyright 2015 IBM Corp.
|
||||
|
||||
This work is licensed under the terms of the GNU GPL, version 2 or later. See
|
||||
the COPYING file in the top-level directory.
|
||||
|
||||
Saving and restoring the state of virtio devices is a bit of a twisty maze,
|
||||
for several reasons:
|
||||
- state is distributed between several parts:
|
||||
- virtio core, for common fields like features, number of queues, ...
|
||||
- virtio transport (pci, ccw, ...), for the different proxy devices and
|
||||
transport specific state (msix vectors, indicators, ...)
|
||||
- virtio device (net, blk, ...), for the different device types and their
|
||||
state (mac address, request queue, ...)
|
||||
- most fields are saved via the stream interface; subsequently, subsections
|
||||
have been added to make cross-version migration possible
|
||||
|
||||
This file attempts to document the current procedure and point out some
|
||||
caveats.
|
||||
|
||||
|
||||
Save state procedure
|
||||
====================
|
||||
|
||||
virtio core virtio transport virtio device
|
||||
----------- ---------------- -------------
|
||||
|
||||
save() function registered
|
||||
via register_savevm()
|
||||
virtio_save() <----------
|
||||
------> save_config()
|
||||
- save proxy device
|
||||
- save transport-specific
|
||||
device fields
|
||||
- save common device
|
||||
fields
|
||||
- save common virtqueue
|
||||
fields
|
||||
------> save_queue()
|
||||
- save transport-specific
|
||||
virtqueue fields
|
||||
------> save_device()
|
||||
- save device-specific
|
||||
fields
|
||||
- save subsections
|
||||
- device endianness,
|
||||
if changed from
|
||||
default endianness
|
||||
- 64 bit features, if
|
||||
any high feature bit
|
||||
is set
|
||||
- virtio-1 virtqueue
|
||||
fields, if VERSION_1
|
||||
is set
|
||||
|
||||
|
||||
Load state procedure
|
||||
====================
|
||||
|
||||
virtio core virtio transport virtio device
|
||||
----------- ---------------- -------------
|
||||
|
||||
load() function registered
|
||||
via register_savevm()
|
||||
virtio_load() <----------
|
||||
------> load_config()
|
||||
- load proxy device
|
||||
- load transport-specific
|
||||
device fields
|
||||
- load common device
|
||||
fields
|
||||
- load common virtqueue
|
||||
fields
|
||||
------> load_queue()
|
||||
- load transport-specific
|
||||
virtqueue fields
|
||||
- notify guest
|
||||
------> load_device()
|
||||
- load device-specific
|
||||
fields
|
||||
- load subsections
|
||||
- device endianness
|
||||
- 64 bit features
|
||||
- virtio-1 virtqueue
|
||||
fields
|
||||
- sanitize endianness
|
||||
- sanitize features
|
||||
- virtqueue index sanity
|
||||
check
|
||||
- feature-dependent setup
|
||||
|
||||
|
||||
Implications of this setup
|
||||
==========================
|
||||
|
||||
Devices need to be careful in their state processing during load: The
|
||||
load_device() procedure is invoked by the core before subsections have
|
||||
been loaded. Any code that depends on information transmitted in subsections
|
||||
therefore has to be invoked in the device's load() function _after_
|
||||
virtio_load() returned (like e.g. code depending on features).
|
||||
|
||||
Any extension of the state being migrated should be done in subsections
|
||||
added to the core for compatibility reasons. If transport or device specific
|
||||
state is added, core needs to invoke a callback from the new subsection.
|
||||
@@ -55,6 +55,9 @@
|
||||
#include "exec/ram_addr.h"
|
||||
|
||||
#include "qemu/range.h"
|
||||
#ifndef _WIN32
|
||||
#include "qemu/mmap-alloc.h"
|
||||
#endif
|
||||
|
||||
//#define DEBUG_SUBPAGE
|
||||
|
||||
@@ -84,9 +87,9 @@ static MemoryRegion io_mem_unassigned;
|
||||
*/
|
||||
#define RAM_RESIZEABLE (1 << 2)
|
||||
|
||||
/* An extra page is mapped on top of this RAM.
|
||||
/* RAM is backed by an mmapped file.
|
||||
*/
|
||||
#define RAM_EXTRA (1 << 3)
|
||||
#define RAM_FILE (1 << 3)
|
||||
#endif
|
||||
|
||||
struct CPUTailQ cpus = QTAILQ_HEAD_INITIALIZER(cpus);
|
||||
@@ -1205,13 +1208,10 @@ static void *file_ram_alloc(RAMBlock *block,
|
||||
char *filename;
|
||||
char *sanitized_name;
|
||||
char *c;
|
||||
void *ptr;
|
||||
void *area = NULL;
|
||||
void *area;
|
||||
int fd;
|
||||
uint64_t hpagesize;
|
||||
uint64_t total;
|
||||
Error *local_err = NULL;
|
||||
size_t offset;
|
||||
|
||||
hpagesize = gethugepagesize(path, &local_err);
|
||||
if (local_err) {
|
||||
@@ -1255,7 +1255,6 @@ static void *file_ram_alloc(RAMBlock *block,
|
||||
g_free(filename);
|
||||
|
||||
memory = ROUND_UP(memory, hpagesize);
|
||||
total = memory + hpagesize;
|
||||
|
||||
/*
|
||||
* ftruncate is not supported by hugetlbfs in older
|
||||
@@ -1267,40 +1266,14 @@ static void *file_ram_alloc(RAMBlock *block,
|
||||
perror("ftruncate");
|
||||
}
|
||||
|
||||
ptr = mmap(0, total, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
if (ptr == MAP_FAILED) {
|
||||
error_setg_errno(errp, errno,
|
||||
"unable to allocate memory range for hugepages");
|
||||
close(fd);
|
||||
goto error;
|
||||
}
|
||||
|
||||
offset = QEMU_ALIGN_UP((uintptr_t)ptr, hpagesize) - (uintptr_t)ptr;
|
||||
|
||||
area = mmap(ptr + offset, memory, PROT_READ | PROT_WRITE,
|
||||
(block->flags & RAM_SHARED ? MAP_SHARED : MAP_PRIVATE) |
|
||||
MAP_FIXED,
|
||||
fd, 0);
|
||||
area = qemu_ram_mmap(fd, memory, hpagesize, block->flags & RAM_SHARED);
|
||||
if (area == MAP_FAILED) {
|
||||
error_setg_errno(errp, errno,
|
||||
"unable to map backing store for hugepages");
|
||||
munmap(ptr, total);
|
||||
close(fd);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (offset > 0) {
|
||||
munmap(ptr, offset);
|
||||
}
|
||||
ptr += offset;
|
||||
total -= offset;
|
||||
|
||||
if (total > memory + getpagesize()) {
|
||||
munmap(ptr + memory + getpagesize(),
|
||||
total - memory - getpagesize());
|
||||
}
|
||||
|
||||
if (mem_prealloc) {
|
||||
os_mem_prealloc(fd, area, memory);
|
||||
}
|
||||
@@ -1618,7 +1591,7 @@ ram_addr_t qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
|
||||
new_block->used_length = size;
|
||||
new_block->max_length = size;
|
||||
new_block->flags = share ? RAM_SHARED : 0;
|
||||
new_block->flags |= RAM_EXTRA;
|
||||
new_block->flags |= RAM_FILE;
|
||||
new_block->host = file_ram_alloc(new_block, size,
|
||||
mem_path, errp);
|
||||
if (!new_block->host) {
|
||||
@@ -1720,8 +1693,8 @@ static void reclaim_ramblock(RAMBlock *block)
|
||||
xen_invalidate_map_cache_entry(block->host);
|
||||
#ifndef _WIN32
|
||||
} else if (block->fd >= 0) {
|
||||
if (block->flags & RAM_EXTRA) {
|
||||
munmap(block->host, block->max_length + getpagesize());
|
||||
if (block->flags & RAM_FILE) {
|
||||
qemu_ram_munmap(block->host, block->max_length);
|
||||
} else {
|
||||
munmap(block->host, block->max_length);
|
||||
}
|
||||
|
||||
+73
-16
@@ -22,6 +22,7 @@
|
||||
#include "hw/sysbus.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "intel_iommu_internal.h"
|
||||
#include "hw/pci/pci.h"
|
||||
|
||||
/*#define DEBUG_INTEL_IOMMU*/
|
||||
#ifdef DEBUG_INTEL_IOMMU
|
||||
@@ -166,19 +167,17 @@ static gboolean vtd_hash_remove_by_page(gpointer key, gpointer value,
|
||||
*/
|
||||
static void vtd_reset_context_cache(IntelIOMMUState *s)
|
||||
{
|
||||
VTDAddressSpace **pvtd_as;
|
||||
VTDAddressSpace *vtd_as;
|
||||
uint32_t bus_it;
|
||||
VTDBus *vtd_bus;
|
||||
GHashTableIter bus_it;
|
||||
uint32_t devfn_it;
|
||||
|
||||
g_hash_table_iter_init(&bus_it, s->vtd_as_by_busptr);
|
||||
|
||||
VTD_DPRINTF(CACHE, "global context_cache_gen=1");
|
||||
for (bus_it = 0; bus_it < VTD_PCI_BUS_MAX; ++bus_it) {
|
||||
pvtd_as = s->address_spaces[bus_it];
|
||||
if (!pvtd_as) {
|
||||
continue;
|
||||
}
|
||||
while (g_hash_table_iter_next (&bus_it, NULL, (void**)&vtd_bus)) {
|
||||
for (devfn_it = 0; devfn_it < VTD_PCI_DEVFN_MAX; ++devfn_it) {
|
||||
vtd_as = pvtd_as[devfn_it];
|
||||
vtd_as = vtd_bus->dev_as[devfn_it];
|
||||
if (!vtd_as) {
|
||||
continue;
|
||||
}
|
||||
@@ -754,12 +753,13 @@ static inline bool vtd_is_interrupt_addr(hwaddr addr)
|
||||
* @is_write: The access is a write operation
|
||||
* @entry: IOMMUTLBEntry that contain the addr to be translated and result
|
||||
*/
|
||||
static void vtd_do_iommu_translate(VTDAddressSpace *vtd_as, uint8_t bus_num,
|
||||
static void vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
|
||||
uint8_t devfn, hwaddr addr, bool is_write,
|
||||
IOMMUTLBEntry *entry)
|
||||
{
|
||||
IntelIOMMUState *s = vtd_as->iommu_state;
|
||||
VTDContextEntry ce;
|
||||
uint8_t bus_num = pci_bus_num(bus);
|
||||
VTDContextCacheEntry *cc_entry = &vtd_as->context_cache_entry;
|
||||
uint64_t slpte;
|
||||
uint32_t level;
|
||||
@@ -874,6 +874,29 @@ static void vtd_context_global_invalidate(IntelIOMMUState *s)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Find the VTD address space currently associated with a given bus number,
|
||||
*/
|
||||
static VTDBus *vtd_find_as_from_bus_num(IntelIOMMUState *s, uint8_t bus_num)
|
||||
{
|
||||
VTDBus *vtd_bus = s->vtd_as_by_bus_num[bus_num];
|
||||
if (!vtd_bus) {
|
||||
/* Iterate over the registered buses to find the one
|
||||
* which currently hold this bus number, and update the bus_num lookup table:
|
||||
*/
|
||||
GHashTableIter iter;
|
||||
|
||||
g_hash_table_iter_init(&iter, s->vtd_as_by_busptr);
|
||||
while (g_hash_table_iter_next (&iter, NULL, (void**)&vtd_bus)) {
|
||||
if (pci_bus_num(vtd_bus->bus) == bus_num) {
|
||||
s->vtd_as_by_bus_num[bus_num] = vtd_bus;
|
||||
return vtd_bus;
|
||||
}
|
||||
}
|
||||
}
|
||||
return vtd_bus;
|
||||
}
|
||||
|
||||
/* Do a context-cache device-selective invalidation.
|
||||
* @func_mask: FM field after shifting
|
||||
*/
|
||||
@@ -882,7 +905,7 @@ static void vtd_context_device_invalidate(IntelIOMMUState *s,
|
||||
uint16_t func_mask)
|
||||
{
|
||||
uint16_t mask;
|
||||
VTDAddressSpace **pvtd_as;
|
||||
VTDBus *vtd_bus;
|
||||
VTDAddressSpace *vtd_as;
|
||||
uint16_t devfn;
|
||||
uint16_t devfn_it;
|
||||
@@ -903,11 +926,11 @@ static void vtd_context_device_invalidate(IntelIOMMUState *s,
|
||||
}
|
||||
VTD_DPRINTF(INV, "device-selective invalidation source 0x%"PRIx16
|
||||
" mask %"PRIu16, source_id, mask);
|
||||
pvtd_as = s->address_spaces[VTD_SID_TO_BUS(source_id)];
|
||||
if (pvtd_as) {
|
||||
vtd_bus = vtd_find_as_from_bus_num(s, VTD_SID_TO_BUS(source_id));
|
||||
if (vtd_bus) {
|
||||
devfn = VTD_SID_TO_DEVFN(source_id);
|
||||
for (devfn_it = 0; devfn_it < VTD_PCI_DEVFN_MAX; ++devfn_it) {
|
||||
vtd_as = pvtd_as[devfn_it];
|
||||
vtd_as = vtd_bus->dev_as[devfn_it];
|
||||
if (vtd_as && ((devfn_it & mask) == (devfn & mask))) {
|
||||
VTD_DPRINTF(INV, "invalidate context-cahce of devfn 0x%"PRIx16,
|
||||
devfn_it);
|
||||
@@ -1805,11 +1828,11 @@ static IOMMUTLBEntry vtd_iommu_translate(MemoryRegion *iommu, hwaddr addr,
|
||||
return ret;
|
||||
}
|
||||
|
||||
vtd_do_iommu_translate(vtd_as, vtd_as->bus_num, vtd_as->devfn, addr,
|
||||
vtd_do_iommu_translate(vtd_as, vtd_as->bus, vtd_as->devfn, addr,
|
||||
is_write, &ret);
|
||||
VTD_DPRINTF(MMU,
|
||||
"bus %"PRIu8 " slot %"PRIu8 " func %"PRIu8 " devfn %"PRIu8
|
||||
" gpa 0x%"PRIx64 " hpa 0x%"PRIx64, vtd_as->bus_num,
|
||||
" gpa 0x%"PRIx64 " hpa 0x%"PRIx64, pci_bus_num(vtd_as->bus),
|
||||
VTD_PCI_SLOT(vtd_as->devfn), VTD_PCI_FUNC(vtd_as->devfn),
|
||||
vtd_as->devfn, addr, ret.translated_addr);
|
||||
return ret;
|
||||
@@ -1839,6 +1862,38 @@ static Property vtd_properties[] = {
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
||||
VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn)
|
||||
{
|
||||
uintptr_t key = (uintptr_t)bus;
|
||||
VTDBus *vtd_bus = g_hash_table_lookup(s->vtd_as_by_busptr, &key);
|
||||
VTDAddressSpace *vtd_dev_as;
|
||||
|
||||
if (!vtd_bus) {
|
||||
/* No corresponding free() */
|
||||
vtd_bus = g_malloc0(sizeof(VTDBus) + sizeof(VTDAddressSpace *) * VTD_PCI_DEVFN_MAX);
|
||||
vtd_bus->bus = bus;
|
||||
key = (uintptr_t)bus;
|
||||
g_hash_table_insert(s->vtd_as_by_busptr, &key, vtd_bus);
|
||||
}
|
||||
|
||||
vtd_dev_as = vtd_bus->dev_as[devfn];
|
||||
|
||||
if (!vtd_dev_as) {
|
||||
vtd_bus->dev_as[devfn] = vtd_dev_as = g_malloc0(sizeof(VTDAddressSpace));
|
||||
|
||||
vtd_dev_as->bus = bus;
|
||||
vtd_dev_as->devfn = (uint8_t)devfn;
|
||||
vtd_dev_as->iommu_state = s;
|
||||
vtd_dev_as->context_cache_entry.context_cache_gen = 0;
|
||||
memory_region_init_iommu(&vtd_dev_as->iommu, OBJECT(s),
|
||||
&s->iommu_ops, "intel_iommu", UINT64_MAX);
|
||||
address_space_init(&vtd_dev_as->as,
|
||||
&vtd_dev_as->iommu, "intel_iommu");
|
||||
}
|
||||
return vtd_dev_as;
|
||||
}
|
||||
|
||||
/* Do the initialization. It will also be called when reset, so pay
|
||||
* attention when adding new initialization stuff.
|
||||
*/
|
||||
@@ -1931,13 +1986,15 @@ static void vtd_realize(DeviceState *dev, Error **errp)
|
||||
IntelIOMMUState *s = INTEL_IOMMU_DEVICE(dev);
|
||||
|
||||
VTD_DPRINTF(GENERAL, "");
|
||||
memset(s->address_spaces, 0, sizeof(s->address_spaces));
|
||||
memset(s->vtd_as_by_bus_num, 0, sizeof(s->vtd_as_by_bus_num));
|
||||
memory_region_init_io(&s->csrmem, OBJECT(s), &vtd_mem_ops, s,
|
||||
"intel_iommu", DMAR_REG_SIZE);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->csrmem);
|
||||
/* No corresponding destroy */
|
||||
s->iotlb = g_hash_table_new_full(vtd_uint64_hash, vtd_uint64_equal,
|
||||
g_free, g_free);
|
||||
s->vtd_as_by_busptr = g_hash_table_new_full(vtd_uint64_hash, vtd_uint64_equal,
|
||||
g_free, g_free);
|
||||
vtd_init(s);
|
||||
}
|
||||
|
||||
|
||||
+8
-9
@@ -1078,11 +1078,10 @@ out:
|
||||
return cpu;
|
||||
}
|
||||
|
||||
static const char *current_cpu_model;
|
||||
|
||||
void pc_hot_add_cpu(const int64_t id, Error **errp)
|
||||
{
|
||||
X86CPU *cpu;
|
||||
MachineState *machine = MACHINE(qdev_get_machine());
|
||||
int64_t apic_id = x86_cpu_apic_id_from_index(id);
|
||||
Error *local_err = NULL;
|
||||
|
||||
@@ -1110,7 +1109,7 @@ void pc_hot_add_cpu(const int64_t id, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
cpu = pc_new_cpu(current_cpu_model, apic_id, &local_err);
|
||||
cpu = pc_new_cpu(machine->cpu_model, apic_id, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
@@ -1118,22 +1117,22 @@ void pc_hot_add_cpu(const int64_t id, Error **errp)
|
||||
object_unref(OBJECT(cpu));
|
||||
}
|
||||
|
||||
void pc_cpus_init(const char *cpu_model)
|
||||
void pc_cpus_init(PCMachineState *pcms)
|
||||
{
|
||||
int i;
|
||||
X86CPU *cpu = NULL;
|
||||
MachineState *machine = MACHINE(pcms);
|
||||
Error *error = NULL;
|
||||
unsigned long apic_id_limit;
|
||||
|
||||
/* init CPUs */
|
||||
if (cpu_model == NULL) {
|
||||
if (machine->cpu_model == NULL) {
|
||||
#ifdef TARGET_X86_64
|
||||
cpu_model = "qemu64";
|
||||
machine->cpu_model = "qemu64";
|
||||
#else
|
||||
cpu_model = "qemu32";
|
||||
machine->cpu_model = "qemu32";
|
||||
#endif
|
||||
}
|
||||
current_cpu_model = cpu_model;
|
||||
|
||||
apic_id_limit = pc_apic_id_limit(max_cpus);
|
||||
if (apic_id_limit > ACPI_CPU_HOTPLUG_ID_LIMIT) {
|
||||
@@ -1143,7 +1142,7 @@ void pc_cpus_init(const char *cpu_model)
|
||||
}
|
||||
|
||||
for (i = 0; i < smp_cpus; i++) {
|
||||
cpu = pc_new_cpu(cpu_model, x86_cpu_apic_id_from_index(i),
|
||||
cpu = pc_new_cpu(machine->cpu_model, x86_cpu_apic_id_from_index(i),
|
||||
&error);
|
||||
if (error) {
|
||||
error_report_err(error);
|
||||
|
||||
+1
-1
@@ -139,7 +139,7 @@ static void pc_init1(MachineState *machine,
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pc_cpus_init(machine->cpu_model);
|
||||
pc_cpus_init(pcms);
|
||||
|
||||
if (kvm_enabled() && kvmclock_enabled) {
|
||||
kvmclock_create();
|
||||
|
||||
+1
-1
@@ -128,7 +128,7 @@ static void pc_q35_init(MachineState *machine)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pc_cpus_init(machine->cpu_model);
|
||||
pc_cpus_init(pcms);
|
||||
pc_acpi_init("q35-acpi-dsdt.aml");
|
||||
|
||||
kvmclock_create();
|
||||
|
||||
+1
-1
@@ -394,7 +394,7 @@ static void ich9_apm_ctrl_changed(uint32_t val, void *arg)
|
||||
|
||||
/* SMI_EN = PMBASE + 30. SMI control and enable register */
|
||||
if (lpc->pm.smi_en & ICH9_PMIO_SMI_EN_APMC_EN) {
|
||||
cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI);
|
||||
cpu_interrupt(current_cpu, CPU_INTERRUPT_SMI);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "sysemu/numa.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "trace.h"
|
||||
#include "hw/virtio/vhost.h"
|
||||
|
||||
typedef struct pc_dimms_capacity {
|
||||
uint64_t size;
|
||||
@@ -96,6 +97,12 @@ void pc_dimm_memory_plug(DeviceState *dev, MemoryHotplugState *hpms,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!vhost_has_free_slot()) {
|
||||
error_setg(&local_err, "a used vhost backend has no free"
|
||||
" memory slots left");
|
||||
goto out;
|
||||
}
|
||||
|
||||
memory_region_add_subregion(&hpms->mr, addr - hpms->base, mr);
|
||||
vmstate_register_ram(mr, dev);
|
||||
numa_set_mem_node_id(addr, memory_region_size(mr), dimm->node);
|
||||
|
||||
+25
-10
@@ -85,6 +85,8 @@ static const int user_feature_bits[] = {
|
||||
VIRTIO_NET_F_CTRL_MAC_ADDR,
|
||||
VIRTIO_NET_F_CTRL_GUEST_OFFLOADS,
|
||||
|
||||
VIRTIO_NET_F_GUEST_ANNOUNCE,
|
||||
|
||||
VIRTIO_NET_F_MQ,
|
||||
|
||||
VHOST_INVALID_FEATURE_BIT
|
||||
@@ -252,8 +254,7 @@ static int vhost_net_start_one(struct vhost_net *net,
|
||||
file.fd = net->backend;
|
||||
for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
|
||||
const VhostOps *vhost_ops = net->dev.vhost_ops;
|
||||
r = vhost_ops->vhost_call(&net->dev, VHOST_NET_SET_BACKEND,
|
||||
&file);
|
||||
r = vhost_ops->vhost_net_set_backend(&net->dev, &file);
|
||||
if (r < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
@@ -266,8 +267,7 @@ fail:
|
||||
if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP) {
|
||||
while (file.index-- > 0) {
|
||||
const VhostOps *vhost_ops = net->dev.vhost_ops;
|
||||
int r = vhost_ops->vhost_call(&net->dev, VHOST_NET_SET_BACKEND,
|
||||
&file);
|
||||
int r = vhost_ops->vhost_net_set_backend(&net->dev, &file);
|
||||
assert(r >= 0);
|
||||
}
|
||||
}
|
||||
@@ -289,15 +289,13 @@ static void vhost_net_stop_one(struct vhost_net *net,
|
||||
if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP) {
|
||||
for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
|
||||
const VhostOps *vhost_ops = net->dev.vhost_ops;
|
||||
int r = vhost_ops->vhost_call(&net->dev, VHOST_NET_SET_BACKEND,
|
||||
&file);
|
||||
int r = vhost_ops->vhost_net_set_backend(&net->dev, &file);
|
||||
assert(r >= 0);
|
||||
}
|
||||
} else if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER) {
|
||||
for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
|
||||
const VhostOps *vhost_ops = net->dev.vhost_ops;
|
||||
int r = vhost_ops->vhost_call(&net->dev, VHOST_RESET_DEVICE,
|
||||
NULL);
|
||||
int r = vhost_ops->vhost_reset_device(&net->dev);
|
||||
assert(r >= 0);
|
||||
}
|
||||
}
|
||||
@@ -390,6 +388,18 @@ void vhost_net_cleanup(struct vhost_net *net)
|
||||
g_free(net);
|
||||
}
|
||||
|
||||
int vhost_net_notify_migration_done(struct vhost_net *net, char* mac_addr)
|
||||
{
|
||||
const VhostOps *vhost_ops = net->dev.vhost_ops;
|
||||
int r = -1;
|
||||
|
||||
if (vhost_ops->vhost_migration_done) {
|
||||
r = vhost_ops->vhost_migration_done(&net->dev, mac_addr);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
bool vhost_net_virtqueue_pending(VHostNetState *net, int idx)
|
||||
{
|
||||
return vhost_virtqueue_pending(&net->dev, idx);
|
||||
@@ -428,8 +438,8 @@ int vhost_set_vring_enable(NetClientState *nc, int enable)
|
||||
VHostNetState *net = get_vhost_net(nc);
|
||||
const VhostOps *vhost_ops = net->dev.vhost_ops;
|
||||
|
||||
if (vhost_ops->vhost_backend_set_vring_enable) {
|
||||
return vhost_ops->vhost_backend_set_vring_enable(&net->dev, enable);
|
||||
if (vhost_ops->vhost_set_vring_enable) {
|
||||
return vhost_ops->vhost_set_vring_enable(&net->dev, enable);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -481,6 +491,11 @@ void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev,
|
||||
{
|
||||
}
|
||||
|
||||
int vhost_net_notify_migration_done(struct vhost_net *net, char* mac_addr)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
VHostNetState *get_vhost_net(NetClientState *nc)
|
||||
{
|
||||
return 0;
|
||||
|
||||
+7
-4
@@ -764,6 +764,7 @@ static int host_pci_config_read(int pos, int len, uint32_t val)
|
||||
/* Access real host bridge. */
|
||||
int rc = snprintf(path, size, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/%s",
|
||||
0, 0, 0, 0, "config");
|
||||
int ret = 0;
|
||||
|
||||
if (rc >= size || rc < 0) {
|
||||
return -ENODEV;
|
||||
@@ -775,16 +776,18 @@ static int host_pci_config_read(int pos, int len, uint32_t val)
|
||||
}
|
||||
|
||||
if (lseek(config_fd, pos, SEEK_SET) != pos) {
|
||||
return -errno;
|
||||
ret = -errno;
|
||||
goto out;
|
||||
}
|
||||
do {
|
||||
rc = read(config_fd, (uint8_t *)&val, len);
|
||||
} while (rc < 0 && (errno == EINTR || errno == EAGAIN));
|
||||
if (rc != len) {
|
||||
return -errno;
|
||||
ret = -errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
out:
|
||||
close(config_fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int igd_pt_i440fx_initfn(struct PCIDevice *pci_dev)
|
||||
|
||||
+3
-22
@@ -426,31 +426,12 @@ static void mch_reset(DeviceState *qdev)
|
||||
static AddressSpace *q35_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
|
||||
{
|
||||
IntelIOMMUState *s = opaque;
|
||||
VTDAddressSpace **pvtd_as;
|
||||
int bus_num = pci_bus_num(bus);
|
||||
VTDAddressSpace *vtd_as;
|
||||
|
||||
assert(0 <= bus_num && bus_num <= VTD_PCI_BUS_MAX);
|
||||
assert(0 <= devfn && devfn <= VTD_PCI_DEVFN_MAX);
|
||||
|
||||
pvtd_as = s->address_spaces[bus_num];
|
||||
if (!pvtd_as) {
|
||||
/* No corresponding free() */
|
||||
pvtd_as = g_malloc0(sizeof(VTDAddressSpace *) * VTD_PCI_DEVFN_MAX);
|
||||
s->address_spaces[bus_num] = pvtd_as;
|
||||
}
|
||||
if (!pvtd_as[devfn]) {
|
||||
pvtd_as[devfn] = g_malloc0(sizeof(VTDAddressSpace));
|
||||
|
||||
pvtd_as[devfn]->bus_num = (uint8_t)bus_num;
|
||||
pvtd_as[devfn]->devfn = (uint8_t)devfn;
|
||||
pvtd_as[devfn]->iommu_state = s;
|
||||
pvtd_as[devfn]->context_cache_entry.context_cache_gen = 0;
|
||||
memory_region_init_iommu(&pvtd_as[devfn]->iommu, OBJECT(s),
|
||||
&s->iommu_ops, "intel_iommu", UINT64_MAX);
|
||||
address_space_init(&pvtd_as[devfn]->as,
|
||||
&pvtd_as[devfn]->iommu, "intel_iommu");
|
||||
}
|
||||
return &pvtd_as[devfn]->as;
|
||||
vtd_as = vtd_find_add_as(s, bus, devfn);
|
||||
return &vtd_as->as;
|
||||
}
|
||||
|
||||
static void mch_init_dmar(MCHPCIState *mch)
|
||||
|
||||
@@ -46,7 +46,7 @@ static int vhost_scsi_set_endpoint(VHostSCSI *s)
|
||||
|
||||
memset(&backend, 0, sizeof(backend));
|
||||
pstrcpy(backend.vhost_wwpn, sizeof(backend.vhost_wwpn), vs->conf.wwpn);
|
||||
ret = vhost_ops->vhost_call(&s->dev, VHOST_SCSI_SET_ENDPOINT, &backend);
|
||||
ret = vhost_ops->vhost_scsi_set_endpoint(&s->dev, &backend);
|
||||
if (ret < 0) {
|
||||
return -errno;
|
||||
}
|
||||
@@ -61,7 +61,7 @@ static void vhost_scsi_clear_endpoint(VHostSCSI *s)
|
||||
|
||||
memset(&backend, 0, sizeof(backend));
|
||||
pstrcpy(backend.vhost_wwpn, sizeof(backend.vhost_wwpn), vs->conf.wwpn);
|
||||
vhost_ops->vhost_call(&s->dev, VHOST_SCSI_CLEAR_ENDPOINT, &backend);
|
||||
vhost_ops->vhost_scsi_clear_endpoint(&s->dev, &backend);
|
||||
}
|
||||
|
||||
static int vhost_scsi_start(VHostSCSI *s)
|
||||
@@ -77,8 +77,7 @@ static int vhost_scsi_start(VHostSCSI *s)
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
ret = vhost_ops->vhost_call(&s->dev,
|
||||
VHOST_SCSI_GET_ABI_VERSION, &abi_version);
|
||||
ret = vhost_ops->vhost_scsi_get_abi_version(&s->dev, &abi_version);
|
||||
if (ret < 0) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
+136
-2
@@ -11,6 +11,7 @@
|
||||
#include "hw/virtio/vhost.h"
|
||||
#include "hw/virtio/vhost-backend.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "linux/vhost.h"
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
@@ -42,6 +43,122 @@ static int vhost_kernel_cleanup(struct vhost_dev *dev)
|
||||
return close(fd);
|
||||
}
|
||||
|
||||
static int vhost_kernel_memslots_limit(struct vhost_dev *dev)
|
||||
{
|
||||
int limit = 64;
|
||||
char *s;
|
||||
|
||||
if (g_file_get_contents("/sys/module/vhost/parameters/max_mem_regions",
|
||||
&s, NULL, NULL)) {
|
||||
uint64_t val = g_ascii_strtoull(s, NULL, 10);
|
||||
if (!((val == G_MAXUINT64 || !val) && errno)) {
|
||||
return val;
|
||||
}
|
||||
error_report("ignoring invalid max_mem_regions value in vhost module:"
|
||||
" %s", s);
|
||||
}
|
||||
return limit;
|
||||
}
|
||||
|
||||
static int vhost_kernel_net_set_backend(struct vhost_dev *dev,
|
||||
struct vhost_vring_file *file)
|
||||
{
|
||||
return vhost_kernel_call(dev, VHOST_NET_SET_BACKEND, file);
|
||||
}
|
||||
|
||||
static int vhost_kernel_scsi_set_endpoint(struct vhost_dev *dev,
|
||||
struct vhost_scsi_target *target)
|
||||
{
|
||||
return vhost_kernel_call(dev, VHOST_SCSI_SET_ENDPOINT, target);
|
||||
}
|
||||
|
||||
static int vhost_kernel_scsi_clear_endpoint(struct vhost_dev *dev,
|
||||
struct vhost_scsi_target *target)
|
||||
{
|
||||
return vhost_kernel_call(dev, VHOST_SCSI_CLEAR_ENDPOINT, target);
|
||||
}
|
||||
|
||||
static int vhost_kernel_scsi_get_abi_version(struct vhost_dev *dev, int *version)
|
||||
{
|
||||
return vhost_kernel_call(dev, VHOST_SCSI_GET_ABI_VERSION, version);
|
||||
}
|
||||
|
||||
static int vhost_kernel_set_log_base(struct vhost_dev *dev, uint64_t base,
|
||||
struct vhost_log *log)
|
||||
{
|
||||
return vhost_kernel_call(dev, VHOST_SET_LOG_BASE, &base);
|
||||
}
|
||||
|
||||
static int vhost_kernel_set_mem_table(struct vhost_dev *dev,
|
||||
struct vhost_memory *mem)
|
||||
{
|
||||
return vhost_kernel_call(dev, VHOST_SET_MEM_TABLE, mem);
|
||||
}
|
||||
|
||||
static int vhost_kernel_set_vring_addr(struct vhost_dev *dev,
|
||||
struct vhost_vring_addr *addr)
|
||||
{
|
||||
return vhost_kernel_call(dev, VHOST_SET_VRING_ADDR, addr);
|
||||
}
|
||||
|
||||
static int vhost_kernel_set_vring_endian(struct vhost_dev *dev,
|
||||
struct vhost_vring_state *ring)
|
||||
{
|
||||
return vhost_kernel_call(dev, VHOST_SET_VRING_ENDIAN, ring);
|
||||
}
|
||||
|
||||
static int vhost_kernel_set_vring_num(struct vhost_dev *dev,
|
||||
struct vhost_vring_state *ring)
|
||||
{
|
||||
return vhost_kernel_call(dev, VHOST_SET_VRING_NUM, ring);
|
||||
}
|
||||
|
||||
static int vhost_kernel_set_vring_base(struct vhost_dev *dev,
|
||||
struct vhost_vring_state *ring)
|
||||
{
|
||||
return vhost_kernel_call(dev, VHOST_SET_VRING_BASE, ring);
|
||||
}
|
||||
|
||||
static int vhost_kernel_get_vring_base(struct vhost_dev *dev,
|
||||
struct vhost_vring_state *ring)
|
||||
{
|
||||
return vhost_kernel_call(dev, VHOST_GET_VRING_BASE, ring);
|
||||
}
|
||||
|
||||
static int vhost_kernel_set_vring_kick(struct vhost_dev *dev,
|
||||
struct vhost_vring_file *file)
|
||||
{
|
||||
return vhost_kernel_call(dev, VHOST_SET_VRING_KICK, file);
|
||||
}
|
||||
|
||||
static int vhost_kernel_set_vring_call(struct vhost_dev *dev,
|
||||
struct vhost_vring_file *file)
|
||||
{
|
||||
return vhost_kernel_call(dev, VHOST_SET_VRING_CALL, file);
|
||||
}
|
||||
|
||||
static int vhost_kernel_set_features(struct vhost_dev *dev,
|
||||
uint64_t features)
|
||||
{
|
||||
return vhost_kernel_call(dev, VHOST_SET_FEATURES, &features);
|
||||
}
|
||||
|
||||
static int vhost_kernel_get_features(struct vhost_dev *dev,
|
||||
uint64_t *features)
|
||||
{
|
||||
return vhost_kernel_call(dev, VHOST_GET_FEATURES, features);
|
||||
}
|
||||
|
||||
static int vhost_kernel_set_owner(struct vhost_dev *dev)
|
||||
{
|
||||
return vhost_kernel_call(dev, VHOST_SET_OWNER, NULL);
|
||||
}
|
||||
|
||||
static int vhost_kernel_reset_device(struct vhost_dev *dev)
|
||||
{
|
||||
return vhost_kernel_call(dev, VHOST_RESET_DEVICE, NULL);
|
||||
}
|
||||
|
||||
static int vhost_kernel_get_vq_index(struct vhost_dev *dev, int idx)
|
||||
{
|
||||
assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs);
|
||||
@@ -51,10 +168,27 @@ static int vhost_kernel_get_vq_index(struct vhost_dev *dev, int idx)
|
||||
|
||||
static const VhostOps kernel_ops = {
|
||||
.backend_type = VHOST_BACKEND_TYPE_KERNEL,
|
||||
.vhost_call = vhost_kernel_call,
|
||||
.vhost_backend_init = vhost_kernel_init,
|
||||
.vhost_backend_cleanup = vhost_kernel_cleanup,
|
||||
.vhost_backend_get_vq_index = vhost_kernel_get_vq_index,
|
||||
.vhost_backend_memslots_limit = vhost_kernel_memslots_limit,
|
||||
.vhost_net_set_backend = vhost_kernel_net_set_backend,
|
||||
.vhost_scsi_set_endpoint = vhost_kernel_scsi_set_endpoint,
|
||||
.vhost_scsi_clear_endpoint = vhost_kernel_scsi_clear_endpoint,
|
||||
.vhost_scsi_get_abi_version = vhost_kernel_scsi_get_abi_version,
|
||||
.vhost_set_log_base = vhost_kernel_set_log_base,
|
||||
.vhost_set_mem_table = vhost_kernel_set_mem_table,
|
||||
.vhost_set_vring_addr = vhost_kernel_set_vring_addr,
|
||||
.vhost_set_vring_endian = vhost_kernel_set_vring_endian,
|
||||
.vhost_set_vring_num = vhost_kernel_set_vring_num,
|
||||
.vhost_set_vring_base = vhost_kernel_set_vring_base,
|
||||
.vhost_get_vring_base = vhost_kernel_get_vring_base,
|
||||
.vhost_set_vring_kick = vhost_kernel_set_vring_kick,
|
||||
.vhost_set_vring_call = vhost_kernel_set_vring_call,
|
||||
.vhost_set_features = vhost_kernel_set_features,
|
||||
.vhost_get_features = vhost_kernel_get_features,
|
||||
.vhost_set_owner = vhost_kernel_set_owner,
|
||||
.vhost_reset_device = vhost_kernel_reset_device,
|
||||
.vhost_get_vq_index = vhost_kernel_get_vq_index,
|
||||
};
|
||||
|
||||
int vhost_set_backend_type(struct vhost_dev *dev, VhostBackendType backend_type)
|
||||
|
||||
+401
-226
File diff suppressed because it is too large
Load Diff
+118
-38
@@ -18,6 +18,7 @@
|
||||
#include "qemu/atomic.h"
|
||||
#include "qemu/range.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/memfd.h"
|
||||
#include <linux/vhost.h>
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/virtio/virtio-bus.h"
|
||||
@@ -25,6 +26,23 @@
|
||||
#include "migration/migration.h"
|
||||
|
||||
static struct vhost_log *vhost_log;
|
||||
static struct vhost_log *vhost_log_shm;
|
||||
|
||||
static unsigned int used_memslots;
|
||||
static QLIST_HEAD(, vhost_dev) vhost_devices =
|
||||
QLIST_HEAD_INITIALIZER(vhost_devices);
|
||||
|
||||
bool vhost_has_free_slot(void)
|
||||
{
|
||||
unsigned int slots_limit = ~0U;
|
||||
struct vhost_dev *hdev;
|
||||
|
||||
QLIST_FOREACH(hdev, &vhost_devices, entry) {
|
||||
unsigned int r = hdev->vhost_ops->vhost_backend_memslots_limit(hdev);
|
||||
slots_limit = MIN(slots_limit, r);
|
||||
}
|
||||
return slots_limit > used_memslots;
|
||||
}
|
||||
|
||||
static void vhost_dev_sync_region(struct vhost_dev *dev,
|
||||
MemoryRegionSection *section,
|
||||
@@ -286,25 +304,46 @@ static uint64_t vhost_get_log_size(struct vhost_dev *dev)
|
||||
}
|
||||
return log_size;
|
||||
}
|
||||
static struct vhost_log *vhost_log_alloc(uint64_t size)
|
||||
|
||||
static struct vhost_log *vhost_log_alloc(uint64_t size, bool share)
|
||||
{
|
||||
struct vhost_log *log = g_malloc0(sizeof *log + size * sizeof(*(log->log)));
|
||||
struct vhost_log *log;
|
||||
uint64_t logsize = size * sizeof(*(log->log));
|
||||
int fd = -1;
|
||||
|
||||
log = g_new0(struct vhost_log, 1);
|
||||
if (share) {
|
||||
log->log = qemu_memfd_alloc("vhost-log", logsize,
|
||||
F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL,
|
||||
&fd);
|
||||
memset(log->log, 0, logsize);
|
||||
} else {
|
||||
log->log = g_malloc0(logsize);
|
||||
}
|
||||
|
||||
log->size = size;
|
||||
log->refcnt = 1;
|
||||
log->fd = fd;
|
||||
|
||||
return log;
|
||||
}
|
||||
|
||||
static struct vhost_log *vhost_log_get(uint64_t size)
|
||||
static struct vhost_log *vhost_log_get(uint64_t size, bool share)
|
||||
{
|
||||
if (!vhost_log || vhost_log->size != size) {
|
||||
vhost_log = vhost_log_alloc(size);
|
||||
struct vhost_log *log = share ? vhost_log_shm : vhost_log;
|
||||
|
||||
if (!log || log->size != size) {
|
||||
log = vhost_log_alloc(size, share);
|
||||
if (share) {
|
||||
vhost_log_shm = log;
|
||||
} else {
|
||||
vhost_log = log;
|
||||
}
|
||||
} else {
|
||||
++vhost_log->refcnt;
|
||||
++log->refcnt;
|
||||
}
|
||||
|
||||
return vhost_log;
|
||||
return log;
|
||||
}
|
||||
|
||||
static void vhost_log_put(struct vhost_dev *dev, bool sync)
|
||||
@@ -321,20 +360,35 @@ static void vhost_log_put(struct vhost_dev *dev, bool sync)
|
||||
if (dev->log_size && sync) {
|
||||
vhost_log_sync_range(dev, 0, dev->log_size * VHOST_LOG_CHUNK - 1);
|
||||
}
|
||||
|
||||
if (vhost_log == log) {
|
||||
g_free(log->log);
|
||||
vhost_log = NULL;
|
||||
} else if (vhost_log_shm == log) {
|
||||
qemu_memfd_free(log->log, log->size * sizeof(*(log->log)),
|
||||
log->fd);
|
||||
vhost_log_shm = NULL;
|
||||
}
|
||||
|
||||
g_free(log);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void vhost_dev_log_resize(struct vhost_dev* dev, uint64_t size)
|
||||
static bool vhost_dev_log_is_shared(struct vhost_dev *dev)
|
||||
{
|
||||
struct vhost_log *log = vhost_log_get(size);
|
||||
return dev->vhost_ops->vhost_requires_shm_log &&
|
||||
dev->vhost_ops->vhost_requires_shm_log(dev);
|
||||
}
|
||||
|
||||
static inline void vhost_dev_log_resize(struct vhost_dev *dev, uint64_t size)
|
||||
{
|
||||
struct vhost_log *log = vhost_log_get(size, vhost_dev_log_is_shared(dev));
|
||||
uint64_t log_base = (uintptr_t)log->log;
|
||||
int r;
|
||||
|
||||
r = dev->vhost_ops->vhost_call(dev, VHOST_SET_LOG_BASE, &log_base);
|
||||
/* inform backend of log switching, this must be done before
|
||||
releasing the current log, to ensure no logging is lost */
|
||||
r = dev->vhost_ops->vhost_set_log_base(dev, log_base, log);
|
||||
assert(r >= 0);
|
||||
vhost_log_put(dev, true);
|
||||
dev->log = log;
|
||||
@@ -457,6 +511,7 @@ static void vhost_set_memory(MemoryListener *listener,
|
||||
dev->mem_changed_start_addr = MIN(dev->mem_changed_start_addr, start_addr);
|
||||
dev->mem_changed_end_addr = MAX(dev->mem_changed_end_addr, start_addr + size - 1);
|
||||
dev->memory_changed = true;
|
||||
used_memslots = dev->mem->nregions;
|
||||
}
|
||||
|
||||
static bool vhost_section(MemoryRegionSection *section)
|
||||
@@ -500,7 +555,7 @@ static void vhost_commit(MemoryListener *listener)
|
||||
}
|
||||
|
||||
if (!dev->log_enabled) {
|
||||
r = dev->vhost_ops->vhost_call(dev, VHOST_SET_MEM_TABLE, dev->mem);
|
||||
r = dev->vhost_ops->vhost_set_mem_table(dev, dev->mem);
|
||||
assert(r >= 0);
|
||||
dev->memory_changed = false;
|
||||
return;
|
||||
@@ -513,7 +568,7 @@ static void vhost_commit(MemoryListener *listener)
|
||||
if (dev->log_size < log_size) {
|
||||
vhost_dev_log_resize(dev, log_size + VHOST_LOG_BUFFER);
|
||||
}
|
||||
r = dev->vhost_ops->vhost_call(dev, VHOST_SET_MEM_TABLE, dev->mem);
|
||||
r = dev->vhost_ops->vhost_set_mem_table(dev, dev->mem);
|
||||
assert(r >= 0);
|
||||
/* To log less, can only decrease log size after table update. */
|
||||
if (dev->log_size > log_size + VHOST_LOG_BUFFER) {
|
||||
@@ -581,7 +636,7 @@ static int vhost_virtqueue_set_addr(struct vhost_dev *dev,
|
||||
.log_guest_addr = vq->used_phys,
|
||||
.flags = enable_log ? (1 << VHOST_VRING_F_LOG) : 0,
|
||||
};
|
||||
int r = dev->vhost_ops->vhost_call(dev, VHOST_SET_VRING_ADDR, &addr);
|
||||
int r = dev->vhost_ops->vhost_set_vring_addr(dev, &addr);
|
||||
if (r < 0) {
|
||||
return -errno;
|
||||
}
|
||||
@@ -595,19 +650,20 @@ static int vhost_dev_set_features(struct vhost_dev *dev, bool enable_log)
|
||||
if (enable_log) {
|
||||
features |= 0x1ULL << VHOST_F_LOG_ALL;
|
||||
}
|
||||
r = dev->vhost_ops->vhost_call(dev, VHOST_SET_FEATURES, &features);
|
||||
r = dev->vhost_ops->vhost_set_features(dev, features);
|
||||
return r < 0 ? -errno : 0;
|
||||
}
|
||||
|
||||
static int vhost_dev_set_log(struct vhost_dev *dev, bool enable_log)
|
||||
{
|
||||
int r, t, i;
|
||||
int r, t, i, idx;
|
||||
r = vhost_dev_set_features(dev, enable_log);
|
||||
if (r < 0) {
|
||||
goto err_features;
|
||||
}
|
||||
for (i = 0; i < dev->nvqs; ++i) {
|
||||
r = vhost_virtqueue_set_addr(dev, dev->vqs + i, i,
|
||||
idx = dev->vhost_ops->vhost_get_vq_index(dev, dev->vq_index + i);
|
||||
r = vhost_virtqueue_set_addr(dev, dev->vqs + i, idx,
|
||||
enable_log);
|
||||
if (r < 0) {
|
||||
goto err_vq;
|
||||
@@ -616,7 +672,8 @@ static int vhost_dev_set_log(struct vhost_dev *dev, bool enable_log)
|
||||
return 0;
|
||||
err_vq:
|
||||
for (; i >= 0; --i) {
|
||||
t = vhost_virtqueue_set_addr(dev, dev->vqs + i, i,
|
||||
idx = dev->vhost_ops->vhost_get_vq_index(dev, dev->vq_index + i);
|
||||
t = vhost_virtqueue_set_addr(dev, dev->vqs + i, idx,
|
||||
dev->log_enabled);
|
||||
assert(t >= 0);
|
||||
}
|
||||
@@ -700,7 +757,7 @@ static int vhost_virtqueue_set_vring_endian_legacy(struct vhost_dev *dev,
|
||||
.num = is_big_endian
|
||||
};
|
||||
|
||||
if (!dev->vhost_ops->vhost_call(dev, VHOST_SET_VRING_ENDIAN, &s)) {
|
||||
if (!dev->vhost_ops->vhost_set_vring_endian(dev, &s)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -719,7 +776,7 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
|
||||
{
|
||||
hwaddr s, l, a;
|
||||
int r;
|
||||
int vhost_vq_index = dev->vhost_ops->vhost_backend_get_vq_index(dev, idx);
|
||||
int vhost_vq_index = dev->vhost_ops->vhost_get_vq_index(dev, idx);
|
||||
struct vhost_vring_file file = {
|
||||
.index = vhost_vq_index
|
||||
};
|
||||
@@ -730,13 +787,13 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
|
||||
|
||||
|
||||
vq->num = state.num = virtio_queue_get_num(vdev, idx);
|
||||
r = dev->vhost_ops->vhost_call(dev, VHOST_SET_VRING_NUM, &state);
|
||||
r = dev->vhost_ops->vhost_set_vring_num(dev, &state);
|
||||
if (r) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
state.num = virtio_queue_get_last_avail_idx(vdev, idx);
|
||||
r = dev->vhost_ops->vhost_call(dev, VHOST_SET_VRING_BASE, &state);
|
||||
r = dev->vhost_ops->vhost_set_vring_base(dev, &state);
|
||||
if (r) {
|
||||
return -errno;
|
||||
}
|
||||
@@ -788,7 +845,7 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
|
||||
}
|
||||
|
||||
file.fd = event_notifier_get_fd(virtio_queue_get_host_notifier(vvq));
|
||||
r = dev->vhost_ops->vhost_call(dev, VHOST_SET_VRING_KICK, &file);
|
||||
r = dev->vhost_ops->vhost_set_vring_kick(dev, &file);
|
||||
if (r) {
|
||||
r = -errno;
|
||||
goto fail_kick;
|
||||
@@ -821,13 +878,13 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev,
|
||||
struct vhost_virtqueue *vq,
|
||||
unsigned idx)
|
||||
{
|
||||
int vhost_vq_index = dev->vhost_ops->vhost_backend_get_vq_index(dev, idx);
|
||||
int vhost_vq_index = dev->vhost_ops->vhost_get_vq_index(dev, idx);
|
||||
struct vhost_vring_state state = {
|
||||
.index = vhost_vq_index,
|
||||
};
|
||||
int r;
|
||||
|
||||
r = dev->vhost_ops->vhost_call(dev, VHOST_GET_VRING_BASE, &state);
|
||||
r = dev->vhost_ops->vhost_get_vring_base(dev, &state);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "vhost VQ %d ring restore failed: %d\n", idx, r);
|
||||
fflush(stderr);
|
||||
@@ -874,7 +931,7 @@ static void vhost_eventfd_del(MemoryListener *listener,
|
||||
static int vhost_virtqueue_init(struct vhost_dev *dev,
|
||||
struct vhost_virtqueue *vq, int n)
|
||||
{
|
||||
int vhost_vq_index = dev->vhost_ops->vhost_backend_get_vq_index(dev, n);
|
||||
int vhost_vq_index = dev->vhost_ops->vhost_get_vq_index(dev, n);
|
||||
struct vhost_vring_file file = {
|
||||
.index = vhost_vq_index,
|
||||
};
|
||||
@@ -884,7 +941,7 @@ static int vhost_virtqueue_init(struct vhost_dev *dev,
|
||||
}
|
||||
|
||||
file.fd = event_notifier_get_fd(&vq->masked_notifier);
|
||||
r = dev->vhost_ops->vhost_call(dev, VHOST_SET_VRING_CALL, &file);
|
||||
r = dev->vhost_ops->vhost_set_vring_call(dev, &file);
|
||||
if (r) {
|
||||
r = -errno;
|
||||
goto fail_call;
|
||||
@@ -906,6 +963,8 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
|
||||
uint64_t features;
|
||||
int i, r;
|
||||
|
||||
hdev->migration_blocker = NULL;
|
||||
|
||||
if (vhost_set_backend_type(hdev, backend_type) < 0) {
|
||||
close((uintptr_t)opaque);
|
||||
return -1;
|
||||
@@ -916,12 +975,20 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
|
||||
return -errno;
|
||||
}
|
||||
|
||||
r = hdev->vhost_ops->vhost_call(hdev, VHOST_SET_OWNER, NULL);
|
||||
if (used_memslots > hdev->vhost_ops->vhost_backend_memslots_limit(hdev)) {
|
||||
fprintf(stderr, "vhost backend memory slots limit is less"
|
||||
" than current number of present memory slots\n");
|
||||
close((uintptr_t)opaque);
|
||||
return -1;
|
||||
}
|
||||
QLIST_INSERT_HEAD(&vhost_devices, hdev, entry);
|
||||
|
||||
r = hdev->vhost_ops->vhost_set_owner(hdev);
|
||||
if (r < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = hdev->vhost_ops->vhost_call(hdev, VHOST_GET_FEATURES, &features);
|
||||
r = hdev->vhost_ops->vhost_get_features(hdev, &features);
|
||||
if (r < 0) {
|
||||
goto fail;
|
||||
}
|
||||
@@ -949,12 +1016,21 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
|
||||
.eventfd_del = vhost_eventfd_del,
|
||||
.priority = 10
|
||||
};
|
||||
hdev->migration_blocker = NULL;
|
||||
if (!(hdev->features & (0x1ULL << VHOST_F_LOG_ALL))) {
|
||||
error_setg(&hdev->migration_blocker,
|
||||
"Migration disabled: vhost lacks VHOST_F_LOG_ALL feature.");
|
||||
|
||||
if (hdev->migration_blocker == NULL) {
|
||||
if (!(hdev->features & (0x1ULL << VHOST_F_LOG_ALL))) {
|
||||
error_setg(&hdev->migration_blocker,
|
||||
"Migration disabled: vhost lacks VHOST_F_LOG_ALL feature.");
|
||||
} else if (!qemu_memfd_check()) {
|
||||
error_setg(&hdev->migration_blocker,
|
||||
"Migration disabled: failed to allocate shared memory");
|
||||
}
|
||||
}
|
||||
|
||||
if (hdev->migration_blocker != NULL) {
|
||||
migrate_add_blocker(hdev->migration_blocker);
|
||||
}
|
||||
|
||||
hdev->mem = g_malloc0(offsetof(struct vhost_memory, regions));
|
||||
hdev->n_mem_sections = 0;
|
||||
hdev->mem_sections = NULL;
|
||||
@@ -972,6 +1048,7 @@ fail_vq:
|
||||
fail:
|
||||
r = -errno;
|
||||
hdev->vhost_ops->vhost_backend_cleanup(hdev);
|
||||
QLIST_REMOVE(hdev, entry);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -989,6 +1066,7 @@ void vhost_dev_cleanup(struct vhost_dev *hdev)
|
||||
g_free(hdev->mem);
|
||||
g_free(hdev->mem_sections);
|
||||
hdev->vhost_ops->vhost_backend_cleanup(hdev);
|
||||
QLIST_REMOVE(hdev, entry);
|
||||
}
|
||||
|
||||
/* Stop processing guest IO notifications in qemu.
|
||||
@@ -1074,8 +1152,8 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,
|
||||
file.fd = event_notifier_get_fd(virtio_queue_get_guest_notifier(vvq));
|
||||
}
|
||||
|
||||
file.index = hdev->vhost_ops->vhost_backend_get_vq_index(hdev, n);
|
||||
r = hdev->vhost_ops->vhost_call(hdev, VHOST_SET_VRING_CALL, &file);
|
||||
file.index = hdev->vhost_ops->vhost_get_vq_index(hdev, n);
|
||||
r = hdev->vhost_ops->vhost_set_vring_call(hdev, &file);
|
||||
assert(r >= 0);
|
||||
}
|
||||
|
||||
@@ -1117,7 +1195,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
|
||||
if (r < 0) {
|
||||
goto fail_features;
|
||||
}
|
||||
r = hdev->vhost_ops->vhost_call(hdev, VHOST_SET_MEM_TABLE, hdev->mem);
|
||||
r = hdev->vhost_ops->vhost_set_mem_table(hdev, hdev->mem);
|
||||
if (r < 0) {
|
||||
r = -errno;
|
||||
goto fail_mem;
|
||||
@@ -1136,10 +1214,12 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
|
||||
uint64_t log_base;
|
||||
|
||||
hdev->log_size = vhost_get_log_size(hdev);
|
||||
hdev->log = vhost_log_get(hdev->log_size);
|
||||
hdev->log = vhost_log_get(hdev->log_size,
|
||||
vhost_dev_log_is_shared(hdev));
|
||||
log_base = (uintptr_t)hdev->log->log;
|
||||
r = hdev->vhost_ops->vhost_call(hdev, VHOST_SET_LOG_BASE,
|
||||
hdev->log_size ? &log_base : NULL);
|
||||
r = hdev->vhost_ops->vhost_set_log_base(hdev,
|
||||
hdev->log_size ? log_base : 0,
|
||||
hdev->log);
|
||||
if (r < 0) {
|
||||
r = -errno;
|
||||
goto fail_log;
|
||||
|
||||
@@ -49,6 +49,7 @@ typedef struct VTDContextCacheEntry VTDContextCacheEntry;
|
||||
typedef struct IntelIOMMUState IntelIOMMUState;
|
||||
typedef struct VTDAddressSpace VTDAddressSpace;
|
||||
typedef struct VTDIOTLBEntry VTDIOTLBEntry;
|
||||
typedef struct VTDBus VTDBus;
|
||||
|
||||
/* Context-Entry */
|
||||
struct VTDContextEntry {
|
||||
@@ -65,7 +66,7 @@ struct VTDContextCacheEntry {
|
||||
};
|
||||
|
||||
struct VTDAddressSpace {
|
||||
uint8_t bus_num;
|
||||
PCIBus *bus;
|
||||
uint8_t devfn;
|
||||
AddressSpace as;
|
||||
MemoryRegion iommu;
|
||||
@@ -73,6 +74,11 @@ struct VTDAddressSpace {
|
||||
VTDContextCacheEntry context_cache_entry;
|
||||
};
|
||||
|
||||
struct VTDBus {
|
||||
PCIBus* bus; /* A reference to the bus to provide translation for */
|
||||
VTDAddressSpace *dev_as[0]; /* A table of VTDAddressSpace objects indexed by devfn */
|
||||
};
|
||||
|
||||
struct VTDIOTLBEntry {
|
||||
uint64_t gfn;
|
||||
uint16_t domain_id;
|
||||
@@ -114,7 +120,13 @@ struct IntelIOMMUState {
|
||||
GHashTable *iotlb; /* IOTLB */
|
||||
|
||||
MemoryRegionIOMMUOps iommu_ops;
|
||||
VTDAddressSpace **address_spaces[VTD_PCI_BUS_MAX];
|
||||
GHashTable *vtd_as_by_busptr; /* VTDBus objects indexed by PCIBus* reference */
|
||||
VTDBus *vtd_as_by_bus_num[VTD_PCI_BUS_MAX]; /* VTDBus objects indexed by bus number */
|
||||
};
|
||||
|
||||
/* Find the VTD Address space associated with the given bus pointer,
|
||||
* create a new one if none exists
|
||||
*/
|
||||
VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -168,7 +168,7 @@ bool pc_machine_is_smm_enabled(PCMachineState *pcms);
|
||||
void pc_register_ferr_irq(qemu_irq irq);
|
||||
void pc_acpi_smi_interrupt(void *opaque, int irq, int level);
|
||||
|
||||
void pc_cpus_init(const char *cpu_model);
|
||||
void pc_cpus_init(PCMachineState *pcms);
|
||||
void pc_hot_add_cpu(const int64_t id, Error **errp);
|
||||
void pc_acpi_init(const char *default_dsdt);
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#ifndef VHOST_BACKEND_H_
|
||||
#define VHOST_BACKEND_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef enum VhostBackendType {
|
||||
VHOST_BACKEND_TYPE_NONE = 0,
|
||||
VHOST_BACKEND_TYPE_KERNEL = 1,
|
||||
@@ -19,21 +21,82 @@ typedef enum VhostBackendType {
|
||||
} VhostBackendType;
|
||||
|
||||
struct vhost_dev;
|
||||
struct vhost_log;
|
||||
struct vhost_memory;
|
||||
struct vhost_vring_file;
|
||||
struct vhost_vring_state;
|
||||
struct vhost_vring_addr;
|
||||
struct vhost_scsi_target;
|
||||
|
||||
typedef int (*vhost_call)(struct vhost_dev *dev, unsigned long int request,
|
||||
void *arg);
|
||||
typedef int (*vhost_backend_init)(struct vhost_dev *dev, void *opaque);
|
||||
typedef int (*vhost_backend_cleanup)(struct vhost_dev *dev);
|
||||
typedef int (*vhost_backend_get_vq_index)(struct vhost_dev *dev, int idx);
|
||||
typedef int (*vhost_backend_set_vring_enable)(struct vhost_dev *dev, int enable);
|
||||
typedef int (*vhost_backend_memslots_limit)(struct vhost_dev *dev);
|
||||
|
||||
typedef int (*vhost_net_set_backend_op)(struct vhost_dev *dev,
|
||||
struct vhost_vring_file *file);
|
||||
typedef int (*vhost_scsi_set_endpoint_op)(struct vhost_dev *dev,
|
||||
struct vhost_scsi_target *target);
|
||||
typedef int (*vhost_scsi_clear_endpoint_op)(struct vhost_dev *dev,
|
||||
struct vhost_scsi_target *target);
|
||||
typedef int (*vhost_scsi_get_abi_version_op)(struct vhost_dev *dev,
|
||||
int *version);
|
||||
typedef int (*vhost_set_log_base_op)(struct vhost_dev *dev, uint64_t base,
|
||||
struct vhost_log *log);
|
||||
typedef int (*vhost_set_mem_table_op)(struct vhost_dev *dev,
|
||||
struct vhost_memory *mem);
|
||||
typedef int (*vhost_set_vring_addr_op)(struct vhost_dev *dev,
|
||||
struct vhost_vring_addr *addr);
|
||||
typedef int (*vhost_set_vring_endian_op)(struct vhost_dev *dev,
|
||||
struct vhost_vring_state *ring);
|
||||
typedef int (*vhost_set_vring_num_op)(struct vhost_dev *dev,
|
||||
struct vhost_vring_state *ring);
|
||||
typedef int (*vhost_set_vring_base_op)(struct vhost_dev *dev,
|
||||
struct vhost_vring_state *ring);
|
||||
typedef int (*vhost_get_vring_base_op)(struct vhost_dev *dev,
|
||||
struct vhost_vring_state *ring);
|
||||
typedef int (*vhost_set_vring_kick_op)(struct vhost_dev *dev,
|
||||
struct vhost_vring_file *file);
|
||||
typedef int (*vhost_set_vring_call_op)(struct vhost_dev *dev,
|
||||
struct vhost_vring_file *file);
|
||||
typedef int (*vhost_set_features_op)(struct vhost_dev *dev,
|
||||
uint64_t features);
|
||||
typedef int (*vhost_get_features_op)(struct vhost_dev *dev,
|
||||
uint64_t *features);
|
||||
typedef int (*vhost_set_owner_op)(struct vhost_dev *dev);
|
||||
typedef int (*vhost_reset_device_op)(struct vhost_dev *dev);
|
||||
typedef int (*vhost_get_vq_index_op)(struct vhost_dev *dev, int idx);
|
||||
typedef int (*vhost_set_vring_enable_op)(struct vhost_dev *dev,
|
||||
int enable);
|
||||
typedef bool (*vhost_requires_shm_log_op)(struct vhost_dev *dev);
|
||||
typedef int (*vhost_migration_done_op)(struct vhost_dev *dev,
|
||||
char *mac_addr);
|
||||
|
||||
typedef struct VhostOps {
|
||||
VhostBackendType backend_type;
|
||||
vhost_call vhost_call;
|
||||
vhost_backend_init vhost_backend_init;
|
||||
vhost_backend_cleanup vhost_backend_cleanup;
|
||||
vhost_backend_get_vq_index vhost_backend_get_vq_index;
|
||||
vhost_backend_set_vring_enable vhost_backend_set_vring_enable;
|
||||
vhost_backend_memslots_limit vhost_backend_memslots_limit;
|
||||
vhost_net_set_backend_op vhost_net_set_backend;
|
||||
vhost_scsi_set_endpoint_op vhost_scsi_set_endpoint;
|
||||
vhost_scsi_clear_endpoint_op vhost_scsi_clear_endpoint;
|
||||
vhost_scsi_get_abi_version_op vhost_scsi_get_abi_version;
|
||||
vhost_set_log_base_op vhost_set_log_base;
|
||||
vhost_set_mem_table_op vhost_set_mem_table;
|
||||
vhost_set_vring_addr_op vhost_set_vring_addr;
|
||||
vhost_set_vring_endian_op vhost_set_vring_endian;
|
||||
vhost_set_vring_num_op vhost_set_vring_num;
|
||||
vhost_set_vring_base_op vhost_set_vring_base;
|
||||
vhost_get_vring_base_op vhost_get_vring_base;
|
||||
vhost_set_vring_kick_op vhost_set_vring_kick;
|
||||
vhost_set_vring_call_op vhost_set_vring_call;
|
||||
vhost_set_features_op vhost_set_features;
|
||||
vhost_get_features_op vhost_get_features;
|
||||
vhost_set_owner_op vhost_set_owner;
|
||||
vhost_reset_device_op vhost_reset_device;
|
||||
vhost_get_vq_index_op vhost_get_vq_index;
|
||||
vhost_set_vring_enable_op vhost_set_vring_enable;
|
||||
vhost_requires_shm_log_op vhost_requires_shm_log;
|
||||
vhost_migration_done_op vhost_migration_done;
|
||||
} VhostOps;
|
||||
|
||||
extern const VhostOps user_ops;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user