Merge remote-tracking branch 'qemu-kvm/uq/master' into staging
* qemu-kvm/uq/master: kvm: i386: Add classic PCI device assignment kvm: i386: Add services required for PCI device assignment kvm: Introduce kvm_has_intx_set_mask kvm: Introduce kvm_irqchip_update_msi_route kvm: Clean up irqfd API qemu: Use valgrind annotations to mark kvm guest memory as defined
This commit is contained in:
commit
6a38e0dc36
3
configure
vendored
3
configure
vendored
@ -2971,11 +2971,12 @@ if compile_prog "-Werror" "" ; then
|
||||
fi
|
||||
|
||||
########################################
|
||||
# check if we have valgrind/valgrind.h
|
||||
# check if we have valgrind/valgrind.h and valgrind/memcheck.h
|
||||
|
||||
valgrind_h=no
|
||||
cat > $TMPC << EOF
|
||||
#include <valgrind/valgrind.h>
|
||||
#include <valgrind/memcheck.h>
|
||||
int main(void) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
obj-$(CONFIG_KVM) += clock.o apic.o i8259.o ioapic.o i8254.o
|
||||
obj-$(CONFIG_KVM) += clock.o apic.o i8259.o ioapic.o i8254.o pci-assign.o
|
||||
|
1915
hw/kvm/pci-assign.c
Normal file
1915
hw/kvm/pci-assign.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -44,6 +44,7 @@ static const QDevAlias qdev_alias_table[] = {
|
||||
{ "virtio-serial-s390", "virtio-serial", QEMU_ARCH_S390X },
|
||||
{ "lsi53c895a", "lsi" },
|
||||
{ "ich9-ahci", "ahci" },
|
||||
{ "kvm-pci-assign", "pci-assign" },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -517,7 +517,7 @@ static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy,
|
||||
}
|
||||
irqfd->users++;
|
||||
|
||||
ret = kvm_irqchip_add_irq_notifier(kvm_state, n, irqfd->virq);
|
||||
ret = kvm_irqchip_add_irqfd_notifier(kvm_state, n, irqfd->virq);
|
||||
if (ret < 0) {
|
||||
if (--irqfd->users == 0) {
|
||||
kvm_irqchip_release_virq(kvm_state, irqfd->virq);
|
||||
@ -538,7 +538,7 @@ static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy,
|
||||
VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
|
||||
int ret;
|
||||
|
||||
ret = kvm_irqchip_remove_irq_notifier(kvm_state, n, irqfd->virq);
|
||||
ret = kvm_irqchip_remove_irqfd_notifier(kvm_state, n, irqfd->virq);
|
||||
assert(ret == 0);
|
||||
|
||||
if (--irqfd->users == 0) {
|
||||
|
75
kvm-all.c
75
kvm-all.c
@ -39,6 +39,10 @@
|
||||
#include <sys/eventfd.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_VALGRIND_H
|
||||
#include <valgrind/memcheck.h>
|
||||
#endif
|
||||
|
||||
/* KVM uses PAGE_SIZE in its definition of COALESCED_MMIO_MAX */
|
||||
#define PAGE_SIZE TARGET_PAGE_SIZE
|
||||
|
||||
@ -84,6 +88,7 @@ struct KVMState
|
||||
int pit_state2;
|
||||
int xsave, xcrs;
|
||||
int many_ioeventfds;
|
||||
int intx_set_mask;
|
||||
/* The man page (and posix) say ioctl numbers are signed int, but
|
||||
* they're not. Linux, glibc and *BSD all treat ioctl numbers as
|
||||
* unsigned, and treating them as signed here can break things */
|
||||
@ -959,6 +964,30 @@ static void kvm_add_routing_entry(KVMState *s,
|
||||
kvm_irqchip_commit_routes(s);
|
||||
}
|
||||
|
||||
static int kvm_update_routing_entry(KVMState *s,
|
||||
struct kvm_irq_routing_entry *new_entry)
|
||||
{
|
||||
struct kvm_irq_routing_entry *entry;
|
||||
int n;
|
||||
|
||||
for (n = 0; n < s->irq_routes->nr; n++) {
|
||||
entry = &s->irq_routes->entries[n];
|
||||
if (entry->gsi != new_entry->gsi) {
|
||||
continue;
|
||||
}
|
||||
|
||||
entry->type = new_entry->type;
|
||||
entry->flags = new_entry->flags;
|
||||
entry->u = new_entry->u;
|
||||
|
||||
kvm_irqchip_commit_routes(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
void kvm_irqchip_add_irq_route(KVMState *s, int irq, int irqchip, int pin)
|
||||
{
|
||||
struct kvm_irq_routing_entry e;
|
||||
@ -1121,6 +1150,24 @@ int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg)
|
||||
return virq;
|
||||
}
|
||||
|
||||
int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg)
|
||||
{
|
||||
struct kvm_irq_routing_entry kroute;
|
||||
|
||||
if (!kvm_irqchip_in_kernel()) {
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
kroute.gsi = virq;
|
||||
kroute.type = KVM_IRQ_ROUTING_MSI;
|
||||
kroute.flags = 0;
|
||||
kroute.u.msi.address_lo = (uint32_t)msg.address;
|
||||
kroute.u.msi.address_hi = msg.address >> 32;
|
||||
kroute.u.msi.data = msg.data;
|
||||
|
||||
return kvm_update_routing_entry(s, &kroute);
|
||||
}
|
||||
|
||||
static int kvm_irqchip_assign_irqfd(KVMState *s, int fd, int virq, bool assign)
|
||||
{
|
||||
struct kvm_irqfd irqfd = {
|
||||
@ -1162,24 +1209,14 @@ static int kvm_irqchip_assign_irqfd(KVMState *s, int fd, int virq, bool assign)
|
||||
}
|
||||
#endif /* !KVM_CAP_IRQ_ROUTING */
|
||||
|
||||
int kvm_irqchip_add_irqfd(KVMState *s, int fd, int virq)
|
||||
int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n, int virq)
|
||||
{
|
||||
return kvm_irqchip_assign_irqfd(s, fd, virq, true);
|
||||
return kvm_irqchip_assign_irqfd(s, event_notifier_get_fd(n), virq, true);
|
||||
}
|
||||
|
||||
int kvm_irqchip_add_irq_notifier(KVMState *s, EventNotifier *n, int virq)
|
||||
int kvm_irqchip_remove_irqfd_notifier(KVMState *s, EventNotifier *n, int virq)
|
||||
{
|
||||
return kvm_irqchip_add_irqfd(s, event_notifier_get_fd(n), virq);
|
||||
}
|
||||
|
||||
int kvm_irqchip_remove_irqfd(KVMState *s, int fd, int virq)
|
||||
{
|
||||
return kvm_irqchip_assign_irqfd(s, fd, virq, false);
|
||||
}
|
||||
|
||||
int kvm_irqchip_remove_irq_notifier(KVMState *s, EventNotifier *n, int virq)
|
||||
{
|
||||
return kvm_irqchip_remove_irqfd(s, event_notifier_get_fd(n), virq);
|
||||
return kvm_irqchip_assign_irqfd(s, event_notifier_get_fd(n), virq, false);
|
||||
}
|
||||
|
||||
static int kvm_irqchip_create(KVMState *s)
|
||||
@ -1350,6 +1387,8 @@ int kvm_init(void)
|
||||
s->direct_msi = (kvm_check_extension(s, KVM_CAP_SIGNAL_MSI) > 0);
|
||||
#endif
|
||||
|
||||
s->intx_set_mask = kvm_check_extension(s, KVM_CAP_PCI_2_3);
|
||||
|
||||
ret = kvm_arch_init(s);
|
||||
if (ret < 0) {
|
||||
goto err;
|
||||
@ -1704,6 +1743,11 @@ int kvm_has_gsi_routing(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
int kvm_has_intx_set_mask(void)
|
||||
{
|
||||
return kvm_state->intx_set_mask;
|
||||
}
|
||||
|
||||
void *kvm_vmalloc(ram_addr_t size)
|
||||
{
|
||||
#ifdef TARGET_S390X
|
||||
@ -1719,6 +1763,9 @@ void *kvm_vmalloc(ram_addr_t size)
|
||||
|
||||
void kvm_setup_guest_memory(void *start, size_t size)
|
||||
{
|
||||
#ifdef CONFIG_VALGRIND_H
|
||||
VALGRIND_MAKE_MEM_DEFINED(start, size);
|
||||
#endif
|
||||
if (!kvm_has_sync_mmu()) {
|
||||
int ret = qemu_madvise(start, size, QEMU_MADV_DONTFORK);
|
||||
|
||||
|
14
kvm-stub.c
14
kvm-stub.c
@ -141,22 +141,12 @@ void kvm_irqchip_release_virq(KVMState *s, int virq)
|
||||
{
|
||||
}
|
||||
|
||||
int kvm_irqchip_add_irqfd(KVMState *s, int fd, int virq)
|
||||
int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n, int virq)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int kvm_irqchip_add_irq_notifier(KVMState *s, EventNotifier *n, int virq)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int kvm_irqchip_remove_irqfd(KVMState *s, int fd, int virq)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int kvm_irqchip_remove_irq_notifier(KVMState *s, EventNotifier *n, int virq)
|
||||
int kvm_irqchip_remove_irqfd_notifier(KVMState *s, EventNotifier *n, int virq)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
8
kvm.h
8
kvm.h
@ -117,6 +117,7 @@ int kvm_has_xcrs(void);
|
||||
int kvm_has_pit_state2(void);
|
||||
int kvm_has_many_ioeventfds(void);
|
||||
int kvm_has_gsi_routing(void);
|
||||
int kvm_has_intx_set_mask(void);
|
||||
|
||||
#ifdef NEED_CPU_H
|
||||
int kvm_init_vcpu(CPUArchState *env);
|
||||
@ -270,10 +271,9 @@ int kvm_set_ioeventfd_mmio(int fd, uint32_t adr, uint32_t val, bool assign,
|
||||
int kvm_set_ioeventfd_pio_word(int fd, uint16_t adr, uint16_t val, bool assign);
|
||||
|
||||
int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg);
|
||||
int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg);
|
||||
void kvm_irqchip_release_virq(KVMState *s, int virq);
|
||||
|
||||
int kvm_irqchip_add_irqfd(KVMState *s, int fd, int virq);
|
||||
int kvm_irqchip_remove_irqfd(KVMState *s, int fd, int virq);
|
||||
int kvm_irqchip_add_irq_notifier(KVMState *s, EventNotifier *n, int virq);
|
||||
int kvm_irqchip_remove_irq_notifier(KVMState *s, EventNotifier *n, int virq);
|
||||
int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n, int virq);
|
||||
int kvm_irqchip_remove_irqfd_notifier(KVMState *s, EventNotifier *n, int virq);
|
||||
#endif
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "hw/apic.h"
|
||||
#include "ioport.h"
|
||||
#include "hyperv.h"
|
||||
#include "hw/pci.h"
|
||||
|
||||
//#define DEBUG_KVM
|
||||
|
||||
@ -2068,3 +2069,143 @@ void kvm_arch_init_irq_routing(KVMState *s)
|
||||
kvm_msi_via_irqfd_allowed = true;
|
||||
kvm_gsi_routing_allowed = true;
|
||||
}
|
||||
|
||||
/* Classic KVM device assignment interface. Will remain x86 only. */
|
||||
int kvm_device_pci_assign(KVMState *s, PCIHostDeviceAddress *dev_addr,
|
||||
uint32_t flags, uint32_t *dev_id)
|
||||
{
|
||||
struct kvm_assigned_pci_dev dev_data = {
|
||||
.segnr = dev_addr->domain,
|
||||
.busnr = dev_addr->bus,
|
||||
.devfn = PCI_DEVFN(dev_addr->slot, dev_addr->function),
|
||||
.flags = flags,
|
||||
};
|
||||
int ret;
|
||||
|
||||
dev_data.assigned_dev_id =
|
||||
(dev_addr->domain << 16) | (dev_addr->bus << 8) | dev_data.devfn;
|
||||
|
||||
ret = kvm_vm_ioctl(s, KVM_ASSIGN_PCI_DEVICE, &dev_data);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
*dev_id = dev_data.assigned_dev_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_device_pci_deassign(KVMState *s, uint32_t dev_id)
|
||||
{
|
||||
struct kvm_assigned_pci_dev dev_data = {
|
||||
.assigned_dev_id = dev_id,
|
||||
};
|
||||
|
||||
return kvm_vm_ioctl(s, KVM_DEASSIGN_PCI_DEVICE, &dev_data);
|
||||
}
|
||||
|
||||
static int kvm_assign_irq_internal(KVMState *s, uint32_t dev_id,
|
||||
uint32_t irq_type, uint32_t guest_irq)
|
||||
{
|
||||
struct kvm_assigned_irq assigned_irq = {
|
||||
.assigned_dev_id = dev_id,
|
||||
.guest_irq = guest_irq,
|
||||
.flags = irq_type,
|
||||
};
|
||||
|
||||
if (kvm_check_extension(s, KVM_CAP_ASSIGN_DEV_IRQ)) {
|
||||
return kvm_vm_ioctl(s, KVM_ASSIGN_DEV_IRQ, &assigned_irq);
|
||||
} else {
|
||||
return kvm_vm_ioctl(s, KVM_ASSIGN_IRQ, &assigned_irq);
|
||||
}
|
||||
}
|
||||
|
||||
int kvm_device_intx_assign(KVMState *s, uint32_t dev_id, bool use_host_msi,
|
||||
uint32_t guest_irq)
|
||||
{
|
||||
uint32_t irq_type = KVM_DEV_IRQ_GUEST_INTX |
|
||||
(use_host_msi ? KVM_DEV_IRQ_HOST_MSI : KVM_DEV_IRQ_HOST_INTX);
|
||||
|
||||
return kvm_assign_irq_internal(s, dev_id, irq_type, guest_irq);
|
||||
}
|
||||
|
||||
int kvm_device_intx_set_mask(KVMState *s, uint32_t dev_id, bool masked)
|
||||
{
|
||||
struct kvm_assigned_pci_dev dev_data = {
|
||||
.assigned_dev_id = dev_id,
|
||||
.flags = masked ? KVM_DEV_ASSIGN_MASK_INTX : 0,
|
||||
};
|
||||
|
||||
return kvm_vm_ioctl(s, KVM_ASSIGN_SET_INTX_MASK, &dev_data);
|
||||
}
|
||||
|
||||
static int kvm_deassign_irq_internal(KVMState *s, uint32_t dev_id,
|
||||
uint32_t type)
|
||||
{
|
||||
struct kvm_assigned_irq assigned_irq = {
|
||||
.assigned_dev_id = dev_id,
|
||||
.flags = type,
|
||||
};
|
||||
|
||||
return kvm_vm_ioctl(s, KVM_DEASSIGN_DEV_IRQ, &assigned_irq);
|
||||
}
|
||||
|
||||
int kvm_device_intx_deassign(KVMState *s, uint32_t dev_id, bool use_host_msi)
|
||||
{
|
||||
return kvm_deassign_irq_internal(s, dev_id, KVM_DEV_IRQ_GUEST_INTX |
|
||||
(use_host_msi ? KVM_DEV_IRQ_HOST_MSI : KVM_DEV_IRQ_HOST_INTX));
|
||||
}
|
||||
|
||||
int kvm_device_msi_assign(KVMState *s, uint32_t dev_id, int virq)
|
||||
{
|
||||
return kvm_assign_irq_internal(s, dev_id, KVM_DEV_IRQ_HOST_MSI |
|
||||
KVM_DEV_IRQ_GUEST_MSI, virq);
|
||||
}
|
||||
|
||||
int kvm_device_msi_deassign(KVMState *s, uint32_t dev_id)
|
||||
{
|
||||
return kvm_deassign_irq_internal(s, dev_id, KVM_DEV_IRQ_GUEST_MSI |
|
||||
KVM_DEV_IRQ_HOST_MSI);
|
||||
}
|
||||
|
||||
bool kvm_device_msix_supported(KVMState *s)
|
||||
{
|
||||
/* The kernel lacks a corresponding KVM_CAP, so we probe by calling
|
||||
* KVM_ASSIGN_SET_MSIX_NR with an invalid parameter. */
|
||||
return kvm_vm_ioctl(s, KVM_ASSIGN_SET_MSIX_NR, NULL) == -EFAULT;
|
||||
}
|
||||
|
||||
int kvm_device_msix_init_vectors(KVMState *s, uint32_t dev_id,
|
||||
uint32_t nr_vectors)
|
||||
{
|
||||
struct kvm_assigned_msix_nr msix_nr = {
|
||||
.assigned_dev_id = dev_id,
|
||||
.entry_nr = nr_vectors,
|
||||
};
|
||||
|
||||
return kvm_vm_ioctl(s, KVM_ASSIGN_SET_MSIX_NR, &msix_nr);
|
||||
}
|
||||
|
||||
int kvm_device_msix_set_vector(KVMState *s, uint32_t dev_id, uint32_t vector,
|
||||
int virq)
|
||||
{
|
||||
struct kvm_assigned_msix_entry msix_entry = {
|
||||
.assigned_dev_id = dev_id,
|
||||
.gsi = virq,
|
||||
.entry = vector,
|
||||
};
|
||||
|
||||
return kvm_vm_ioctl(s, KVM_ASSIGN_SET_MSIX_ENTRY, &msix_entry);
|
||||
}
|
||||
|
||||
int kvm_device_msix_assign(KVMState *s, uint32_t dev_id)
|
||||
{
|
||||
return kvm_assign_irq_internal(s, dev_id, KVM_DEV_IRQ_HOST_MSIX |
|
||||
KVM_DEV_IRQ_GUEST_MSIX, 0);
|
||||
}
|
||||
|
||||
int kvm_device_msix_deassign(KVMState *s, uint32_t dev_id)
|
||||
{
|
||||
return kvm_deassign_irq_internal(s, dev_id, KVM_DEV_IRQ_GUEST_MSIX |
|
||||
KVM_DEV_IRQ_HOST_MSIX);
|
||||
}
|
||||
|
@ -11,6 +11,28 @@
|
||||
#ifndef QEMU_KVM_I386_H
|
||||
#define QEMU_KVM_I386_H
|
||||
|
||||
#include "kvm.h"
|
||||
|
||||
bool kvm_allows_irq0_override(void);
|
||||
|
||||
int kvm_device_pci_assign(KVMState *s, PCIHostDeviceAddress *dev_addr,
|
||||
uint32_t flags, uint32_t *dev_id);
|
||||
int kvm_device_pci_deassign(KVMState *s, uint32_t dev_id);
|
||||
|
||||
int kvm_device_intx_assign(KVMState *s, uint32_t dev_id,
|
||||
bool use_host_msi, uint32_t guest_irq);
|
||||
int kvm_device_intx_set_mask(KVMState *s, uint32_t dev_id, bool masked);
|
||||
int kvm_device_intx_deassign(KVMState *s, uint32_t dev_id, bool use_host_msi);
|
||||
|
||||
int kvm_device_msi_assign(KVMState *s, uint32_t dev_id, int virq);
|
||||
int kvm_device_msi_deassign(KVMState *s, uint32_t dev_id);
|
||||
|
||||
bool kvm_device_msix_supported(KVMState *s);
|
||||
int kvm_device_msix_init_vectors(KVMState *s, uint32_t dev_id,
|
||||
uint32_t nr_vectors);
|
||||
int kvm_device_msix_set_vector(KVMState *s, uint32_t dev_id, uint32_t vector,
|
||||
int virq);
|
||||
int kvm_device_msix_assign(KVMState *s, uint32_t dev_id);
|
||||
int kvm_device_msix_deassign(KVMState *s, uint32_t dev_id);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user