Commit e54cfa97 authored by Takuya Yoshikawa's avatar Takuya Yoshikawa Committed by Marcelo Tosatti

KVM: Fix emulate_sys[call, enter, exit]()'s fault handling

This patch fixes emulate_syscall(), emulate_sysenter() and
emulate_sysexit() to handle injected faults properly.

Even though original code injects faults in these functions,
we cannot handle these unless we use the different return
value from the UNHANDLEABLE case. So this patch use X86EMUL_*
codes instead of -1 and 0 and makes x86_emulate_insn() to
handle these propagated faults.

Be sure that, in x86_emulate_insn(), goto cannot_emulate and
goto done with rc equals X86EMUL_UNHANDLEABLE have same effect.
Signed-off-by: default avatarTakuya Yoshikawa <yoshikawa.takuya@oss.ntt.co.jp>
Signed-off-by: default avatarGleb Natapov <gleb@redhat.com>
Signed-off-by: default avatarAvi Kivity <avi@redhat.com>
parent c697518a
...@@ -1599,7 +1599,7 @@ emulate_syscall(struct x86_emulate_ctxt *ctxt) ...@@ -1599,7 +1599,7 @@ emulate_syscall(struct x86_emulate_ctxt *ctxt)
/* syscall is not available in real mode */ /* syscall is not available in real mode */
if (ctxt->mode == X86EMUL_MODE_REAL || ctxt->mode == X86EMUL_MODE_VM86) if (ctxt->mode == X86EMUL_MODE_REAL || ctxt->mode == X86EMUL_MODE_VM86)
return -1; return X86EMUL_UNHANDLEABLE;
setup_syscalls_segments(ctxt, &cs, &ss); setup_syscalls_segments(ctxt, &cs, &ss);
...@@ -1636,7 +1636,7 @@ emulate_syscall(struct x86_emulate_ctxt *ctxt) ...@@ -1636,7 +1636,7 @@ emulate_syscall(struct x86_emulate_ctxt *ctxt)
ctxt->eflags &= ~(EFLG_VM | EFLG_IF | EFLG_RF); ctxt->eflags &= ~(EFLG_VM | EFLG_IF | EFLG_RF);
} }
return 0; return X86EMUL_CONTINUE;
} }
static int static int
...@@ -1649,14 +1649,14 @@ emulate_sysenter(struct x86_emulate_ctxt *ctxt) ...@@ -1649,14 +1649,14 @@ emulate_sysenter(struct x86_emulate_ctxt *ctxt)
/* inject #GP if in real mode */ /* inject #GP if in real mode */
if (ctxt->mode == X86EMUL_MODE_REAL) { if (ctxt->mode == X86EMUL_MODE_REAL) {
kvm_inject_gp(ctxt->vcpu, 0); kvm_inject_gp(ctxt->vcpu, 0);
return -1; return X86EMUL_UNHANDLEABLE;
} }
/* XXX sysenter/sysexit have not been tested in 64bit mode. /* XXX sysenter/sysexit have not been tested in 64bit mode.
* Therefore, we inject an #UD. * Therefore, we inject an #UD.
*/ */
if (ctxt->mode == X86EMUL_MODE_PROT64) if (ctxt->mode == X86EMUL_MODE_PROT64)
return -1; return X86EMUL_UNHANDLEABLE;
setup_syscalls_segments(ctxt, &cs, &ss); setup_syscalls_segments(ctxt, &cs, &ss);
...@@ -1665,13 +1665,13 @@ emulate_sysenter(struct x86_emulate_ctxt *ctxt) ...@@ -1665,13 +1665,13 @@ emulate_sysenter(struct x86_emulate_ctxt *ctxt)
case X86EMUL_MODE_PROT32: case X86EMUL_MODE_PROT32:
if ((msr_data & 0xfffc) == 0x0) { if ((msr_data & 0xfffc) == 0x0) {
kvm_inject_gp(ctxt->vcpu, 0); kvm_inject_gp(ctxt->vcpu, 0);
return -1; return X86EMUL_PROPAGATE_FAULT;
} }
break; break;
case X86EMUL_MODE_PROT64: case X86EMUL_MODE_PROT64:
if (msr_data == 0x0) { if (msr_data == 0x0) {
kvm_inject_gp(ctxt->vcpu, 0); kvm_inject_gp(ctxt->vcpu, 0);
return -1; return X86EMUL_PROPAGATE_FAULT;
} }
break; break;
} }
...@@ -1696,7 +1696,7 @@ emulate_sysenter(struct x86_emulate_ctxt *ctxt) ...@@ -1696,7 +1696,7 @@ emulate_sysenter(struct x86_emulate_ctxt *ctxt)
kvm_x86_ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_ESP, &msr_data); kvm_x86_ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_ESP, &msr_data);
c->regs[VCPU_REGS_RSP] = msr_data; c->regs[VCPU_REGS_RSP] = msr_data;
return 0; return X86EMUL_CONTINUE;
} }
static int static int
...@@ -1711,7 +1711,7 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt) ...@@ -1711,7 +1711,7 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt)
if (ctxt->mode == X86EMUL_MODE_REAL || if (ctxt->mode == X86EMUL_MODE_REAL ||
ctxt->mode == X86EMUL_MODE_VM86) { ctxt->mode == X86EMUL_MODE_VM86) {
kvm_inject_gp(ctxt->vcpu, 0); kvm_inject_gp(ctxt->vcpu, 0);
return -1; return X86EMUL_UNHANDLEABLE;
} }
setup_syscalls_segments(ctxt, &cs, &ss); setup_syscalls_segments(ctxt, &cs, &ss);
...@@ -1729,7 +1729,7 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt) ...@@ -1729,7 +1729,7 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt)
cs.selector = (u16)(msr_data + 16); cs.selector = (u16)(msr_data + 16);
if ((msr_data & 0xfffc) == 0x0) { if ((msr_data & 0xfffc) == 0x0) {
kvm_inject_gp(ctxt->vcpu, 0); kvm_inject_gp(ctxt->vcpu, 0);
return -1; return X86EMUL_PROPAGATE_FAULT;
} }
ss.selector = (u16)(msr_data + 24); ss.selector = (u16)(msr_data + 24);
break; break;
...@@ -1737,7 +1737,7 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt) ...@@ -1737,7 +1737,7 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt)
cs.selector = (u16)(msr_data + 32); cs.selector = (u16)(msr_data + 32);
if (msr_data == 0x0) { if (msr_data == 0x0) {
kvm_inject_gp(ctxt->vcpu, 0); kvm_inject_gp(ctxt->vcpu, 0);
return -1; return X86EMUL_PROPAGATE_FAULT;
} }
ss.selector = cs.selector + 8; ss.selector = cs.selector + 8;
cs.db = 0; cs.db = 0;
...@@ -1753,7 +1753,7 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt) ...@@ -1753,7 +1753,7 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt)
c->eip = ctxt->vcpu->arch.regs[VCPU_REGS_RDX]; c->eip = ctxt->vcpu->arch.regs[VCPU_REGS_RDX];
c->regs[VCPU_REGS_RSP] = ctxt->vcpu->arch.regs[VCPU_REGS_RCX]; c->regs[VCPU_REGS_RSP] = ctxt->vcpu->arch.regs[VCPU_REGS_RCX];
return 0; return X86EMUL_CONTINUE;
} }
static bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt) static bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt)
...@@ -2476,8 +2476,9 @@ twobyte_insn: ...@@ -2476,8 +2476,9 @@ twobyte_insn:
} }
break; break;
case 0x05: /* syscall */ case 0x05: /* syscall */
if (emulate_syscall(ctxt) == -1) rc = emulate_syscall(ctxt);
goto cannot_emulate; if (rc != X86EMUL_CONTINUE)
goto done;
else else
goto writeback; goto writeback;
break; break;
...@@ -2548,14 +2549,16 @@ twobyte_insn: ...@@ -2548,14 +2549,16 @@ twobyte_insn:
c->dst.type = OP_NONE; c->dst.type = OP_NONE;
break; break;
case 0x34: /* sysenter */ case 0x34: /* sysenter */
if (emulate_sysenter(ctxt) == -1) rc = emulate_sysenter(ctxt);
goto cannot_emulate; if (rc != X86EMUL_CONTINUE)
goto done;
else else
goto writeback; goto writeback;
break; break;
case 0x35: /* sysexit */ case 0x35: /* sysexit */
if (emulate_sysexit(ctxt) == -1) rc = emulate_sysexit(ctxt);
goto cannot_emulate; if (rc != X86EMUL_CONTINUE)
goto done;
else else
goto writeback; goto writeback;
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment