diff options
author | Avi Kivity <avi@qumranet.com> | 2007-01-05 19:36:51 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2007-01-06 02:55:26 -0500 |
commit | 32b35627355c3bf17e1903efd117efed7653a54e (patch) | |
tree | 9ef6ca5a32f6e224f4d463a89c21dda2ac08eafe /drivers/kvm | |
parent | 3bb65a22a4502067f8cd3cb4c923ffa70be62091 (diff) |
[PATCH] KVM: MMU: Fix cmpxchg8b emulation
cmpxchg8b uses edx:eax as the compare operand, not edi:eax.
cmpxchg8b is used by 32-bit pae guests to set page table entries atomically,
and this is emulated touching shadowed guest page tables.
Also, implement it for 32-bit hosts.
Signed-off-by: Avi Kivity <avi@qumranet.com>
Acked-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/kvm')
-rw-r--r-- | drivers/kvm/kvm_main.c | 27 | ||||
-rw-r--r-- | drivers/kvm/x86_emulate.c | 2 |
2 files changed, 28 insertions, 1 deletions
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index cec10106ce77..2e6bc5659953 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c | |||
@@ -936,6 +936,30 @@ static int emulator_cmpxchg_emulated(unsigned long addr, | |||
936 | return emulator_write_emulated(addr, new, bytes, ctxt); | 936 | return emulator_write_emulated(addr, new, bytes, ctxt); |
937 | } | 937 | } |
938 | 938 | ||
939 | #ifdef CONFIG_X86_32 | ||
940 | |||
941 | static int emulator_cmpxchg8b_emulated(unsigned long addr, | ||
942 | unsigned long old_lo, | ||
943 | unsigned long old_hi, | ||
944 | unsigned long new_lo, | ||
945 | unsigned long new_hi, | ||
946 | struct x86_emulate_ctxt *ctxt) | ||
947 | { | ||
948 | static int reported; | ||
949 | int r; | ||
950 | |||
951 | if (!reported) { | ||
952 | reported = 1; | ||
953 | printk(KERN_WARNING "kvm: emulating exchange8b as write\n"); | ||
954 | } | ||
955 | r = emulator_write_emulated(addr, new_lo, 4, ctxt); | ||
956 | if (r != X86EMUL_CONTINUE) | ||
957 | return r; | ||
958 | return emulator_write_emulated(addr+4, new_hi, 4, ctxt); | ||
959 | } | ||
960 | |||
961 | #endif | ||
962 | |||
939 | static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg) | 963 | static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg) |
940 | { | 964 | { |
941 | return kvm_arch_ops->get_segment_base(vcpu, seg); | 965 | return kvm_arch_ops->get_segment_base(vcpu, seg); |
@@ -1010,6 +1034,9 @@ struct x86_emulate_ops emulate_ops = { | |||
1010 | .read_emulated = emulator_read_emulated, | 1034 | .read_emulated = emulator_read_emulated, |
1011 | .write_emulated = emulator_write_emulated, | 1035 | .write_emulated = emulator_write_emulated, |
1012 | .cmpxchg_emulated = emulator_cmpxchg_emulated, | 1036 | .cmpxchg_emulated = emulator_cmpxchg_emulated, |
1037 | #ifdef CONFIG_X86_32 | ||
1038 | .cmpxchg8b_emulated = emulator_cmpxchg8b_emulated, | ||
1039 | #endif | ||
1013 | }; | 1040 | }; |
1014 | 1041 | ||
1015 | int emulate_instruction(struct kvm_vcpu *vcpu, | 1042 | int emulate_instruction(struct kvm_vcpu *vcpu, |
diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c index 1bff3e925fda..be70795b4822 100644 --- a/drivers/kvm/x86_emulate.c +++ b/drivers/kvm/x86_emulate.c | |||
@@ -1323,7 +1323,7 @@ twobyte_special_insn: | |||
1323 | ctxt)) != 0)) | 1323 | ctxt)) != 0)) |
1324 | goto done; | 1324 | goto done; |
1325 | if ((old_lo != _regs[VCPU_REGS_RAX]) | 1325 | if ((old_lo != _regs[VCPU_REGS_RAX]) |
1326 | || (old_hi != _regs[VCPU_REGS_RDI])) { | 1326 | || (old_hi != _regs[VCPU_REGS_RDX])) { |
1327 | _regs[VCPU_REGS_RAX] = old_lo; | 1327 | _regs[VCPU_REGS_RAX] = old_lo; |
1328 | _regs[VCPU_REGS_RDX] = old_hi; | 1328 | _regs[VCPU_REGS_RDX] = old_hi; |
1329 | _eflags &= ~EFLG_ZF; | 1329 | _eflags &= ~EFLG_ZF; |