diff options
author | Nadav Amit <namit@cs.technion.ac.il> | 2014-08-29 04:26:55 -0400 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2014-08-29 08:02:49 -0400 |
commit | 0f54a321302dfbdbd707ba989b2f468e58b9a363 (patch) | |
tree | dd6ae5b4184d341db6cbdaf317c1a1f3837a5c0c | |
parent | 48d89b92609a66bc41f479c560640bc413add3b4 (diff) |
KVM: vmx: VMXOFF emulation in vm86 should cause #UD
Unlike VMCALL, the instructions VMXOFF, VMLAUNCH and VMRESUME should cause a UD
exception in real-mode or vm86. However, the emulator considers all these
instructions the same for the matter of mode checks, and emulation upon exit
due to #UD exception.
As a result, the hypervisor behaves incorrectly on vm86 mode. VMXOFF, VMLAUNCH
or VMRESUME cause on vm86 exit due to #UD. The hypervisor then emulates these
instruction and inject #GP to the guest instead of #UD.
This patch creates a new group for these instructions and mark only VMCALL as
an instruction which can be emulated.
Signed-off-by: Nadav Amit <namit@cs.technion.ac.il>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r-- | arch/x86/kvm/emulate.c | 14 |
1 files changed, 8 insertions, 6 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index e5bf13003cd2..a240fac29e76 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
@@ -3139,12 +3139,8 @@ static int em_clts(struct x86_emulate_ctxt *ctxt) | |||
3139 | 3139 | ||
3140 | static int em_vmcall(struct x86_emulate_ctxt *ctxt) | 3140 | static int em_vmcall(struct x86_emulate_ctxt *ctxt) |
3141 | { | 3141 | { |
3142 | int rc; | 3142 | int rc = ctxt->ops->fix_hypercall(ctxt); |
3143 | |||
3144 | if (ctxt->modrm_mod != 3 || ctxt->modrm_rm != 1) | ||
3145 | return X86EMUL_UNHANDLEABLE; | ||
3146 | 3143 | ||
3147 | rc = ctxt->ops->fix_hypercall(ctxt); | ||
3148 | if (rc != X86EMUL_CONTINUE) | 3144 | if (rc != X86EMUL_CONTINUE) |
3149 | return rc; | 3145 | return rc; |
3150 | 3146 | ||
@@ -3562,6 +3558,12 @@ static int check_perm_out(struct x86_emulate_ctxt *ctxt) | |||
3562 | F2bv(((_f) | DstReg | SrcMem | ModRM) & ~Lock, _e), \ | 3558 | F2bv(((_f) | DstReg | SrcMem | ModRM) & ~Lock, _e), \ |
3563 | F2bv(((_f) & ~Lock) | DstAcc | SrcImm, _e) | 3559 | F2bv(((_f) & ~Lock) | DstAcc | SrcImm, _e) |
3564 | 3560 | ||
3561 | static const struct opcode group7_rm0[] = { | ||
3562 | N, | ||
3563 | I(SrcNone | Priv | EmulateOnUD, em_vmcall), | ||
3564 | N, N, N, N, N, N, | ||
3565 | }; | ||
3566 | |||
3565 | static const struct opcode group7_rm1[] = { | 3567 | static const struct opcode group7_rm1[] = { |
3566 | DI(SrcNone | Priv, monitor), | 3568 | DI(SrcNone | Priv, monitor), |
3567 | DI(SrcNone | Priv, mwait), | 3569 | DI(SrcNone | Priv, mwait), |
@@ -3655,7 +3657,7 @@ static const struct group_dual group7 = { { | |||
3655 | II(SrcMem16 | Mov | Priv, em_lmsw, lmsw), | 3657 | II(SrcMem16 | Mov | Priv, em_lmsw, lmsw), |
3656 | II(SrcMem | ByteOp | Priv | NoAccess, em_invlpg, invlpg), | 3658 | II(SrcMem | ByteOp | Priv | NoAccess, em_invlpg, invlpg), |
3657 | }, { | 3659 | }, { |
3658 | I(SrcNone | Priv | EmulateOnUD, em_vmcall), | 3660 | EXT(0, group7_rm0), |
3659 | EXT(0, group7_rm1), | 3661 | EXT(0, group7_rm1), |
3660 | N, EXT(0, group7_rm3), | 3662 | N, EXT(0, group7_rm3), |
3661 | II(SrcNone | DstMem | Mov, em_smsw, smsw), N, | 3663 | II(SrcNone | DstMem | Mov, em_smsw, smsw), N, |