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 15656be1b8SSasha Levin extern __thread struct kvm_cpu *current_kvm_cpu; 16656be1b8SSasha Levin 1743835ac9SSasha Levin void kvm_cpu__enable_singlestep(struct kvm_cpu *vcpu) 185c3d55faSPekka Enberg { 195c3d55faSPekka Enberg struct kvm_guest_debug debug = { 205c3d55faSPekka Enberg .control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP, 215c3d55faSPekka Enberg }; 225c3d55faSPekka Enberg 2343835ac9SSasha Levin if (ioctl(vcpu->vcpu_fd, KVM_SET_GUEST_DEBUG, &debug) < 0) 244542f276SCyrill Gorcunov pr_warning("KVM_SET_GUEST_DEBUG failed"); 255c3d55faSPekka Enberg } 265c3d55faSPekka Enberg 2743835ac9SSasha Levin void kvm_cpu__run(struct kvm_cpu *vcpu) 285c3d55faSPekka Enberg { 295c3d55faSPekka Enberg int err; 305c3d55faSPekka Enberg 31f9fdf5cdSAsias He if (!vcpu->is_running) 32f9fdf5cdSAsias He return; 33f9fdf5cdSAsias He 3443835ac9SSasha Levin err = ioctl(vcpu->vcpu_fd, KVM_RUN, 0); 3576b75d32SMatt Evans if (err < 0 && (errno != EINTR && errno != EAGAIN)) 365c3d55faSPekka Enberg die_perror("KVM_RUN failed"); 375c3d55faSPekka Enberg } 3865bab644SPekka Enberg 394298ddadSSasha Levin static void kvm_cpu_signal_handler(int signum) 4049e5227dSSasha Levin { 414298ddadSSasha Levin if (signum == SIGKVMEXIT) { 42714e5b7fSSasha Levin if (current_kvm_cpu && current_kvm_cpu->is_running) { 43656be1b8SSasha Levin current_kvm_cpu->is_running = false; 444346fd8fSSasha Levin kvm__continue(current_kvm_cpu->kvm); 45656be1b8SSasha Levin } 464298ddadSSasha Levin } else if (signum == SIGKVMPAUSE) { 474298ddadSSasha Levin current_kvm_cpu->paused = 1; 484298ddadSSasha Levin } 4949e5227dSSasha Levin } 5049e5227dSSasha Levin 5173f7e5b3SSasha Levin static void kvm_cpu__handle_coalesced_mmio(struct kvm_cpu *cpu) 5273f7e5b3SSasha Levin { 5373f7e5b3SSasha Levin if (cpu->ring) { 5473f7e5b3SSasha Levin while (cpu->ring->first != cpu->ring->last) { 5573f7e5b3SSasha Levin struct kvm_coalesced_mmio *m; 5673f7e5b3SSasha Levin m = &cpu->ring->coalesced_mmio[cpu->ring->first]; 57*9b735910SMarc Zyngier kvm_cpu__emulate_mmio(cpu, 5873f7e5b3SSasha Levin m->phys_addr, 5973f7e5b3SSasha Levin m->data, 6073f7e5b3SSasha Levin m->len, 6173f7e5b3SSasha Levin 1); 6273f7e5b3SSasha Levin cpu->ring->first = (cpu->ring->first + 1) % KVM_COALESCED_MMIO_MAX; 6373f7e5b3SSasha Levin } 6473f7e5b3SSasha Levin } 6573f7e5b3SSasha Levin } 6673f7e5b3SSasha Levin 67df4239fbSSasha Levin void kvm_cpu__reboot(struct kvm *kvm) 68714e5b7fSSasha Levin { 69c23d9748SSasha Levin int i; 70c23d9748SSasha Levin 71df4239fbSSasha Levin /* The kvm->cpus array contains a null pointer in the last location */ 72e2077857SMatt Evans for (i = 0; ; i++) { 73df4239fbSSasha Levin if (kvm->cpus[i]) 74df4239fbSSasha Levin pthread_kill(kvm->cpus[i]->thread, SIGKVMEXIT); 75e2077857SMatt Evans else 76e2077857SMatt Evans break; 77e2077857SMatt Evans } 78714e5b7fSSasha Levin } 79714e5b7fSSasha Levin 8065bab644SPekka Enberg int kvm_cpu__start(struct kvm_cpu *cpu) 8165bab644SPekka Enberg { 825ee154d1SPekka Enberg sigset_t sigset; 835ee154d1SPekka Enberg 845ee154d1SPekka Enberg sigemptyset(&sigset); 855ee154d1SPekka Enberg sigaddset(&sigset, SIGALRM); 865ee154d1SPekka Enberg 875ee154d1SPekka Enberg pthread_sigmask(SIG_BLOCK, &sigset, NULL); 885ee154d1SPekka Enberg 894298ddadSSasha Levin signal(SIGKVMEXIT, kvm_cpu_signal_handler); 904298ddadSSasha Levin signal(SIGKVMPAUSE, kvm_cpu_signal_handler); 9149e5227dSSasha Levin 925d1a249cSPekka Enberg kvm_cpu__reset_vcpu(cpu); 935d1a249cSPekka Enberg 94809f088bSSasha Levin if (cpu->kvm->cfg.single_step) 956d6a4d41SPekka Enberg kvm_cpu__enable_singlestep(cpu); 966d6a4d41SPekka Enberg 97c23d9748SSasha Levin while (cpu->is_running) { 984298ddadSSasha Levin if (cpu->paused) { 994298ddadSSasha Levin kvm__notify_paused(); 1004298ddadSSasha Levin cpu->paused = 0; 1014298ddadSSasha Levin } 1024298ddadSSasha Levin 1034b1c6f6eSSasha Levin if (cpu->needs_nmi) { 1044b1c6f6eSSasha Levin kvm_cpu__arch_nmi(cpu); 1054b1c6f6eSSasha Levin cpu->needs_nmi = 0; 1064b1c6f6eSSasha Levin } 1074b1c6f6eSSasha Levin 10865bab644SPekka Enberg kvm_cpu__run(cpu); 10965bab644SPekka Enberg 11065bab644SPekka Enberg switch (cpu->kvm_run->exit_reason) { 1111621292eSSasha Levin case KVM_EXIT_UNKNOWN: 1121621292eSSasha Levin break; 11365bab644SPekka Enberg case KVM_EXIT_DEBUG: 11465bab644SPekka Enberg kvm_cpu__show_registers(cpu); 11565bab644SPekka Enberg kvm_cpu__show_code(cpu); 11665bab644SPekka Enberg break; 11765bab644SPekka Enberg case KVM_EXIT_IO: { 11865bab644SPekka Enberg bool ret; 11965bab644SPekka Enberg 12017edd536SMatt Evans ret = kvm_cpu__emulate_io(cpu->kvm, 12165bab644SPekka Enberg cpu->kvm_run->io.port, 1223fdf659dSSasha Levin (u8 *)cpu->kvm_run + 12365bab644SPekka Enberg cpu->kvm_run->io.data_offset, 12465bab644SPekka Enberg cpu->kvm_run->io.direction, 12565bab644SPekka Enberg cpu->kvm_run->io.size, 12665bab644SPekka Enberg cpu->kvm_run->io.count); 12765bab644SPekka Enberg 12865bab644SPekka Enberg if (!ret) 12965bab644SPekka Enberg goto panic_kvm; 13065bab644SPekka Enberg break; 13165bab644SPekka Enberg } 13265bab644SPekka Enberg case KVM_EXIT_MMIO: { 13365bab644SPekka Enberg bool ret; 13465bab644SPekka Enberg 135a7518f05SSasha Levin /* 136a7518f05SSasha Levin * If we had MMIO exit, coalesced ring should be processed 137a7518f05SSasha Levin * *before* processing the exit itself 138a7518f05SSasha Levin */ 139a7518f05SSasha Levin kvm_cpu__handle_coalesced_mmio(cpu); 140a7518f05SSasha Levin 141*9b735910SMarc Zyngier ret = kvm_cpu__emulate_mmio(cpu, 14265bab644SPekka Enberg cpu->kvm_run->mmio.phys_addr, 14365bab644SPekka Enberg cpu->kvm_run->mmio.data, 14465bab644SPekka Enberg cpu->kvm_run->mmio.len, 14565bab644SPekka Enberg cpu->kvm_run->mmio.is_write); 14665bab644SPekka Enberg 14765bab644SPekka Enberg if (!ret) 14865bab644SPekka Enberg goto panic_kvm; 14965bab644SPekka Enberg break; 15065bab644SPekka Enberg } 1515ee154d1SPekka Enberg case KVM_EXIT_INTR: 152656be1b8SSasha Levin if (cpu->is_running) 153656be1b8SSasha Levin break; 15449e5227dSSasha Levin goto exit_kvm; 15565bab644SPekka Enberg case KVM_EXIT_SHUTDOWN: 15665bab644SPekka Enberg goto exit_kvm; 157341ee0d4SMatt Evans default: { 158341ee0d4SMatt Evans bool ret; 159341ee0d4SMatt Evans 160341ee0d4SMatt Evans ret = kvm_cpu__handle_exit(cpu); 161341ee0d4SMatt Evans if (!ret) 16265bab644SPekka Enberg goto panic_kvm; 163341ee0d4SMatt Evans break; 164341ee0d4SMatt Evans } 16565bab644SPekka Enberg } 16673f7e5b3SSasha Levin kvm_cpu__handle_coalesced_mmio(cpu); 16765bab644SPekka Enberg } 16865bab644SPekka Enberg 16965bab644SPekka Enberg exit_kvm: 17065bab644SPekka Enberg return 0; 17165bab644SPekka Enberg 17265bab644SPekka Enberg panic_kvm: 17365bab644SPekka Enberg return 1; 17465bab644SPekka Enberg } 175df4239fbSSasha Levin 176df4239fbSSasha Levin int kvm_cpu__init(struct kvm *kvm) 177df4239fbSSasha Levin { 178df4239fbSSasha Levin int max_cpus, recommended_cpus, i; 179df4239fbSSasha Levin 180df4239fbSSasha Levin max_cpus = kvm__max_cpus(kvm); 181df4239fbSSasha Levin recommended_cpus = kvm__recommended_cpus(kvm); 182df4239fbSSasha Levin 183df4239fbSSasha Levin if (kvm->cfg.nrcpus > max_cpus) { 184df4239fbSSasha Levin printf(" # Limit the number of CPUs to %d\n", max_cpus); 185df4239fbSSasha Levin kvm->cfg.nrcpus = max_cpus; 186df4239fbSSasha Levin } else if (kvm->cfg.nrcpus > recommended_cpus) { 187df4239fbSSasha Levin printf(" # Warning: The maximum recommended amount of VCPUs" 188df4239fbSSasha Levin " is %d\n", recommended_cpus); 189df4239fbSSasha Levin } 190df4239fbSSasha Levin 191df4239fbSSasha Levin kvm->nrcpus = kvm->cfg.nrcpus; 192df4239fbSSasha Levin 193df4239fbSSasha Levin /* Alloc one pointer too many, so array ends up 0-terminated */ 194df4239fbSSasha Levin kvm->cpus = calloc(kvm->nrcpus + 1, sizeof(void *)); 195df4239fbSSasha Levin if (!kvm->cpus) { 196df4239fbSSasha Levin pr_warning("Couldn't allocate array for %d CPUs", kvm->nrcpus); 197df4239fbSSasha Levin return -ENOMEM; 198df4239fbSSasha Levin } 199df4239fbSSasha Levin 200df4239fbSSasha Levin for (i = 0; i < kvm->nrcpus; i++) { 201df4239fbSSasha Levin kvm->cpus[i] = kvm_cpu__arch_init(kvm, i); 202df4239fbSSasha Levin if (!kvm->cpus[i]) { 203df4239fbSSasha Levin pr_warning("unable to initialize KVM VCPU"); 204df4239fbSSasha Levin goto fail_alloc; 205df4239fbSSasha Levin } 206df4239fbSSasha Levin } 207df4239fbSSasha Levin 208df4239fbSSasha Levin return 0; 209df4239fbSSasha Levin 210df4239fbSSasha Levin fail_alloc: 211df4239fbSSasha Levin for (i = 0; i < kvm->nrcpus; i++) 212df4239fbSSasha Levin free(kvm->cpus[i]); 213df4239fbSSasha Levin return -ENOMEM; 214df4239fbSSasha Levin } 21549a8afd1SSasha Levin base_init(kvm_cpu__init); 216df4239fbSSasha Levin 217df4239fbSSasha Levin int kvm_cpu__exit(struct kvm *kvm) 218df4239fbSSasha Levin { 219df4239fbSSasha Levin int i, r; 220df4239fbSSasha Levin void *ret = NULL; 221df4239fbSSasha Levin 222df4239fbSSasha Levin kvm_cpu__delete(kvm->cpus[0]); 223df4239fbSSasha Levin kvm->cpus[0] = NULL; 224df4239fbSSasha Levin 225df4239fbSSasha Levin for (i = 1; i < kvm->nrcpus; i++) { 226df4239fbSSasha Levin if (kvm->cpus[i]->is_running) { 227df4239fbSSasha Levin pthread_kill(kvm->cpus[i]->thread, SIGKVMEXIT); 228df4239fbSSasha Levin if (pthread_join(kvm->cpus[i]->thread, &ret) != 0) 229df4239fbSSasha Levin die("pthread_join"); 230df4239fbSSasha Levin kvm_cpu__delete(kvm->cpus[i]); 231df4239fbSSasha Levin } 232df4239fbSSasha Levin if (ret == NULL) 233df4239fbSSasha Levin r = 0; 234df4239fbSSasha Levin } 235df4239fbSSasha Levin 236df4239fbSSasha Levin free(kvm->cpus); 237df4239fbSSasha Levin 238df4239fbSSasha Levin kvm->nrcpus = 0; 239df4239fbSSasha Levin 240df4239fbSSasha Levin return r; 241df4239fbSSasha Levin } 24249a8afd1SSasha Levin late_exit(kvm_cpu__exit); 243