aboutsummaryrefslogtreecommitdiff
path: root/drivers/kvm/kvm_main.c
diff options
context:
space:
mode:
authorAvi Kivity <avi@qumranet.com>2007-02-22 19:39:30 +0200
committerAvi Kivity <avi@qumranet.com>2007-05-03 10:52:23 +0300
commit46fc1477887c41c8e900f2c95485e222b9a54822 (patch)
treeef9d4d4b6fc32f3d6b4e77a87d1b47b6da455574 /drivers/kvm/kvm_main.c
parent9a2bb7f486dc639a1cf2ad803bf2227f0dc0809d (diff)
KVM: Do not communicate to userspace through cpu registers during PIO
Currently when passing the a PIO emulation request to userspace, we rely on userspace updating %rax (on 'in' instructions) and %rsi/%rdi/%rcx (on string instructions). This (a) requires two extra ioctls for getting and setting the registers and (b) is unfriendly to non-x86 archs, when they get kvm ports. So fix by doing the register fixups in the kernel and passing to userspace only an abstract description of the PIO to be done. Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm/kvm_main.c')
-rw-r--r--drivers/kvm/kvm_main.c48
1 files changed, 45 insertions, 3 deletions
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index 42be8a8f299..ff8bcfee76e 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -1504,6 +1504,44 @@ void save_msrs(struct vmx_msr_entry *e, int n)
}
EXPORT_SYMBOL_GPL(save_msrs);
+static void complete_pio(struct kvm_vcpu *vcpu)
+{
+ struct kvm_io *io = &vcpu->run->io;
+ long delta;
+
+ kvm_arch_ops->cache_regs(vcpu);
+
+ if (!io->string) {
+ if (io->direction == KVM_EXIT_IO_IN)
+ memcpy(&vcpu->regs[VCPU_REGS_RAX], &io->value,
+ io->size);
+ } else {
+ delta = 1;
+ if (io->rep) {
+ delta *= io->count;
+ /*
+ * The size of the register should really depend on
+ * current address size.
+ */
+ vcpu->regs[VCPU_REGS_RCX] -= delta;
+ }
+ if (io->string_down)
+ delta = -delta;
+ delta *= io->size;
+ if (io->direction == KVM_EXIT_IO_IN)
+ vcpu->regs[VCPU_REGS_RDI] += delta;
+ else
+ vcpu->regs[VCPU_REGS_RSI] += delta;
+ }
+
+ vcpu->pio_pending = 0;
+ vcpu->run->io_completed = 0;
+
+ kvm_arch_ops->decache_regs(vcpu);
+
+ kvm_arch_ops->skip_emulated_instruction(vcpu);
+}
+
static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
int r;
@@ -1518,9 +1556,13 @@ static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
kvm_run->emulated = 0;
}
- if (kvm_run->mmio_completed) {
- memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8);
- vcpu->mmio_read_completed = 1;
+ if (kvm_run->io_completed) {
+ if (vcpu->pio_pending)
+ complete_pio(vcpu);
+ else {
+ memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8);
+ vcpu->mmio_read_completed = 1;
+ }
}
vcpu->mmio_needed = 0;