X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/b0c883b5e079a4f719c43f875034e5e665ccc232..19e83f6bdf86f92ee90db77d606affe5b08f8b40:/kvm-all.c diff --git a/kvm-all.c b/kvm-all.c index 9976762f87..1d7e8eabf4 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -78,7 +78,7 @@ struct KVMState int many_ioeventfds; }; -static KVMState *kvm_state; +KVMState *kvm_state; static const KVMCapabilityInfo kvm_required_capabilites[] = { KVM_CAP_INFO(USER_MEMORY), @@ -91,10 +91,6 @@ static KVMSlot *kvm_alloc_slot(KVMState *s) int i; for (i = 0; i < ARRAY_SIZE(s->slots); i++) { - /* KVM private memory slots */ - if (i >= 8 && i < 12) { - continue; - } if (s->slots[i].memory_size == 0) { return &s->slots[i]; } @@ -199,7 +195,6 @@ int kvm_pit_in_kernel(void) return kvm_state->pit_in_kernel; } - int kvm_init_vcpu(CPUState *env) { KVMState *s = kvm_state; @@ -216,9 +211,11 @@ int kvm_init_vcpu(CPUState *env) env->kvm_fd = ret; env->kvm_state = s; + env->kvm_vcpu_dirty = 1; mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0); if (mmap_size < 0) { + ret = mmap_size; DPRINTF("KVM_GET_VCPU_MMAP_SIZE failed\n"); goto err; } @@ -278,13 +275,15 @@ static int kvm_dirty_pages_log_change(target_phys_addr_t phys_addr, return kvm_set_user_memory_region(s, mem); } -int kvm_log_start(target_phys_addr_t phys_addr, ram_addr_t size) +static int kvm_log_start(CPUPhysMemoryClient *client, + target_phys_addr_t phys_addr, ram_addr_t size) { return kvm_dirty_pages_log_change(phys_addr, size, KVM_MEM_LOG_DIRTY_PAGES, KVM_MEM_LOG_DIRTY_PAGES); } -int kvm_log_stop(target_phys_addr_t phys_addr, ram_addr_t size) +static int kvm_log_stop(CPUPhysMemoryClient *client, + target_phys_addr_t phys_addr, ram_addr_t size) { return kvm_dirty_pages_log_change(phys_addr, size, 0, KVM_MEM_LOG_DIRTY_PAGES); @@ -448,10 +447,14 @@ int kvm_check_extension(KVMState *s, unsigned int extension) static int kvm_check_many_ioeventfds(void) { - /* Older kernels have a 6 device limit on the KVM io bus. Find out so we + /* Userspace can use ioeventfd for io notification. This requires a host + * that supports eventfd(2) and an I/O thread; since eventfd does not + * support SIGIO it cannot interrupt the vcpu. + * + * Older kernels have a 6 device limit on the KVM io bus. Find out so we * can avoid creating too many ioeventfds. */ -#ifdef CONFIG_EVENTFD +#if defined(CONFIG_EVENTFD) && defined(CONFIG_IOTHREAD) int ioeventfds[7]; int i, ret = 0; for (i = 0; i < ARRAY_SIZE(ioeventfds); i++) { @@ -644,6 +647,8 @@ static CPUPhysMemoryClient kvm_cpu_phys_memory_client = { .set_memory = kvm_client_set_memory, .sync_dirty_bitmap = kvm_client_sync_dirty_bitmap, .migration_log = kvm_client_migration_log, + .log_start = kvm_log_start, + .log_stop = kvm_log_stop, }; int kvm_init(void) @@ -770,8 +775,8 @@ err: return ret; } -static int kvm_handle_io(uint16_t port, void *data, int direction, int size, - uint32_t count) +static void kvm_handle_io(uint16_t port, void *data, int direction, int size, + uint32_t count) { int i; uint8_t *ptr = data; @@ -805,8 +810,6 @@ static int kvm_handle_io(uint16_t port, void *data, int direction, int size, ptr += size; } - - return 1; } #ifdef KVM_CAP_INTERNAL_ERROR_DATA @@ -828,7 +831,7 @@ static int kvm_handle_internal_error(CPUState *env, struct kvm_run *run) fprintf(stderr, "emulation failure\n"); if (!kvm_arch_stop_on_emulation_error(env)) { cpu_dump_state(env, stderr, fprintf, CPU_DUMP_CODE); - return 0; + return EXCP_INTERRUPT; } } /* FIXME: Should trigger a qmp message to let management know @@ -887,60 +890,63 @@ void kvm_cpu_synchronize_post_init(CPUState *env) int kvm_cpu_exec(CPUState *env) { struct kvm_run *run = env->kvm_run; - int ret; + int ret, run_ret; DPRINTF("kvm_cpu_exec()\n"); - do { -#ifndef CONFIG_IOTHREAD - if (env->exit_request) { - DPRINTF("interrupt exit requested\n"); - ret = 0; - break; - } -#endif + if (kvm_arch_process_async_events(env)) { + env->exit_request = 0; + return EXCP_HLT; + } - if (kvm_arch_process_irqchip_events(env)) { - ret = 0; - break; - } + cpu_single_env = env; + do { if (env->kvm_vcpu_dirty) { kvm_arch_put_registers(env, KVM_PUT_RUNTIME_STATE); env->kvm_vcpu_dirty = 0; } kvm_arch_pre_run(env, run); + if (env->exit_request) { + DPRINTF("interrupt exit requested\n"); + /* + * KVM requires us to reenter the kernel after IO exits to complete + * instruction emulation. This self-signal will ensure that we + * leave ASAP again. + */ + qemu_cpu_kick_self(); + } cpu_single_env = NULL; qemu_mutex_unlock_iothread(); - ret = kvm_vcpu_ioctl(env, KVM_RUN, 0); + + run_ret = kvm_vcpu_ioctl(env, KVM_RUN, 0); + qemu_mutex_lock_iothread(); cpu_single_env = env; kvm_arch_post_run(env, run); kvm_flush_coalesced_mmio_buffer(); - if (ret == -EINTR || ret == -EAGAIN) { - cpu_exit(env); - DPRINTF("io window exit\n"); - ret = 0; - break; - } - - if (ret < 0) { - DPRINTF("kvm run failed %s\n", strerror(-ret)); + if (run_ret < 0) { + if (run_ret == -EINTR || run_ret == -EAGAIN) { + DPRINTF("io window exit\n"); + ret = EXCP_INTERRUPT; + break; + } + DPRINTF("kvm run failed %s\n", strerror(-run_ret)); abort(); } - ret = 0; /* exit loop */ switch (run->exit_reason) { case KVM_EXIT_IO: DPRINTF("handle_io\n"); - ret = kvm_handle_io(run->io.port, - (uint8_t *)run + run->io.data_offset, - run->io.direction, - run->io.size, - run->io.count); + kvm_handle_io(run->io.port, + (uint8_t *)run + run->io.data_offset, + run->io.direction, + run->io.size, + run->io.count); + ret = 0; break; case KVM_EXIT_MMIO: DPRINTF("handle_mmio\n"); @@ -948,15 +954,16 @@ int kvm_cpu_exec(CPUState *env) run->mmio.data, run->mmio.len, run->mmio.is_write); - ret = 1; + ret = 0; break; case KVM_EXIT_IRQ_WINDOW_OPEN: DPRINTF("irq_window_open\n"); + ret = EXCP_INTERRUPT; break; case KVM_EXIT_SHUTDOWN: DPRINTF("shutdown\n"); qemu_system_reset_request(); - ret = 1; + ret = EXCP_INTERRUPT; break; case KVM_EXIT_UNKNOWN: fprintf(stderr, "KVM: unknown exit, hardware reason %" PRIx64 "\n", @@ -968,34 +975,20 @@ int kvm_cpu_exec(CPUState *env) ret = kvm_handle_internal_error(env, run); break; #endif - case KVM_EXIT_DEBUG: - DPRINTF("kvm_exit_debug\n"); -#ifdef KVM_CAP_SET_GUEST_DEBUG - if (kvm_arch_debug(&run->debug.arch)) { - env->exception_index = EXCP_DEBUG; - return 0; - } - /* re-enter, this exception was guest-internal */ - ret = 1; -#endif /* KVM_CAP_SET_GUEST_DEBUG */ - break; default: DPRINTF("kvm_arch_handle_exit\n"); ret = kvm_arch_handle_exit(env, run); break; } - } while (ret > 0); + } while (ret == 0); if (ret < 0) { cpu_dump_state(env, stderr, fprintf, CPU_DUMP_CODE); - vm_stop(0); - env->exit_request = 1; - } - if (env->exit_request) { - env->exit_request = 0; - env->exception_index = EXCP_INTERRUPT; + vm_stop(VMSTOP_PANIC); } + env->exit_request = 0; + cpu_single_env = NULL; return ret; } @@ -1361,3 +1354,13 @@ int kvm_set_ioeventfd_pio_word(int fd, uint16_t addr, uint16_t val, bool assign) return -ENOSYS; #endif } + +int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr) +{ + return kvm_arch_on_sigbus_vcpu(env, code, addr); +} + +int kvm_on_sigbus(int code, void *addr) +{ + return kvm_arch_on_sigbus(code, addr); +}