From patchwork Tue Mar 9 14:09:18 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gleb Natapov X-Patchwork-Id: 84287 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o29E9cWJ029228 for ; Tue, 9 Mar 2010 14:09:38 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753080Ab0CIOJe (ORCPT ); Tue, 9 Mar 2010 09:09:34 -0500 Received: from mx1.redhat.com ([209.132.183.28]:17260 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752953Ab0CIOJ1 (ORCPT ); Tue, 9 Mar 2010 09:09:27 -0500 Received: from int-mx04.intmail.prod.int.phx2.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.17]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o29E9Rsw004968 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Tue, 9 Mar 2010 09:09:27 -0500 Received: from dhcp-1-237.tlv.redhat.com (dhcp-1-237.tlv.redhat.com [10.35.1.237]) by int-mx04.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o29E9PY0013593 for ; Tue, 9 Mar 2010 09:09:26 -0500 Received: by dhcp-1-237.tlv.redhat.com (Postfix, from userid 13519) id 691901339AB; Tue, 9 Mar 2010 16:09:23 +0200 (IST) From: Gleb Natapov To: kvm@vger.kernel.org Subject: [PATCH 20/24] KVM: x86 emulator: Move string pio emulation into emulator.c Date: Tue, 9 Mar 2010 16:09:18 +0200 Message-Id: <1268143762-4000-21-git-send-email-gleb@redhat.com> In-Reply-To: <1268143762-4000-1-git-send-email-gleb@redhat.com> References: <1268143762-4000-1-git-send-email-gleb@redhat.com> X-Scanned-By: MIMEDefang 2.67 on 10.5.11.17 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Tue, 09 Mar 2010 14:09:38 +0000 (UTC) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 1e15a0a..8507b22 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -224,14 +224,9 @@ struct kvm_pv_mmu_op_buffer { struct kvm_pio_request { unsigned long count; - int cur_count; - gva_t guest_gva; int in; int port; int size; - int string; - int down; - int rep; }; /* diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 0ec7b9b..505dfba 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -151,8 +151,8 @@ static u32 opcode_table[256] = { 0, 0, 0, 0, /* 0x68 - 0x6F */ SrcImm | Mov | Stack, 0, SrcImmByte | Mov | Stack, 0, - SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* insb, insw/insd */ - SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* outsb, outsw/outsd */ + DstMem | ByteOp | Mov | String, DstMem | Mov | String, /* insb, insw/insd */ + SrcMem | ByteOp | ImplicitOps | String, SrcMem | ImplicitOps | String, /* outsb, outsw/outsd */ /* 0x70 - 0x77 */ SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte, @@ -2439,7 +2439,12 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) goto done; } } - c->regs[VCPU_REGS_RCX]--; + if (c->src.type == OP_MEM) + memop = register_address(c, seg_override_base(ctxt, c), + c->regs[VCPU_REGS_RSI]); + if (c->dst.type == OP_MEM) + memop = register_address(c, es_base(ctxt), + c->regs[VCPU_REGS_RDI]); c->eip = ctxt->eip; } @@ -2596,20 +2601,14 @@ special_insn: kvm_inject_gp(ctxt->vcpu, 0); goto done; } - if (kvm_emulate_pio_string(ctxt->vcpu, - 1, - (c->d & ByteOp) ? 1 : c->op_bytes, - c->rep_prefix ? - address_mask(c, c->regs[VCPU_REGS_RCX]) : 1, - (ctxt->eflags & EFLG_DF), - register_address(c, es_base(ctxt), - c->regs[VCPU_REGS_RDI]), - c->rep_prefix, - c->regs[VCPU_REGS_RDX]) == 0) { - c->eip = saved_eip; - return -1; - } - return 0; + if (!ops->pio_in_emulated(c->dst.bytes, c->regs[VCPU_REGS_RDX], + &c->dst.val, 1, ctxt->vcpu)) + goto done; /* IO is needed, skip writeback */ + + register_address_increment(c, &c->regs[VCPU_REGS_RDI], + (ctxt->eflags & EFLG_DF) ? + -c->dst.bytes : c->dst.bytes); + break; case 0x6e: /* outsb */ case 0x6f: /* outsw/outsd */ if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX], @@ -2617,21 +2616,14 @@ special_insn: kvm_inject_gp(ctxt->vcpu, 0); goto done; } - if (kvm_emulate_pio_string(ctxt->vcpu, - 0, - (c->d & ByteOp) ? 1 : c->op_bytes, - c->rep_prefix ? - address_mask(c, c->regs[VCPU_REGS_RCX]) : 1, - (ctxt->eflags & EFLG_DF), - register_address(c, - seg_override_base(ctxt, c), - c->regs[VCPU_REGS_RSI]), - c->rep_prefix, - c->regs[VCPU_REGS_RDX]) == 0) { - c->eip = saved_eip; - return -1; - } - return 0; + ops->pio_out_emulated(c->src.bytes, c->regs[VCPU_REGS_RDX], + &c->src.val, 1, ctxt->vcpu); + + register_address_increment(c, &c->regs[VCPU_REGS_RSI], + (ctxt->eflags & EFLG_DF) ? + -c->src.bytes : c->src.bytes); + c->dst.type = OP_NONE; /* nothing to writeback */ + break; case 0x70 ... 0x7f: /* jcc (short) */ if (test_cc(c->b, ctxt->eflags)) jmp_rel(c, c->src.val); @@ -2977,6 +2969,11 @@ special_insn: } writeback: + if (c->rep_prefix) { + c->regs[VCPU_REGS_RCX]--; + c->eip = ctxt->eip; + } + rc = writeback(ctxt, ops); if (rc != X86EMUL_CONTINUE) goto done; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 7f6aa8d..b25ef4b 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3169,18 +3169,17 @@ static int kvm_read_guest_virt_system(gva_t addr, void *val, unsigned int bytes, return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, 0, error); } -static int kvm_write_guest_virt_helper(gva_t addr, void *val, +static int kvm_write_guest_virt_system(gva_t addr, void *val, unsigned int bytes, - struct kvm_vcpu *vcpu, u32 access, + struct kvm_vcpu *vcpu, u32 *error) { void *data = val; int r = X86EMUL_CONTINUE; - access |= PFERR_WRITE_MASK; - while (bytes) { - gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr, access, error); + gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr, + PFERR_WRITE_MASK, error); unsigned offset = addr & (PAGE_SIZE-1); unsigned towrite = min(bytes, (unsigned)PAGE_SIZE - offset); int ret; @@ -3203,20 +3202,6 @@ out: return r; } -static int kvm_write_guest_virt(gva_t addr, void *val, unsigned int bytes, - struct kvm_vcpu *vcpu, u32 *error) -{ - u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0; - return kvm_write_guest_virt_helper(addr, val, bytes, vcpu, access, error); -} - -static int kvm_write_guest_virt_system(gva_t addr, void *val, - unsigned int bytes, - struct kvm_vcpu *vcpu, u32 *error) -{ - return kvm_write_guest_virt_helper(addr, val, bytes, vcpu, 0, error); -} - static int emulator_read_emulated(unsigned long addr, void *val, unsigned int bytes, @@ -3397,23 +3382,20 @@ static int kernel_pio(struct kvm_vcpu *vcpu, void *pd) static int emulator_pio_in_emulated(int size, unsigned short port, void *val, unsigned int count, struct kvm_vcpu *vcpu) { - if (vcpu->arch.pio.cur_count) + if (vcpu->arch.pio.count) goto data_avail; trace_kvm_pio(1, port, size, 1); vcpu->arch.pio.port = port; vcpu->arch.pio.in = 1; - vcpu->arch.pio.string = 0; - vcpu->arch.pio.down = 0; - vcpu->arch.pio.rep = 0; - vcpu->arch.pio.count = vcpu->arch.pio.cur_count = count; + vcpu->arch.pio.count = count; vcpu->arch.pio.size = size; if (!kernel_pio(vcpu, vcpu->arch.pio_data)) { data_avail: memcpy(val, vcpu->arch.pio_data, size * count); - vcpu->arch.pio.cur_count = 0; + vcpu->arch.pio.count = 0; return 1; } @@ -3435,16 +3417,13 @@ static int emulator_pio_out_emulated(int size, unsigned short port, vcpu->arch.pio.port = port; vcpu->arch.pio.in = 0; - vcpu->arch.pio.string = 0; - vcpu->arch.pio.down = 0; - vcpu->arch.pio.rep = 0; - vcpu->arch.pio.count = vcpu->arch.pio.cur_count = count; + vcpu->arch.pio.count = count; vcpu->arch.pio.size = size; memcpy(vcpu->arch.pio_data, val, size * count); if (!kernel_pio(vcpu, vcpu->arch.pio_data)) { - vcpu->arch.pio.cur_count = 0; + vcpu->arch.pio.count = 0; return 1; } @@ -3685,7 +3664,6 @@ int emulate_instruction(struct kvm_vcpu *vcpu, cache_all_regs(vcpu); vcpu->mmio_is_write = 0; - vcpu->arch.pio.string = 0; if (!(emulation_type & EMULTYPE_NO_DECODE)) { int cs_db, cs_l; @@ -3752,12 +3730,9 @@ int emulate_instruction(struct kvm_vcpu *vcpu, if (r == 0) kvm_x86_ops->set_interrupt_shadow(vcpu, shadow_mask); - if (vcpu->arch.pio.string) - return EMULATE_DO_MMIO; - - if (vcpu->arch.pio.cur_count && !vcpu->arch.pio.string) { + if (vcpu->arch.pio.count) { if (!vcpu->arch.pio.in) - vcpu->arch.pio.cur_count = 0; + vcpu->arch.pio.count = 0; return EMULATE_DO_MMIO; } @@ -3790,152 +3765,6 @@ int emulate_instruction(struct kvm_vcpu *vcpu, } EXPORT_SYMBOL_GPL(emulate_instruction); -static int pio_copy_data(struct kvm_vcpu *vcpu) -{ - void *p = vcpu->arch.pio_data; - gva_t q = vcpu->arch.pio.guest_gva; - unsigned bytes; - int ret; - u32 error_code; - - bytes = vcpu->arch.pio.size * vcpu->arch.pio.cur_count; - if (vcpu->arch.pio.in) - ret = kvm_write_guest_virt(q, p, bytes, vcpu, &error_code); - else - ret = kvm_read_guest_virt(q, p, bytes, vcpu, &error_code); - - if (ret == X86EMUL_PROPAGATE_FAULT) - kvm_inject_page_fault(vcpu, q, error_code); - - return ret; -} - -int complete_pio(struct kvm_vcpu *vcpu) -{ - struct kvm_pio_request *io = &vcpu->arch.pio; - long delta; - int r; - unsigned long val; - - if (io->in) { - r = pio_copy_data(vcpu); - if (r) - goto out; - } - - delta = 1; - if (io->rep) { - delta *= io->cur_count; - /* - * The size of the register should really depend on - * current address size. - */ - val = kvm_register_read(vcpu, VCPU_REGS_RCX); - val -= delta; - kvm_register_write(vcpu, VCPU_REGS_RCX, val); - } - if (io->down) - delta = -delta; - delta *= io->size; - if (io->in) { - val = kvm_register_read(vcpu, VCPU_REGS_RDI); - val += delta; - kvm_register_write(vcpu, VCPU_REGS_RDI, val); - } else { - val = kvm_register_read(vcpu, VCPU_REGS_RSI); - val += delta; - kvm_register_write(vcpu, VCPU_REGS_RSI, val); - } - -out: - io->count -= io->cur_count; - io->cur_count = 0; - - return 0; -} - -static int pio_string_write(struct kvm_vcpu *vcpu) -{ - struct kvm_pio_request *io = &vcpu->arch.pio; - void *pd = vcpu->arch.pio_data; - int i, r = 0; - - for (i = 0; i < io->cur_count; i++) { - if (kvm_io_bus_write(vcpu->kvm, KVM_PIO_BUS, - io->port, io->size, pd)) { - r = -EOPNOTSUPP; - break; - } - pd += io->size; - } - return r; -} - -int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, int in, - int size, unsigned long count, int down, - gva_t address, int rep, unsigned port) -{ - unsigned now, in_page; - int ret = 0; - - trace_kvm_pio(!in, port, size, count); - - vcpu->run->exit_reason = KVM_EXIT_IO; - vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT; - vcpu->run->io.size = vcpu->arch.pio.size = size; - vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE; - vcpu->run->io.count = vcpu->arch.pio.count = vcpu->arch.pio.cur_count = count; - vcpu->run->io.port = vcpu->arch.pio.port = port; - vcpu->arch.pio.in = in; - vcpu->arch.pio.string = 1; - vcpu->arch.pio.down = down; - vcpu->arch.pio.rep = rep; - - if (!count) { - kvm_x86_ops->skip_emulated_instruction(vcpu); - return 1; - } - - if (!down) - in_page = PAGE_SIZE - offset_in_page(address); - else - in_page = offset_in_page(address) + size; - now = min(count, (unsigned long)in_page / size); - if (!now) - now = 1; - if (down) { - /* - * String I/O in reverse. Yuck. Kill the guest, fix later. - */ - pr_unimpl(vcpu, "guest string pio down\n"); - kvm_inject_gp(vcpu, 0); - return 1; - } - vcpu->run->io.count = now; - vcpu->arch.pio.cur_count = now; - - if (vcpu->arch.pio.cur_count == vcpu->arch.pio.count) - kvm_x86_ops->skip_emulated_instruction(vcpu); - - vcpu->arch.pio.guest_gva = address; - - if (!vcpu->arch.pio.in) { - /* string PIO write */ - ret = pio_copy_data(vcpu); - if (ret == X86EMUL_PROPAGATE_FAULT) - return 1; - if (ret == 0 && !pio_string_write(vcpu)) { - complete_pio(vcpu); - if (vcpu->arch.pio.count == 0) - ret = 1; - } - } - /* no string PIO read support yet */ - - return ret; -} -EXPORT_SYMBOL_GPL(kvm_emulate_pio_string); - static void bounce_off(void *info) { /* nothing */ @@ -4661,15 +4490,14 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) if (!irqchip_in_kernel(vcpu->kvm)) kvm_set_cr8(vcpu, kvm_run->cr8); - if (vcpu->arch.pio.cur_count) { + if (vcpu->arch.pio.count) { vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); - if (!vcpu->arch.pio.string) - r = emulate_instruction(vcpu, 0, 0, EMULTYPE_NO_DECODE); - else - r = complete_pio(vcpu); + r = emulate_instruction(vcpu, 0, 0, EMULTYPE_NO_DECODE); srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx); - if (r == EMULATE_DO_MMIO) + if (r == EMULATE_DO_MMIO) { + r = 0; goto out; + } } if (vcpu->mmio_needed) { memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8);