@samitouri / QOSamiQemu / commits / b7d4ec4832

target/i386/tcg: move VEX validation early

Perform the X86_VEX_REPScalar transformation on X86OpEntry instead of X86DecodedOp; everything else can be checked equally well before immediates are fetched etc. This is especially important for APX, which may decode operands differently depending on the NDD bit: if EVEX.NDD=0, VEX.vvvv is ignored and must be zero. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

Paolo Bonzini committed Dec 23, 2025 at 11:51 UTC b7d4ec4832d427208717c8b726d6dbb214d851a7
1 file changed +30 -24
target/i386/tcg/decode-new.c.inc
+30 -24
@@ -2542,6 +2542,22 @@ static bool decode_ops(DisasContext *s, CPUX86State *env, X86DecodeFunc decode_f
2542 decode->immediate = insn_get_signed(env, s, MO_8);
2543 }
2544
2545 + if (e->vex_class == 12) {
2546 + /* Check no overlap between registers. */
2547 + if (!decode->op[0].has_ea &&
2548 + (decode->op[0].n == decode->mem.index || decode->op[0].n == decode->op[1].n)) {
2549 + return false;
2550 + }
2551 + assert(!decode->op[1].has_ea);
2552 + if (decode->op[1].n == decode->mem.index) {
2553 + return false;
2554 + }
2555 + if (!decode->op[2].has_ea &&
2556 + (decode->op[2].n == decode->mem.index || decode->op[2].n == decode->op[1].n)) {
2557 + return false;
2558 + }
2559 + }
2560 +
2561 return true;
2562 }
2563
@@ -2648,9 +2664,9 @@ static bool validate_vex(DisasContext *s, X86DecodedInsn *decode)
2664 if (s->vex_l) {
2665 goto illegal;
2666 }
2651 - assert(decode->e.s2 == X86_SIZE_x);
2652 - if (decode->op[2].has_ea) {
2653 - decode->op[2].ot = s->prefix & PREFIX_REPZ ? MO_32 : MO_64;
2667 + assert(e->op2 == X86_TYPE_W && e->s2 == X86_SIZE_x);
2668 + if ((s->modrm >> 6) != 3) {
2669 + e->s2 = s->prefix & PREFIX_REPNZ ? X86_SIZE_sd : X86_SIZE_ss;
2670 }
2671 }
2672 break;
@@ -2667,10 +2683,7 @@ static bool validate_vex(DisasContext *s, X86DecodedInsn *decode)
2683
2684 switch (e->vex_class) {
2685 case 0:
2670 - if (s->prefix & PREFIX_VEX) {
2671 - goto illegal;
2672 - }
2673 - return true;
2686 + g_assert_not_reached();
2687 case 1:
2688 case 2:
2689 case 3:
@@ -2695,19 +2708,6 @@ static bool validate_vex(DisasContext *s, X86DecodedInsn *decode)
2708 goto illegal;
2709 }
2710
2698 - /* Check no overlap between registers. */
2699 - if (!decode->op[0].has_ea &&
2700 - (decode->op[0].n == decode->mem.index || decode->op[0].n == decode->op[1].n)) {
2701 - goto illegal;
2702 - }
2703 - assert(!decode->op[1].has_ea);
2704 - if (decode->op[1].n == decode->mem.index) {
2705 - goto illegal;
2706 - }
2707 - if (!decode->op[2].has_ea &&
2708 - (decode->op[2].n == decode->mem.index || decode->op[2].n == decode->op[1].n)) {
2709 - goto illegal;
2710 - }
2711 /* fall through */
2712 case 6:
2713 case 11:
@@ -3024,6 +3024,16 @@ static void disas_insn(DisasContext *s, CPUState *cpu)
3024 get_modrm(s, env);
3025 }
3026
3027 + if (decode.e.vex_class == 0) {
3028 + if (s->prefix & PREFIX_VEX) {
3029 + goto illegal_op;
3030 + }
3031 + } else {
3032 + if (!validate_vex(s, &decode)) {
3033 + return;
3034 + }
3035 + }
3036 +
3037 if (!decode_ops(s, env, decode_func, &decode)) {
3038 goto illegal_op;
3039 }
@@ -3085,10 +3095,6 @@ static void disas_insn(DisasContext *s, CPUState *cpu)
3095 goto illegal_op;
3096 }
3097
3088 - if (!validate_vex(s, &decode)) {
3089 - return;
3090 - }
3091 -
3098 /*
3099 * Checks that result in #GP or VMEXIT come second. Intercepts are
3100 * generally checked after non-memory exceptions (i.e. after all