Skip to contentSkip to conversation

target/i386: Fixed CR0.TS check in gen_sse

PATCH In review Alexandro Sanchez Bach 2 participants 2 messages May 29, 2018 – Jun 27, 2018

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 target/i386: Fixed CR0.TS check in gen_sse

The function gen_sse assumes all of its instructions require CR0.TS=0. However, integer extensions at 0F 38 F[0-F] and 0F 3A F[0-F] such as CRC32, MOVBE, ADX, BMI1, BMI2 that are handled by gen_sse are not supposed to throw an exception in this scenario. This causes issues while booting some FreeBSD-based guests.

target/i386/translate.c +0 -0
index 7c21814676..079ab7afef 100644
@@ -3049,8 +3049,16 @@ static void gen_sse(CPUX86State *env, DisasContext

*s, int b,

             is_xmm = 1;
         }
     }
+
+    modrm = x86_ldub_code(env, s);
+    reg = ((modrm >> 3) & 7);
+    if (is_xmm)
+        reg |= rex_r;
+    mod = (modrm >> 6) & 3;
+
     /* simple MMX/SSE operation */
-    if (s->flags & HF_TS_MASK) {
+    if (s->flags & HF_TS_MASK
+        && ((b != 0x38 && b != 0x3A) || !(modrm & 0xF0))) {
         gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
         return;
     }
@@ -3084,11 +3092,6 @@ static void gen_sse(CPUX86State *env, DisasContext
*s, int b,
         gen_helper_enter_mmx(cpu_env);
     }
-    modrm = x86_ldub_code(env, s);
-    reg = ((modrm >> 3) & 7);
-    if (is_xmm)
-        reg |= rex_r;
-    mod = (modrm >> 6) & 3;
     if (sse_fn_epp == SSE_SPECIAL) {
         b |= (b1 << 8);
         switch(b) {
#1 lore raw
Quoted 14 lines · Alexandro Sanchez Bach

The function gen_sse assumes all of its instructions require CR0.TS=0. However, integer extensions at 0F 38 F[0-F] and 0F 3A F[0-F] such as CRC32, MOVBE, ADX, BMI1, BMI2 that are handled by gen_sse are not supposed to throw an exception in this scenario. This causes issues while booting some FreeBSD-based guests.

target/i386/translate.c +0 -0
index 7c21814676..079ab7afef 100644

target/i386/translate.c static void gen_sse(CPUX86State *env, DisasContext · line 3058

Quoted 10 lines
target/i386/translate.c +6 -0
@@ -3049,8 +3049,16 @@ static void gen_sse(CPUX86State *env, DisasContext
 *s, int b,
             is_xmm = 1;
         }
     }
+
+    modrm = x86_ldub_code(env, s);
+    reg = ((modrm >> 3) & 7);
+    if (is_xmm)
+        reg |= rex_r;
+    mod = (modrm >> 6) & 3;

The problem here is that EMMS and FEMMS instructions do not have a mod/rm byte. However, this change should apply easily on top of another patch to move EMMS and FEMMS out of gen_sse.

I'll queue the patch, and wait applying it until I have time to do that other change (or someone else does it ;)).

Thanks,

Paolo

Quoted 23 lines
target/i386/translate.c +2 -6
     /* simple MMX/SSE operation */
-    if (s->flags & HF_TS_MASK) {
+    if (s->flags & HF_TS_MASK
+        && ((b != 0x38 && b != 0x3A) || !(modrm & 0xF0))) {
         gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
         return;
     }
@@ -3084,11 +3092,6 @@ static void gen_sse(CPUX86State *env, DisasContext
 *s, int b,
         gen_helper_enter_mmx(cpu_env);
     }
 
-    modrm = x86_ldub_code(env, s);
-    reg = ((modrm >> 3) & 7);
-    if (is_xmm)
-        reg |= rex_r;
-    mod = (modrm >> 6) & 3;
     if (sse_fn_epp == SSE_SPECIAL) {
         b |= (b1 << 8);
         switch(b) {