aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm
diff options
context:
space:
mode:
authorAvi Kivity <avi@redhat.com>2012-06-07 10:49:24 -0400
committerAvi Kivity <avi@redhat.com>2012-07-09 07:19:01 -0400
commitf47cfa3174ad8bd39e56524b36e79c463bf820b1 (patch)
tree2bfcce8b48dc11d54fd719899fd3d8d8ff3ba3a3 /arch/x86/kvm
parentb8405c184b4ef3abcebc5cf2211215944d6e2acc (diff)
KVM: x86 emulator: emulate LEAVE
Opcode c9; used by some variants of Windows during boot, in big real mode. Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm')
-rw-r--r--arch/x86/kvm/emulate.c25
1 files changed, 24 insertions, 1 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 24c84251648..33ccd757cb1 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -433,11 +433,27 @@ static int emulator_check_intercept(struct x86_emulate_ctxt *ctxt,
433 return ctxt->ops->intercept(ctxt, &info, stage); 433 return ctxt->ops->intercept(ctxt, &info, stage);
434} 434}
435 435
436static void assign_masked(ulong *dest, ulong src, ulong mask)
437{
438 *dest = (*dest & ~mask) | (src & mask);
439}
440
436static inline unsigned long ad_mask(struct x86_emulate_ctxt *ctxt) 441static inline unsigned long ad_mask(struct x86_emulate_ctxt *ctxt)
437{ 442{
438 return (1UL << (ctxt->ad_bytes << 3)) - 1; 443 return (1UL << (ctxt->ad_bytes << 3)) - 1;
439} 444}
440 445
446static ulong stack_mask(struct x86_emulate_ctxt *ctxt)
447{
448 u16 sel;
449 struct desc_struct ss;
450
451 if (ctxt->mode == X86EMUL_MODE_PROT64)
452 return ~0UL;
453 ctxt->ops->get_segment(ctxt, &sel, &ss, NULL, VCPU_SREG_SS);
454 return ~0U >> ((ss.d ^ 1) * 16); /* d=0: 0xffff; d=1: 0xffffffff */
455}
456
441/* Access/update address held in a register, based on addressing mode. */ 457/* Access/update address held in a register, based on addressing mode. */
442static inline unsigned long 458static inline unsigned long
443address_mask(struct x86_emulate_ctxt *ctxt, unsigned long reg) 459address_mask(struct x86_emulate_ctxt *ctxt, unsigned long reg)
@@ -1560,6 +1576,13 @@ static int em_popf(struct x86_emulate_ctxt *ctxt)
1560 return emulate_popf(ctxt, &ctxt->dst.val, ctxt->op_bytes); 1576 return emulate_popf(ctxt, &ctxt->dst.val, ctxt->op_bytes);
1561} 1577}
1562 1578
1579static int em_leave(struct x86_emulate_ctxt *ctxt)
1580{
1581 assign_masked(&ctxt->regs[VCPU_REGS_RSP], ctxt->regs[VCPU_REGS_RBP],
1582 stack_mask(ctxt));
1583 return emulate_pop(ctxt, &ctxt->regs[VCPU_REGS_RBP], ctxt->op_bytes);
1584}
1585
1563static int em_push_sreg(struct x86_emulate_ctxt *ctxt) 1586static int em_push_sreg(struct x86_emulate_ctxt *ctxt)
1564{ 1587{
1565 int seg = ctxt->src2.val; 1588 int seg = ctxt->src2.val;
@@ -3582,7 +3605,7 @@ static struct opcode opcode_table[256] = {
3582 I(DstReg | SrcMemFAddr | ModRM | No64 | Src2DS, em_lseg), 3605 I(DstReg | SrcMemFAddr | ModRM | No64 | Src2DS, em_lseg),
3583 G(ByteOp, group11), G(0, group11), 3606 G(ByteOp, group11), G(0, group11),
3584 /* 0xC8 - 0xCF */ 3607 /* 0xC8 - 0xCF */
3585 N, N, N, I(ImplicitOps | Stack, em_ret_far), 3608 N, I(Stack, em_leave), N, I(ImplicitOps | Stack, em_ret_far),
3586 D(ImplicitOps), DI(SrcImmByte, intn), 3609 D(ImplicitOps), DI(SrcImmByte, intn),
3587 D(ImplicitOps | No64), II(ImplicitOps, em_iret, iret), 3610 D(ImplicitOps | No64), II(ImplicitOps, em_iret, iret),
3588 /* 0xD0 - 0xD7 */ 3611 /* 0xD0 - 0xD7 */