aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAvi Kivity <avi@qumranet.com>2007-02-22 12:39:30 -0500
committerAvi Kivity <avi@qumranet.com>2007-05-03 03:52:23 -0400
commit46fc1477887c41c8e900f2c95485e222b9a54822 (patch)
treeef9d4d4b6fc32f3d6b4e77a87d1b47b6da455574
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>
-rw-r--r--drivers/kvm/kvm.h1
-rw-r--r--drivers/kvm/kvm_main.c48
-rw-r--r--drivers/kvm/svm.c2
-rw-r--r--drivers/kvm/vmx.c2
-rw-r--r--include/linux/kvm.h6
5 files changed, 53 insertions, 6 deletions
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index 901b8d917b55..59cbc5b1d905 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -274,6 +274,7 @@ struct kvm_vcpu {
274 int mmio_size; 274 int mmio_size;
275 unsigned char mmio_data[8]; 275 unsigned char mmio_data[8];
276 gpa_t mmio_phys_addr; 276 gpa_t mmio_phys_addr;
277 int pio_pending;
277 278
278 struct { 279 struct {
279 int active; 280 int active;
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index 42be8a8f299d..ff8bcfee76e5 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)
1504} 1504}
1505EXPORT_SYMBOL_GPL(save_msrs); 1505EXPORT_SYMBOL_GPL(save_msrs);
1506 1506
1507static void complete_pio(struct kvm_vcpu *vcpu)
1508{
1509 struct kvm_io *io = &vcpu->run->io;
1510 long delta;
1511
1512 kvm_arch_ops->cache_regs(vcpu);
1513
1514 if (!io->string) {
1515 if (io->direction == KVM_EXIT_IO_IN)
1516 memcpy(&vcpu->regs[VCPU_REGS_RAX], &io->value,
1517 io->size);
1518 } else {
1519 delta = 1;
1520 if (io->rep) {
1521 delta *= io->count;
1522 /*
1523 * The size of the register should really depend on
1524 * current address size.
1525 */
1526 vcpu->regs[VCPU_REGS_RCX] -= delta;
1527 }
1528 if (io->string_down)
1529 delta = -delta;
1530 delta *= io->size;
1531 if (io->direction == KVM_EXIT_IO_IN)
1532 vcpu->regs[VCPU_REGS_RDI] += delta;
1533 else
1534 vcpu->regs[VCPU_REGS_RSI] += delta;
1535 }
1536
1537 vcpu->pio_pending = 0;
1538 vcpu->run->io_completed = 0;
1539
1540 kvm_arch_ops->decache_regs(vcpu);
1541
1542 kvm_arch_ops->skip_emulated_instruction(vcpu);
1543}
1544
1507static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) 1545static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1508{ 1546{
1509 int r; 1547 int r;
@@ -1518,9 +1556,13 @@ static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1518 kvm_run->emulated = 0; 1556 kvm_run->emulated = 0;
1519 } 1557 }
1520 1558
1521 if (kvm_run->mmio_completed) { 1559 if (kvm_run->io_completed) {
1522 memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8); 1560 if (vcpu->pio_pending)
1523 vcpu->mmio_read_completed = 1; 1561 complete_pio(vcpu);
1562 else {
1563 memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8);
1564 vcpu->mmio_read_completed = 1;
1565 }
1524 } 1566 }
1525 1567
1526 vcpu->mmio_needed = 0; 1568 vcpu->mmio_needed = 0;
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c
index 6787f11738cf..c35b8c83bf3f 100644
--- a/drivers/kvm/svm.c
+++ b/drivers/kvm/svm.c
@@ -1037,6 +1037,7 @@ static int io_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1037 kvm_run->io.size = ((io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT); 1037 kvm_run->io.size = ((io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT);
1038 kvm_run->io.string = (io_info & SVM_IOIO_STR_MASK) != 0; 1038 kvm_run->io.string = (io_info & SVM_IOIO_STR_MASK) != 0;
1039 kvm_run->io.rep = (io_info & SVM_IOIO_REP_MASK) != 0; 1039 kvm_run->io.rep = (io_info & SVM_IOIO_REP_MASK) != 0;
1040 kvm_run->io.count = 1;
1040 1041
1041 if (kvm_run->io.string) { 1042 if (kvm_run->io.string) {
1042 unsigned addr_mask; 1043 unsigned addr_mask;
@@ -1056,6 +1057,7 @@ static int io_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1056 } 1057 }
1057 } else 1058 } else
1058 kvm_run->io.value = vcpu->svm->vmcb->save.rax; 1059 kvm_run->io.value = vcpu->svm->vmcb->save.rax;
1060 vcpu->pio_pending = 1;
1059 return 0; 1061 return 0;
1060} 1062}
1061 1063
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index a721b60f7385..4d5f40fcb651 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -1459,12 +1459,14 @@ static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1459 = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_DF) != 0; 1459 = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_DF) != 0;
1460 kvm_run->io.rep = (exit_qualification & 32) != 0; 1460 kvm_run->io.rep = (exit_qualification & 32) != 0;
1461 kvm_run->io.port = exit_qualification >> 16; 1461 kvm_run->io.port = exit_qualification >> 16;
1462 kvm_run->io.count = 1;
1462 if (kvm_run->io.string) { 1463 if (kvm_run->io.string) {
1463 if (!get_io_count(vcpu, &kvm_run->io.count)) 1464 if (!get_io_count(vcpu, &kvm_run->io.count))
1464 return 1; 1465 return 1;
1465 kvm_run->io.address = vmcs_readl(GUEST_LINEAR_ADDRESS); 1466 kvm_run->io.address = vmcs_readl(GUEST_LINEAR_ADDRESS);
1466 } else 1467 } else
1467 kvm_run->io.value = vcpu->regs[VCPU_REGS_RAX]; /* rax */ 1468 kvm_run->io.value = vcpu->regs[VCPU_REGS_RAX]; /* rax */
1469 vcpu->pio_pending = 1;
1468 return 0; 1470 return 0;
1469} 1471}
1470 1472
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index d88e7508ee0a..19aeb3385188 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -11,7 +11,7 @@
11#include <asm/types.h> 11#include <asm/types.h>
12#include <linux/ioctl.h> 12#include <linux/ioctl.h>
13 13
14#define KVM_API_VERSION 5 14#define KVM_API_VERSION 6
15 15
16/* 16/*
17 * Architectural interrupt line count, and the size of the bitmap needed 17 * Architectural interrupt line count, and the size of the bitmap needed
@@ -53,7 +53,7 @@ enum kvm_exit_reason {
53struct kvm_run { 53struct kvm_run {
54 /* in */ 54 /* in */
55 __u32 emulated; /* skip current instruction */ 55 __u32 emulated; /* skip current instruction */
56 __u32 mmio_completed; /* mmio request completed */ 56 __u32 io_completed; /* mmio/pio request completed */
57 __u8 request_interrupt_window; 57 __u8 request_interrupt_window;
58 __u8 padding1[7]; 58 __u8 padding1[7];
59 59
@@ -80,7 +80,7 @@ struct kvm_run {
80 __u32 error_code; 80 __u32 error_code;
81 } ex; 81 } ex;
82 /* KVM_EXIT_IO */ 82 /* KVM_EXIT_IO */
83 struct { 83 struct kvm_io {
84#define KVM_EXIT_IO_IN 0 84#define KVM_EXIT_IO_IN 0
85#define KVM_EXIT_IO_OUT 1 85#define KVM_EXIT_IO_OUT 1
86 __u8 direction; 86 __u8 direction;