Skip to content

Commit 4668f05

Browse files
aprzywaravikivity
authored andcommitted
KVM: x86 emulator: Add sysexit emulation
Handle #UD intercept of the sysexit instruction in 64bit mode returning to 32bit compat mode on an AMD host. Setup the segment descriptors for CS and SS and the EIP/ESP registers according to the manual. Signed-off-by: Christoph Egger <[email protected]> Signed-off-by: Amit Shah <[email protected]> Signed-off-by: Andre Przywara <[email protected]> Signed-off-by: Avi Kivity <[email protected]>
1 parent 8c60435 commit 4668f05

File tree

1 file changed

+71
-1
lines changed

1 file changed

+71
-1
lines changed

arch/x86/kvm/x86_emulate.c

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1541,6 +1541,73 @@ emulate_sysenter(struct x86_emulate_ctxt *ctxt)
15411541
return 0;
15421542
}
15431543

1544+
static int
1545+
emulate_sysexit(struct x86_emulate_ctxt *ctxt)
1546+
{
1547+
struct decode_cache *c = &ctxt->decode;
1548+
struct kvm_segment cs, ss;
1549+
u64 msr_data;
1550+
int usermode;
1551+
1552+
/* inject #UD if LOCK prefix is used */
1553+
if (c->lock_prefix)
1554+
return -1;
1555+
1556+
/* inject #GP if in real mode or paging is disabled */
1557+
if (ctxt->mode == X86EMUL_MODE_REAL
1558+
|| !(ctxt->vcpu->arch.cr0 & X86_CR0_PE)) {
1559+
kvm_inject_gp(ctxt->vcpu, 0);
1560+
return -1;
1561+
}
1562+
1563+
/* sysexit must be called from CPL 0 */
1564+
if (kvm_x86_ops->get_cpl(ctxt->vcpu) != 0) {
1565+
kvm_inject_gp(ctxt->vcpu, 0);
1566+
return -1;
1567+
}
1568+
1569+
setup_syscalls_segments(ctxt, &cs, &ss);
1570+
1571+
if ((c->rex_prefix & 0x8) != 0x0)
1572+
usermode = X86EMUL_MODE_PROT64;
1573+
else
1574+
usermode = X86EMUL_MODE_PROT32;
1575+
1576+
cs.dpl = 3;
1577+
ss.dpl = 3;
1578+
kvm_x86_ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_CS, &msr_data);
1579+
switch (usermode) {
1580+
case X86EMUL_MODE_PROT32:
1581+
cs.selector = (u16)(msr_data + 16);
1582+
if ((msr_data & 0xfffc) == 0x0) {
1583+
kvm_inject_gp(ctxt->vcpu, 0);
1584+
return -1;
1585+
}
1586+
ss.selector = (u16)(msr_data + 24);
1587+
break;
1588+
case X86EMUL_MODE_PROT64:
1589+
cs.selector = (u16)(msr_data + 32);
1590+
if (msr_data == 0x0) {
1591+
kvm_inject_gp(ctxt->vcpu, 0);
1592+
return -1;
1593+
}
1594+
ss.selector = cs.selector + 8;
1595+
cs.db = 0;
1596+
cs.l = 1;
1597+
break;
1598+
}
1599+
cs.selector |= SELECTOR_RPL_MASK;
1600+
ss.selector |= SELECTOR_RPL_MASK;
1601+
1602+
kvm_x86_ops->set_segment(ctxt->vcpu, &cs, VCPU_SREG_CS);
1603+
kvm_x86_ops->set_segment(ctxt->vcpu, &ss, VCPU_SREG_SS);
1604+
1605+
c->eip = ctxt->vcpu->arch.regs[VCPU_REGS_RDX];
1606+
c->regs[VCPU_REGS_RSP] = ctxt->vcpu->arch.regs[VCPU_REGS_RCX];
1607+
1608+
return 0;
1609+
}
1610+
15441611
int
15451612
x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
15461613
{
@@ -2215,7 +2282,10 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
22152282
goto writeback;
22162283
break;
22172284
case 0x35: /* sysexit */
2218-
goto cannot_emulate;
2285+
if (emulate_sysexit(ctxt) == -1)
2286+
goto cannot_emulate;
2287+
else
2288+
goto writeback;
22192289
break;
22202290
case 0x40 ... 0x4f: /* cmov */
22212291
c->dst.val = c->dst.orig_val = c->src.val;

0 commit comments

Comments
 (0)