As a first step towards handling EVEX prefixes, fetch the modrm byte before decode_ops(). This way, EVEX validation can use the mod bits: for example, APX instructions require X4=0 if the r/m operand is a register.
Signed-off-by: Paolo Bonzini <[email protected]> --- target/i386/tcg/decode-new.c.inc | 65 ++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 15 deletions(-) diff --git a/target/i386/tcg/decode-new.c.inc b/target/i386/tcg/decode-new.c.inc index d8a5025ac07..3205a046a6b 100644 --- a/target/i386/tcg/decode-new.c.inc +++ b/target/i386/tcg/decode-new.c.inc @@ -2085,9 +2085,8 @@ static int reg_nb_mask(DisasContext *s, int unit) static void decode_modrm(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode, X86DecodedOp *op) { - int modrm = get_modrm(s, env); - int mod = (modrm >> 6) & 3; - int rm = modrm & 7; + int mod = (s->modrm >> 6) & 3; + int rm = s->modrm & 7; bool is_vsib = decode->e.vex_class == 12; int sib = -1; @@ -2296,11 +2295,33 @@ static bool decode_op_size(DisasContext *s, X86OpEntry *e, X86OpSize size, MemOp } } +static bool op_has_modrm(X86OpType type) +{ + switch (type) { + case X86_TYPE_C: /* REG in the modrm byte selects a control register */ + case X86_TYPE_D: /* REG in the modrm byte selects a debug register */ + case X86_TYPE_E: /* ALU modrm operand */ + case X86_TYPE_EM: /* modrm byte selects an ALU memory operand */ + case X86_TYPE_G: /* REG in the modrm byte selects a GPR */ + case X86_TYPE_M: /* modrm byte selects a memory operand */ + case X86_TYPE_nop: /* modrm operand decoded but not fetched */ + case X86_TYPE_N: /* R/M in the modrm byte selects an MMX register */ + case X86_TYPE_P: /* REG in the modrm byte selects an MMX register */ + case X86_TYPE_Q: /* MMX modrm operand */ + case X86_TYPE_R: /* R/M in the modrm byte selects a register */ + case X86_TYPE_U: /* R/M in the modrm byte selects an XMM/YMM register */ + case X86_TYPE_V: /* reg in the modrm byte selects an XMM/YMM register */ + case X86_TYPE_WM: /* modrm byte selects an XMM/YMM memory operand */ + case X86_TYPE_W: /* XMM/YMM modrm operand */ + return true; + default: + return false; + } +} + static bool decode_op(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode, X86DecodedOp *op, X86OpType type, int b) { - int modrm; - switch (type) { case X86_TYPE_None: /* Implicit or absent */ case X86_TYPE_A: /* Implicit */ @@ -2316,7 +2337,7 @@ static bool decode_op(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode, case X86_TYPE_C: /* REG in the modrm byte selects a control register */ op->unit = X86_OP_CR; - op->n = ((get_modrm(s, env) >> 3) & 7) | REX_R(s); + op->n = ((s->modrm >> 3) & 7) | REX_R(s); if (op->n == 0 && (s->prefix & PREFIX_LOCK) && (s->cpuid_ext3_features & CPUID_EXT3_CR8LEG)) { op->n = 8; @@ -2332,7 +2353,7 @@ static bool decode_op(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode, case X86_TYPE_D: /* REG in the modrm byte selects a debug register */ op->unit = X86_OP_DR; - op->n = ((get_modrm(s, env) >> 3) & 7) | REX_R(s); + op->n = ((s->modrm >> 3) & 7) | REX_R(s); if (op->n >= 8) { /* * illegal opcode. The DR4 and DR5 case is checked in the generated @@ -2351,14 +2372,14 @@ static bool decode_op(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode, case X86_TYPE_S: /* reg selects a segment register */ op->unit = X86_OP_SEG; - op->n = (get_modrm(s, env) >> 3) & 7; + op->n = (s->modrm >> 3) & 7; /* Values outside [CDEFGS]S, as well as storing to CS, are invalid. */ if (op->n >= 6 || (op->n == R_CS && op == &decode->op[0])) { return false; } break; - case X86_TYPE_P: + case X86_TYPE_P: /* REG in the modrm byte selects an MMX register */ op->unit = X86_OP_MMX; goto get_reg; @@ -2370,7 +2391,7 @@ static bool decode_op(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode, op->unit = X86_OP_SSE; } get_reg: - op->n = ((get_modrm(s, env) >> 3) & 7); + op->n = ((s->modrm >> 3) & 7); op->n |= REX_R(s) & reg_nb_mask(s, op->unit); break; @@ -2407,8 +2428,7 @@ static bool decode_op(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode, case X86_TYPE_R: /* R/M in the modrm byte selects a register */ op->unit = X86_OP_INT; get_modrm_reg: - modrm = get_modrm(s, env); - if ((modrm >> 6) != 3) { + if ((s->modrm >> 6) != 3) { return false; } goto get_modrm; @@ -2422,8 +2442,7 @@ static bool decode_op(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode, /* fall through */ case X86_TYPE_M: /* modrm byte selects a memory operand */ get_modrm_mem: - modrm = get_modrm(s, env); - if ((modrm >> 6) == 3) { + if ((s->modrm >> 6) == 3) { return false; } /* fall through */ @@ -2531,7 +2550,7 @@ static bool decode_insn(DisasContext *s, CPUX86State *env, X86DecodeFunc decode_ return false; } - /* First compute size of operands in order to initialize s->rip_offset. */ + /* Compute size of operands here in order to initialize s->rip_offset. */ if (e->op0 != X86_TYPE_None) { if (!decode_op_size(s, e, e->s0, &decode->op[0].ot)) { return false; @@ -2564,6 +2583,13 @@ static bool decode_insn(DisasContext *s, CPUX86State *env, X86DecodeFunc decode_ assert(e->op3 == X86_TYPE_I && e->s3 == X86_SIZE_b); s->rip_offset += 1; } + return true; +} + +static bool decode_ops(DisasContext *s, CPUX86State *env, X86DecodeFunc decode_func, + X86DecodedInsn *decode) +{ + X86OpEntry *e = &decode->e; if (e->op0 != X86_TYPE_None && !decode_op(s, env, decode, &decode->op[0], e->op0, decode->b)) { @@ -3087,6 +3113,15 @@ static void disas_insn(DisasContext *s, CPUState *cpu) } } + if (op_has_modrm(decode.e.op0) || op_has_modrm(decode.e.op1) || + op_has_modrm(decode.e.op2)) { + get_modrm(s, env); + } + + if (!decode_ops(s, env, decode_func, &decode)) { + goto illegal_op; + } + switch (decode.e.special) { case X86_SPECIAL_None: break; -- 2.52.0
