KVM: x86 emulator: streamline decode of segment registers

The opcodes

  push %seg
  pop %seg
  l%seg, %mem, %reg  (e.g. lds/les/lss/lfs/lgs)

all have an segment register encoded in the instruction.  To allow reuse,
decode the segment number into src2 during the decode stage instead of the
execution stage.

Signed-off-by: Avi Kivity <avi@redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
This commit is contained in:
Avi Kivity 2011-09-13 10:45:49 +03:00
parent 41ddf9784c
commit c191a7a0f4

View File

@ -51,6 +51,12 @@
#define OpImmFAddr 17ull /* Immediate far address */ #define OpImmFAddr 17ull /* Immediate far address */
#define OpMemFAddr 18ull /* Far address in memory */ #define OpMemFAddr 18ull /* Far address in memory */
#define OpImmU16 19ull /* Immediate operand, 16 bits, zero extended */ #define OpImmU16 19ull /* Immediate operand, 16 bits, zero extended */
#define OpES 20ull /* ES */
#define OpCS 21ull /* CS */
#define OpSS 22ull /* SS */
#define OpDS 23ull /* DS */
#define OpFS 24ull /* FS */
#define OpGS 25ull /* GS */
#define OpBits 5 /* Width of operand field */ #define OpBits 5 /* Width of operand field */
#define OpMask ((1ull << OpBits) - 1) #define OpMask ((1ull << OpBits) - 1)
@ -126,6 +132,12 @@
#define Src2ImmByte (OpImmByte << Src2Shift) #define Src2ImmByte (OpImmByte << Src2Shift)
#define Src2One (OpOne << Src2Shift) #define Src2One (OpOne << Src2Shift)
#define Src2Imm (OpImm << Src2Shift) #define Src2Imm (OpImm << Src2Shift)
#define Src2ES (OpES << Src2Shift)
#define Src2CS (OpCS << Src2Shift)
#define Src2SS (OpSS << Src2Shift)
#define Src2DS (OpDS << Src2Shift)
#define Src2FS (OpFS << Src2Shift)
#define Src2GS (OpGS << Src2Shift)
#define Src2Mask (OpMask << Src2Shift) #define Src2Mask (OpMask << Src2Shift)
#define X2(x...) x, x #define X2(x...) x, x
@ -3101,16 +3113,19 @@ static struct gprefix pfx_0f_6f_0f_7f = {
static struct opcode opcode_table[256] = { static struct opcode opcode_table[256] = {
/* 0x00 - 0x07 */ /* 0x00 - 0x07 */
I6ALU(Lock, em_add), I6ALU(Lock, em_add),
D(ImplicitOps | Stack | No64), D(ImplicitOps | Stack | No64), D(ImplicitOps | Stack | No64 | Src2ES),
D(ImplicitOps | Stack | No64 | Src2ES),
/* 0x08 - 0x0F */ /* 0x08 - 0x0F */
I6ALU(Lock, em_or), I6ALU(Lock, em_or),
D(ImplicitOps | Stack | No64), N, D(ImplicitOps | Stack | No64 | Src2CS), N,
/* 0x10 - 0x17 */ /* 0x10 - 0x17 */
I6ALU(Lock, em_adc), I6ALU(Lock, em_adc),
D(ImplicitOps | Stack | No64), D(ImplicitOps | Stack | No64), D(ImplicitOps | Stack | No64 | Src2SS),
D(ImplicitOps | Stack | No64 | Src2SS),
/* 0x18 - 0x1F */ /* 0x18 - 0x1F */
I6ALU(Lock, em_sbb), I6ALU(Lock, em_sbb),
D(ImplicitOps | Stack | No64), D(ImplicitOps | Stack | No64), D(ImplicitOps | Stack | No64 | Src2DS),
D(ImplicitOps | Stack | No64 | Src2DS),
/* 0x20 - 0x27 */ /* 0x20 - 0x27 */
I6ALU(Lock, em_and), N, N, I6ALU(Lock, em_and), N, N,
/* 0x28 - 0x2F */ /* 0x28 - 0x2F */
@ -3178,7 +3193,8 @@ static struct opcode opcode_table[256] = {
D2bv(DstMem | SrcImmByte | ModRM), D2bv(DstMem | SrcImmByte | ModRM),
I(ImplicitOps | Stack | SrcImmU16, em_ret_near_imm), I(ImplicitOps | Stack | SrcImmU16, em_ret_near_imm),
I(ImplicitOps | Stack, em_ret), I(ImplicitOps | Stack, em_ret),
D(DstReg | SrcMemFAddr | ModRM | No64), D(DstReg | SrcMemFAddr | ModRM | No64), D(DstReg | SrcMemFAddr | ModRM | No64 | Src2ES),
D(DstReg | SrcMemFAddr | ModRM | No64 | Src2DS),
G(ByteOp, group11), G(0, group11), G(ByteOp, group11), G(0, group11),
/* 0xC8 - 0xCF */ /* 0xC8 - 0xCF */
N, N, N, I(ImplicitOps | Stack, em_ret_far), N, N, N, I(ImplicitOps | Stack, em_ret_far),
@ -3253,20 +3269,22 @@ static struct opcode twobyte_table[256] = {
/* 0x90 - 0x9F */ /* 0x90 - 0x9F */
X16(D(ByteOp | DstMem | SrcNone | ModRM| Mov)), X16(D(ByteOp | DstMem | SrcNone | ModRM| Mov)),
/* 0xA0 - 0xA7 */ /* 0xA0 - 0xA7 */
D(ImplicitOps | Stack), D(ImplicitOps | Stack), D(Stack | Src2FS), D(Stack | Src2FS),
DI(ImplicitOps, cpuid), D(DstMem | SrcReg | ModRM | BitOp), DI(ImplicitOps, cpuid), D(DstMem | SrcReg | ModRM | BitOp),
D(DstMem | SrcReg | Src2ImmByte | ModRM), D(DstMem | SrcReg | Src2ImmByte | ModRM),
D(DstMem | SrcReg | Src2CL | ModRM), N, N, D(DstMem | SrcReg | Src2CL | ModRM), N, N,
/* 0xA8 - 0xAF */ /* 0xA8 - 0xAF */
D(ImplicitOps | Stack), D(ImplicitOps | Stack), D(Stack | Src2GS), D(Stack | Src2GS),
DI(ImplicitOps, rsm), D(DstMem | SrcReg | ModRM | BitOp | Lock), DI(ImplicitOps, rsm), D(DstMem | SrcReg | ModRM | BitOp | Lock),
D(DstMem | SrcReg | Src2ImmByte | ModRM), D(DstMem | SrcReg | Src2ImmByte | ModRM),
D(DstMem | SrcReg | Src2CL | ModRM), D(DstMem | SrcReg | Src2CL | ModRM),
D(ModRM), I(DstReg | SrcMem | ModRM, em_imul), D(ModRM), I(DstReg | SrcMem | ModRM, em_imul),
/* 0xB0 - 0xB7 */ /* 0xB0 - 0xB7 */
D2bv(DstMem | SrcReg | ModRM | Lock), D2bv(DstMem | SrcReg | ModRM | Lock),
D(DstReg | SrcMemFAddr | ModRM), D(DstMem | SrcReg | ModRM | BitOp | Lock), D(DstReg | SrcMemFAddr | ModRM | Src2SS),
D(DstReg | SrcMemFAddr | ModRM), D(DstReg | SrcMemFAddr | ModRM), D(DstMem | SrcReg | ModRM | BitOp | Lock),
D(DstReg | SrcMemFAddr | ModRM | Src2FS),
D(DstReg | SrcMemFAddr | ModRM | Src2GS),
D(ByteOp | DstReg | SrcMem | ModRM | Mov), D(DstReg | SrcMem16 | ModRM | Mov), D(ByteOp | DstReg | SrcMem | ModRM | Mov), D(DstReg | SrcMem16 | ModRM | Mov),
/* 0xB8 - 0xBF */ /* 0xB8 - 0xBF */
N, N, N, N,
@ -3436,6 +3454,24 @@ static int decode_operand(struct x86_emulate_ctxt *ctxt, struct operand *op,
case OpMemFAddr: case OpMemFAddr:
ctxt->memop.bytes = ctxt->op_bytes + 2; ctxt->memop.bytes = ctxt->op_bytes + 2;
goto mem_common; goto mem_common;
case OpES:
op->val = VCPU_SREG_ES;
break;
case OpCS:
op->val = VCPU_SREG_CS;
break;
case OpSS:
op->val = VCPU_SREG_SS;
break;
case OpDS:
op->val = VCPU_SREG_DS;
break;
case OpFS:
op->val = VCPU_SREG_FS;
break;
case OpGS:
op->val = VCPU_SREG_GS;
break;
case OpImplicit: case OpImplicit:
/* Special instructions do their own operand decoding. */ /* Special instructions do their own operand decoding. */
default: default:
@ -3803,26 +3839,15 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
switch (ctxt->b) { switch (ctxt->b) {
case 0x06: /* push es */ case 0x06: /* push es */
rc = emulate_push_sreg(ctxt, VCPU_SREG_ES); case 0x0e: /* push cs */
case 0x16: /* push ss */
case 0x1e: /* push ds */
rc = emulate_push_sreg(ctxt, ctxt->src2.val);
break; break;
case 0x07: /* pop es */ case 0x07: /* pop es */
rc = emulate_pop_sreg(ctxt, VCPU_SREG_ES);
break;
case 0x0e: /* push cs */
rc = emulate_push_sreg(ctxt, VCPU_SREG_CS);
break;
case 0x16: /* push ss */
rc = emulate_push_sreg(ctxt, VCPU_SREG_SS);
break;
case 0x17: /* pop ss */ case 0x17: /* pop ss */
rc = emulate_pop_sreg(ctxt, VCPU_SREG_SS);
break;
case 0x1e: /* push ds */
rc = emulate_push_sreg(ctxt, VCPU_SREG_DS);
break;
case 0x1f: /* pop ds */ case 0x1f: /* pop ds */
rc = emulate_pop_sreg(ctxt, VCPU_SREG_DS); rc = emulate_pop_sreg(ctxt, ctxt->src2.val);
break;
case 0x40 ... 0x47: /* inc r16/r32 */ case 0x40 ... 0x47: /* inc r16/r32 */
emulate_1op(ctxt, "inc"); emulate_1op(ctxt, "inc");
break; break;
@ -3869,10 +3894,8 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
rc = em_grp2(ctxt); rc = em_grp2(ctxt);
break; break;
case 0xc4: /* les */ case 0xc4: /* les */
rc = emulate_load_segment(ctxt, VCPU_SREG_ES);
break;
case 0xc5: /* lds */ case 0xc5: /* lds */
rc = emulate_load_segment(ctxt, VCPU_SREG_DS); rc = emulate_load_segment(ctxt, ctxt->src2.val);
break; break;
case 0xcc: /* int3 */ case 0xcc: /* int3 */
rc = emulate_int(ctxt, 3); rc = emulate_int(ctxt, 3);
@ -4078,10 +4101,12 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
ctxt->dst.val = test_cc(ctxt->b, ctxt->eflags); ctxt->dst.val = test_cc(ctxt->b, ctxt->eflags);
break; break;
case 0xa0: /* push fs */ case 0xa0: /* push fs */
rc = emulate_push_sreg(ctxt, VCPU_SREG_FS); case 0xa8: /* push gs */
rc = emulate_push_sreg(ctxt, ctxt->src2.val);
break; break;
case 0xa1: /* pop fs */ case 0xa1: /* pop fs */
rc = emulate_pop_sreg(ctxt, VCPU_SREG_FS); case 0xa9: /* pop gs */
rc = emulate_pop_sreg(ctxt, ctxt->src2.val);
break; break;
case 0xa3: case 0xa3:
bt: /* bt */ bt: /* bt */
@ -4094,12 +4119,6 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
case 0xa5: /* shld cl, r, r/m */ case 0xa5: /* shld cl, r, r/m */
emulate_2op_cl(ctxt, "shld"); emulate_2op_cl(ctxt, "shld");
break; break;
case 0xa8: /* push gs */
rc = emulate_push_sreg(ctxt, VCPU_SREG_GS);
break;
case 0xa9: /* pop gs */
rc = emulate_pop_sreg(ctxt, VCPU_SREG_GS);
break;
case 0xab: case 0xab:
bts: /* bts */ bts: /* bts */
emulate_2op_SrcV_nobyte(ctxt, "bts"); emulate_2op_SrcV_nobyte(ctxt, "bts");
@ -4128,18 +4147,14 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
} }
break; break;
case 0xb2: /* lss */ case 0xb2: /* lss */
rc = emulate_load_segment(ctxt, VCPU_SREG_SS); case 0xb4: /* lfs */
case 0xb5: /* lgs */
rc = emulate_load_segment(ctxt, ctxt->src2.val);
break; break;
case 0xb3: case 0xb3:
btr: /* btr */ btr: /* btr */
emulate_2op_SrcV_nobyte(ctxt, "btr"); emulate_2op_SrcV_nobyte(ctxt, "btr");
break; break;
case 0xb4: /* lfs */
rc = emulate_load_segment(ctxt, VCPU_SREG_FS);
break;
case 0xb5: /* lgs */
rc = emulate_load_segment(ctxt, VCPU_SREG_GS);
break;
case 0xb6 ... 0xb7: /* movzx */ case 0xb6 ... 0xb7: /* movzx */
ctxt->dst.bytes = ctxt->op_bytes; ctxt->dst.bytes = ctxt->op_bytes;
ctxt->dst.val = (ctxt->d & ByteOp) ? (u8) ctxt->src.val ctxt->dst.val = (ctxt->d & ByteOp) ? (u8) ctxt->src.val