Skip to content

Commit

Permalink
KVM: x86 emulator: handle "far address" source operand
Browse files Browse the repository at this point in the history
ljmp/lcall instruction operand contains address and segment.
It can be 10 bytes long. Currently we decode it as two different
operands. Fix it by introducing new kind of operand that can hold
entire far address.

Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
  • Loading branch information
Gleb Natapov authored and Avi Kivity committed Aug 1, 2010
1 parent b8a9894 commit 414e627
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 25 deletions.
6 changes: 5 additions & 1 deletion arch/x86/include/asm/kvm_emulate.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,11 @@ struct x86_emulate_ops {
struct operand {
enum { OP_REG, OP_MEM, OP_IMM, OP_NONE } type;
unsigned int bytes;
unsigned long val, orig_val, *ptr;
unsigned long orig_val, *ptr;
union {
unsigned long val;
char valptr[sizeof(unsigned long) + 2];
};
};

struct fetch_cache {
Expand Down
56 changes: 32 additions & 24 deletions arch/x86/kvm/emulate.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@
#define SrcImmUByte (8<<4) /* 8-bit unsigned immediate operand. */
#define SrcImmU (9<<4) /* Immediate operand, unsigned */
#define SrcSI (0xa<<4) /* Source is in the DS:RSI */
#define SrcImmFAddr (0xb<<4) /* Source is immediate far address */
#define SrcMemFAddr (0xc<<4) /* Source is far address in memory */
#define SrcMask (0xf<<4)
/* Generic ModRM decode. */
#define ModRM (1<<8)
Expand All @@ -88,10 +90,6 @@
#define Src2CL (1<<29)
#define Src2ImmByte (2<<29)
#define Src2One (3<<29)
#define Src2Imm16 (4<<29)
#define Src2Mem16 (5<<29) /* Used for Ep encoding. First argument has to be
in memory and second argument is located
immediately after the first one in memory. */
#define Src2Mask (7<<29)

enum {
Expand Down Expand Up @@ -175,7 +173,7 @@ static u32 opcode_table[256] = {
/* 0x90 - 0x97 */
DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg,
/* 0x98 - 0x9F */
0, 0, SrcImm | Src2Imm16 | No64, 0,
0, 0, SrcImmFAddr | No64, 0,
ImplicitOps | Stack, ImplicitOps | Stack, 0, 0,
/* 0xA0 - 0xA7 */
ByteOp | DstReg | SrcMem | Mov | MemAbs, DstReg | SrcMem | Mov | MemAbs,
Expand Down Expand Up @@ -215,7 +213,7 @@ static u32 opcode_table[256] = {
ByteOp | SrcImmUByte | DstAcc, SrcImmUByte | DstAcc,
/* 0xE8 - 0xEF */
SrcImm | Stack, SrcImm | ImplicitOps,
SrcImmU | Src2Imm16 | No64, SrcImmByte | ImplicitOps,
SrcImmFAddr | No64, SrcImmByte | ImplicitOps,
SrcNone | ByteOp | DstAcc, SrcNone | DstAcc,
SrcNone | ByteOp | DstAcc, SrcNone | DstAcc,
/* 0xF0 - 0xF7 */
Expand Down Expand Up @@ -350,7 +348,7 @@ static u32 group_table[] = {
[Group5*8] =
DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM,
SrcMem | ModRM | Stack, 0,
SrcMem | ModRM | Stack, SrcMem | ModRM | Src2Mem16 | ImplicitOps,
SrcMem | ModRM | Stack, SrcMemFAddr | ModRM | ImplicitOps,
SrcMem | ModRM | Stack, 0,
[Group7*8] =
0, 0, ModRM | SrcMem | Priv, ModRM | SrcMem | Priv,
Expand Down Expand Up @@ -576,6 +574,13 @@ static u32 group2_table[] = {
(_type)_x; \
})

#define insn_fetch_arr(_arr, _size, _eip) \
({ rc = do_insn_fetch(ctxt, ops, (_eip), _arr, (_size)); \
if (rc != X86EMUL_CONTINUE) \
goto done; \
(_eip) += (_size); \
})

static inline unsigned long ad_mask(struct decode_cache *c)
{
return (1UL << (c->ad_bytes << 3)) - 1;
Expand Down Expand Up @@ -1160,6 +1165,17 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
c->regs[VCPU_REGS_RSI]);
c->src.val = 0;
break;
case SrcImmFAddr:
c->src.type = OP_IMM;
c->src.ptr = (unsigned long *)c->eip;
c->src.bytes = c->op_bytes + 2;
insn_fetch_arr(c->src.valptr, c->src.bytes, c->eip);
break;
case SrcMemFAddr:
c->src.type = OP_MEM;
c->src.ptr = (unsigned long *)c->modrm_ea;
c->src.bytes = c->op_bytes + 2;
break;
}

/*
Expand All @@ -1179,22 +1195,10 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
c->src2.bytes = 1;
c->src2.val = insn_fetch(u8, 1, c->eip);
break;
case Src2Imm16:
c->src2.type = OP_IMM;
c->src2.ptr = (unsigned long *)c->eip;
c->src2.bytes = 2;
c->src2.val = insn_fetch(u16, 2, c->eip);
break;
case Src2One:
c->src2.bytes = 1;
c->src2.val = 1;
break;
case Src2Mem16:
c->src2.type = OP_MEM;
c->src2.bytes = 2;
c->src2.ptr = (unsigned long *)(c->modrm_ea + c->src.bytes);
c->src2.val = 0;
break;
}

/* Decode and fetch the destination operand: register or memory. */
Expand Down Expand Up @@ -2558,7 +2562,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)

if (c->src.type == OP_MEM) {
rc = read_emulated(ctxt, ops, (unsigned long)c->src.ptr,
&c->src.val, c->src.bytes);
c->src.valptr, c->src.bytes);
if (rc != X86EMUL_CONTINUE)
goto done;
c->src.orig_val = c->src.val;
Expand Down Expand Up @@ -2884,14 +2888,18 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
}
case 0xe9: /* jmp rel */
goto jmp;
case 0xea: /* jmp far */
case 0xea: { /* jmp far */
unsigned short sel;
jump_far:
if (load_segment_descriptor(ctxt, ops, c->src2.val,
VCPU_SREG_CS))
memcpy(&sel, c->src.valptr + c->op_bytes, 2);

if (load_segment_descriptor(ctxt, ops, sel, VCPU_SREG_CS))
goto done;

c->eip = c->src.val;
c->eip = 0;
memcpy(&c->eip, c->src.valptr, c->op_bytes);
break;
}
case 0xeb:
jmp: /* jmp rel short */
jmp_rel(c, c->src.val);
Expand Down

0 comments on commit 414e627

Please sign in to comment.