diff options
author | Carsten Otte <cotte@de.ibm.com> | 2007-10-30 13:44:21 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2008-01-30 10:52:58 -0500 |
commit | bbd9b64e37aff5aa715ec5e168425790f5983bf1 (patch) | |
tree | ad69fb6e400801430e7a69019bd8fc40599ff20d /drivers/kvm/x86.c | |
parent | 15c4a6406f6c40632260861e1db7c539e79dcf1a (diff) |
KVM: Portability: Move x86 emulation and mmio device hook to x86.c
This patch moves the following functions to from kvm_main.c to x86.c:
emulator_read/write_std, vcpu_find_pervcpu_dev, vcpu_find_mmio_dev,
emulator_read/write_emulated, emulator_write_phys,
emulator_write_emulated_onepage, emulator_cmpxchg_emulated,
get_setment_base, emulate_invlpg, emulate_clts, emulator_get/set_dr,
kvm_report_emulation_failure, emulate_instruction
The following data type is moved to x86.c:
struct x86_emulate_ops emulate_ops
Signed-off-by: Carsten Otte <cotte@de.ibm.com>
Acked-by: Hollis Blanchard <hollisb@us.ibm.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm/x86.c')
-rw-r--r-- | drivers/kvm/x86.c | 358 |
1 files changed, 358 insertions, 0 deletions
diff --git a/drivers/kvm/x86.c b/drivers/kvm/x86.c index 786274347512..fe3733d8ece5 100644 --- a/drivers/kvm/x86.c +++ b/drivers/kvm/x86.c | |||
@@ -983,6 +983,364 @@ static __init void kvm_init_msr_list(void) | |||
983 | num_msrs_to_save = j; | 983 | num_msrs_to_save = j; |
984 | } | 984 | } |
985 | 985 | ||
986 | /* | ||
987 | * Only apic need an MMIO device hook, so shortcut now.. | ||
988 | */ | ||
989 | static struct kvm_io_device *vcpu_find_pervcpu_dev(struct kvm_vcpu *vcpu, | ||
990 | gpa_t addr) | ||
991 | { | ||
992 | struct kvm_io_device *dev; | ||
993 | |||
994 | if (vcpu->apic) { | ||
995 | dev = &vcpu->apic->dev; | ||
996 | if (dev->in_range(dev, addr)) | ||
997 | return dev; | ||
998 | } | ||
999 | return NULL; | ||
1000 | } | ||
1001 | |||
1002 | |||
1003 | static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu, | ||
1004 | gpa_t addr) | ||
1005 | { | ||
1006 | struct kvm_io_device *dev; | ||
1007 | |||
1008 | dev = vcpu_find_pervcpu_dev(vcpu, addr); | ||
1009 | if (dev == NULL) | ||
1010 | dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr); | ||
1011 | return dev; | ||
1012 | } | ||
1013 | |||
1014 | int emulator_read_std(unsigned long addr, | ||
1015 | void *val, | ||
1016 | unsigned int bytes, | ||
1017 | struct kvm_vcpu *vcpu) | ||
1018 | { | ||
1019 | void *data = val; | ||
1020 | |||
1021 | while (bytes) { | ||
1022 | gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr); | ||
1023 | unsigned offset = addr & (PAGE_SIZE-1); | ||
1024 | unsigned tocopy = min(bytes, (unsigned)PAGE_SIZE - offset); | ||
1025 | int ret; | ||
1026 | |||
1027 | if (gpa == UNMAPPED_GVA) | ||
1028 | return X86EMUL_PROPAGATE_FAULT; | ||
1029 | ret = kvm_read_guest(vcpu->kvm, gpa, data, tocopy); | ||
1030 | if (ret < 0) | ||
1031 | return X86EMUL_UNHANDLEABLE; | ||
1032 | |||
1033 | bytes -= tocopy; | ||
1034 | data += tocopy; | ||
1035 | addr += tocopy; | ||
1036 | } | ||
1037 | |||
1038 | return X86EMUL_CONTINUE; | ||
1039 | } | ||
1040 | EXPORT_SYMBOL_GPL(emulator_read_std); | ||
1041 | |||
1042 | static int emulator_write_std(unsigned long addr, | ||
1043 | const void *val, | ||
1044 | unsigned int bytes, | ||
1045 | struct kvm_vcpu *vcpu) | ||
1046 | { | ||
1047 | pr_unimpl(vcpu, "emulator_write_std: addr %lx n %d\n", addr, bytes); | ||
1048 | return X86EMUL_UNHANDLEABLE; | ||
1049 | } | ||
1050 | |||
1051 | static int emulator_read_emulated(unsigned long addr, | ||
1052 | void *val, | ||
1053 | unsigned int bytes, | ||
1054 | struct kvm_vcpu *vcpu) | ||
1055 | { | ||
1056 | struct kvm_io_device *mmio_dev; | ||
1057 | gpa_t gpa; | ||
1058 | |||
1059 | if (vcpu->mmio_read_completed) { | ||
1060 | memcpy(val, vcpu->mmio_data, bytes); | ||
1061 | vcpu->mmio_read_completed = 0; | ||
1062 | return X86EMUL_CONTINUE; | ||
1063 | } | ||
1064 | |||
1065 | gpa = vcpu->mmu.gva_to_gpa(vcpu, addr); | ||
1066 | |||
1067 | /* For APIC access vmexit */ | ||
1068 | if ((gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE) | ||
1069 | goto mmio; | ||
1070 | |||
1071 | if (emulator_read_std(addr, val, bytes, vcpu) | ||
1072 | == X86EMUL_CONTINUE) | ||
1073 | return X86EMUL_CONTINUE; | ||
1074 | if (gpa == UNMAPPED_GVA) | ||
1075 | return X86EMUL_PROPAGATE_FAULT; | ||
1076 | |||
1077 | mmio: | ||
1078 | /* | ||
1079 | * Is this MMIO handled locally? | ||
1080 | */ | ||
1081 | mmio_dev = vcpu_find_mmio_dev(vcpu, gpa); | ||
1082 | if (mmio_dev) { | ||
1083 | kvm_iodevice_read(mmio_dev, gpa, bytes, val); | ||
1084 | return X86EMUL_CONTINUE; | ||
1085 | } | ||
1086 | |||
1087 | vcpu->mmio_needed = 1; | ||
1088 | vcpu->mmio_phys_addr = gpa; | ||
1089 | vcpu->mmio_size = bytes; | ||
1090 | vcpu->mmio_is_write = 0; | ||
1091 | |||
1092 | return X86EMUL_UNHANDLEABLE; | ||
1093 | } | ||
1094 | |||
1095 | static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, | ||
1096 | const void *val, int bytes) | ||
1097 | { | ||
1098 | int ret; | ||
1099 | |||
1100 | ret = kvm_write_guest(vcpu->kvm, gpa, val, bytes); | ||
1101 | if (ret < 0) | ||
1102 | return 0; | ||
1103 | kvm_mmu_pte_write(vcpu, gpa, val, bytes); | ||
1104 | return 1; | ||
1105 | } | ||
1106 | |||
1107 | static int emulator_write_emulated_onepage(unsigned long addr, | ||
1108 | const void *val, | ||
1109 | unsigned int bytes, | ||
1110 | struct kvm_vcpu *vcpu) | ||
1111 | { | ||
1112 | struct kvm_io_device *mmio_dev; | ||
1113 | gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr); | ||
1114 | |||
1115 | if (gpa == UNMAPPED_GVA) { | ||
1116 | kvm_x86_ops->inject_page_fault(vcpu, addr, 2); | ||
1117 | return X86EMUL_PROPAGATE_FAULT; | ||
1118 | } | ||
1119 | |||
1120 | /* For APIC access vmexit */ | ||
1121 | if ((gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE) | ||
1122 | goto mmio; | ||
1123 | |||
1124 | if (emulator_write_phys(vcpu, gpa, val, bytes)) | ||
1125 | return X86EMUL_CONTINUE; | ||
1126 | |||
1127 | mmio: | ||
1128 | /* | ||
1129 | * Is this MMIO handled locally? | ||
1130 | */ | ||
1131 | mmio_dev = vcpu_find_mmio_dev(vcpu, gpa); | ||
1132 | if (mmio_dev) { | ||
1133 | kvm_iodevice_write(mmio_dev, gpa, bytes, val); | ||
1134 | return X86EMUL_CONTINUE; | ||
1135 | } | ||
1136 | |||
1137 | vcpu->mmio_needed = 1; | ||
1138 | vcpu->mmio_phys_addr = gpa; | ||
1139 | vcpu->mmio_size = bytes; | ||
1140 | vcpu->mmio_is_write = 1; | ||
1141 | memcpy(vcpu->mmio_data, val, bytes); | ||
1142 | |||
1143 | return X86EMUL_CONTINUE; | ||
1144 | } | ||
1145 | |||
1146 | int emulator_write_emulated(unsigned long addr, | ||
1147 | const void *val, | ||
1148 | unsigned int bytes, | ||
1149 | struct kvm_vcpu *vcpu) | ||
1150 | { | ||
1151 | /* Crossing a page boundary? */ | ||
1152 | if (((addr + bytes - 1) ^ addr) & PAGE_MASK) { | ||
1153 | int rc, now; | ||
1154 | |||
1155 | now = -addr & ~PAGE_MASK; | ||
1156 | rc = emulator_write_emulated_onepage(addr, val, now, vcpu); | ||
1157 | if (rc != X86EMUL_CONTINUE) | ||
1158 | return rc; | ||
1159 | addr += now; | ||
1160 | val += now; | ||
1161 | bytes -= now; | ||
1162 | } | ||
1163 | return emulator_write_emulated_onepage(addr, val, bytes, vcpu); | ||
1164 | } | ||
1165 | EXPORT_SYMBOL_GPL(emulator_write_emulated); | ||
1166 | |||
1167 | static int emulator_cmpxchg_emulated(unsigned long addr, | ||
1168 | const void *old, | ||
1169 | const void *new, | ||
1170 | unsigned int bytes, | ||
1171 | struct kvm_vcpu *vcpu) | ||
1172 | { | ||
1173 | static int reported; | ||
1174 | |||
1175 | if (!reported) { | ||
1176 | reported = 1; | ||
1177 | printk(KERN_WARNING "kvm: emulating exchange as write\n"); | ||
1178 | } | ||
1179 | return emulator_write_emulated(addr, new, bytes, vcpu); | ||
1180 | } | ||
1181 | |||
1182 | static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg) | ||
1183 | { | ||
1184 | return kvm_x86_ops->get_segment_base(vcpu, seg); | ||
1185 | } | ||
1186 | |||
1187 | int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address) | ||
1188 | { | ||
1189 | return X86EMUL_CONTINUE; | ||
1190 | } | ||
1191 | |||
1192 | int emulate_clts(struct kvm_vcpu *vcpu) | ||
1193 | { | ||
1194 | kvm_x86_ops->set_cr0(vcpu, vcpu->cr0 & ~X86_CR0_TS); | ||
1195 | return X86EMUL_CONTINUE; | ||
1196 | } | ||
1197 | |||
1198 | int emulator_get_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long *dest) | ||
1199 | { | ||
1200 | struct kvm_vcpu *vcpu = ctxt->vcpu; | ||
1201 | |||
1202 | switch (dr) { | ||
1203 | case 0 ... 3: | ||
1204 | *dest = kvm_x86_ops->get_dr(vcpu, dr); | ||
1205 | return X86EMUL_CONTINUE; | ||
1206 | default: | ||
1207 | pr_unimpl(vcpu, "%s: unexpected dr %u\n", __FUNCTION__, dr); | ||
1208 | return X86EMUL_UNHANDLEABLE; | ||
1209 | } | ||
1210 | } | ||
1211 | |||
1212 | int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value) | ||
1213 | { | ||
1214 | unsigned long mask = (ctxt->mode == X86EMUL_MODE_PROT64) ? ~0ULL : ~0U; | ||
1215 | int exception; | ||
1216 | |||
1217 | kvm_x86_ops->set_dr(ctxt->vcpu, dr, value & mask, &exception); | ||
1218 | if (exception) { | ||
1219 | /* FIXME: better handling */ | ||
1220 | return X86EMUL_UNHANDLEABLE; | ||
1221 | } | ||
1222 | return X86EMUL_CONTINUE; | ||
1223 | } | ||
1224 | |||
1225 | void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context) | ||
1226 | { | ||
1227 | static int reported; | ||
1228 | u8 opcodes[4]; | ||
1229 | unsigned long rip = vcpu->rip; | ||
1230 | unsigned long rip_linear; | ||
1231 | |||
1232 | rip_linear = rip + get_segment_base(vcpu, VCPU_SREG_CS); | ||
1233 | |||
1234 | if (reported) | ||
1235 | return; | ||
1236 | |||
1237 | emulator_read_std(rip_linear, (void *)opcodes, 4, vcpu); | ||
1238 | |||
1239 | printk(KERN_ERR "emulation failed (%s) rip %lx %02x %02x %02x %02x\n", | ||
1240 | context, rip, opcodes[0], opcodes[1], opcodes[2], opcodes[3]); | ||
1241 | reported = 1; | ||
1242 | } | ||
1243 | EXPORT_SYMBOL_GPL(kvm_report_emulation_failure); | ||
1244 | |||
1245 | struct x86_emulate_ops emulate_ops = { | ||
1246 | .read_std = emulator_read_std, | ||
1247 | .write_std = emulator_write_std, | ||
1248 | .read_emulated = emulator_read_emulated, | ||
1249 | .write_emulated = emulator_write_emulated, | ||
1250 | .cmpxchg_emulated = emulator_cmpxchg_emulated, | ||
1251 | }; | ||
1252 | |||
1253 | int emulate_instruction(struct kvm_vcpu *vcpu, | ||
1254 | struct kvm_run *run, | ||
1255 | unsigned long cr2, | ||
1256 | u16 error_code, | ||
1257 | int no_decode) | ||
1258 | { | ||
1259 | int r; | ||
1260 | |||
1261 | vcpu->mmio_fault_cr2 = cr2; | ||
1262 | kvm_x86_ops->cache_regs(vcpu); | ||
1263 | |||
1264 | vcpu->mmio_is_write = 0; | ||
1265 | vcpu->pio.string = 0; | ||
1266 | |||
1267 | if (!no_decode) { | ||
1268 | int cs_db, cs_l; | ||
1269 | kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); | ||
1270 | |||
1271 | vcpu->emulate_ctxt.vcpu = vcpu; | ||
1272 | vcpu->emulate_ctxt.eflags = kvm_x86_ops->get_rflags(vcpu); | ||
1273 | vcpu->emulate_ctxt.cr2 = cr2; | ||
1274 | vcpu->emulate_ctxt.mode = | ||
1275 | (vcpu->emulate_ctxt.eflags & X86_EFLAGS_VM) | ||
1276 | ? X86EMUL_MODE_REAL : cs_l | ||
1277 | ? X86EMUL_MODE_PROT64 : cs_db | ||
1278 | ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16; | ||
1279 | |||
1280 | if (vcpu->emulate_ctxt.mode == X86EMUL_MODE_PROT64) { | ||
1281 | vcpu->emulate_ctxt.cs_base = 0; | ||
1282 | vcpu->emulate_ctxt.ds_base = 0; | ||
1283 | vcpu->emulate_ctxt.es_base = 0; | ||
1284 | vcpu->emulate_ctxt.ss_base = 0; | ||
1285 | } else { | ||
1286 | vcpu->emulate_ctxt.cs_base = | ||
1287 | get_segment_base(vcpu, VCPU_SREG_CS); | ||
1288 | vcpu->emulate_ctxt.ds_base = | ||
1289 | get_segment_base(vcpu, VCPU_SREG_DS); | ||
1290 | vcpu->emulate_ctxt.es_base = | ||
1291 | get_segment_base(vcpu, VCPU_SREG_ES); | ||
1292 | vcpu->emulate_ctxt.ss_base = | ||
1293 | get_segment_base(vcpu, VCPU_SREG_SS); | ||
1294 | } | ||
1295 | |||
1296 | vcpu->emulate_ctxt.gs_base = | ||
1297 | get_segment_base(vcpu, VCPU_SREG_GS); | ||
1298 | vcpu->emulate_ctxt.fs_base = | ||
1299 | get_segment_base(vcpu, VCPU_SREG_FS); | ||
1300 | |||
1301 | r = x86_decode_insn(&vcpu->emulate_ctxt, &emulate_ops); | ||
1302 | if (r) { | ||
1303 | if (kvm_mmu_unprotect_page_virt(vcpu, cr2)) | ||
1304 | return EMULATE_DONE; | ||
1305 | return EMULATE_FAIL; | ||
1306 | } | ||
1307 | } | ||
1308 | |||
1309 | r = x86_emulate_insn(&vcpu->emulate_ctxt, &emulate_ops); | ||
1310 | |||
1311 | if (vcpu->pio.string) | ||
1312 | return EMULATE_DO_MMIO; | ||
1313 | |||
1314 | if ((r || vcpu->mmio_is_write) && run) { | ||
1315 | run->exit_reason = KVM_EXIT_MMIO; | ||
1316 | run->mmio.phys_addr = vcpu->mmio_phys_addr; | ||
1317 | memcpy(run->mmio.data, vcpu->mmio_data, 8); | ||
1318 | run->mmio.len = vcpu->mmio_size; | ||
1319 | run->mmio.is_write = vcpu->mmio_is_write; | ||
1320 | } | ||
1321 | |||
1322 | if (r) { | ||
1323 | if (kvm_mmu_unprotect_page_virt(vcpu, cr2)) | ||
1324 | return EMULATE_DONE; | ||
1325 | if (!vcpu->mmio_needed) { | ||
1326 | kvm_report_emulation_failure(vcpu, "mmio"); | ||
1327 | return EMULATE_FAIL; | ||
1328 | } | ||
1329 | return EMULATE_DO_MMIO; | ||
1330 | } | ||
1331 | |||
1332 | kvm_x86_ops->decache_regs(vcpu); | ||
1333 | kvm_x86_ops->set_rflags(vcpu, vcpu->emulate_ctxt.eflags); | ||
1334 | |||
1335 | if (vcpu->mmio_is_write) { | ||
1336 | vcpu->mmio_needed = 0; | ||
1337 | return EMULATE_DO_MMIO; | ||
1338 | } | ||
1339 | |||
1340 | return EMULATE_DONE; | ||
1341 | } | ||
1342 | EXPORT_SYMBOL_GPL(emulate_instruction); | ||
1343 | |||
986 | __init void kvm_arch_init(void) | 1344 | __init void kvm_arch_init(void) |
987 | { | 1345 | { |
988 | kvm_init_msr_list(); | 1346 | kvm_init_msr_list(); |