diff options
-rw-r--r-- | arch/x86/include/asm/kvm_x86_emulate.h | 3 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 6 | ||||
-rw-r--r-- | arch/x86/kvm/x86_emulate.c | 20 |
3 files changed, 28 insertions, 1 deletions
diff --git a/arch/x86/include/asm/kvm_x86_emulate.h b/arch/x86/include/asm/kvm_x86_emulate.h index be40d6e2b6bb..b7ed2c423116 100644 --- a/arch/x86/include/asm/kvm_x86_emulate.h +++ b/arch/x86/include/asm/kvm_x86_emulate.h | |||
@@ -155,6 +155,9 @@ struct x86_emulate_ctxt { | |||
155 | int mode; | 155 | int mode; |
156 | u32 cs_base; | 156 | u32 cs_base; |
157 | 157 | ||
158 | /* interruptibility state, as a result of execution of STI or MOV SS */ | ||
159 | int interruptibility; | ||
160 | |||
158 | /* decode cache */ | 161 | /* decode cache */ |
159 | struct decode_cache decode; | 162 | struct decode_cache decode; |
160 | }; | 163 | }; |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 7475b029b2ad..48f744ff0bc1 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -2379,7 +2379,7 @@ int emulate_instruction(struct kvm_vcpu *vcpu, | |||
2379 | u16 error_code, | 2379 | u16 error_code, |
2380 | int emulation_type) | 2380 | int emulation_type) |
2381 | { | 2381 | { |
2382 | int r; | 2382 | int r, shadow_mask; |
2383 | struct decode_cache *c; | 2383 | struct decode_cache *c; |
2384 | 2384 | ||
2385 | kvm_clear_exception_queue(vcpu); | 2385 | kvm_clear_exception_queue(vcpu); |
@@ -2433,6 +2433,10 @@ int emulate_instruction(struct kvm_vcpu *vcpu, | |||
2433 | } | 2433 | } |
2434 | 2434 | ||
2435 | r = x86_emulate_insn(&vcpu->arch.emulate_ctxt, &emulate_ops); | 2435 | r = x86_emulate_insn(&vcpu->arch.emulate_ctxt, &emulate_ops); |
2436 | shadow_mask = vcpu->arch.emulate_ctxt.interruptibility; | ||
2437 | |||
2438 | if (r == 0) | ||
2439 | kvm_x86_ops->set_interrupt_shadow(vcpu, shadow_mask); | ||
2436 | 2440 | ||
2437 | if (vcpu->arch.pio.string) | 2441 | if (vcpu->arch.pio.string) |
2438 | return EMULATE_DO_MMIO; | 2442 | return EMULATE_DO_MMIO; |
diff --git a/arch/x86/kvm/x86_emulate.c b/arch/x86/kvm/x86_emulate.c index d2664fcba7fa..c1b6c232e02b 100644 --- a/arch/x86/kvm/x86_emulate.c +++ b/arch/x86/kvm/x86_emulate.c | |||
@@ -1361,6 +1361,20 @@ static inline int writeback(struct x86_emulate_ctxt *ctxt, | |||
1361 | return 0; | 1361 | return 0; |
1362 | } | 1362 | } |
1363 | 1363 | ||
1364 | void toggle_interruptibility(struct x86_emulate_ctxt *ctxt, u32 mask) | ||
1365 | { | ||
1366 | u32 int_shadow = kvm_x86_ops->get_interrupt_shadow(ctxt->vcpu, mask); | ||
1367 | /* | ||
1368 | * an sti; sti; sequence only disable interrupts for the first | ||
1369 | * instruction. So, if the last instruction, be it emulated or | ||
1370 | * not, left the system with the INT_STI flag enabled, it | ||
1371 | * means that the last instruction is an sti. We should not | ||
1372 | * leave the flag on in this case. The same goes for mov ss | ||
1373 | */ | ||
1374 | if (!(int_shadow & mask)) | ||
1375 | ctxt->interruptibility = mask; | ||
1376 | } | ||
1377 | |||
1364 | int | 1378 | int |
1365 | x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) | 1379 | x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) |
1366 | { | 1380 | { |
@@ -1372,6 +1386,8 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) | |||
1372 | int io_dir_in; | 1386 | int io_dir_in; |
1373 | int rc = 0; | 1387 | int rc = 0; |
1374 | 1388 | ||
1389 | ctxt->interruptibility = 0; | ||
1390 | |||
1375 | /* Shadow copy of register state. Committed on successful emulation. | 1391 | /* Shadow copy of register state. Committed on successful emulation. |
1376 | * NOTE: we can copy them from vcpu as x86_decode_insn() doesn't | 1392 | * NOTE: we can copy them from vcpu as x86_decode_insn() doesn't |
1377 | * modify them. | 1393 | * modify them. |
@@ -1618,6 +1634,9 @@ special_insn: | |||
1618 | int err; | 1634 | int err; |
1619 | 1635 | ||
1620 | sel = c->src.val; | 1636 | sel = c->src.val; |
1637 | if (c->modrm_reg == VCPU_SREG_SS) | ||
1638 | toggle_interruptibility(ctxt, X86_SHADOW_INT_MOV_SS); | ||
1639 | |||
1621 | if (c->modrm_reg <= 5) { | 1640 | if (c->modrm_reg <= 5) { |
1622 | type_bits = (c->modrm_reg == 1) ? 9 : 1; | 1641 | type_bits = (c->modrm_reg == 1) ? 9 : 1; |
1623 | err = kvm_load_segment_descriptor(ctxt->vcpu, sel, | 1642 | err = kvm_load_segment_descriptor(ctxt->vcpu, sel, |
@@ -1847,6 +1866,7 @@ special_insn: | |||
1847 | c->dst.type = OP_NONE; /* Disable writeback. */ | 1866 | c->dst.type = OP_NONE; /* Disable writeback. */ |
1848 | break; | 1867 | break; |
1849 | case 0xfb: /* sti */ | 1868 | case 0xfb: /* sti */ |
1869 | toggle_interruptibility(ctxt, X86_SHADOW_INT_STI); | ||
1850 | ctxt->eflags |= X86_EFLAGS_IF; | 1870 | ctxt->eflags |= X86_EFLAGS_IF; |
1851 | c->dst.type = OP_NONE; /* Disable writeback. */ | 1871 | c->dst.type = OP_NONE; /* Disable writeback. */ |
1852 | break; | 1872 | break; |