diff options
-rw-r--r-- | arch/x86/kvm/x86_emulate.c | 72 |
1 files changed, 71 insertions, 1 deletions
diff --git a/arch/x86/kvm/x86_emulate.c b/arch/x86/kvm/x86_emulate.c index 7a9bddb3ebd4..c6663d46f328 100644 --- a/arch/x86/kvm/x86_emulate.c +++ b/arch/x86/kvm/x86_emulate.c | |||
@@ -1541,6 +1541,73 @@ emulate_sysenter(struct x86_emulate_ctxt *ctxt) | |||
1541 | return 0; | 1541 | return 0; |
1542 | } | 1542 | } |
1543 | 1543 | ||
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 | |||
1544 | int | 1611 | int |
1545 | x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) | 1612 | x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) |
1546 | { | 1613 | { |
@@ -2215,7 +2282,10 @@ twobyte_insn: | |||
2215 | goto writeback; | 2282 | goto writeback; |
2216 | break; | 2283 | break; |
2217 | case 0x35: /* sysexit */ | 2284 | case 0x35: /* sysexit */ |
2218 | goto cannot_emulate; | 2285 | if (emulate_sysexit(ctxt) == -1) |
2286 | goto cannot_emulate; | ||
2287 | else | ||
2288 | goto writeback; | ||
2219 | break; | 2289 | break; |
2220 | case 0x40 ... 0x4f: /* cmov */ | 2290 | case 0x40 ... 0x4f: /* cmov */ |
2221 | c->dst.val = c->dst.orig_val = c->src.val; | 2291 | c->dst.val = c->dst.orig_val = c->src.val; |