diff options
author | Avi Kivity <avi@qumranet.com> | 2007-04-22 08:28:19 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2007-05-03 03:52:31 -0400 |
commit | 4c690a1e8667a84b61a6114a4ad293681f32cb11 (patch) | |
tree | ed5ffaedc83068a7cf791530a2f54483107f3d21 /drivers | |
parent | 1165f5fec18c077bdba88e7125fd41f8e3617cb4 (diff) |
KVM: Allow passing 64-bit values to the emulated read/write API
This simplifies the API somewhat (by eliminating the special-case
cmpxchg8b on i386).
Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/kvm/kvm_main.c | 45 | ||||
-rw-r--r-- | drivers/kvm/x86_emulate.c | 46 | ||||
-rw-r--r-- | drivers/kvm/x86_emulate.h | 32 |
3 files changed, 24 insertions, 99 deletions
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index 911c8175cc0..67554034d00 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c | |||
@@ -970,7 +970,7 @@ void mark_page_dirty(struct kvm *kvm, gfn_t gfn) | |||
970 | } | 970 | } |
971 | 971 | ||
972 | static int emulator_read_std(unsigned long addr, | 972 | static int emulator_read_std(unsigned long addr, |
973 | unsigned long *val, | 973 | void *val, |
974 | unsigned int bytes, | 974 | unsigned int bytes, |
975 | struct x86_emulate_ctxt *ctxt) | 975 | struct x86_emulate_ctxt *ctxt) |
976 | { | 976 | { |
@@ -1006,7 +1006,7 @@ static int emulator_read_std(unsigned long addr, | |||
1006 | } | 1006 | } |
1007 | 1007 | ||
1008 | static int emulator_write_std(unsigned long addr, | 1008 | static int emulator_write_std(unsigned long addr, |
1009 | unsigned long val, | 1009 | const void *val, |
1010 | unsigned int bytes, | 1010 | unsigned int bytes, |
1011 | struct x86_emulate_ctxt *ctxt) | 1011 | struct x86_emulate_ctxt *ctxt) |
1012 | { | 1012 | { |
@@ -1016,7 +1016,7 @@ static int emulator_write_std(unsigned long addr, | |||
1016 | } | 1016 | } |
1017 | 1017 | ||
1018 | static int emulator_read_emulated(unsigned long addr, | 1018 | static int emulator_read_emulated(unsigned long addr, |
1019 | unsigned long *val, | 1019 | void *val, |
1020 | unsigned int bytes, | 1020 | unsigned int bytes, |
1021 | struct x86_emulate_ctxt *ctxt) | 1021 | struct x86_emulate_ctxt *ctxt) |
1022 | { | 1022 | { |
@@ -1044,7 +1044,7 @@ static int emulator_read_emulated(unsigned long addr, | |||
1044 | } | 1044 | } |
1045 | 1045 | ||
1046 | static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, | 1046 | static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, |
1047 | unsigned long val, int bytes) | 1047 | const void *val, int bytes) |
1048 | { | 1048 | { |
1049 | struct page *page; | 1049 | struct page *page; |
1050 | void *virt; | 1050 | void *virt; |
@@ -1057,14 +1057,14 @@ static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, | |||
1057 | kvm_mmu_pre_write(vcpu, gpa, bytes); | 1057 | kvm_mmu_pre_write(vcpu, gpa, bytes); |
1058 | mark_page_dirty(vcpu->kvm, gpa >> PAGE_SHIFT); | 1058 | mark_page_dirty(vcpu->kvm, gpa >> PAGE_SHIFT); |
1059 | virt = kmap_atomic(page, KM_USER0); | 1059 | virt = kmap_atomic(page, KM_USER0); |
1060 | memcpy(virt + offset_in_page(gpa), &val, bytes); | 1060 | memcpy(virt + offset_in_page(gpa), val, bytes); |
1061 | kunmap_atomic(virt, KM_USER0); | 1061 | kunmap_atomic(virt, KM_USER0); |
1062 | kvm_mmu_post_write(vcpu, gpa, bytes); | 1062 | kvm_mmu_post_write(vcpu, gpa, bytes); |
1063 | return 1; | 1063 | return 1; |
1064 | } | 1064 | } |
1065 | 1065 | ||
1066 | static int emulator_write_emulated(unsigned long addr, | 1066 | static int emulator_write_emulated(unsigned long addr, |
1067 | unsigned long val, | 1067 | const void *val, |
1068 | unsigned int bytes, | 1068 | unsigned int bytes, |
1069 | struct x86_emulate_ctxt *ctxt) | 1069 | struct x86_emulate_ctxt *ctxt) |
1070 | { | 1070 | { |
@@ -1083,14 +1083,14 @@ static int emulator_write_emulated(unsigned long addr, | |||
1083 | vcpu->mmio_phys_addr = gpa; | 1083 | vcpu->mmio_phys_addr = gpa; |
1084 | vcpu->mmio_size = bytes; | 1084 | vcpu->mmio_size = bytes; |
1085 | vcpu->mmio_is_write = 1; | 1085 | vcpu->mmio_is_write = 1; |
1086 | memcpy(vcpu->mmio_data, &val, bytes); | 1086 | memcpy(vcpu->mmio_data, val, bytes); |
1087 | 1087 | ||
1088 | return X86EMUL_CONTINUE; | 1088 | return X86EMUL_CONTINUE; |
1089 | } | 1089 | } |
1090 | 1090 | ||
1091 | static int emulator_cmpxchg_emulated(unsigned long addr, | 1091 | static int emulator_cmpxchg_emulated(unsigned long addr, |
1092 | unsigned long old, | 1092 | const void *old, |
1093 | unsigned long new, | 1093 | const void *new, |
1094 | unsigned int bytes, | 1094 | unsigned int bytes, |
1095 | struct x86_emulate_ctxt *ctxt) | 1095 | struct x86_emulate_ctxt *ctxt) |
1096 | { | 1096 | { |
@@ -1103,30 +1103,6 @@ static int emulator_cmpxchg_emulated(unsigned long addr, | |||
1103 | return emulator_write_emulated(addr, new, bytes, ctxt); | 1103 | return emulator_write_emulated(addr, new, bytes, ctxt); |
1104 | } | 1104 | } |
1105 | 1105 | ||
1106 | #ifdef CONFIG_X86_32 | ||
1107 | |||
1108 | static int emulator_cmpxchg8b_emulated(unsigned long addr, | ||
1109 | unsigned long old_lo, | ||
1110 | unsigned long old_hi, | ||
1111 | unsigned long new_lo, | ||
1112 | unsigned long new_hi, | ||
1113 | struct x86_emulate_ctxt *ctxt) | ||
1114 | { | ||
1115 | static int reported; | ||
1116 | int r; | ||
1117 | |||
1118 | if (!reported) { | ||
1119 | reported = 1; | ||
1120 | printk(KERN_WARNING "kvm: emulating exchange8b as write\n"); | ||
1121 | } | ||
1122 | r = emulator_write_emulated(addr, new_lo, 4, ctxt); | ||
1123 | if (r != X86EMUL_CONTINUE) | ||
1124 | return r; | ||
1125 | return emulator_write_emulated(addr+4, new_hi, 4, ctxt); | ||
1126 | } | ||
1127 | |||
1128 | #endif | ||
1129 | |||
1130 | static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg) | 1106 | static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg) |
1131 | { | 1107 | { |
1132 | return kvm_arch_ops->get_segment_base(vcpu, seg); | 1108 | return kvm_arch_ops->get_segment_base(vcpu, seg); |
@@ -1201,9 +1177,6 @@ struct x86_emulate_ops emulate_ops = { | |||
1201 | .read_emulated = emulator_read_emulated, | 1177 | .read_emulated = emulator_read_emulated, |
1202 | .write_emulated = emulator_write_emulated, | 1178 | .write_emulated = emulator_write_emulated, |
1203 | .cmpxchg_emulated = emulator_cmpxchg_emulated, | 1179 | .cmpxchg_emulated = emulator_cmpxchg_emulated, |
1204 | #ifdef CONFIG_X86_32 | ||
1205 | .cmpxchg8b_emulated = emulator_cmpxchg8b_emulated, | ||
1206 | #endif | ||
1207 | }; | 1180 | }; |
1208 | 1181 | ||
1209 | int emulate_instruction(struct kvm_vcpu *vcpu, | 1182 | int emulate_instruction(struct kvm_vcpu *vcpu, |
diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c index bcf872bdaf7..7ade09086aa 100644 --- a/drivers/kvm/x86_emulate.c +++ b/drivers/kvm/x86_emulate.c | |||
@@ -1045,7 +1045,7 @@ done_prefixes: | |||
1045 | if ((rc = ops->write_std( | 1045 | if ((rc = ops->write_std( |
1046 | register_address(ctxt->ss_base, | 1046 | register_address(ctxt->ss_base, |
1047 | _regs[VCPU_REGS_RSP]), | 1047 | _regs[VCPU_REGS_RSP]), |
1048 | dst.val, dst.bytes, ctxt)) != 0) | 1048 | &dst.val, dst.bytes, ctxt)) != 0) |
1049 | goto done; | 1049 | goto done; |
1050 | dst.val = dst.orig_val; /* skanky: disable writeback */ | 1050 | dst.val = dst.orig_val; /* skanky: disable writeback */ |
1051 | break; | 1051 | break; |
@@ -1078,12 +1078,12 @@ writeback: | |||
1078 | case OP_MEM: | 1078 | case OP_MEM: |
1079 | if (lock_prefix) | 1079 | if (lock_prefix) |
1080 | rc = ops->cmpxchg_emulated((unsigned long)dst. | 1080 | rc = ops->cmpxchg_emulated((unsigned long)dst. |
1081 | ptr, dst.orig_val, | 1081 | ptr, &dst.orig_val, |
1082 | dst.val, dst.bytes, | 1082 | &dst.val, dst.bytes, |
1083 | ctxt); | 1083 | ctxt); |
1084 | else | 1084 | else |
1085 | rc = ops->write_emulated((unsigned long)dst.ptr, | 1085 | rc = ops->write_emulated((unsigned long)dst.ptr, |
1086 | dst.val, dst.bytes, | 1086 | &dst.val, dst.bytes, |
1087 | ctxt); | 1087 | ctxt); |
1088 | if (rc != 0) | 1088 | if (rc != 0) |
1089 | goto done; | 1089 | goto done; |
@@ -1321,36 +1321,8 @@ twobyte_special_insn: | |||
1321 | realmode_set_cr(ctxt->vcpu, modrm_reg, modrm_val, &_eflags); | 1321 | realmode_set_cr(ctxt->vcpu, modrm_reg, modrm_val, &_eflags); |
1322 | break; | 1322 | break; |
1323 | case 0xc7: /* Grp9 (cmpxchg8b) */ | 1323 | case 0xc7: /* Grp9 (cmpxchg8b) */ |
1324 | #if defined(__i386__) | ||
1325 | { | 1324 | { |
1326 | unsigned long old_lo, old_hi; | 1325 | u64 old, new; |
1327 | if (((rc = ops->read_emulated(cr2 + 0, &old_lo, 4, | ||
1328 | ctxt)) != 0) | ||
1329 | || ((rc = ops->read_emulated(cr2 + 4, &old_hi, 4, | ||
1330 | ctxt)) != 0)) | ||
1331 | goto done; | ||
1332 | if ((old_lo != _regs[VCPU_REGS_RAX]) | ||
1333 | || (old_hi != _regs[VCPU_REGS_RDX])) { | ||
1334 | _regs[VCPU_REGS_RAX] = old_lo; | ||
1335 | _regs[VCPU_REGS_RDX] = old_hi; | ||
1336 | _eflags &= ~EFLG_ZF; | ||
1337 | } else if (ops->cmpxchg8b_emulated == NULL) { | ||
1338 | rc = X86EMUL_UNHANDLEABLE; | ||
1339 | goto done; | ||
1340 | } else { | ||
1341 | if ((rc = ops->cmpxchg8b_emulated(cr2, old_lo, | ||
1342 | old_hi, | ||
1343 | _regs[VCPU_REGS_RBX], | ||
1344 | _regs[VCPU_REGS_RCX], | ||
1345 | ctxt)) != 0) | ||
1346 | goto done; | ||
1347 | _eflags |= EFLG_ZF; | ||
1348 | } | ||
1349 | break; | ||
1350 | } | ||
1351 | #elif defined(CONFIG_X86_64) | ||
1352 | { | ||
1353 | unsigned long old, new; | ||
1354 | if ((rc = ops->read_emulated(cr2, &old, 8, ctxt)) != 0) | 1326 | if ((rc = ops->read_emulated(cr2, &old, 8, ctxt)) != 0) |
1355 | goto done; | 1327 | goto done; |
1356 | if (((u32) (old >> 0) != (u32) _regs[VCPU_REGS_RAX]) || | 1328 | if (((u32) (old >> 0) != (u32) _regs[VCPU_REGS_RAX]) || |
@@ -1359,15 +1331,15 @@ twobyte_special_insn: | |||
1359 | _regs[VCPU_REGS_RDX] = (u32) (old >> 32); | 1331 | _regs[VCPU_REGS_RDX] = (u32) (old >> 32); |
1360 | _eflags &= ~EFLG_ZF; | 1332 | _eflags &= ~EFLG_ZF; |
1361 | } else { | 1333 | } else { |
1362 | new = (_regs[VCPU_REGS_RCX] << 32) | (u32) _regs[VCPU_REGS_RBX]; | 1334 | new = ((u64)_regs[VCPU_REGS_RCX] << 32) |
1363 | if ((rc = ops->cmpxchg_emulated(cr2, old, | 1335 | | (u32) _regs[VCPU_REGS_RBX]; |
1364 | new, 8, ctxt)) != 0) | 1336 | if ((rc = ops->cmpxchg_emulated(cr2, &old, |
1337 | &new, 8, ctxt)) != 0) | ||
1365 | goto done; | 1338 | goto done; |
1366 | _eflags |= EFLG_ZF; | 1339 | _eflags |= EFLG_ZF; |
1367 | } | 1340 | } |
1368 | break; | 1341 | break; |
1369 | } | 1342 | } |
1370 | #endif | ||
1371 | } | 1343 | } |
1372 | goto writeback; | 1344 | goto writeback; |
1373 | 1345 | ||
diff --git a/drivers/kvm/x86_emulate.h b/drivers/kvm/x86_emulate.h index 5d41bd55125..ea3407d7fee 100644 --- a/drivers/kvm/x86_emulate.h +++ b/drivers/kvm/x86_emulate.h | |||
@@ -59,8 +59,7 @@ struct x86_emulate_ops { | |||
59 | * @val: [OUT] Value read from memory, zero-extended to 'u_long'. | 59 | * @val: [OUT] Value read from memory, zero-extended to 'u_long'. |
60 | * @bytes: [IN ] Number of bytes to read from memory. | 60 | * @bytes: [IN ] Number of bytes to read from memory. |
61 | */ | 61 | */ |
62 | int (*read_std)(unsigned long addr, | 62 | int (*read_std)(unsigned long addr, void *val, |
63 | unsigned long *val, | ||
64 | unsigned int bytes, struct x86_emulate_ctxt * ctxt); | 63 | unsigned int bytes, struct x86_emulate_ctxt * ctxt); |
65 | 64 | ||
66 | /* | 65 | /* |
@@ -71,8 +70,7 @@ struct x86_emulate_ops { | |||
71 | * required). | 70 | * required). |
72 | * @bytes: [IN ] Number of bytes to write to memory. | 71 | * @bytes: [IN ] Number of bytes to write to memory. |
73 | */ | 72 | */ |
74 | int (*write_std)(unsigned long addr, | 73 | int (*write_std)(unsigned long addr, const void *val, |
75 | unsigned long val, | ||
76 | unsigned int bytes, struct x86_emulate_ctxt * ctxt); | 74 | unsigned int bytes, struct x86_emulate_ctxt * ctxt); |
77 | 75 | ||
78 | /* | 76 | /* |
@@ -82,7 +80,7 @@ struct x86_emulate_ops { | |||
82 | * @bytes: [IN ] Number of bytes to read from memory. | 80 | * @bytes: [IN ] Number of bytes to read from memory. |
83 | */ | 81 | */ |
84 | int (*read_emulated) (unsigned long addr, | 82 | int (*read_emulated) (unsigned long addr, |
85 | unsigned long *val, | 83 | void *val, |
86 | unsigned int bytes, | 84 | unsigned int bytes, |
87 | struct x86_emulate_ctxt * ctxt); | 85 | struct x86_emulate_ctxt * ctxt); |
88 | 86 | ||
@@ -94,7 +92,7 @@ struct x86_emulate_ops { | |||
94 | * @bytes: [IN ] Number of bytes to write to memory. | 92 | * @bytes: [IN ] Number of bytes to write to memory. |
95 | */ | 93 | */ |
96 | int (*write_emulated) (unsigned long addr, | 94 | int (*write_emulated) (unsigned long addr, |
97 | unsigned long val, | 95 | const void *val, |
98 | unsigned int bytes, | 96 | unsigned int bytes, |
99 | struct x86_emulate_ctxt * ctxt); | 97 | struct x86_emulate_ctxt * ctxt); |
100 | 98 | ||
@@ -107,29 +105,11 @@ struct x86_emulate_ops { | |||
107 | * @bytes: [IN ] Number of bytes to access using CMPXCHG. | 105 | * @bytes: [IN ] Number of bytes to access using CMPXCHG. |
108 | */ | 106 | */ |
109 | int (*cmpxchg_emulated) (unsigned long addr, | 107 | int (*cmpxchg_emulated) (unsigned long addr, |
110 | unsigned long old, | 108 | const void *old, |
111 | unsigned long new, | 109 | const void *new, |
112 | unsigned int bytes, | 110 | unsigned int bytes, |
113 | struct x86_emulate_ctxt * ctxt); | 111 | struct x86_emulate_ctxt * ctxt); |
114 | 112 | ||
115 | /* | ||
116 | * cmpxchg8b_emulated: Emulate an atomic (LOCKed) CMPXCHG8B operation on an | ||
117 | * emulated/special memory area. | ||
118 | * @addr: [IN ] Linear address to access. | ||
119 | * @old: [IN ] Value expected to be current at @addr. | ||
120 | * @new: [IN ] Value to write to @addr. | ||
121 | * NOTES: | ||
122 | * 1. This function is only ever called when emulating a real CMPXCHG8B. | ||
123 | * 2. This function is *never* called on x86/64 systems. | ||
124 | * 2. Not defining this function (i.e., specifying NULL) is equivalent | ||
125 | * to defining a function that always returns X86EMUL_UNHANDLEABLE. | ||
126 | */ | ||
127 | int (*cmpxchg8b_emulated) (unsigned long addr, | ||
128 | unsigned long old_lo, | ||
129 | unsigned long old_hi, | ||
130 | unsigned long new_lo, | ||
131 | unsigned long new_hi, | ||
132 | struct x86_emulate_ctxt * ctxt); | ||
133 | }; | 113 | }; |
134 | 114 | ||
135 | struct cpu_user_regs; | 115 | struct cpu_user_regs; |