diff options
Diffstat (limited to 'kvm/user/kvmctl.c')
-rw-r--r-- | kvm/user/kvmctl.c | 69 |
1 files changed, 48 insertions, 21 deletions
diff --git a/kvm/user/kvmctl.c b/kvm/user/kvmctl.c index 509c12b21..533d4aa0c 100644 --- a/kvm/user/kvmctl.c +++ b/kvm/user/kvmctl.c @@ -205,7 +205,7 @@ void kvm_destroy_phys_mem(kvm_context_t kvm, unsigned long phys_start, } -void kvm_get_dirty_pages(kvm_context_t kvm, int slot, void *buf) +int kvm_get_dirty_pages(kvm_context_t kvm, int slot, void *buf) { int r; struct kvm_dirty_log log = { @@ -216,7 +216,7 @@ void kvm_get_dirty_pages(kvm_context_t kvm, int slot, void *buf) r = ioctl(kvm->fd, KVM_GET_DIRTY_LOG, &log); if (r == -1) - exit(1); + return -errno; } static int more_io(struct kvm_run *run, int first_time) @@ -234,27 +234,35 @@ static int handle_io(kvm_context_t kvm, struct kvm_run *run) int first_time = 1; int delta; struct translation_cache tr; + int _in = (run->io.direction == KVM_EXIT_IO_IN); + int r; translation_cache_init(&tr); - regs.vcpu = run->vcpu; - ioctl(kvm->fd, KVM_GET_REGS, ®s); + if (run->io.string || _in) { + regs.vcpu = run->vcpu; + r = ioctl(kvm->fd, KVM_GET_REGS, ®s); + if (r == -1) + return -errno; + } delta = run->io.string_down ? -run->io.size : run->io.size; while (more_io(run, first_time)) { void *value_addr; - int r; - if (!run->io.string) - value_addr = ®s.rax; - else { + if (!run->io.string) { + if (_in) + value_addr = ®s.rax; + else + value_addr = &run->io.value; + } else { r = translate(kvm, run->vcpu, &tr, run->io.address, &value_addr); if (r) { fprintf(stderr, "failed translating I/O address %x\n", run->io.address); - exit(1); + return r; } } @@ -280,8 +288,8 @@ static int handle_io(kvm_context_t kvm, struct kvm_run *run) break; } default: - fprintf(stderr, "bad I/O size\n"); - exit(1); + fprintf(stderr, "bad I/O size %d\n", run->io.size); + return -EMSGSIZE; } break; } @@ -300,13 +308,13 @@ static int handle_io(kvm_context_t kvm, struct kvm_run *run) *(uint32_t *)value_addr); break; default: - fprintf(stderr, "bad I/O size\n"); - exit(1); + fprintf(stderr, "bad I/O size %d\n", run->io.size); + return -EMSGSIZE; } break; default: - fprintf(stderr, "bad I/O size\n"); - exit(1); + fprintf(stderr, "bad I/O direction %d\n", run->io.direction); + return -EPROTO; } if (run->io.string) { run->io.address += delta; @@ -321,12 +329,22 @@ static int handle_io(kvm_context_t kvm, struct kvm_run *run) } first_time = 0; if (r) { - ioctl(kvm->fd, KVM_SET_REGS, ®s); - return r; + int savedret = r; + r = ioctl(kvm->fd, KVM_SET_REGS, ®s); + if (r == -1) + return -errno; + + return savedret; } } - ioctl(kvm->fd, KVM_SET_REGS, ®s); + if (run->io.string || _in) { + r = ioctl(kvm->fd, KVM_SET_REGS, ®s); + if (r == -1) + return -errno; + + } + run->emulated = 1; return 0; } @@ -439,7 +457,7 @@ void kvm_show_regs(kvm_context_t kvm, int vcpu) r = ioctl(fd, KVM_GET_REGS, ®s); if (r == -1) { perror("KVM_GET_REGS"); - exit(1); + return; } fprintf(stderr, "rax %016llx rbx %016llx rcx %016llx rdx %016llx\n" @@ -522,6 +540,11 @@ static int handle_halt(kvm_context_t kvm, struct kvm_run *kvm_run) return kvm->callbacks->halt(kvm->opaque, kvm_run->vcpu); } +static int handle_shutdown(kvm_context_t kvm, struct kvm_run *kvm_run) +{ + return kvm->callbacks->shutdown(kvm->opaque, kvm_run->vcpu); +} + int try_push_interrupts(kvm_context_t kvm) { return kvm->callbacks->try_push_interrupts(kvm->opaque); @@ -556,8 +579,9 @@ again: kvm_run.emulated = 0; kvm_run.mmio_completed = 0; if (r == -1 && errno != EINTR) { + r = -errno; printf("kvm_run: %m\n"); - exit(1); + return r; } if (r == -1) { r = handle_io_window(kvm, &kvm_run); @@ -567,7 +591,7 @@ again: case KVM_EXIT_TYPE_FAIL_ENTRY: fprintf(stderr, "kvm_run: failed entry, reason %u\n", kvm_run.exit_reason & 0xffff); - exit(1); + return -ENOEXEC; break; case KVM_EXIT_TYPE_VM_EXIT: switch (kvm_run.exit_reason) { @@ -600,6 +624,9 @@ again: break; case KVM_EXIT_IRQ_WINDOW_OPEN: break; + case KVM_EXIT_SHUTDOWN: + r = handle_shutdown(kvm, &kvm_run); + break; default: fprintf(stderr, "unhandled vm exit: 0x%x\n", kvm_run.exit_reason); kvm_show_regs(kvm, vcpu); |