diff options
author | Andre Przywara <andre.przywara@amd.com> | 2009-06-18 06:56:01 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2009-09-10 01:33:01 -0400 |
commit | 8c60435261deaefeb53ce3222d04d7d5bea81296 (patch) | |
tree | 4225e92f082d673ffa97f878b7e9209f89e21d5a | |
parent | e66bb2ccdcf76d032bbb464b35c292bb3ee58f9b (diff) |
KVM: x86 emulator: Add sysenter emulation
Handle #UD intercept of the sysenter instruction in 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 <christoph.egger@amd.com>
Signed-off-by: Amit Shah <amit.shah@redhat.com>
Signed-off-by: Andre Przywara <andre.przywara@amd.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r-- | arch/x86/kvm/x86_emulate.c | 70 |
1 files changed, 69 insertions, 1 deletions
diff --git a/arch/x86/kvm/x86_emulate.c b/arch/x86/kvm/x86_emulate.c index 4d7256da59d8..7a9bddb3ebd4 100644 --- a/arch/x86/kvm/x86_emulate.c +++ b/arch/x86/kvm/x86_emulate.c | |||
@@ -1476,6 +1476,71 @@ emulate_syscall(struct x86_emulate_ctxt *ctxt) | |||
1476 | return 0; | 1476 | return 0; |
1477 | } | 1477 | } |
1478 | 1478 | ||
1479 | static int | ||
1480 | emulate_sysenter(struct x86_emulate_ctxt *ctxt) | ||
1481 | { | ||
1482 | struct decode_cache *c = &ctxt->decode; | ||
1483 | struct kvm_segment cs, ss; | ||
1484 | u64 msr_data; | ||
1485 | |||
1486 | /* inject #UD if LOCK prefix is used */ | ||
1487 | if (c->lock_prefix) | ||
1488 | return -1; | ||
1489 | |||
1490 | /* inject #GP if in real mode or paging is disabled */ | ||
1491 | if (ctxt->mode == X86EMUL_MODE_REAL || | ||
1492 | !(ctxt->vcpu->arch.cr0 & X86_CR0_PE)) { | ||
1493 | kvm_inject_gp(ctxt->vcpu, 0); | ||
1494 | return -1; | ||
1495 | } | ||
1496 | |||
1497 | /* XXX sysenter/sysexit have not been tested in 64bit mode. | ||
1498 | * Therefore, we inject an #UD. | ||
1499 | */ | ||
1500 | if (ctxt->mode == X86EMUL_MODE_PROT64) | ||
1501 | return -1; | ||
1502 | |||
1503 | setup_syscalls_segments(ctxt, &cs, &ss); | ||
1504 | |||
1505 | kvm_x86_ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_CS, &msr_data); | ||
1506 | switch (ctxt->mode) { | ||
1507 | case X86EMUL_MODE_PROT32: | ||
1508 | if ((msr_data & 0xfffc) == 0x0) { | ||
1509 | kvm_inject_gp(ctxt->vcpu, 0); | ||
1510 | return -1; | ||
1511 | } | ||
1512 | break; | ||
1513 | case X86EMUL_MODE_PROT64: | ||
1514 | if (msr_data == 0x0) { | ||
1515 | kvm_inject_gp(ctxt->vcpu, 0); | ||
1516 | return -1; | ||
1517 | } | ||
1518 | break; | ||
1519 | } | ||
1520 | |||
1521 | ctxt->eflags &= ~(EFLG_VM | EFLG_IF | EFLG_RF); | ||
1522 | cs.selector = (u16)msr_data; | ||
1523 | cs.selector &= ~SELECTOR_RPL_MASK; | ||
1524 | ss.selector = cs.selector + 8; | ||
1525 | ss.selector &= ~SELECTOR_RPL_MASK; | ||
1526 | if (ctxt->mode == X86EMUL_MODE_PROT64 | ||
1527 | || is_long_mode(ctxt->vcpu)) { | ||
1528 | cs.db = 0; | ||
1529 | cs.l = 1; | ||
1530 | } | ||
1531 | |||
1532 | kvm_x86_ops->set_segment(ctxt->vcpu, &cs, VCPU_SREG_CS); | ||
1533 | kvm_x86_ops->set_segment(ctxt->vcpu, &ss, VCPU_SREG_SS); | ||
1534 | |||
1535 | kvm_x86_ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_EIP, &msr_data); | ||
1536 | c->eip = msr_data; | ||
1537 | |||
1538 | kvm_x86_ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_ESP, &msr_data); | ||
1539 | c->regs[VCPU_REGS_RSP] = msr_data; | ||
1540 | |||
1541 | return 0; | ||
1542 | } | ||
1543 | |||
1479 | int | 1544 | int |
1480 | x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) | 1545 | x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) |
1481 | { | 1546 | { |
@@ -2144,7 +2209,10 @@ twobyte_insn: | |||
2144 | c->dst.type = OP_NONE; | 2209 | c->dst.type = OP_NONE; |
2145 | break; | 2210 | break; |
2146 | case 0x34: /* sysenter */ | 2211 | case 0x34: /* sysenter */ |
2147 | goto cannot_emulate; | 2212 | if (emulate_sysenter(ctxt) == -1) |
2213 | goto cannot_emulate; | ||
2214 | else | ||
2215 | goto writeback; | ||
2148 | break; | 2216 | break; |
2149 | case 0x35: /* sysexit */ | 2217 | case 0x35: /* sysexit */ |
2150 | goto cannot_emulate; | 2218 | goto cannot_emulate; |