diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/kvm/kvm.h | 1 | ||||
-rw-r--r-- | drivers/kvm/kvm_main.c | 48 | ||||
-rw-r--r-- | drivers/kvm/svm.c | 2 | ||||
-rw-r--r-- | drivers/kvm/vmx.c | 2 |
4 files changed, 50 insertions, 3 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 | } |
1505 | EXPORT_SYMBOL_GPL(save_msrs); | 1505 | EXPORT_SYMBOL_GPL(save_msrs); |
1506 | 1506 | ||
1507 | static 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 | |||
1507 | static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | 1545 | static 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 | ||