diff options
author | Laurent Vivier <Laurent.Vivier@bull.net> | 2007-09-18 05:27:37 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2008-01-30 10:52:47 -0500 |
commit | 3427318fd2244737a466a06a93c5fe579852f871 (patch) | |
tree | 7c6760dbbdd067498c470e6e4f711e5baeef491c /drivers | |
parent | 1be3aa47182e94944e57b176a5c4ee4e74f1ce33 (diff) |
KVM: Call x86_decode_insn() only when needed
Move emulate_ctxt to kvm_vcpu to keep emulate context when we exit from kvm
module. Call x86_decode_insn() only when needed. Modify x86_emulate_insn() to
not modify the context if it must be re-entered.
Signed-off-by: Laurent Vivier <Laurent.Vivier@bull.net>
Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/kvm/kvm.h | 8 | ||||
-rw-r--r-- | drivers/kvm/kvm_main.c | 77 | ||||
-rw-r--r-- | drivers/kvm/svm.c | 9 | ||||
-rw-r--r-- | drivers/kvm/vmx.c | 9 | ||||
-rw-r--r-- | drivers/kvm/x86_emulate.c | 24 |
5 files changed, 82 insertions, 45 deletions
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h index da9c3aa1c08c..e885b190b798 100644 --- a/drivers/kvm/kvm.h +++ b/drivers/kvm/kvm.h | |||
@@ -207,6 +207,8 @@ enum { | |||
207 | VCPU_SREG_LDTR, | 207 | VCPU_SREG_LDTR, |
208 | }; | 208 | }; |
209 | 209 | ||
210 | #include "x86_emulate.h" | ||
211 | |||
210 | struct kvm_pio_request { | 212 | struct kvm_pio_request { |
211 | unsigned long count; | 213 | unsigned long count; |
212 | int cur_count; | 214 | int cur_count; |
@@ -380,6 +382,10 @@ struct kvm_vcpu { | |||
380 | 382 | ||
381 | int cpuid_nent; | 383 | int cpuid_nent; |
382 | struct kvm_cpuid_entry cpuid_entries[KVM_MAX_CPUID_ENTRIES]; | 384 | struct kvm_cpuid_entry cpuid_entries[KVM_MAX_CPUID_ENTRIES]; |
385 | |||
386 | /* emulate context */ | ||
387 | |||
388 | struct x86_emulate_ctxt emulate_ctxt; | ||
383 | }; | 389 | }; |
384 | 390 | ||
385 | struct kvm_mem_alias { | 391 | struct kvm_mem_alias { |
@@ -555,7 +561,7 @@ enum emulation_result { | |||
555 | }; | 561 | }; |
556 | 562 | ||
557 | int emulate_instruction(struct kvm_vcpu *vcpu, struct kvm_run *run, | 563 | int emulate_instruction(struct kvm_vcpu *vcpu, struct kvm_run *run, |
558 | unsigned long cr2, u16 error_code); | 564 | unsigned long cr2, u16 error_code, int no_decode); |
559 | void kvm_report_emulation_failure(struct kvm_vcpu *cvpu, const char *context); | 565 | void kvm_report_emulation_failure(struct kvm_vcpu *cvpu, const char *context); |
560 | void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address); | 566 | void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address); |
561 | void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long address); | 567 | void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long address); |
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index 800ab5028ed3..710483669f34 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c | |||
@@ -1251,45 +1251,56 @@ struct x86_emulate_ops emulate_ops = { | |||
1251 | int emulate_instruction(struct kvm_vcpu *vcpu, | 1251 | int emulate_instruction(struct kvm_vcpu *vcpu, |
1252 | struct kvm_run *run, | 1252 | struct kvm_run *run, |
1253 | unsigned long cr2, | 1253 | unsigned long cr2, |
1254 | u16 error_code) | 1254 | u16 error_code, |
1255 | int no_decode) | ||
1255 | { | 1256 | { |
1256 | struct x86_emulate_ctxt emulate_ctxt; | 1257 | int r = 0; |
1257 | int r; | ||
1258 | int cs_db, cs_l; | ||
1259 | 1258 | ||
1260 | vcpu->mmio_fault_cr2 = cr2; | 1259 | vcpu->mmio_fault_cr2 = cr2; |
1261 | kvm_x86_ops->cache_regs(vcpu); | 1260 | kvm_x86_ops->cache_regs(vcpu); |
1262 | 1261 | ||
1263 | kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); | ||
1264 | |||
1265 | emulate_ctxt.vcpu = vcpu; | ||
1266 | emulate_ctxt.eflags = kvm_x86_ops->get_rflags(vcpu); | ||
1267 | emulate_ctxt.cr2 = cr2; | ||
1268 | emulate_ctxt.mode = (emulate_ctxt.eflags & X86_EFLAGS_VM) | ||
1269 | ? X86EMUL_MODE_REAL : cs_l | ||
1270 | ? X86EMUL_MODE_PROT64 : cs_db | ||
1271 | ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16; | ||
1272 | |||
1273 | if (emulate_ctxt.mode == X86EMUL_MODE_PROT64) { | ||
1274 | emulate_ctxt.cs_base = 0; | ||
1275 | emulate_ctxt.ds_base = 0; | ||
1276 | emulate_ctxt.es_base = 0; | ||
1277 | emulate_ctxt.ss_base = 0; | ||
1278 | } else { | ||
1279 | emulate_ctxt.cs_base = get_segment_base(vcpu, VCPU_SREG_CS); | ||
1280 | emulate_ctxt.ds_base = get_segment_base(vcpu, VCPU_SREG_DS); | ||
1281 | emulate_ctxt.es_base = get_segment_base(vcpu, VCPU_SREG_ES); | ||
1282 | emulate_ctxt.ss_base = get_segment_base(vcpu, VCPU_SREG_SS); | ||
1283 | } | ||
1284 | |||
1285 | emulate_ctxt.gs_base = get_segment_base(vcpu, VCPU_SREG_GS); | ||
1286 | emulate_ctxt.fs_base = get_segment_base(vcpu, VCPU_SREG_FS); | ||
1287 | |||
1288 | vcpu->mmio_is_write = 0; | 1262 | vcpu->mmio_is_write = 0; |
1289 | vcpu->pio.string = 0; | 1263 | vcpu->pio.string = 0; |
1290 | r = x86_decode_insn(&emulate_ctxt, &emulate_ops); | 1264 | |
1265 | if (!no_decode) { | ||
1266 | int cs_db, cs_l; | ||
1267 | kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); | ||
1268 | |||
1269 | vcpu->emulate_ctxt.vcpu = vcpu; | ||
1270 | vcpu->emulate_ctxt.eflags = kvm_x86_ops->get_rflags(vcpu); | ||
1271 | vcpu->emulate_ctxt.cr2 = cr2; | ||
1272 | vcpu->emulate_ctxt.mode = | ||
1273 | (vcpu->emulate_ctxt.eflags & X86_EFLAGS_VM) | ||
1274 | ? X86EMUL_MODE_REAL : cs_l | ||
1275 | ? X86EMUL_MODE_PROT64 : cs_db | ||
1276 | ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16; | ||
1277 | |||
1278 | if (vcpu->emulate_ctxt.mode == X86EMUL_MODE_PROT64) { | ||
1279 | vcpu->emulate_ctxt.cs_base = 0; | ||
1280 | vcpu->emulate_ctxt.ds_base = 0; | ||
1281 | vcpu->emulate_ctxt.es_base = 0; | ||
1282 | vcpu->emulate_ctxt.ss_base = 0; | ||
1283 | } else { | ||
1284 | vcpu->emulate_ctxt.cs_base = | ||
1285 | get_segment_base(vcpu, VCPU_SREG_CS); | ||
1286 | vcpu->emulate_ctxt.ds_base = | ||
1287 | get_segment_base(vcpu, VCPU_SREG_DS); | ||
1288 | vcpu->emulate_ctxt.es_base = | ||
1289 | get_segment_base(vcpu, VCPU_SREG_ES); | ||
1290 | vcpu->emulate_ctxt.ss_base = | ||
1291 | get_segment_base(vcpu, VCPU_SREG_SS); | ||
1292 | } | ||
1293 | |||
1294 | vcpu->emulate_ctxt.gs_base = | ||
1295 | get_segment_base(vcpu, VCPU_SREG_GS); | ||
1296 | vcpu->emulate_ctxt.fs_base = | ||
1297 | get_segment_base(vcpu, VCPU_SREG_FS); | ||
1298 | |||
1299 | r = x86_decode_insn(&vcpu->emulate_ctxt, &emulate_ops); | ||
1300 | } | ||
1301 | |||
1291 | if (r == 0) | 1302 | if (r == 0) |
1292 | r = x86_emulate_insn(&emulate_ctxt, &emulate_ops); | 1303 | r = x86_emulate_insn(&vcpu->emulate_ctxt, &emulate_ops); |
1293 | 1304 | ||
1294 | if (vcpu->pio.string) | 1305 | if (vcpu->pio.string) |
1295 | return EMULATE_DO_MMIO; | 1306 | return EMULATE_DO_MMIO; |
@@ -1313,7 +1324,7 @@ int emulate_instruction(struct kvm_vcpu *vcpu, | |||
1313 | } | 1324 | } |
1314 | 1325 | ||
1315 | kvm_x86_ops->decache_regs(vcpu); | 1326 | kvm_x86_ops->decache_regs(vcpu); |
1316 | kvm_x86_ops->set_rflags(vcpu, emulate_ctxt.eflags); | 1327 | kvm_x86_ops->set_rflags(vcpu, vcpu->emulate_ctxt.eflags); |
1317 | 1328 | ||
1318 | if (vcpu->mmio_is_write) { | 1329 | if (vcpu->mmio_is_write) { |
1319 | vcpu->mmio_needed = 0; | 1330 | vcpu->mmio_needed = 0; |
@@ -2055,7 +2066,7 @@ static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
2055 | vcpu->mmio_read_completed = 1; | 2066 | vcpu->mmio_read_completed = 1; |
2056 | vcpu->mmio_needed = 0; | 2067 | vcpu->mmio_needed = 0; |
2057 | r = emulate_instruction(vcpu, kvm_run, | 2068 | r = emulate_instruction(vcpu, kvm_run, |
2058 | vcpu->mmio_fault_cr2, 0); | 2069 | vcpu->mmio_fault_cr2, 0, 1); |
2059 | if (r == EMULATE_DO_MMIO) { | 2070 | if (r == EMULATE_DO_MMIO) { |
2060 | /* | 2071 | /* |
2061 | * Read-modify-write. Back to userspace. | 2072 | * Read-modify-write. Back to userspace. |
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c index 794d95416f7b..f268bd51f337 100644 --- a/drivers/kvm/svm.c +++ b/drivers/kvm/svm.c | |||
@@ -960,7 +960,7 @@ static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) | |||
960 | return 1; | 960 | return 1; |
961 | } | 961 | } |
962 | er = emulate_instruction(&svm->vcpu, kvm_run, fault_address, | 962 | er = emulate_instruction(&svm->vcpu, kvm_run, fault_address, |
963 | error_code); | 963 | error_code, 0); |
964 | mutex_unlock(&kvm->lock); | 964 | mutex_unlock(&kvm->lock); |
965 | 965 | ||
966 | switch (er) { | 966 | switch (er) { |
@@ -984,7 +984,7 @@ static int ud_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) | |||
984 | { | 984 | { |
985 | int er; | 985 | int er; |
986 | 986 | ||
987 | er = emulate_instruction(&svm->vcpu, kvm_run, 0, 0); | 987 | er = emulate_instruction(&svm->vcpu, kvm_run, 0, 0, 0); |
988 | if (er != EMULATE_DONE) | 988 | if (er != EMULATE_DONE) |
989 | inject_ud(&svm->vcpu); | 989 | inject_ud(&svm->vcpu); |
990 | 990 | ||
@@ -1027,7 +1027,8 @@ static int io_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) | |||
1027 | string = (io_info & SVM_IOIO_STR_MASK) != 0; | 1027 | string = (io_info & SVM_IOIO_STR_MASK) != 0; |
1028 | 1028 | ||
1029 | if (string) { | 1029 | if (string) { |
1030 | if (emulate_instruction(&svm->vcpu, kvm_run, 0, 0) == EMULATE_DO_MMIO) | 1030 | if (emulate_instruction(&svm->vcpu, |
1031 | kvm_run, 0, 0, 0) == EMULATE_DO_MMIO) | ||
1031 | return 0; | 1032 | return 0; |
1032 | return 1; | 1033 | return 1; |
1033 | } | 1034 | } |
@@ -1086,7 +1087,7 @@ static int cpuid_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) | |||
1086 | static int emulate_on_interception(struct vcpu_svm *svm, | 1087 | static int emulate_on_interception(struct vcpu_svm *svm, |
1087 | struct kvm_run *kvm_run) | 1088 | struct kvm_run *kvm_run) |
1088 | { | 1089 | { |
1089 | if (emulate_instruction(&svm->vcpu, NULL, 0, 0) != EMULATE_DONE) | 1090 | if (emulate_instruction(&svm->vcpu, NULL, 0, 0, 0) != EMULATE_DONE) |
1090 | pr_unimpl(&svm->vcpu, "%s: failed\n", __FUNCTION__); | 1091 | pr_unimpl(&svm->vcpu, "%s: failed\n", __FUNCTION__); |
1091 | return 1; | 1092 | return 1; |
1092 | } | 1093 | } |
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c index 47c827d3007c..91768d5dbfb9 100644 --- a/drivers/kvm/vmx.c +++ b/drivers/kvm/vmx.c | |||
@@ -1750,7 +1750,7 @@ static int handle_rmode_exception(struct kvm_vcpu *vcpu, | |||
1750 | * Cause the #SS fault with 0 error code in VM86 mode. | 1750 | * Cause the #SS fault with 0 error code in VM86 mode. |
1751 | */ | 1751 | */ |
1752 | if (((vec == GP_VECTOR) || (vec == SS_VECTOR)) && err_code == 0) | 1752 | if (((vec == GP_VECTOR) || (vec == SS_VECTOR)) && err_code == 0) |
1753 | if (emulate_instruction(vcpu, NULL, 0, 0) == EMULATE_DONE) | 1753 | if (emulate_instruction(vcpu, NULL, 0, 0, 0) == EMULATE_DONE) |
1754 | return 1; | 1754 | return 1; |
1755 | return 0; | 1755 | return 0; |
1756 | } | 1756 | } |
@@ -1787,7 +1787,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
1787 | } | 1787 | } |
1788 | 1788 | ||
1789 | if (is_invalid_opcode(intr_info)) { | 1789 | if (is_invalid_opcode(intr_info)) { |
1790 | er = emulate_instruction(vcpu, kvm_run, 0, 0); | 1790 | er = emulate_instruction(vcpu, kvm_run, 0, 0, 0); |
1791 | if (er != EMULATE_DONE) | 1791 | if (er != EMULATE_DONE) |
1792 | vmx_inject_ud(vcpu); | 1792 | vmx_inject_ud(vcpu); |
1793 | 1793 | ||
@@ -1812,7 +1812,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
1812 | return 1; | 1812 | return 1; |
1813 | } | 1813 | } |
1814 | 1814 | ||
1815 | er = emulate_instruction(vcpu, kvm_run, cr2, error_code); | 1815 | er = emulate_instruction(vcpu, kvm_run, cr2, error_code, 0); |
1816 | mutex_unlock(&vcpu->kvm->lock); | 1816 | mutex_unlock(&vcpu->kvm->lock); |
1817 | 1817 | ||
1818 | switch (er) { | 1818 | switch (er) { |
@@ -1873,7 +1873,8 @@ static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
1873 | string = (exit_qualification & 16) != 0; | 1873 | string = (exit_qualification & 16) != 0; |
1874 | 1874 | ||
1875 | if (string) { | 1875 | if (string) { |
1876 | if (emulate_instruction(vcpu, kvm_run, 0, 0) == EMULATE_DO_MMIO) | 1876 | if (emulate_instruction(vcpu, |
1877 | kvm_run, 0, 0, 0) == EMULATE_DO_MMIO) | ||
1877 | return 0; | 1878 | return 0; |
1878 | return 1; | 1879 | return 1; |
1879 | } | 1880 | } |
diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c index c191093982d8..dc9d2a870fbc 100644 --- a/drivers/kvm/x86_emulate.c +++ b/drivers/kvm/x86_emulate.c | |||
@@ -913,10 +913,19 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) | |||
913 | unsigned long cr2 = ctxt->cr2; | 913 | unsigned long cr2 = ctxt->cr2; |
914 | int no_wb = 0; | 914 | int no_wb = 0; |
915 | u64 msr_data; | 915 | u64 msr_data; |
916 | unsigned long saved_eip = 0; | ||
916 | unsigned long _eflags = ctxt->eflags; | 917 | unsigned long _eflags = ctxt->eflags; |
917 | struct decode_cache *c = &ctxt->decode; | 918 | struct decode_cache *c = &ctxt->decode; |
918 | int rc = 0; | 919 | int rc = 0; |
919 | 920 | ||
921 | /* Shadow copy of register state. Committed on successful emulation. | ||
922 | * NOTE: we can copy them from vcpu as x86_decode_insn() doesn't | ||
923 | * modify them. | ||
924 | */ | ||
925 | |||
926 | memcpy(c->regs, ctxt->vcpu->regs, sizeof c->regs); | ||
927 | saved_eip = c->eip; | ||
928 | |||
920 | if ((c->d & ModRM) && (c->modrm_mod != 3)) | 929 | if ((c->d & ModRM) && (c->modrm_mod != 3)) |
921 | cr2 = c->modrm_ea; | 930 | cr2 = c->modrm_ea; |
922 | 931 | ||
@@ -1250,7 +1259,11 @@ writeback: | |||
1250 | ctxt->vcpu->rip = c->eip; | 1259 | ctxt->vcpu->rip = c->eip; |
1251 | 1260 | ||
1252 | done: | 1261 | done: |
1253 | return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0; | 1262 | if (rc == X86EMUL_UNHANDLEABLE) { |
1263 | c->eip = saved_eip; | ||
1264 | return -1; | ||
1265 | } | ||
1266 | return 0; | ||
1254 | 1267 | ||
1255 | special_insn: | 1268 | special_insn: |
1256 | if (c->twobyte) | 1269 | if (c->twobyte) |
@@ -1305,8 +1318,10 @@ push: | |||
1305 | register_address(ctxt->es_base, | 1318 | register_address(ctxt->es_base, |
1306 | c->regs[VCPU_REGS_RDI]), | 1319 | c->regs[VCPU_REGS_RDI]), |
1307 | c->rep_prefix, | 1320 | c->rep_prefix, |
1308 | c->regs[VCPU_REGS_RDX]) == 0) | 1321 | c->regs[VCPU_REGS_RDX]) == 0) { |
1322 | c->eip = saved_eip; | ||
1309 | return -1; | 1323 | return -1; |
1324 | } | ||
1310 | return 0; | 1325 | return 0; |
1311 | case 0x6e: /* outsb */ | 1326 | case 0x6e: /* outsb */ |
1312 | case 0x6f: /* outsw/outsd */ | 1327 | case 0x6f: /* outsw/outsd */ |
@@ -1321,8 +1336,10 @@ push: | |||
1321 | ctxt->ds_base, | 1336 | ctxt->ds_base, |
1322 | c->regs[VCPU_REGS_RSI]), | 1337 | c->regs[VCPU_REGS_RSI]), |
1323 | c->rep_prefix, | 1338 | c->rep_prefix, |
1324 | c->regs[VCPU_REGS_RDX]) == 0) | 1339 | c->regs[VCPU_REGS_RDX]) == 0) { |
1340 | c->eip = saved_eip; | ||
1325 | return -1; | 1341 | return -1; |
1342 | } | ||
1326 | return 0; | 1343 | return 0; |
1327 | case 0x70 ... 0x7f: /* jcc (short) */ { | 1344 | case 0x70 ... 0x7f: /* jcc (short) */ { |
1328 | int rel = insn_fetch(s8, 1, c->eip); | 1345 | int rel = insn_fetch(s8, 1, c->eip); |
@@ -1711,5 +1728,6 @@ twobyte_special_insn: | |||
1711 | 1728 | ||
1712 | cannot_emulate: | 1729 | cannot_emulate: |
1713 | DPRINTF("Cannot emulate %02x\n", c->b); | 1730 | DPRINTF("Cannot emulate %02x\n", c->b); |
1731 | c->eip = saved_eip; | ||
1714 | return -1; | 1732 | return -1; |
1715 | } | 1733 | } |