15c3d55faSPekka Enberg #include "kvm/kvm-cpu.h" 25c3d55faSPekka Enberg 3b0b42ba0SPekka Enberg #include "kvm/symbol.h" 45c3d55faSPekka Enberg #include "kvm/util.h" 55c3d55faSPekka Enberg #include "kvm/kvm.h" 65c3d55faSPekka Enberg 75c3d55faSPekka Enberg #include <sys/ioctl.h> 85c3d55faSPekka Enberg #include <sys/mman.h> 95ee154d1SPekka Enberg #include <signal.h> 105c3d55faSPekka Enberg #include <stdlib.h> 11b0b42ba0SPekka Enberg #include <string.h> 125c3d55faSPekka Enberg #include <errno.h> 135c3d55faSPekka Enberg #include <stdio.h> 145c3d55faSPekka Enberg 15714e5b7fSSasha Levin extern struct kvm_cpu *kvm_cpus[KVM_NR_CPUS]; 16656be1b8SSasha Levin extern __thread struct kvm_cpu *current_kvm_cpu; 17656be1b8SSasha Levin 1843835ac9SSasha Levin void kvm_cpu__enable_singlestep(struct kvm_cpu *vcpu) 195c3d55faSPekka Enberg { 205c3d55faSPekka Enberg struct kvm_guest_debug debug = { 215c3d55faSPekka Enberg .control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP, 225c3d55faSPekka Enberg }; 235c3d55faSPekka Enberg 2443835ac9SSasha Levin if (ioctl(vcpu->vcpu_fd, KVM_SET_GUEST_DEBUG, &debug) < 0) 254542f276SCyrill Gorcunov pr_warning("KVM_SET_GUEST_DEBUG failed"); 265c3d55faSPekka Enberg } 275c3d55faSPekka Enberg 2843835ac9SSasha Levin void kvm_cpu__run(struct kvm_cpu *vcpu) 295c3d55faSPekka Enberg { 305c3d55faSPekka Enberg int err; 315c3d55faSPekka Enberg 3243835ac9SSasha Levin err = ioctl(vcpu->vcpu_fd, KVM_RUN, 0); 3376b75d32SMatt Evans if (err < 0 && (errno != EINTR && errno != EAGAIN)) 345c3d55faSPekka Enberg die_perror("KVM_RUN failed"); 355c3d55faSPekka Enberg } 3665bab644SPekka Enberg 374298ddadSSasha Levin static void kvm_cpu_signal_handler(int signum) 3849e5227dSSasha Levin { 394298ddadSSasha Levin if (signum == SIGKVMEXIT) { 40714e5b7fSSasha Levin if (current_kvm_cpu && current_kvm_cpu->is_running) { 41656be1b8SSasha Levin current_kvm_cpu->is_running = false; 42656be1b8SSasha Levin pthread_kill(pthread_self(), SIGKVMEXIT); 43656be1b8SSasha Levin } 444298ddadSSasha Levin } else if (signum == SIGKVMPAUSE) { 454298ddadSSasha Levin current_kvm_cpu->paused = 1; 464298ddadSSasha Levin } 4749e5227dSSasha Levin } 4849e5227dSSasha Levin 4973f7e5b3SSasha Levin static void kvm_cpu__handle_coalesced_mmio(struct kvm_cpu *cpu) 5073f7e5b3SSasha Levin { 5173f7e5b3SSasha Levin if (cpu->ring) { 5273f7e5b3SSasha Levin while (cpu->ring->first != cpu->ring->last) { 5373f7e5b3SSasha Levin struct kvm_coalesced_mmio *m; 5473f7e5b3SSasha Levin m = &cpu->ring->coalesced_mmio[cpu->ring->first]; 5573f7e5b3SSasha Levin kvm__emulate_mmio(cpu->kvm, 5673f7e5b3SSasha Levin m->phys_addr, 5773f7e5b3SSasha Levin m->data, 5873f7e5b3SSasha Levin m->len, 5973f7e5b3SSasha Levin 1); 6073f7e5b3SSasha Levin cpu->ring->first = (cpu->ring->first + 1) % KVM_COALESCED_MMIO_MAX; 6173f7e5b3SSasha Levin } 6273f7e5b3SSasha Levin } 6373f7e5b3SSasha Levin } 6473f7e5b3SSasha Levin 65714e5b7fSSasha Levin void kvm_cpu__reboot(void) 66714e5b7fSSasha Levin { 67c23d9748SSasha Levin int i; 68c23d9748SSasha Levin 69c23d9748SSasha Levin for (i = 0; i < KVM_NR_CPUS; i++) 70c23d9748SSasha Levin if (kvm_cpus[i]) 71c23d9748SSasha Levin pthread_kill(kvm_cpus[i]->thread, SIGKVMEXIT); 72714e5b7fSSasha Levin } 73714e5b7fSSasha Levin 7465bab644SPekka Enberg int kvm_cpu__start(struct kvm_cpu *cpu) 7565bab644SPekka Enberg { 765ee154d1SPekka Enberg sigset_t sigset; 775ee154d1SPekka Enberg 785ee154d1SPekka Enberg sigemptyset(&sigset); 795ee154d1SPekka Enberg sigaddset(&sigset, SIGALRM); 805ee154d1SPekka Enberg 815ee154d1SPekka Enberg pthread_sigmask(SIG_BLOCK, &sigset, NULL); 825ee154d1SPekka Enberg 834298ddadSSasha Levin signal(SIGKVMEXIT, kvm_cpu_signal_handler); 844298ddadSSasha Levin signal(SIGKVMPAUSE, kvm_cpu_signal_handler); 8549e5227dSSasha Levin 865d1a249cSPekka Enberg kvm_cpu__reset_vcpu(cpu); 875d1a249cSPekka Enberg 886d6a4d41SPekka Enberg if (cpu->kvm->single_step) 896d6a4d41SPekka Enberg kvm_cpu__enable_singlestep(cpu); 906d6a4d41SPekka Enberg 91c23d9748SSasha Levin while (cpu->is_running) { 924298ddadSSasha Levin if (cpu->paused) { 934298ddadSSasha Levin kvm__notify_paused(); 944298ddadSSasha Levin cpu->paused = 0; 954298ddadSSasha Levin } 964298ddadSSasha Levin 97*4b1c6f6eSSasha Levin if (cpu->needs_nmi) { 98*4b1c6f6eSSasha Levin kvm_cpu__arch_nmi(cpu); 99*4b1c6f6eSSasha Levin cpu->needs_nmi = 0; 100*4b1c6f6eSSasha Levin } 101*4b1c6f6eSSasha Levin 10265bab644SPekka Enberg kvm_cpu__run(cpu); 10365bab644SPekka Enberg 10465bab644SPekka Enberg switch (cpu->kvm_run->exit_reason) { 1051621292eSSasha Levin case KVM_EXIT_UNKNOWN: 1061621292eSSasha Levin break; 10765bab644SPekka Enberg case KVM_EXIT_DEBUG: 10865bab644SPekka Enberg kvm_cpu__show_registers(cpu); 10965bab644SPekka Enberg kvm_cpu__show_code(cpu); 11065bab644SPekka Enberg break; 11165bab644SPekka Enberg case KVM_EXIT_IO: { 11265bab644SPekka Enberg bool ret; 11365bab644SPekka Enberg 11465bab644SPekka Enberg ret = kvm__emulate_io(cpu->kvm, 11565bab644SPekka Enberg cpu->kvm_run->io.port, 1163fdf659dSSasha Levin (u8 *)cpu->kvm_run + 11765bab644SPekka Enberg cpu->kvm_run->io.data_offset, 11865bab644SPekka Enberg cpu->kvm_run->io.direction, 11965bab644SPekka Enberg cpu->kvm_run->io.size, 12065bab644SPekka Enberg cpu->kvm_run->io.count); 12165bab644SPekka Enberg 12265bab644SPekka Enberg if (!ret) 12365bab644SPekka Enberg goto panic_kvm; 12465bab644SPekka Enberg break; 12565bab644SPekka Enberg } 12665bab644SPekka Enberg case KVM_EXIT_MMIO: { 12765bab644SPekka Enberg bool ret; 12865bab644SPekka Enberg 12965bab644SPekka Enberg ret = kvm__emulate_mmio(cpu->kvm, 13065bab644SPekka Enberg cpu->kvm_run->mmio.phys_addr, 13165bab644SPekka Enberg cpu->kvm_run->mmio.data, 13265bab644SPekka Enberg cpu->kvm_run->mmio.len, 13365bab644SPekka Enberg cpu->kvm_run->mmio.is_write); 13465bab644SPekka Enberg 13565bab644SPekka Enberg if (!ret) 13665bab644SPekka Enberg goto panic_kvm; 13765bab644SPekka Enberg break; 13865bab644SPekka Enberg } 1395ee154d1SPekka Enberg case KVM_EXIT_INTR: 140656be1b8SSasha Levin if (cpu->is_running) 141656be1b8SSasha Levin break; 14249e5227dSSasha Levin goto exit_kvm; 14365bab644SPekka Enberg case KVM_EXIT_SHUTDOWN: 14465bab644SPekka Enberg goto exit_kvm; 145341ee0d4SMatt Evans default: { 146341ee0d4SMatt Evans bool ret; 147341ee0d4SMatt Evans 148341ee0d4SMatt Evans ret = kvm_cpu__handle_exit(cpu); 149341ee0d4SMatt Evans if (!ret) 15065bab644SPekka Enberg goto panic_kvm; 151341ee0d4SMatt Evans break; 152341ee0d4SMatt Evans } 15365bab644SPekka Enberg } 15473f7e5b3SSasha Levin kvm_cpu__handle_coalesced_mmio(cpu); 15565bab644SPekka Enberg } 15665bab644SPekka Enberg 15765bab644SPekka Enberg exit_kvm: 15865bab644SPekka Enberg return 0; 15965bab644SPekka Enberg 16065bab644SPekka Enberg panic_kvm: 16165bab644SPekka Enberg return 1; 16265bab644SPekka Enberg } 163