diff options
author | Avi Kivity <avi@redhat.com> | 2012-06-12 13:03:23 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2012-07-09 07:19:03 -0400 |
commit | 612e89f01569f562dfa76cd5b76310a42b34a214 (patch) | |
tree | 44dffc8c7aaa386a3e2e147499cad2b1adf3d386 | |
parent | 51ddff50cbd77568fe40e17a966b3a2ef1231b36 (diff) |
KVM: x86 emulator: implement ENTER
Opcode C8.
Only ENTER with lexical nesting depth 0 is implemented, since others are
very rare. We'll fail emulation if nonzero lexical depth is used so data
is not corrupted.
Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r-- | arch/x86/kvm/emulate.c | 28 |
1 files changed, 27 insertions, 1 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index acc647d63701..b4b326ebc835 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
@@ -454,6 +454,11 @@ static ulong stack_mask(struct x86_emulate_ctxt *ctxt) | |||
454 | return ~0U >> ((ss.d ^ 1) * 16); /* d=0: 0xffff; d=1: 0xffffffff */ | 454 | return ~0U >> ((ss.d ^ 1) * 16); /* d=0: 0xffff; d=1: 0xffffffff */ |
455 | } | 455 | } |
456 | 456 | ||
457 | static int stack_size(struct x86_emulate_ctxt *ctxt) | ||
458 | { | ||
459 | return (__fls(stack_mask(ctxt)) + 1) >> 3; | ||
460 | } | ||
461 | |||
457 | /* Access/update address held in a register, based on addressing mode. */ | 462 | /* Access/update address held in a register, based on addressing mode. */ |
458 | static inline unsigned long | 463 | static inline unsigned long |
459 | address_mask(struct x86_emulate_ctxt *ctxt, unsigned long reg) | 464 | address_mask(struct x86_emulate_ctxt *ctxt, unsigned long reg) |
@@ -1592,6 +1597,26 @@ static int em_popf(struct x86_emulate_ctxt *ctxt) | |||
1592 | return emulate_popf(ctxt, &ctxt->dst.val, ctxt->op_bytes); | 1597 | return emulate_popf(ctxt, &ctxt->dst.val, ctxt->op_bytes); |
1593 | } | 1598 | } |
1594 | 1599 | ||
1600 | static int em_enter(struct x86_emulate_ctxt *ctxt) | ||
1601 | { | ||
1602 | int rc; | ||
1603 | unsigned frame_size = ctxt->src.val; | ||
1604 | unsigned nesting_level = ctxt->src2.val & 31; | ||
1605 | |||
1606 | if (nesting_level) | ||
1607 | return X86EMUL_UNHANDLEABLE; | ||
1608 | |||
1609 | rc = push(ctxt, &ctxt->regs[VCPU_REGS_RBP], stack_size(ctxt)); | ||
1610 | if (rc != X86EMUL_CONTINUE) | ||
1611 | return rc; | ||
1612 | assign_masked(&ctxt->regs[VCPU_REGS_RBP], ctxt->regs[VCPU_REGS_RSP], | ||
1613 | stack_mask(ctxt)); | ||
1614 | assign_masked(&ctxt->regs[VCPU_REGS_RSP], | ||
1615 | ctxt->regs[VCPU_REGS_RSP] - frame_size, | ||
1616 | stack_mask(ctxt)); | ||
1617 | return X86EMUL_CONTINUE; | ||
1618 | } | ||
1619 | |||
1595 | static int em_leave(struct x86_emulate_ctxt *ctxt) | 1620 | static int em_leave(struct x86_emulate_ctxt *ctxt) |
1596 | { | 1621 | { |
1597 | assign_masked(&ctxt->regs[VCPU_REGS_RSP], ctxt->regs[VCPU_REGS_RBP], | 1622 | assign_masked(&ctxt->regs[VCPU_REGS_RSP], ctxt->regs[VCPU_REGS_RBP], |
@@ -3657,7 +3682,8 @@ static struct opcode opcode_table[256] = { | |||
3657 | I(DstReg | SrcMemFAddr | ModRM | No64 | Src2DS, em_lseg), | 3682 | I(DstReg | SrcMemFAddr | ModRM | No64 | Src2DS, em_lseg), |
3658 | G(ByteOp, group11), G(0, group11), | 3683 | G(ByteOp, group11), G(0, group11), |
3659 | /* 0xC8 - 0xCF */ | 3684 | /* 0xC8 - 0xCF */ |
3660 | N, I(Stack, em_leave), N, I(ImplicitOps | Stack, em_ret_far), | 3685 | I(Stack | SrcImmU16 | Src2ImmByte, em_enter), I(Stack, em_leave), |
3686 | N, I(ImplicitOps | Stack, em_ret_far), | ||
3661 | D(ImplicitOps), DI(SrcImmByte, intn), | 3687 | D(ImplicitOps), DI(SrcImmByte, intn), |
3662 | D(ImplicitOps | No64), II(ImplicitOps, em_iret, iret), | 3688 | D(ImplicitOps | No64), II(ImplicitOps, em_iret, iret), |
3663 | /* 0xD0 - 0xD7 */ | 3689 | /* 0xD0 - 0xD7 */ |