diff options
Diffstat (limited to 'drivers/kvm/x86_emulate.c')
-rw-r--r-- | drivers/kvm/x86_emulate.c | 51 |
1 files changed, 12 insertions, 39 deletions
diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c index 7513cddb929f..7ade09086aa5 100644 --- a/drivers/kvm/x86_emulate.c +++ b/drivers/kvm/x86_emulate.c | |||
@@ -833,8 +833,9 @@ done_prefixes: | |||
833 | dst.ptr = (unsigned long *)cr2; | 833 | dst.ptr = (unsigned long *)cr2; |
834 | dst.bytes = (d & ByteOp) ? 1 : op_bytes; | 834 | dst.bytes = (d & ByteOp) ? 1 : op_bytes; |
835 | if (d & BitOp) { | 835 | if (d & BitOp) { |
836 | dst.ptr += src.val / BITS_PER_LONG; | 836 | unsigned long mask = ~(dst.bytes * 8 - 1); |
837 | dst.bytes = sizeof(long); | 837 | |
838 | dst.ptr = (void *)dst.ptr + (src.val & mask) / 8; | ||
838 | } | 839 | } |
839 | if (!(d & Mov) && /* optimisation - avoid slow emulated read */ | 840 | if (!(d & Mov) && /* optimisation - avoid slow emulated read */ |
840 | ((rc = ops->read_emulated((unsigned long)dst.ptr, | 841 | ((rc = ops->read_emulated((unsigned long)dst.ptr, |
@@ -1044,7 +1045,7 @@ done_prefixes: | |||
1044 | if ((rc = ops->write_std( | 1045 | if ((rc = ops->write_std( |
1045 | register_address(ctxt->ss_base, | 1046 | register_address(ctxt->ss_base, |
1046 | _regs[VCPU_REGS_RSP]), | 1047 | _regs[VCPU_REGS_RSP]), |
1047 | dst.val, dst.bytes, ctxt)) != 0) | 1048 | &dst.val, dst.bytes, ctxt)) != 0) |
1048 | goto done; | 1049 | goto done; |
1049 | dst.val = dst.orig_val; /* skanky: disable writeback */ | 1050 | dst.val = dst.orig_val; /* skanky: disable writeback */ |
1050 | break; | 1051 | break; |
@@ -1077,12 +1078,12 @@ writeback: | |||
1077 | case OP_MEM: | 1078 | case OP_MEM: |
1078 | if (lock_prefix) | 1079 | if (lock_prefix) |
1079 | rc = ops->cmpxchg_emulated((unsigned long)dst. | 1080 | rc = ops->cmpxchg_emulated((unsigned long)dst. |
1080 | ptr, dst.orig_val, | 1081 | ptr, &dst.orig_val, |
1081 | dst.val, dst.bytes, | 1082 | &dst.val, dst.bytes, |
1082 | ctxt); | 1083 | ctxt); |
1083 | else | 1084 | else |
1084 | rc = ops->write_emulated((unsigned long)dst.ptr, | 1085 | rc = ops->write_emulated((unsigned long)dst.ptr, |
1085 | dst.val, dst.bytes, | 1086 | &dst.val, dst.bytes, |
1086 | ctxt); | 1087 | ctxt); |
1087 | if (rc != 0) | 1088 | if (rc != 0) |
1088 | goto done; | 1089 | goto done; |
@@ -1320,36 +1321,8 @@ twobyte_special_insn: | |||
1320 | realmode_set_cr(ctxt->vcpu, modrm_reg, modrm_val, &_eflags); | 1321 | realmode_set_cr(ctxt->vcpu, modrm_reg, modrm_val, &_eflags); |
1321 | break; | 1322 | break; |
1322 | case 0xc7: /* Grp9 (cmpxchg8b) */ | 1323 | case 0xc7: /* Grp9 (cmpxchg8b) */ |
1323 | #if defined(__i386__) | ||
1324 | { | ||
1325 | unsigned long old_lo, old_hi; | ||
1326 | if (((rc = ops->read_emulated(cr2 + 0, &old_lo, 4, | ||
1327 | ctxt)) != 0) | ||
1328 | || ((rc = ops->read_emulated(cr2 + 4, &old_hi, 4, | ||
1329 | ctxt)) != 0)) | ||
1330 | goto done; | ||
1331 | if ((old_lo != _regs[VCPU_REGS_RAX]) | ||
1332 | || (old_hi != _regs[VCPU_REGS_RDX])) { | ||
1333 | _regs[VCPU_REGS_RAX] = old_lo; | ||
1334 | _regs[VCPU_REGS_RDX] = old_hi; | ||
1335 | _eflags &= ~EFLG_ZF; | ||
1336 | } else if (ops->cmpxchg8b_emulated == NULL) { | ||
1337 | rc = X86EMUL_UNHANDLEABLE; | ||
1338 | goto done; | ||
1339 | } else { | ||
1340 | if ((rc = ops->cmpxchg8b_emulated(cr2, old_lo, | ||
1341 | old_hi, | ||
1342 | _regs[VCPU_REGS_RBX], | ||
1343 | _regs[VCPU_REGS_RCX], | ||
1344 | ctxt)) != 0) | ||
1345 | goto done; | ||
1346 | _eflags |= EFLG_ZF; | ||
1347 | } | ||
1348 | break; | ||
1349 | } | ||
1350 | #elif defined(CONFIG_X86_64) | ||
1351 | { | 1324 | { |
1352 | unsigned long old, new; | 1325 | u64 old, new; |
1353 | if ((rc = ops->read_emulated(cr2, &old, 8, ctxt)) != 0) | 1326 | if ((rc = ops->read_emulated(cr2, &old, 8, ctxt)) != 0) |
1354 | goto done; | 1327 | goto done; |
1355 | if (((u32) (old >> 0) != (u32) _regs[VCPU_REGS_RAX]) || | 1328 | if (((u32) (old >> 0) != (u32) _regs[VCPU_REGS_RAX]) || |
@@ -1358,15 +1331,15 @@ twobyte_special_insn: | |||
1358 | _regs[VCPU_REGS_RDX] = (u32) (old >> 32); | 1331 | _regs[VCPU_REGS_RDX] = (u32) (old >> 32); |
1359 | _eflags &= ~EFLG_ZF; | 1332 | _eflags &= ~EFLG_ZF; |
1360 | } else { | 1333 | } else { |
1361 | new = (_regs[VCPU_REGS_RCX] << 32) | (u32) _regs[VCPU_REGS_RBX]; | 1334 | new = ((u64)_regs[VCPU_REGS_RCX] << 32) |
1362 | if ((rc = ops->cmpxchg_emulated(cr2, old, | 1335 | | (u32) _regs[VCPU_REGS_RBX]; |
1363 | new, 8, ctxt)) != 0) | 1336 | if ((rc = ops->cmpxchg_emulated(cr2, &old, |
1337 | &new, 8, ctxt)) != 0) | ||
1364 | goto done; | 1338 | goto done; |
1365 | _eflags |= EFLG_ZF; | 1339 | _eflags |= EFLG_ZF; |
1366 | } | 1340 | } |
1367 | break; | 1341 | break; |
1368 | } | 1342 | } |
1369 | #endif | ||
1370 | } | 1343 | } |
1371 | goto writeback; | 1344 | goto writeback; |
1372 | 1345 | ||