diff options
author | Laurent Vivier <Laurent.Vivier@bull.net> | 2007-08-05 03:36:40 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2007-10-13 04:18:23 -0400 |
commit | e70669abd4e60dfea3ac1639848e20e2b8dd1255 (patch) | |
tree | 4625f787efdf5f586514cd6306e045a97edb490e /drivers/kvm/vmx.c | |
parent | 9fdaaac38e8c8a63c6383b807b91fea2d51da95d (diff) |
KVM: Cleanup string I/O instruction emulation
Both vmx and svm decode the I/O instructions, and both botch the job,
requiring the instruction prefixes to be fetched in order to completely
decode the instruction.
So, if we see a string I/O instruction, use the x86 emulator to decode it,
as it already has all the prefix decoding machinery.
This patch defines ins/outs opcodes in x86_emulate.c and calls
emulate_instruction() from io_interception() (svm.c) and from handle_io()
(vmx.c). It removes all vmx/svm prefix instruction decoders
(get_addr_size(), io_get_override(), io_address(), get_io_count())
Signed-off-by: Laurent Vivier <Laurent.Vivier@bull.net>
Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm/vmx.c')
-rw-r--r-- | drivers/kvm/vmx.c | 76 |
1 files changed, 12 insertions, 64 deletions
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c index 30c627d3b21d..044722bc1a7f 100644 --- a/drivers/kvm/vmx.c +++ b/drivers/kvm/vmx.c | |||
@@ -1763,82 +1763,30 @@ static int handle_triple_fault(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
1763 | return 0; | 1763 | return 0; |
1764 | } | 1764 | } |
1765 | 1765 | ||
1766 | static int get_io_count(struct kvm_vcpu *vcpu, unsigned long *count) | ||
1767 | { | ||
1768 | u64 inst; | ||
1769 | gva_t rip; | ||
1770 | int countr_size; | ||
1771 | int i; | ||
1772 | |||
1773 | if ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_VM)) { | ||
1774 | countr_size = 2; | ||
1775 | } else { | ||
1776 | u32 cs_ar = vmcs_read32(GUEST_CS_AR_BYTES); | ||
1777 | |||
1778 | countr_size = (cs_ar & AR_L_MASK) ? 8: | ||
1779 | (cs_ar & AR_DB_MASK) ? 4: 2; | ||
1780 | } | ||
1781 | |||
1782 | rip = vmcs_readl(GUEST_RIP); | ||
1783 | if (countr_size != 8) | ||
1784 | rip += vmcs_readl(GUEST_CS_BASE); | ||
1785 | |||
1786 | if (emulator_read_std(rip, &inst, sizeof(inst), vcpu) != | ||
1787 | X86EMUL_CONTINUE) | ||
1788 | return 0; | ||
1789 | |||
1790 | for (i = 0; i < sizeof(inst); i++) { | ||
1791 | switch (((u8*)&inst)[i]) { | ||
1792 | case 0xf0: | ||
1793 | case 0xf2: | ||
1794 | case 0xf3: | ||
1795 | case 0x2e: | ||
1796 | case 0x36: | ||
1797 | case 0x3e: | ||
1798 | case 0x26: | ||
1799 | case 0x64: | ||
1800 | case 0x65: | ||
1801 | case 0x66: | ||
1802 | break; | ||
1803 | case 0x67: | ||
1804 | countr_size = (countr_size == 2) ? 4: (countr_size >> 1); | ||
1805 | default: | ||
1806 | goto done; | ||
1807 | } | ||
1808 | } | ||
1809 | return 0; | ||
1810 | done: | ||
1811 | countr_size *= 8; | ||
1812 | *count = vcpu->regs[VCPU_REGS_RCX] & (~0ULL >> (64 - countr_size)); | ||
1813 | //printk("cx: %lx\n", vcpu->regs[VCPU_REGS_RCX]); | ||
1814 | return 1; | ||
1815 | } | ||
1816 | |||
1817 | static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | 1766 | static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) |
1818 | { | 1767 | { |
1819 | u64 exit_qualification; | 1768 | u64 exit_qualification; |
1820 | int size, down, in, string, rep; | 1769 | int size, down, in, string, rep; |
1821 | unsigned port; | 1770 | unsigned port; |
1822 | unsigned long count; | ||
1823 | gva_t address; | ||
1824 | 1771 | ||
1825 | ++vcpu->stat.io_exits; | 1772 | ++vcpu->stat.io_exits; |
1826 | exit_qualification = vmcs_read64(EXIT_QUALIFICATION); | 1773 | exit_qualification = vmcs_read64(EXIT_QUALIFICATION); |
1827 | in = (exit_qualification & 8) != 0; | ||
1828 | size = (exit_qualification & 7) + 1; | ||
1829 | string = (exit_qualification & 16) != 0; | 1774 | string = (exit_qualification & 16) != 0; |
1775 | |||
1776 | if (string) { | ||
1777 | if (emulate_instruction(vcpu, kvm_run, 0, 0) == EMULATE_DO_MMIO) | ||
1778 | return 0; | ||
1779 | return 1; | ||
1780 | } | ||
1781 | |||
1782 | size = (exit_qualification & 7) + 1; | ||
1783 | in = (exit_qualification & 8) != 0; | ||
1830 | down = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_DF) != 0; | 1784 | down = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_DF) != 0; |
1831 | count = 1; | ||
1832 | rep = (exit_qualification & 32) != 0; | 1785 | rep = (exit_qualification & 32) != 0; |
1833 | port = exit_qualification >> 16; | 1786 | port = exit_qualification >> 16; |
1834 | address = 0; | 1787 | |
1835 | if (string) { | 1788 | return kvm_setup_pio(vcpu, kvm_run, in, size, 1, 0, down, |
1836 | if (rep && !get_io_count(vcpu, &count)) | 1789 | 0, rep, port); |
1837 | return 1; | ||
1838 | address = vmcs_readl(GUEST_LINEAR_ADDRESS); | ||
1839 | } | ||
1840 | return kvm_setup_pio(vcpu, kvm_run, in, size, count, string, down, | ||
1841 | address, rep, port); | ||
1842 | } | 1790 | } |
1843 | 1791 | ||
1844 | static void | 1792 | static void |