Author: kib
Date: Tue Jul 31 10:18:30 2018
New Revision: 336963
URL: https://svnweb.freebsd.org/changeset/base/336963

Log:
  MFC r336683:
  Extend ranges of the critical sections to ensure that context switch
  code never sees FPU pcb flags not consistent with the hardware state.

Modified:
  stable/11/sys/amd64/amd64/fpu.c
  stable/11/sys/amd64/amd64/machdep.c
  stable/11/sys/i386/i386/machdep.c
  stable/11/sys/i386/isa/npx.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/amd64/amd64/fpu.c
==============================================================================
--- stable/11/sys/amd64/amd64/fpu.c     Tue Jul 31 06:27:05 2018        
(r336962)
+++ stable/11/sys/amd64/amd64/fpu.c     Tue Jul 31 10:18:30 2018        
(r336963)
@@ -744,22 +744,22 @@ fpugetregs(struct thread *td)
        int max_ext_n, i, owned;
 
        pcb = td->td_pcb;
+       critical_enter();
        if ((pcb->pcb_flags & PCB_USERFPUINITDONE) == 0) {
                bcopy(fpu_initialstate, get_pcb_user_save_pcb(pcb),
                    cpu_max_ext_state_size);
                get_pcb_user_save_pcb(pcb)->sv_env.en_cw =
                    pcb->pcb_initial_fpucw;
                fpuuserinited(td);
+               critical_exit();
                return (_MC_FPOWNED_PCB);
        }
-       critical_enter();
        if (td == PCPU_GET(fpcurthread) && PCB_USER_FPU(pcb)) {
                fpusave(get_pcb_user_save_pcb(pcb));
                owned = _MC_FPOWNED_FPU;
        } else {
                owned = _MC_FPOWNED_PCB;
        }
-       critical_exit();
        if (use_xsave) {
                /*
                 * Handle partially saved state.
@@ -779,6 +779,7 @@ fpugetregs(struct thread *td)
                        *xstate_bv |= bit;
                }
        }
+       critical_exit();
        return (owned);
 }
 
@@ -787,6 +788,7 @@ fpuuserinited(struct thread *td)
 {
        struct pcb *pcb;
 
+       CRITICAL_ASSERT(td);
        pcb = td->td_pcb;
        if (PCB_USER_FPU(pcb))
                set_pcb_flags(pcb,
@@ -845,26 +847,25 @@ fpusetregs(struct thread *td, struct savefpu *addr, ch
 
        addr->sv_env.en_mxcsr &= cpu_mxcsr_mask;
        pcb = td->td_pcb;
+       error = 0;
        critical_enter();
        if (td == PCPU_GET(fpcurthread) && PCB_USER_FPU(pcb)) {
                error = fpusetxstate(td, xfpustate, xfpustate_size);
-               if (error != 0) {
-                       critical_exit();
-                       return (error);
+               if (error == 0) {
+                       bcopy(addr, get_pcb_user_save_td(td), sizeof(*addr));
+                       fpurestore(get_pcb_user_save_td(td));
+                       set_pcb_flags(pcb, PCB_FPUINITDONE |
+                           PCB_USERFPUINITDONE);
                }
-               bcopy(addr, get_pcb_user_save_td(td), sizeof(*addr));
-               fpurestore(get_pcb_user_save_td(td));
-               critical_exit();
-               set_pcb_flags(pcb, PCB_FPUINITDONE | PCB_USERFPUINITDONE);
        } else {
-               critical_exit();
                error = fpusetxstate(td, xfpustate, xfpustate_size);
-               if (error != 0)
-                       return (error);
-               bcopy(addr, get_pcb_user_save_td(td), sizeof(*addr));
-               fpuuserinited(td);
+               if (error == 0) {
+                       bcopy(addr, get_pcb_user_save_td(td), sizeof(*addr));
+                       fpuuserinited(td);
+               }
        }
-       return (0);
+       critical_exit();
+       return (error);
 }
 
 /*
@@ -1037,6 +1038,7 @@ fpu_kern_enter(struct thread *td, struct fpu_kern_ctx 
                ctx->flags = FPU_KERN_CTX_DUMMY | FPU_KERN_CTX_INUSE;
                return (0);
        }
+       critical_enter();
        KASSERT(!PCB_USER_FPU(pcb) || pcb->pcb_save ==
            get_pcb_user_save_pcb(pcb), ("mangled pcb_save"));
        ctx->flags = FPU_KERN_CTX_INUSE;
@@ -1047,6 +1049,7 @@ fpu_kern_enter(struct thread *td, struct fpu_kern_ctx 
        pcb->pcb_save = fpu_kern_ctx_savefpu(ctx);
        set_pcb_flags(pcb, PCB_KERNFPU);
        clear_pcb_flags(pcb, PCB_FPUINITDONE);
+       critical_exit();
        return (0);
 }
 
@@ -1065,7 +1068,6 @@ fpu_kern_leave(struct thread *td, struct fpu_kern_ctx 
 
                clear_pcb_flags(pcb,  PCB_FPUNOSAVE | PCB_FPUINITDONE);
                start_emulating();
-               critical_exit();
        } else {
                KASSERT((ctx->flags & FPU_KERN_CTX_INUSE) != 0,
                    ("leaving not inuse ctx"));
@@ -1079,7 +1081,6 @@ fpu_kern_leave(struct thread *td, struct fpu_kern_ctx 
                critical_enter();
                if (curthread == PCPU_GET(fpcurthread))
                        fpudrop();
-               critical_exit();
                pcb->pcb_save = ctx->prev;
        }
 
@@ -1096,6 +1097,7 @@ fpu_kern_leave(struct thread *td, struct fpu_kern_ctx 
                        clear_pcb_flags(pcb, PCB_FPUINITDONE);
                KASSERT(!PCB_USER_FPU(pcb), ("unpaired fpu_kern_leave"));
        }
+       critical_exit();
        return (0);
 }
 

Modified: stable/11/sys/amd64/amd64/machdep.c
==============================================================================
--- stable/11/sys/amd64/amd64/machdep.c Tue Jul 31 06:27:05 2018        
(r336962)
+++ stable/11/sys/amd64/amd64/machdep.c Tue Jul 31 10:18:30 2018        
(r336963)
@@ -2158,8 +2158,10 @@ int
 set_fpregs(struct thread *td, struct fpreg *fpregs)
 {
 
+       critical_enter();
        set_fpregs_xmm(fpregs, get_pcb_user_save_td(td));
        fpuuserinited(td);
+       critical_exit();
        return (0);
 }
 

Modified: stable/11/sys/i386/i386/machdep.c
==============================================================================
--- stable/11/sys/i386/i386/machdep.c   Tue Jul 31 06:27:05 2018        
(r336962)
+++ stable/11/sys/i386/i386/machdep.c   Tue Jul 31 10:18:30 2018        
(r336963)
@@ -3004,6 +3004,7 @@ int
 set_fpregs(struct thread *td, struct fpreg *fpregs)
 {
 
+       critical_enter();
        if (cpu_fxsr)
                npx_set_fpregs_xmm((struct save87 *)fpregs,
                    &get_pcb_user_save_td(td)->sv_xmm);
@@ -3011,6 +3012,7 @@ set_fpregs(struct thread *td, struct fpreg *fpregs)
                bcopy(fpregs, &get_pcb_user_save_td(td)->sv_87,
                    sizeof(*fpregs));
        npxuserinited(td);
+       critical_exit();
        return (0);
 }
 

Modified: stable/11/sys/i386/isa/npx.c
==============================================================================
--- stable/11/sys/i386/isa/npx.c        Tue Jul 31 06:27:05 2018        
(r336962)
+++ stable/11/sys/i386/isa/npx.c        Tue Jul 31 10:18:30 2018        
(r336963)
@@ -974,14 +974,15 @@ npxgetregs(struct thread *td)
                return (_MC_FPOWNED_NONE);
 
        pcb = td->td_pcb;
+       critical_enter();
        if ((pcb->pcb_flags & PCB_NPXINITDONE) == 0) {
                bcopy(npx_initialstate, get_pcb_user_save_pcb(pcb),
                    cpu_max_ext_state_size);
                SET_FPU_CW(get_pcb_user_save_pcb(pcb), pcb->pcb_initial_npxcw);
                npxuserinited(td);
+               critical_exit();
                return (_MC_FPOWNED_PCB);
        }
-       critical_enter();
        if (td == PCPU_GET(fpcurthread)) {
                fpusave(get_pcb_user_save_pcb(pcb));
                if (!cpu_fxsr)
@@ -995,7 +996,6 @@ npxgetregs(struct thread *td)
        } else {
                owned = _MC_FPOWNED_PCB;
        }
-       critical_exit();
        if (use_xsave) {
                /*
                 * Handle partially saved state.
@@ -1018,6 +1018,7 @@ npxgetregs(struct thread *td)
                        *xstate_bv |= bit;
                }
        }
+       critical_exit();
        return (owned);
 }
 
@@ -1026,6 +1027,7 @@ npxuserinited(struct thread *td)
 {
        struct pcb *pcb;
 
+       CRITICAL_ASSERT(td);
        pcb = td->td_pcb;
        if (PCB_USER_FPU(pcb))
                pcb->pcb_flags |= PCB_NPXINITDONE;
@@ -1083,28 +1085,26 @@ npxsetregs(struct thread *td, union savefpu *addr, cha
        if (cpu_fxsr)
                addr->sv_xmm.sv_env.en_mxcsr &= cpu_mxcsr_mask;
        pcb = td->td_pcb;
+       error = 0;
        critical_enter();
        if (td == PCPU_GET(fpcurthread) && PCB_USER_FPU(pcb)) {
                error = npxsetxstate(td, xfpustate, xfpustate_size);
-               if (error != 0) {
-                       critical_exit();
-                       return (error);
+               if (error == 0) {
+                       if (!cpu_fxsr)
+                               fnclex();       /* As in npxdrop(). */
+                       bcopy(addr, get_pcb_user_save_td(td), sizeof(*addr));
+                       fpurstor(get_pcb_user_save_td(td));
+                       pcb->pcb_flags |= PCB_NPXUSERINITDONE | PCB_NPXINITDONE;
                }
-               if (!cpu_fxsr)
-                       fnclex();       /* As in npxdrop(). */
-               bcopy(addr, get_pcb_user_save_td(td), sizeof(*addr));
-               fpurstor(get_pcb_user_save_td(td));
-               critical_exit();
-               pcb->pcb_flags |= PCB_NPXUSERINITDONE | PCB_NPXINITDONE;
        } else {
-               critical_exit();
                error = npxsetxstate(td, xfpustate, xfpustate_size);
-               if (error != 0)
-                       return (error);
-               bcopy(addr, get_pcb_user_save_td(td), sizeof(*addr));
-               npxuserinited(td);
+               if (error == 0) {
+                       bcopy(addr, get_pcb_user_save_td(td), sizeof(*addr));
+                       npxuserinited(td);
+               }
        }
-       return (0);
+       critical_exit();
+       return (error);
 }
 
 static void
@@ -1373,6 +1373,7 @@ fpu_kern_enter(struct thread *td, struct fpu_kern_ctx 
                return (0);
        }
        pcb = td->td_pcb;
+       critical_enter();
        KASSERT(!PCB_USER_FPU(pcb) || pcb->pcb_save ==
            get_pcb_user_save_pcb(pcb), ("mangled pcb_save"));
        ctx->flags = FPU_KERN_CTX_INUSE;
@@ -1383,6 +1384,7 @@ fpu_kern_enter(struct thread *td, struct fpu_kern_ctx 
        pcb->pcb_save = fpu_kern_ctx_savefpu(ctx);
        pcb->pcb_flags |= PCB_KERNNPX;
        pcb->pcb_flags &= ~PCB_NPXINITDONE;
+       critical_exit();
        return (0);
 }
 
@@ -1401,7 +1403,6 @@ fpu_kern_leave(struct thread *td, struct fpu_kern_ctx 
        critical_enter();
        if (curthread == PCPU_GET(fpcurthread))
                npxdrop();
-       critical_exit();
        pcb->pcb_save = ctx->prev;
        if (pcb->pcb_save == get_pcb_user_save_pcb(pcb)) {
                if ((pcb->pcb_flags & PCB_NPXUSERINITDONE) != 0)
@@ -1416,6 +1417,7 @@ fpu_kern_leave(struct thread *td, struct fpu_kern_ctx 
                        pcb->pcb_flags &= ~PCB_NPXINITDONE;
                KASSERT(!PCB_USER_FPU(pcb), ("unpaired fpu_kern_leave"));
        }
+       critical_exit();
        return (0);
 }
 
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to