aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/kvm/x86.c
diff options
context:
space:
mode:
authorCarsten Otte <cotte@de.ibm.com>2007-10-30 13:44:21 -0400
committerAvi Kivity <avi@qumranet.com>2008-01-30 10:52:58 -0500
commitbbd9b64e37aff5aa715ec5e168425790f5983bf1 (patch)
treead69fb6e400801430e7a69019bd8fc40599ff20d /drivers/kvm/x86.c
parent15c4a6406f6c40632260861e1db7c539e79dcf1a (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.c358
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 */
989static 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
1003static 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
1014int 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}
1040EXPORT_SYMBOL_GPL(emulator_read_std);
1041
1042static 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
1051static 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
1077mmio:
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
1095static 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
1107static 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
1127mmio:
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
1146int 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}
1165EXPORT_SYMBOL_GPL(emulator_write_emulated);
1166
1167static 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
1182static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg)
1183{
1184 return kvm_x86_ops->get_segment_base(vcpu, seg);
1185}
1186
1187int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address)
1188{
1189 return X86EMUL_CONTINUE;
1190}
1191
1192int 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
1198int 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
1212int 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
1225void 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}
1243EXPORT_SYMBOL_GPL(kvm_report_emulation_failure);
1244
1245struct 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
1253int 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}
1342EXPORT_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();