X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=kvm-all.c;h=3a316023593a4c3d46fc4806dec6ecc6d44b8c8d;hb=2b720018060179b394f8ce736983373ab80dd37c;hp=792cdf1d6602ec459718f4c0906d447ed684910d;hpb=20d695a9254c1b086a456d3b79a3c311236643ba;p=qemu.git diff --git a/kvm-all.c b/kvm-all.c index 792cdf1d6..3a3160235 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -21,18 +21,19 @@ #include #include "qemu-common.h" -#include "qemu-barrier.h" -#include "qemu-option.h" -#include "qemu-config.h" -#include "sysemu.h" +#include "qemu/atomic.h" +#include "qemu/option.h" +#include "qemu/config-file.h" +#include "sysemu/sysemu.h" #include "hw/hw.h" -#include "hw/msi.h" -#include "gdbstub.h" -#include "kvm.h" -#include "bswap.h" -#include "memory.h" -#include "exec-memory.h" -#include "event_notifier.h" +#include "hw/pci/msi.h" +#include "exec/gdbstub.h" +#include "sysemu/kvm.h" +#include "qemu/bswap.h" +#include "exec/memory.h" +#include "exec/address-spaces.h" +#include "qemu/event_notifier.h" +#include "trace.h" /* This check must be after config-host.h is included */ #ifdef CONFIG_EVENTFD @@ -109,6 +110,7 @@ bool kvm_async_interrupts_allowed; bool kvm_irqfds_allowed; bool kvm_msi_via_irqfd_allowed; bool kvm_gsi_routing_allowed; +bool kvm_allowed; static const KVMCapabilityInfo kvm_required_capabilites[] = { KVM_CAP_INFO(USER_MEMORY), @@ -214,23 +216,22 @@ static void kvm_reset_vcpu(void *opaque) kvm_arch_reset_vcpu(cpu); } -int kvm_init_vcpu(CPUArchState *env) +int kvm_init_vcpu(CPUState *cpu) { - CPUState *cpu = ENV_GET_CPU(env); KVMState *s = kvm_state; long mmap_size; int ret; DPRINTF("kvm_init_vcpu\n"); - ret = kvm_vm_ioctl(s, KVM_CREATE_VCPU, env->cpu_index); + ret = kvm_vm_ioctl(s, KVM_CREATE_VCPU, (void *)kvm_arch_vcpu_id(cpu)); if (ret < 0) { DPRINTF("kvm_create_vcpu failed\n"); goto err; } cpu->kvm_fd = ret; - env->kvm_state = s; + cpu->kvm_state = s; cpu->kvm_vcpu_dirty = true; mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0); @@ -240,9 +241,9 @@ int kvm_init_vcpu(CPUArchState *env) goto err; } - env->kvm_run = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, + cpu->kvm_run = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, cpu->kvm_fd, 0); - if (env->kvm_run == MAP_FAILED) { + if (cpu->kvm_run == MAP_FAILED) { ret = -errno; DPRINTF("mmap'ing vcpu state failed\n"); goto err; @@ -250,7 +251,7 @@ int kvm_init_vcpu(CPUArchState *env) if (s->coalesced_mmio && !s->coalesced_mmio_ring) { s->coalesced_mmio_ring = - (void *)env->kvm_run + s->coalesced_mmio * PAGE_SIZE; + (void *)cpu->kvm_run + s->coalesced_mmio * PAGE_SIZE; } ret = kvm_arch_init_vcpu(cpu); @@ -501,6 +502,66 @@ int kvm_check_extension(KVMState *s, unsigned int extension) return ret; } +static int kvm_set_ioeventfd_mmio(int fd, uint32_t addr, uint32_t val, + bool assign, uint32_t size, bool datamatch) +{ + int ret; + struct kvm_ioeventfd iofd; + + iofd.datamatch = datamatch ? val : 0; + iofd.addr = addr; + iofd.len = size; + iofd.flags = 0; + iofd.fd = fd; + + if (!kvm_enabled()) { + return -ENOSYS; + } + + if (datamatch) { + iofd.flags |= KVM_IOEVENTFD_FLAG_DATAMATCH; + } + if (!assign) { + iofd.flags |= KVM_IOEVENTFD_FLAG_DEASSIGN; + } + + ret = kvm_vm_ioctl(kvm_state, KVM_IOEVENTFD, &iofd); + + if (ret < 0) { + return -errno; + } + + return 0; +} + +static int kvm_set_ioeventfd_pio(int fd, uint16_t addr, uint16_t val, + bool assign, uint32_t size, bool datamatch) +{ + struct kvm_ioeventfd kick = { + .datamatch = datamatch ? val : 0, + .addr = addr, + .flags = KVM_IOEVENTFD_FLAG_PIO, + .len = size, + .fd = fd, + }; + int r; + if (!kvm_enabled()) { + return -ENOSYS; + } + if (datamatch) { + kick.flags |= KVM_IOEVENTFD_FLAG_DATAMATCH; + } + if (!assign) { + kick.flags |= KVM_IOEVENTFD_FLAG_DEASSIGN; + } + r = kvm_vm_ioctl(kvm_state, KVM_IOEVENTFD, &kick); + if (r < 0) { + return r; + } + return 0; +} + + static int kvm_check_many_ioeventfds(void) { /* Userspace can use ioeventfd for io notification. This requires a host @@ -518,7 +579,7 @@ static int kvm_check_many_ioeventfds(void) if (ioeventfds[i] < 0) { break; } - ret = kvm_set_ioeventfd_pio_word(ioeventfds[i], 0, i, true); + ret = kvm_set_ioeventfd_pio(ioeventfds[i], 0, i, true, 2, true); if (ret < 0) { close(ioeventfds[i]); break; @@ -529,7 +590,7 @@ static int kvm_check_many_ioeventfds(void) ret = i == ARRAY_SIZE(ioeventfds); while (i-- > 0) { - kvm_set_ioeventfd_pio_word(ioeventfds[i], 0, i, false); + kvm_set_ioeventfd_pio(ioeventfds[i], 0, i, false, 2, true); close(ioeventfds[i]); } return ret; @@ -749,10 +810,8 @@ static void kvm_mem_ioeventfd_add(MemoryListener *listener, int fd = event_notifier_get_fd(e); int r; - assert(match_data && section->size <= 8); - r = kvm_set_ioeventfd_mmio(fd, section->offset_within_address_space, - data, true, section->size); + data, true, section->size, match_data); if (r < 0) { abort(); } @@ -767,7 +826,7 @@ static void kvm_mem_ioeventfd_del(MemoryListener *listener, int r; r = kvm_set_ioeventfd_mmio(fd, section->offset_within_address_space, - data, false, section->size); + data, false, section->size, match_data); if (r < 0) { abort(); } @@ -781,10 +840,8 @@ static void kvm_io_ioeventfd_add(MemoryListener *listener, int fd = event_notifier_get_fd(e); int r; - assert(match_data && section->size == 2); - - r = kvm_set_ioeventfd_pio_word(fd, section->offset_within_address_space, - data, true); + r = kvm_set_ioeventfd_pio(fd, section->offset_within_address_space, + data, true, section->size, match_data); if (r < 0) { abort(); } @@ -799,8 +856,8 @@ static void kvm_io_ioeventfd_del(MemoryListener *listener, int fd = event_notifier_get_fd(e); int r; - r = kvm_set_ioeventfd_pio_word(fd, section->offset_within_address_space, - data, false); + r = kvm_set_ioeventfd_pio(fd, section->offset_within_address_space, + data, false, section->size, match_data); if (r < 0) { abort(); } @@ -827,11 +884,9 @@ static MemoryListener kvm_io_listener = { .priority = 10, }; -static void kvm_handle_interrupt(CPUArchState *env, int mask) +static void kvm_handle_interrupt(CPUState *cpu, int mask) { - CPUState *cpu = ENV_GET_CPU(env); - - env->interrupt_request |= mask; + cpu->interrupt_request |= mask; if (!qemu_cpu_is_self(cpu)) { qemu_cpu_kick(cpu); @@ -992,8 +1047,6 @@ void kvm_irqchip_release_virq(KVMState *s, int virq) } } clear_gsi(s, virq); - - kvm_irqchip_commit_routes(s); } static unsigned int kvm_hash_msi(uint32_t data) @@ -1184,6 +1237,11 @@ static int kvm_irqchip_assign_irqfd(KVMState *s, int fd, int virq, bool assign) { abort(); } + +int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg) +{ + return -ENOSYS; +} #endif /* !KVM_CAP_IRQ_ROUTING */ int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n, int virq) @@ -1510,18 +1568,14 @@ void kvm_cpu_synchronize_state(CPUArchState *env) } } -void kvm_cpu_synchronize_post_reset(CPUArchState *env) +void kvm_cpu_synchronize_post_reset(CPUState *cpu) { - CPUState *cpu = ENV_GET_CPU(env); - kvm_arch_put_registers(cpu, KVM_PUT_RESET_STATE); cpu->kvm_vcpu_dirty = false; } -void kvm_cpu_synchronize_post_init(CPUArchState *env) +void kvm_cpu_synchronize_post_init(CPUState *cpu) { - CPUState *cpu = ENV_GET_CPU(env); - kvm_arch_put_registers(cpu, KVM_PUT_FULL_STATE); cpu->kvm_vcpu_dirty = false; } @@ -1529,13 +1583,13 @@ void kvm_cpu_synchronize_post_init(CPUArchState *env) int kvm_cpu_exec(CPUArchState *env) { CPUState *cpu = ENV_GET_CPU(env); - struct kvm_run *run = env->kvm_run; + struct kvm_run *run = cpu->kvm_run; int ret, run_ret; DPRINTF("kvm_cpu_exec()\n"); if (kvm_arch_process_async_events(cpu)) { - env->exit_request = 0; + cpu->exit_request = 0; return EXCP_HLT; } @@ -1546,7 +1600,7 @@ int kvm_cpu_exec(CPUArchState *env) } kvm_arch_pre_run(cpu, run); - if (env->exit_request) { + if (cpu->exit_request) { DPRINTF("interrupt exit requested\n"); /* * KVM requires us to reenter the kernel after IO exits to complete @@ -1557,7 +1611,7 @@ int kvm_cpu_exec(CPUArchState *env) } qemu_mutex_unlock_iothread(); - run_ret = kvm_vcpu_ioctl(env, KVM_RUN, 0); + run_ret = kvm_vcpu_ioctl(cpu, KVM_RUN, 0); qemu_mutex_lock_iothread(); kvm_arch_post_run(cpu, run); @@ -1573,6 +1627,7 @@ int kvm_cpu_exec(CPUArchState *env) abort(); } + trace_kvm_run_exit(cpu->cpu_index, run->exit_reason); switch (run->exit_reason) { case KVM_EXIT_IO: DPRINTF("handle_io\n"); @@ -1620,7 +1675,7 @@ int kvm_cpu_exec(CPUArchState *env) vm_stop(RUN_STATE_INTERNAL_ERROR); } - env->exit_request = 0; + cpu->exit_request = 0; return ret; } @@ -1634,6 +1689,7 @@ int kvm_ioctl(KVMState *s, int type, ...) arg = va_arg(ap, void *); va_end(ap); + trace_kvm_ioctl(type, arg); ret = ioctl(s->fd, type, arg); if (ret == -1) { ret = -errno; @@ -1651,6 +1707,7 @@ int kvm_vm_ioctl(KVMState *s, int type, ...) arg = va_arg(ap, void *); va_end(ap); + trace_kvm_vm_ioctl(type, arg); ret = ioctl(s->vmfd, type, arg); if (ret == -1) { ret = -errno; @@ -1658,9 +1715,8 @@ int kvm_vm_ioctl(KVMState *s, int type, ...) return ret; } -int kvm_vcpu_ioctl(CPUArchState *env, int type, ...) +int kvm_vcpu_ioctl(CPUState *cpu, int type, ...) { - CPUState *cpu = ENV_GET_CPU(env); int ret; void *arg; va_list ap; @@ -1669,6 +1725,7 @@ int kvm_vcpu_ioctl(CPUArchState *env, int type, ...) arg = va_arg(ap, void *); va_end(ap); + trace_kvm_vcpu_ioctl(cpu->cpu_index, type, arg); ret = ioctl(cpu->kvm_fd, type, arg); if (ret == -1) { ret = -errno; @@ -1764,12 +1821,12 @@ void kvm_setup_guest_memory(void *start, size_t size) } #ifdef KVM_CAP_SET_GUEST_DEBUG -struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUArchState *env, +struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *cpu, target_ulong pc) { struct kvm_sw_breakpoint *bp; - QTAILQ_FOREACH(bp, &env->kvm_state->kvm_sw_breakpoints, entry) { + QTAILQ_FOREACH(bp, &cpu->kvm_state->kvm_sw_breakpoints, entry) { if (bp->pc == pc) { return bp; } @@ -1777,23 +1834,23 @@ struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUArchState *env, return NULL; } -int kvm_sw_breakpoints_active(CPUArchState *env) +int kvm_sw_breakpoints_active(CPUState *cpu) { - return !QTAILQ_EMPTY(&env->kvm_state->kvm_sw_breakpoints); + return !QTAILQ_EMPTY(&cpu->kvm_state->kvm_sw_breakpoints); } struct kvm_set_guest_debug_data { struct kvm_guest_debug dbg; - CPUArchState *env; + CPUState *cpu; int err; }; static void kvm_invoke_set_guest_debug(void *data) { struct kvm_set_guest_debug_data *dbg_data = data; - CPUArchState *env = dbg_data->env; - dbg_data->err = kvm_vcpu_ioctl(env, KVM_SET_GUEST_DEBUG, &dbg_data->dbg); + dbg_data->err = kvm_vcpu_ioctl(dbg_data->cpu, KVM_SET_GUEST_DEBUG, + &dbg_data->dbg); } int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap) @@ -1807,7 +1864,7 @@ int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap) data.dbg.control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP; } kvm_arch_update_guest_debug(cpu, &data.dbg); - data.env = env; + data.cpu = cpu; run_on_cpu(cpu, kvm_invoke_set_guest_debug, &data); return data.err; @@ -1822,7 +1879,7 @@ int kvm_insert_breakpoint(CPUArchState *current_env, target_ulong addr, int err; if (type == GDB_BREAKPOINT_SW) { - bp = kvm_find_sw_breakpoint(current_env, addr); + bp = kvm_find_sw_breakpoint(current_cpu, addr); if (bp) { bp->use_count++; return 0; @@ -1841,7 +1898,7 @@ int kvm_insert_breakpoint(CPUArchState *current_env, target_ulong addr, return err; } - QTAILQ_INSERT_HEAD(¤t_env->kvm_state->kvm_sw_breakpoints, + QTAILQ_INSERT_HEAD(¤t_cpu->kvm_state->kvm_sw_breakpoints, bp, entry); } else { err = kvm_arch_insert_hw_breakpoint(addr, len, type); @@ -1868,7 +1925,7 @@ int kvm_remove_breakpoint(CPUArchState *current_env, target_ulong addr, int err; if (type == GDB_BREAKPOINT_SW) { - bp = kvm_find_sw_breakpoint(current_env, addr); + bp = kvm_find_sw_breakpoint(current_cpu, addr); if (!bp) { return -ENOENT; } @@ -1883,7 +1940,7 @@ int kvm_remove_breakpoint(CPUArchState *current_env, target_ulong addr, return err; } - QTAILQ_REMOVE(¤t_env->kvm_state->kvm_sw_breakpoints, bp, entry); + QTAILQ_REMOVE(¤t_cpu->kvm_state->kvm_sw_breakpoints, bp, entry); g_free(bp); } else { err = kvm_arch_remove_hw_breakpoint(addr, len, type); @@ -1905,7 +1962,7 @@ void kvm_remove_all_breakpoints(CPUArchState *current_env) { CPUState *current_cpu = ENV_GET_CPU(current_env); struct kvm_sw_breakpoint *bp, *next; - KVMState *s = current_env->kvm_state; + KVMState *s = current_cpu->kvm_state; CPUArchState *env; CPUState *cpu; @@ -1955,78 +2012,25 @@ void kvm_remove_all_breakpoints(CPUArchState *current_env) int kvm_set_signal_mask(CPUArchState *env, const sigset_t *sigset) { + CPUState *cpu = ENV_GET_CPU(env); struct kvm_signal_mask *sigmask; int r; if (!sigset) { - return kvm_vcpu_ioctl(env, KVM_SET_SIGNAL_MASK, NULL); + return kvm_vcpu_ioctl(cpu, KVM_SET_SIGNAL_MASK, NULL); } sigmask = g_malloc(sizeof(*sigmask) + sizeof(*sigset)); sigmask->len = 8; memcpy(sigmask->sigset, sigset, sizeof(*sigset)); - r = kvm_vcpu_ioctl(env, KVM_SET_SIGNAL_MASK, sigmask); + r = kvm_vcpu_ioctl(cpu, KVM_SET_SIGNAL_MASK, sigmask); g_free(sigmask); return r; } - -int kvm_set_ioeventfd_mmio(int fd, uint32_t addr, uint32_t val, bool assign, - uint32_t size) -{ - int ret; - struct kvm_ioeventfd iofd; - - iofd.datamatch = val; - iofd.addr = addr; - iofd.len = size; - iofd.flags = KVM_IOEVENTFD_FLAG_DATAMATCH; - iofd.fd = fd; - - if (!kvm_enabled()) { - return -ENOSYS; - } - - if (!assign) { - iofd.flags |= KVM_IOEVENTFD_FLAG_DEASSIGN; - } - - ret = kvm_vm_ioctl(kvm_state, KVM_IOEVENTFD, &iofd); - - if (ret < 0) { - return -errno; - } - - return 0; -} - -int kvm_set_ioeventfd_pio_word(int fd, uint16_t addr, uint16_t val, bool assign) -{ - struct kvm_ioeventfd kick = { - .datamatch = val, - .addr = addr, - .len = 2, - .flags = KVM_IOEVENTFD_FLAG_DATAMATCH | KVM_IOEVENTFD_FLAG_PIO, - .fd = fd, - }; - int r; - if (!kvm_enabled()) { - return -ENOSYS; - } - if (!assign) { - kick.flags |= KVM_IOEVENTFD_FLAG_DEASSIGN; - } - r = kvm_vm_ioctl(kvm_state, KVM_IOEVENTFD, &kick); - if (r < 0) { - return r; - } - return 0; -} - -int kvm_on_sigbus_vcpu(CPUArchState *env, int code, void *addr) +int kvm_on_sigbus_vcpu(CPUState *cpu, int code, void *addr) { - CPUState *cpu = ENV_GET_CPU(env); return kvm_arch_on_sigbus_vcpu(cpu, code, addr); }