Clear x86_default_fpu STX/MMX register state at boot
authorMichael Taufen <mtaufen@gmail.com>
Tue, 12 Apr 2016 16:22:17 +0000 (09:22 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 14 Apr 2016 21:27:47 +0000 (17:27 -0400)
Also improved some comments

Signed-off-by: Michael Taufen <mtaufen@gmail.com>
Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/arch/x86/init.c
kern/arch/x86/smp_boot.c

index 4c02909..60fd72b 100644 (file)
@@ -122,14 +122,21 @@ void ancillary_state_init(void)
                // It may be possible for memset to clobber SSE registers.
                memset(&x86_default_fpu, 0x00, sizeof(struct ancillary_state));
 
-               // FNINIT clears FIP and FDP and, even though it is technically a
-               // control instruction, it clears FOP while initializing the FPU.
+               /*
+                * FNINIT clears FIP and FDP and, even though it is technically a
+                * control instruction, it clears FOP while initializing the FPU.
+                *
+                * This marks the STX/MMX registers as empty in the FPU tag word,
+                * but does not actually clear the values in the registers,
+                * so we manually clear them in the xsave area after saving.
+                */
                asm volatile ("fninit");
 
                /*
                 * Save only the x87 FPU state so that the extended state registers
-                * remain zeroed in the default. There is a caveat to this that
-                * involves the MXCSR register, this is handled below.
+                * remain zeroed in the default. The MXCSR is in a separate state
+                * component (SSE), so we manually set its value in the default state.
+                *
                 * We use XSAVE64 instead of XSAVEOPT64 (save_fp_state uses
                 * XSAVEOPT64), because XSAVEOPT64 may decide to skip saving a state
                 * component if that state component is in its initial configuration,
@@ -141,6 +148,9 @@ void ancillary_state_init(void)
                eax = 0x1;
                asm volatile("xsave64 %0" : : "m"(x86_default_fpu), "a"(eax), "d"(edx));
 
+               // Clear junk that might have been saved from STX/MMX registers
+               memset(&(x86_default_fpu.st0_mm0), 0x00, 128);
+
                /* We must set the MXCSR field in the default state struct to its
                 * power-on value of 0x1f80. This masks all SIMD floating
                 * point exceptions and clears all SIMD floating-point exception
@@ -176,21 +186,29 @@ void ancillary_state_init(void)
                // It may be possible for memset to clobber SSE registers.
                memset(&x86_default_fpu, 0x00, sizeof(struct ancillary_state));
 
-               // FNINIT clears FIP and FDP and, even though it is technically a
-               // control instruction, it clears FOP while initializing the FPU.
+               /*
+                * FNINIT clears FIP and FDP and, even though it is technically a
+                * control instruction, it clears FOP while initializing the FPU.
+                *
+                * This marks the STX/MMX registers as empty in the FPU tag word,
+                * but does not actually clear the values in the registers,
+                * so we manually clear them in the xsave area after saving.
+                */
                asm volatile ("fninit");
 
                // Save the x87 FPU state
                asm volatile("fxsave64 %0" : : "m"(x86_default_fpu));
 
                /*
-                * Because FXSAVE may have also saved junk from the XMM registers,
+                * Clear junk that might have been saved from the STX/MMX registers.
+                *
+                * FXSAVE may have also saved junk from the XMM registers,
                 * depending on how the hardware was implemented and the setting
-                * of CR4.OSFXSR, we manually zero the region of the ancillary_state
-                * containing those registers after saving FPU state. There are 16
-                * XMM registers, each 128 bits, for a total size of 256 bytes.
+                * of CR4.OSFXSR. So we clear that too.
+                *
+                * MMX: 128 bytes, XMM: 256 bytes
                 */
-               memset(&(x86_default_fpu.xmm0), 0x00, 256);
+               memset(&(x86_default_fpu.st0_mm0), 0x00, 128 + 256);
 
                /*
                 * Finally, because Only the Paranoid Survive, we set the MXCSR
index ba50b1a..efb11e2 100644 (file)
@@ -289,7 +289,7 @@ void __arch_pcpu_init(uint32_t coreid)
        /*
         * Enable SSE instructions.
         * CR4.OSFXSR enables SSE and ensures that MXCSR/XMM gets saved with FXSAVE
-        * CR4.OSXSAVE enables XSAVE instructions. Only set if XSAVEOPT supported.
+        * CR4.OSXSAVE enables XSAVE instructions. Only set if XSAVE supported.
         * CR4.OSXMME indicates OS support for software exception handlers for
         * SIMD floating-point exceptions (turn it on to get #XM exceptions
         * in the event of a SIMD error instead of #UD exceptions).