aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;