diff options
author | Gleb Natapov <gleb@redhat.com> | 2010-03-18 09:20:26 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2010-05-17 05:16:29 -0400 |
commit | 5cd21917da245fbe98bd443de2c7f519b3df6814 (patch) | |
tree | 0bb2d4ee197011a92002a5cc32d19758a1e87ed0 /arch/x86/kvm/emulate.c | |
parent | cb404fe0898779ec5fe5e06e90aaddcf40aefad8 (diff) |
KVM: x86 emulator: restart string instruction without going back to a guest.
Currently when string instruction is only partially complete we go back
to a guest mode, guest tries to reexecute instruction and exits again
and at this point emulation continues. Avoid all of this by restarting
instruction without going back to a guest mode, but return to a guest
mode each 1024 iterations to allow interrupt injection. Pending
exception causes immediate guest entry too.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/x86/kvm/emulate.c')
-rw-r--r-- | arch/x86/kvm/emulate.c | 34 |
1 files changed, 23 insertions, 11 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 0579d9dd9aac..6de6ad1610d8 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
@@ -927,8 +927,11 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) | |||
927 | int mode = ctxt->mode; | 927 | int mode = ctxt->mode; |
928 | int def_op_bytes, def_ad_bytes, group; | 928 | int def_op_bytes, def_ad_bytes, group; |
929 | 929 | ||
930 | /* Shadow copy of register state. Committed on successful emulation. */ | ||
931 | 930 | ||
931 | /* we cannot decode insn before we complete previous rep insn */ | ||
932 | WARN_ON(ctxt->restart); | ||
933 | |||
934 | /* Shadow copy of register state. Committed on successful emulation. */ | ||
932 | memset(c, 0, sizeof(struct decode_cache)); | 935 | memset(c, 0, sizeof(struct decode_cache)); |
933 | c->eip = ctxt->eip; | 936 | c->eip = ctxt->eip; |
934 | ctxt->cs_base = seg_base(ctxt, VCPU_SREG_CS); | 937 | ctxt->cs_base = seg_base(ctxt, VCPU_SREG_CS); |
@@ -2426,6 +2429,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) | |||
2426 | u64 msr_data; | 2429 | u64 msr_data; |
2427 | struct decode_cache *c = &ctxt->decode; | 2430 | struct decode_cache *c = &ctxt->decode; |
2428 | int rc = X86EMUL_CONTINUE; | 2431 | int rc = X86EMUL_CONTINUE; |
2432 | int saved_dst_type = c->dst.type; | ||
2429 | 2433 | ||
2430 | ctxt->interruptibility = 0; | 2434 | ctxt->interruptibility = 0; |
2431 | 2435 | ||
@@ -2454,8 +2458,11 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) | |||
2454 | } | 2458 | } |
2455 | 2459 | ||
2456 | if (c->rep_prefix && (c->d & String)) { | 2460 | if (c->rep_prefix && (c->d & String)) { |
2461 | ctxt->restart = true; | ||
2457 | /* All REP prefixes have the same first termination condition */ | 2462 | /* All REP prefixes have the same first termination condition */ |
2458 | if (address_mask(c, c->regs[VCPU_REGS_RCX]) == 0) { | 2463 | if (address_mask(c, c->regs[VCPU_REGS_RCX]) == 0) { |
2464 | string_done: | ||
2465 | ctxt->restart = false; | ||
2459 | kvm_rip_write(ctxt->vcpu, c->eip); | 2466 | kvm_rip_write(ctxt->vcpu, c->eip); |
2460 | goto done; | 2467 | goto done; |
2461 | } | 2468 | } |
@@ -2467,17 +2474,13 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) | |||
2467 | * - if REPNE/REPNZ and ZF = 1 then done | 2474 | * - if REPNE/REPNZ and ZF = 1 then done |
2468 | */ | 2475 | */ |
2469 | if ((c->b == 0xa6) || (c->b == 0xa7) || | 2476 | if ((c->b == 0xa6) || (c->b == 0xa7) || |
2470 | (c->b == 0xae) || (c->b == 0xaf)) { | 2477 | (c->b == 0xae) || (c->b == 0xaf)) { |
2471 | if ((c->rep_prefix == REPE_PREFIX) && | 2478 | if ((c->rep_prefix == REPE_PREFIX) && |
2472 | ((ctxt->eflags & EFLG_ZF) == 0)) { | 2479 | ((ctxt->eflags & EFLG_ZF) == 0)) |
2473 | kvm_rip_write(ctxt->vcpu, c->eip); | 2480 | goto string_done; |
2474 | goto done; | ||
2475 | } | ||
2476 | if ((c->rep_prefix == REPNE_PREFIX) && | 2481 | if ((c->rep_prefix == REPNE_PREFIX) && |
2477 | ((ctxt->eflags & EFLG_ZF) == EFLG_ZF)) { | 2482 | ((ctxt->eflags & EFLG_ZF) == EFLG_ZF)) |
2478 | kvm_rip_write(ctxt->vcpu, c->eip); | 2483 | goto string_done; |
2479 | goto done; | ||
2480 | } | ||
2481 | } | 2484 | } |
2482 | c->eip = ctxt->eip; | 2485 | c->eip = ctxt->eip; |
2483 | } | 2486 | } |
@@ -2911,6 +2914,12 @@ writeback: | |||
2911 | if (rc != X86EMUL_CONTINUE) | 2914 | if (rc != X86EMUL_CONTINUE) |
2912 | goto done; | 2915 | goto done; |
2913 | 2916 | ||
2917 | /* | ||
2918 | * restore dst type in case the decoding will be reused | ||
2919 | * (happens for string instruction ) | ||
2920 | */ | ||
2921 | c->dst.type = saved_dst_type; | ||
2922 | |||
2914 | if ((c->d & SrcMask) == SrcSI) | 2923 | if ((c->d & SrcMask) == SrcSI) |
2915 | string_addr_inc(ctxt, seg_override_base(ctxt, c), VCPU_REGS_RSI, | 2924 | string_addr_inc(ctxt, seg_override_base(ctxt, c), VCPU_REGS_RSI, |
2916 | &c->src); | 2925 | &c->src); |
@@ -2918,8 +2927,11 @@ writeback: | |||
2918 | if ((c->d & DstMask) == DstDI) | 2927 | if ((c->d & DstMask) == DstDI) |
2919 | string_addr_inc(ctxt, es_base(ctxt), VCPU_REGS_RDI, &c->dst); | 2928 | string_addr_inc(ctxt, es_base(ctxt), VCPU_REGS_RDI, &c->dst); |
2920 | 2929 | ||
2921 | if (c->rep_prefix && (c->d & String)) | 2930 | if (c->rep_prefix && (c->d & String)) { |
2922 | register_address_increment(c, &c->regs[VCPU_REGS_RCX], -1); | 2931 | register_address_increment(c, &c->regs[VCPU_REGS_RCX], -1); |
2932 | if (!(c->regs[VCPU_REGS_RCX] & 0x3ff)) | ||
2933 | ctxt->restart = false; | ||
2934 | } | ||
2923 | 2935 | ||
2924 | /* Commit shadow register state. */ | 2936 | /* Commit shadow register state. */ |
2925 | memcpy(ctxt->vcpu->arch.regs, c->regs, sizeof c->regs); | 2937 | memcpy(ctxt->vcpu->arch.regs, c->regs, sizeof c->regs); |