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 <pbonzini@redhat.com>
---
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