qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v2 07/42] Enforce VEX encoding restrictions


From: Paolo Bonzini
Subject: Re: [PATCH v2 07/42] Enforce VEX encoding restrictions
Date: Wed, 27 Apr 2022 11:08:19 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.8.0

On 4/25/22 00:01, Paul Brook wrote:
+/* If a VEX prefix is used then it must have V=1111b */
+#define CHECK_AVX_V0(s) do { \
+    CHECK_AVX(s); \
+    if ((s->prefix & PREFIX_VEX) && (s->vex_v != 0)) \
+        goto illegal_op; \
+    } while (0)
+

What do you think about

#define CHECK_AVX(s, flags) \
    do {
        if ((s->prefix & PREFIX_VEX) && !(env->hflags & HF_AVX_EN_MASK)) {
            goto illegal_op;
        }
        if ((flags) & SSE_OPF_AVX2) {
            CHECK_AVX2(s);
        }
        if ((flags) & SSE_OPF_AVX_128) {
            CHECK_AVX_128(s);
        }
        if ((flags) & SSE_OPF_V0) {
            CHECK_V0(s);
        }
    }

Macros such as CHECK_AVX_V0_128(s) would become CHECK_AVX(s, SSE_OPF_V0 | SSE_OPF_AVX_128); a bit longer but still bearable. And here you would have:

          case 0x210: /* movss xmm, ea */
              if (mod != 3) {
+                CHECK_AVX_V0_128(s);
                  gen_lea_modrm(env, s, modrm);
                  gen_op_ld_v(s, MO_32, s->T0, s->A0);
                  tcg_gen_st32_tl(s->T0, cpu_env,
@@ -3379,6 +3432,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
                  tcg_gen_st32_tl(s->T0, cpu_env,
                                  offsetof(CPUX86State, 
xmm_regs[reg].ZMM_L(3)));
              } else {
+                CHECK_AVX_128(s);

    CHECK_AVX(s, SSE_OPF_AVX_128);
    if (mod != 3) {
        CHECK_V0(s);
        ...
    } else {
        ...
    }

Another possibility is to add SSE_OPF_V0_MEM (i.e. V0 if mod != 3), and use

    CHECK_AVX(s, SSE_OPF_AVX_128 | SSE_OPF_AVX_V0_MEM);


It's okay not to move _all_ flags checks in the macros, but for example here:

+            if (op6.ext_mask == CPUID_EXT_AVX
+                    && (s->prefix & PREFIX_VEX) == 0) {
+                goto illegal_op;
+            }
+            if (op6.flags & SSE_OPF_AVX2) {
+                CHECK_AVX2(s);
+            }
+
              if (b1) {
+                if (op6.flags & SSE_OPF_V0) {
+                    CHECK_AVX_V0(s);
+                } else {
+                    CHECK_AVX(s);
+                }
                  op1_offset = offsetof(CPUX86State,xmm_regs[reg]);
+
+                if (op6.flags & SSE_OPF_MMX) {
+                    CHECK_AVX2_256(s);
+                }

there is a lot of room for using a flags-extended CHECK_AVX macro.


Also, SSE_OPF_V0 seems overloaded, because it means depending on the place in the code:

- always 2-operand

- 2-operand except if SCALAR && !CMP

- 2-operand except if SCALAR && !CMP && has REPZ/REPNZ prefixes

It is not clear to me if the former overlaps with the last (i.e. if there are any SCALAR && !CMP operations that are always 2-operand). If so, please use different constants for all three; if not, please use a different constant for the last, e.g. SSE_OPF_V0 and SSE_OPF_VEC_V0, so that the difference is visible in the flags-extended CHECK_AVX macro.

Also related to overloading, here and in patch 37 there is code like this:

+            if (op7.flags & SSE_OPF_BLENDV && !(s->prefix & PREFIX_VEX)) {
+                /* Only VEX encodings are valid for these blendv opcodes */
+                goto illegal_op;
+            }

If this is for all SSE_OPF_BLENDV operations, it can be handled in the flags-enabled CHECK_AVX() macro above. If it is only for some, it should be a new flag SSE_OPF_VEX_ONLY.

Finally (replying here just to keep things together), patch 29 has "We abuse the SSE_OPF_SCALAR flag to select the memory operand width appropriately". Please don't; use a separate function that takes in "b" and returns a bool, with just a switch statement in it.

+            CHECK_AVX(s);
+            scalar_op = (s->prefix & PREFIX_VEX)
+                && (op7.flags & SSE_OPF_SCALAR)
+                && !(op7.flags & SSE_OPF_CMP);
+            if (is_xmm && (op7.flags & SSE_OPF_MMX)) {
+                CHECK_AVX2_256(s);
+            }

I think the is_xmm check is always true here (inside case 0x03a: case 0x13a:, i.e. b is inside the 0x10..0x5f range)?

Paolo



reply via email to

[Prev in Thread] Current Thread [Next in Thread]