Author: jhb
Date: Tue Oct 13 17:27:37 2020
New Revision: 366673
URL: https://svnweb.freebsd.org/changeset/base/366673

Log:
  Add support for FPU_KERN_NOCTX.
  
  This mirrors the implementation on amd64.
  
  Reviewed by:  kib
  Sponsored by: Netflix
  Differential Revision:        https://reviews.freebsd.org/D26754

Modified:
  head/sys/i386/i386/npx.c
  head/sys/i386/include/npx.h
  head/sys/i386/include/pcb.h

Modified: head/sys/i386/i386/npx.c
==============================================================================
--- head/sys/i386/i386/npx.c    Tue Oct 13 17:26:12 2020        (r366672)
+++ head/sys/i386/i386/npx.c    Tue Oct 13 17:27:37 2020        (r366673)
@@ -886,6 +886,9 @@ npxdna(void)
                return (0);
        td = curthread;
        critical_enter();
+
+       KASSERT((curpcb->pcb_flags & PCB_NPXNOSAVE) == 0,
+           ("npxdna while in fpu_kern_enter(FPU_KERN_NOCTX)"));
        if (__predict_false(PCPU_GET(fpcurthread) == td)) {
                /*
                 * Some virtual machines seems to set %cr0.TS at
@@ -1390,8 +1393,34 @@ fpu_kern_enter(struct thread *td, struct fpu_kern_ctx 
 {
        struct pcb *pcb;
 
-       KASSERT((ctx->flags & FPU_KERN_CTX_INUSE) == 0, ("using inuse ctx"));
+       pcb = td->td_pcb;
+       KASSERT((flags & FPU_KERN_NOCTX) != 0 || ctx != NULL,
+           ("ctx is required when !FPU_KERN_NOCTX"));
+       KASSERT(ctx == NULL || (ctx->flags & FPU_KERN_CTX_INUSE) == 0,
+           ("using inuse ctx"));
+       KASSERT((pcb->pcb_flags & PCB_NPXNOSAVE) == 0,
+           ("recursive fpu_kern_enter while in PCB_NPXNOSAVE state"));
 
+       if ((flags & FPU_KERN_NOCTX) != 0) {
+               critical_enter();
+               stop_emulating();
+               if (curthread == PCPU_GET(fpcurthread)) {
+                       fpusave(curpcb->pcb_save);
+                       PCPU_SET(fpcurthread, NULL);
+               } else {
+                       KASSERT(PCPU_GET(fpcurthread) == NULL,
+                           ("invalid fpcurthread"));
+               }
+
+               /*
+                * This breaks XSAVEOPT tracker, but
+                * PCB_NPXNOSAVE state is supposed to never need to
+                * save FPU context at all.
+                */
+               fpurstor(npx_initialstate);
+               pcb->pcb_flags |= PCB_KERNNPX | PCB_NPXNOSAVE | PCB_NPXINITDONE;
+               return;
+       }
        if ((flags & FPU_KERN_KTHR) != 0 && is_fpu_kern_thread(0)) {
                ctx->flags = FPU_KERN_CTX_DUMMY | FPU_KERN_CTX_INUSE;
                return;
@@ -1416,17 +1445,32 @@ fpu_kern_leave(struct thread *td, struct fpu_kern_ctx 
 {
        struct pcb *pcb;
 
-       KASSERT((ctx->flags & FPU_KERN_CTX_INUSE) != 0,
-           ("leaving not inuse ctx"));
-       ctx->flags &= ~FPU_KERN_CTX_INUSE;
-
-       if (is_fpu_kern_thread(0) && (ctx->flags & FPU_KERN_CTX_DUMMY) != 0)
-               return (0);
        pcb = td->td_pcb;
-       critical_enter();
-       if (curthread == PCPU_GET(fpcurthread))
-               npxdrop();
-       pcb->pcb_save = ctx->prev;
+
+       if ((pcb->pcb_flags & PCB_NPXNOSAVE) != 0) {
+               KASSERT(ctx == NULL, ("non-null ctx after FPU_KERN_NOCTX"));
+               KASSERT(PCPU_GET(fpcurthread) == NULL,
+                   ("non-NULL fpcurthread for PCB_NPXNOSAVE"));
+               CRITICAL_ASSERT(td);
+
+               pcb->pcb_flags &= ~(PCB_NPXNOSAVE | PCB_NPXINITDONE);
+               start_emulating();
+       } else {
+               KASSERT((ctx->flags & FPU_KERN_CTX_INUSE) != 0,
+                   ("leaving not inuse ctx"));
+               ctx->flags &= ~FPU_KERN_CTX_INUSE;
+
+               if (is_fpu_kern_thread(0) &&
+                   (ctx->flags & FPU_KERN_CTX_DUMMY) != 0)
+                       return (0);
+               KASSERT((ctx->flags & FPU_KERN_CTX_DUMMY) == 0,
+                   ("dummy ctx"));
+               critical_enter();
+               if (curthread == PCPU_GET(fpcurthread))
+                       npxdrop();
+               pcb->pcb_save = ctx->prev;
+       }
+
        if (pcb->pcb_save == get_pcb_user_save_pcb(pcb)) {
                if ((pcb->pcb_flags & PCB_NPXUSERINITDONE) != 0)
                        pcb->pcb_flags |= PCB_NPXINITDONE;

Modified: head/sys/i386/include/npx.h
==============================================================================
--- head/sys/i386/include/npx.h Tue Oct 13 17:26:12 2020        (r366672)
+++ head/sys/i386/include/npx.h Tue Oct 13 17:27:37 2020        (r366673)
@@ -92,6 +92,7 @@ void  fpu_save_area_reset(union savefpu *fsa);
 #define        FPU_KERN_NORMAL 0x0000
 #define        FPU_KERN_NOWAIT 0x0001
 #define        FPU_KERN_KTHR   0x0002
+#define        FPU_KERN_NOCTX  0x0004
 
 #endif
 

Modified: head/sys/i386/include/pcb.h
==============================================================================
--- head/sys/i386/include/pcb.h Tue Oct 13 17:26:12 2020        (r366672)
+++ head/sys/i386/include/pcb.h Tue Oct 13 17:27:37 2020        (r366673)
@@ -86,6 +86,7 @@ struct pcb {
 #define        PCB_VM86CALL    0x10    /* in vm86 call */
 #define        PCB_NPXUSERINITDONE 0x20 /* user fpu state is initialized */
 #define        PCB_KERNNPX     0x40    /* kernel uses npx */
+#define        PCB_NPXNOSAVE   0x80    /* no save area for current FPU ctx */
 
        uint16_t pcb_initial_npxcw;
 
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to