Author: jkim
Date: Wed Dec 22 00:18:42 2010
New Revision: 216634
URL: http://svn.freebsd.org/changeset/base/216634

Log:
  Improve PCB flags handling and make it more robust.  Add two new functions
  for manipulating pcb_flags.  These inline functions are very similar to
  atomic_set_char(9) and atomic_clear_char(9) but without unnecessary LOCK
  prefix for SMP.  Add comments about the rationale[1].  Use these functions
  wherever possible.  Although there are some places where it is not strictly
  necessary (e.g., a PCB is copied to create a new PCB), it is done across
  the board for sake of consistency.  Turn pcb_full_iret into a PCB flag as
  it is safe now.  Move rarely used fields before pcb_flags and reduce size
  of pcb_flags to one byte.  Fix some style(9) nits in pcb.h while I am in
  the neighborhood.
  
  Reviewed by:  kib
  Submitted by: kib[1]
  MFC after:    2 months

Modified:
  head/sys/amd64/amd64/cpu_switch.S
  head/sys/amd64/amd64/exception.S
  head/sys/amd64/amd64/fpu.c
  head/sys/amd64/amd64/genassym.c
  head/sys/amd64/amd64/machdep.c
  head/sys/amd64/amd64/sys_machdep.c
  head/sys/amd64/amd64/vm_machdep.c
  head/sys/amd64/ia32/ia32_reg.c
  head/sys/amd64/ia32/ia32_signal.c
  head/sys/amd64/include/pcb.h
  head/sys/amd64/linux32/linux32_machdep.c
  head/sys/amd64/linux32/linux32_sysvec.c

Modified: head/sys/amd64/amd64/cpu_switch.S
==============================================================================
--- head/sys/amd64/amd64/cpu_switch.S   Tue Dec 21 23:15:40 2010        
(r216633)
+++ head/sys/amd64/amd64/cpu_switch.S   Wed Dec 22 00:18:42 2010        
(r216634)
@@ -94,7 +94,7 @@ END(cpu_throw)
 ENTRY(cpu_switch)
        /* Switch to new thread.  First, save context. */
        movq    TD_PCB(%rdi),%r8
-       movb    $1,PCB_FULL_IRET(%r8)
+       orb     $PCB_FULL_IRET,PCB_FLAGS(%r8)
 
        movq    (%rsp),%rax                     /* Hardware registers */
        movq    %r15,PCB_R15(%r8)
@@ -106,7 +106,7 @@ ENTRY(cpu_switch)
        movq    %rbx,PCB_RBX(%r8)
        movq    %rax,PCB_RIP(%r8)
 
-       testl   $PCB_DBREGS,PCB_FLAGS(%r8)
+       testb   $PCB_DBREGS,PCB_FLAGS(%r8)
        jnz     store_dr                        /* static predict not taken */
 done_store_dr:
 
@@ -210,7 +210,7 @@ done_tss:
        movq    %rsi,PCPU(CURTHREAD)            /* into next thread */
 
        /* Test if debug registers should be restored. */
-       testl   $PCB_DBREGS,PCB_FLAGS(%r8)
+       testb   $PCB_DBREGS,PCB_FLAGS(%r8)
        jnz     load_dr                         /* static predict not taken */
 done_load_dr:
 

Modified: head/sys/amd64/amd64/exception.S
==============================================================================
--- head/sys/amd64/amd64/exception.S    Tue Dec 21 23:15:40 2010        
(r216633)
+++ head/sys/amd64/amd64/exception.S    Wed Dec 22 00:18:42 2010        
(r216634)
@@ -170,7 +170,7 @@ alltraps:
        jz      alltraps_testi          /* already running with kernel GS.base 
*/
        swapgs
        movq    PCPU(CURPCB),%rdi
-       movb    $0,PCB_FULL_IRET(%rdi)
+       andb    $~PCB_FULL_IRET,PCB_FLAGS(%rdi)
        movw    %fs,TF_FS(%rsp)
        movw    %gs,TF_GS(%rsp)
        movw    %es,TF_ES(%rsp)
@@ -243,7 +243,7 @@ alltraps_noen:
        jz      1f      /* already running with kernel GS.base */
        swapgs
        movq    PCPU(CURPCB),%rdi
-       movb    $0,PCB_FULL_IRET(%rdi)
+       andb    $~PCB_FULL_IRET,PCB_FLAGS(%rdi)
 1:     movw    %fs,TF_FS(%rsp)
        movw    %gs,TF_GS(%rsp)
        movw    %es,TF_ES(%rsp)
@@ -294,7 +294,7 @@ IDTVEC(page)
        jz      1f                      /* already running with kernel GS.base 
*/
        swapgs
        movq    PCPU(CURPCB),%rdi
-       movb    $0,PCB_FULL_IRET(%rdi)
+       andb    $~PCB_FULL_IRET,PCB_FLAGS(%rdi)
 1:     movq    %cr2,%rdi               /* preserve %cr2 before ..  */
        movq    %rdi,TF_ADDR(%rsp)      /* enabling interrupts. */
        movw    %fs,TF_FS(%rsp)
@@ -324,7 +324,7 @@ IDTVEC(prot)
        jz      2f                      /* already running with kernel GS.base 
*/
 1:     swapgs
 2:     movq    PCPU(CURPCB),%rdi
-       movb    $1,PCB_FULL_IRET(%rdi)  /* always full iret from GPF */
+       orb     $PCB_FULL_IRET,PCB_FLAGS(%rdi)  /* always full iret from GPF */
        movw    %fs,TF_FS(%rsp)
        movw    %gs,TF_GS(%rsp)
        movw    %es,TF_ES(%rsp)
@@ -356,7 +356,7 @@ IDTVEC(fast_syscall)
        movw    %es,TF_ES(%rsp)
        movw    %ds,TF_DS(%rsp)
        movq    PCPU(CURPCB),%r11
-       movb    $0,PCB_FULL_IRET(%r11)
+       andb    $~PCB_FULL_IRET,PCB_FLAGS(%r11)
        sti
        movq    $KUDSEL,TF_SS(%rsp)
        movq    $KUCSEL,TF_CS(%rsp)
@@ -661,8 +661,8 @@ doreti_exit:
         */
        testb   $SEL_RPL_MASK,TF_CS(%rsp)
        jz      ld_regs
-       cmpb    $0,PCB_FULL_IRET(%r8)
-       je      ld_regs
+       testb   $PCB_FULL_IRET,PCB_FLAGS(%r8)
+       jz      ld_regs
        testl   $TF_HASSEGS,TF_FLAGS(%rsp)
        je      set_segs
 

Modified: head/sys/amd64/amd64/fpu.c
==============================================================================
--- head/sys/amd64/amd64/fpu.c  Tue Dec 21 23:15:40 2010        (r216633)
+++ head/sys/amd64/amd64/fpu.c  Wed Dec 22 00:18:42 2010        (r216634)
@@ -426,9 +426,11 @@ fpudna(void)
                fxrstor(&fpu_initialstate);
                if (pcb->pcb_initial_fpucw != __INITIAL_FPUCW__)
                        fldcw(pcb->pcb_initial_fpucw);
-               pcb->pcb_flags |= PCB_FPUINITDONE;
                if (PCB_USER_FPU(pcb))
-                       pcb->pcb_flags |= PCB_USERFPUINITDONE;
+                       set_pcb_flags(pcb,
+                           PCB_FPUINITDONE | PCB_USERFPUINITDONE);
+               else
+                       set_pcb_flags(pcb, PCB_FPUINITDONE);
        } else
                fxrstor(pcb->pcb_save);
        critical_exit();
@@ -443,7 +445,7 @@ fpudrop()
        KASSERT(td == curthread, ("fpudrop: fpcurthread != curthread"));
        CRITICAL_ASSERT(td);
        PCPU_SET(fpcurthread, NULL);
-       td->td_pcb->pcb_flags &= ~PCB_FPUINITDONE;
+       clear_pcb_flags(td->td_pcb, PCB_FPUINITDONE);
        start_emulating();
 }
 
@@ -483,8 +485,10 @@ fpuuserinited(struct thread *td)
 
        pcb = td->td_pcb;
        if (PCB_USER_FPU(pcb))
-               pcb->pcb_flags |= PCB_FPUINITDONE;
-       pcb->pcb_flags |= PCB_USERFPUINITDONE;
+               set_pcb_flags(pcb,
+                   PCB_FPUINITDONE | PCB_USERFPUINITDONE);
+       else
+               set_pcb_flags(pcb, PCB_FPUINITDONE);
 }
 
 /*
@@ -500,7 +504,7 @@ fpusetregs(struct thread *td, struct sav
        if (td == PCPU_GET(fpcurthread) && PCB_USER_FPU(pcb)) {
                fxrstor(addr);
                critical_exit();
-               pcb->pcb_flags |= PCB_FPUINITDONE | PCB_USERFPUINITDONE;
+               set_pcb_flags(pcb, PCB_FPUINITDONE | PCB_USERFPUINITDONE);
        } else {
                critical_exit();
                bcopy(addr, &td->td_pcb->pcb_user_save, sizeof(*addr));
@@ -609,8 +613,8 @@ fpu_kern_enter(struct thread *td, struct
        fpuexit(td);
        ctx->prev = pcb->pcb_save;
        pcb->pcb_save = &ctx->hwstate;
-       pcb->pcb_flags |= PCB_KERNFPU;
-       pcb->pcb_flags &= ~PCB_FPUINITDONE;
+       set_pcb_flags(pcb, PCB_KERNFPU);
+       clear_pcb_flags(pcb, PCB_FPUINITDONE);
        return (0);
 }
 
@@ -626,16 +630,16 @@ fpu_kern_leave(struct thread *td, struct
        critical_exit();
        pcb->pcb_save = ctx->prev;
        if (pcb->pcb_save == &pcb->pcb_user_save) {
-               if ((pcb->pcb_flags & PCB_USERFPUINITDONE) != 0)
-                       pcb->pcb_flags |= PCB_FPUINITDONE;
-               else
-                       pcb->pcb_flags &= ~PCB_FPUINITDONE;
-               pcb->pcb_flags &= ~PCB_KERNFPU;
+               if ((pcb->pcb_flags & PCB_USERFPUINITDONE) != 0) {
+                       set_pcb_flags(pcb, PCB_FPUINITDONE);
+                       clear_pcb_flags(pcb, PCB_KERNFPU);
+               } else
+                       clear_pcb_flags(pcb, PCB_FPUINITDONE | PCB_KERNFPU);
        } else {
                if ((ctx->flags & FPU_KERN_CTX_FPUINITDONE) != 0)
-                       pcb->pcb_flags |= PCB_FPUINITDONE;
+                       set_pcb_flags(pcb, PCB_FPUINITDONE);
                else
-                       pcb->pcb_flags &= ~PCB_FPUINITDONE;
+                       clear_pcb_flags(pcb, PCB_FPUINITDONE);
                KASSERT(!PCB_USER_FPU(pcb), ("unpaired fpu_kern_leave"));
        }
        return (0);
@@ -652,7 +656,7 @@ fpu_kern_thread(u_int flags)
        KASSERT(pcb->pcb_save == &pcb->pcb_user_save, ("mangled pcb_save"));
        KASSERT(PCB_USER_FPU(pcb), ("recursive call"));
 
-       pcb->pcb_flags |= PCB_KERNFPU;
+       set_pcb_flags(pcb, PCB_KERNFPU);
        return (0);
 }
 

Modified: head/sys/amd64/amd64/genassym.c
==============================================================================
--- head/sys/amd64/amd64/genassym.c     Tue Dec 21 23:15:40 2010        
(r216633)
+++ head/sys/amd64/amd64/genassym.c     Wed Dec 22 00:18:42 2010        
(r216634)
@@ -145,22 +145,22 @@ ASSYM(PCB_DR2, offsetof(struct pcb, pcb_
 ASSYM(PCB_DR3, offsetof(struct pcb, pcb_dr3));
 ASSYM(PCB_DR6, offsetof(struct pcb, pcb_dr6));
 ASSYM(PCB_DR7, offsetof(struct pcb, pcb_dr7));
+ASSYM(PCB_GDT, offsetof(struct pcb, pcb_gdt));
+ASSYM(PCB_IDT, offsetof(struct pcb, pcb_idt));
+ASSYM(PCB_LDT, offsetof(struct pcb, pcb_ldt));
+ASSYM(PCB_TR, offsetof(struct pcb, pcb_tr));
 ASSYM(PCB_FLAGS, offsetof(struct pcb, pcb_flags));
 ASSYM(PCB_ONFAULT, offsetof(struct pcb, pcb_onfault));
 ASSYM(PCB_GS32SD, offsetof(struct pcb, pcb_gs32sd));
 ASSYM(PCB_TSSP, offsetof(struct pcb, pcb_tssp));
 ASSYM(PCB_SAVEFPU, offsetof(struct pcb, pcb_save));
 ASSYM(PCB_SAVEFPU_SIZE, sizeof(struct savefpu));
-ASSYM(PCB_FULL_IRET, offsetof(struct pcb, pcb_full_iret));
-ASSYM(PCB_GDT, offsetof(struct pcb, pcb_gdt));
-ASSYM(PCB_IDT, offsetof(struct pcb, pcb_idt));
-ASSYM(PCB_LDT, offsetof(struct pcb, pcb_ldt));
-ASSYM(PCB_TR, offsetof(struct pcb, pcb_tr));
 ASSYM(PCB_USERFPU, offsetof(struct pcb, pcb_user_save));
 ASSYM(PCB_SIZE, sizeof(struct pcb));
+ASSYM(PCB_FULL_IRET, PCB_FULL_IRET);
 ASSYM(PCB_DBREGS, PCB_DBREGS);
-ASSYM(PCB_32BIT, PCB_32BIT);
 ASSYM(PCB_GS32BIT, PCB_GS32BIT);
+ASSYM(PCB_32BIT, PCB_32BIT);
 
 ASSYM(COMMON_TSS_RSP0, offsetof(struct amd64tss, tss_rsp0));
 

Modified: head/sys/amd64/amd64/machdep.c
==============================================================================
--- head/sys/amd64/amd64/machdep.c      Tue Dec 21 23:15:40 2010        
(r216633)
+++ head/sys/amd64/amd64/machdep.c      Wed Dec 22 00:18:42 2010        
(r216634)
@@ -303,6 +303,7 @@ void
 sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
 {
        struct sigframe sf, *sfp;
+       struct pcb *pcb;
        struct proc *p;
        struct thread *td;
        struct sigacts *psp;
@@ -312,6 +313,7 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, 
        int oonstack;
 
        td = curthread;
+       pcb = td->td_pcb;
        p = td->td_proc;
        PROC_LOCK_ASSERT(p, MA_OWNED);
        sig = ksi->ksi_signo;
@@ -331,8 +333,8 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, 
        sf.sf_uc.uc_mcontext.mc_len = sizeof(sf.sf_uc.uc_mcontext); /* magic */
        get_fpcontext(td, &sf.sf_uc.uc_mcontext);
        fpstate_drop(td);
-       sf.sf_uc.uc_mcontext.mc_fsbase = td->td_pcb->pcb_fsbase;
-       sf.sf_uc.uc_mcontext.mc_gsbase = td->td_pcb->pcb_gsbase;
+       sf.sf_uc.uc_mcontext.mc_fsbase = pcb->pcb_fsbase;
+       sf.sf_uc.uc_mcontext.mc_gsbase = pcb->pcb_gsbase;
 
        /* Allocate space for the signal handler context. */
        if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack &&
@@ -392,7 +394,7 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, 
        regs->tf_fs = _ufssel;
        regs->tf_gs = _ugssel;
        regs->tf_flags = TF_HASSEGS;
-       td->td_pcb->pcb_full_iret = 1;
+       set_pcb_flags(pcb, PCB_FULL_IRET);
        PROC_LOCK(p);
        mtx_lock(&psp->ps_mtx);
 }
@@ -416,13 +418,17 @@ sigreturn(td, uap)
        } */ *uap;
 {
        ucontext_t uc;
-       struct proc *p = td->td_proc;
+       struct pcb *pcb;
+       struct proc *p;
        struct trapframe *regs;
        ucontext_t *ucp;
        long rflags;
        int cs, error, ret;
        ksiginfo_t ksi;
 
+       pcb = td->td_pcb;
+       p = td->td_proc;
+
        error = copyin(uap->sigcntxp, &uc, sizeof(uc));
        if (error != 0) {
                uprintf("pid %d (%s): sigreturn copyin failed\n",
@@ -481,8 +487,8 @@ sigreturn(td, uap)
                return (ret);
        }
        bcopy(&ucp->uc_mcontext.mc_rdi, regs, sizeof(*regs));
-       td->td_pcb->pcb_fsbase = ucp->uc_mcontext.mc_fsbase;
-       td->td_pcb->pcb_gsbase = ucp->uc_mcontext.mc_gsbase;
+       pcb->pcb_fsbase = ucp->uc_mcontext.mc_fsbase;
+       pcb->pcb_gsbase = ucp->uc_mcontext.mc_gsbase;
 
 #if defined(COMPAT_43)
        if (ucp->uc_mcontext.mc_onstack & 1)
@@ -492,7 +498,7 @@ sigreturn(td, uap)
 #endif
 
        kern_sigprocmask(td, SIG_SETMASK, &ucp->uc_sigmask, NULL, 0);
-       td->td_pcb->pcb_full_iret = 1;
+       set_pcb_flags(pcb, PCB_FULL_IRET);
        return (EJUSTRETURN);
 }
 
@@ -857,9 +863,9 @@ exec_setregs(struct thread *td, struct i
        
        pcb->pcb_fsbase = 0;
        pcb->pcb_gsbase = 0;
-       pcb->pcb_flags &= ~(PCB_32BIT | PCB_GS32BIT);
+       clear_pcb_flags(pcb, PCB_32BIT | PCB_GS32BIT);
        pcb->pcb_initial_fpucw = __INITIAL_FPUCW__;
-       pcb->pcb_full_iret = 1;
+       set_pcb_flags(pcb, PCB_FULL_IRET);
 
        bzero((char *)regs, sizeof(struct trapframe));
        regs->tf_rip = imgp->entry_addr;
@@ -894,7 +900,7 @@ exec_setregs(struct thread *td, struct i
                         */
                        reset_dbregs();
                }
-               pcb->pcb_flags &= ~PCB_DBREGS;
+               clear_pcb_flags(pcb, PCB_DBREGS);
        }
 
        /*
@@ -1904,7 +1910,7 @@ set_regs(struct thread *td, struct reg *
                tp->tf_fs = regs->r_fs;
                tp->tf_gs = regs->r_gs;
                tp->tf_flags = TF_HASSEGS;
-               td->td_pcb->pcb_full_iret = 1;
+               set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
        }
        return (0);
 }
@@ -1996,8 +2002,10 @@ set_fpregs(struct thread *td, struct fpr
 int
 get_mcontext(struct thread *td, mcontext_t *mcp, int flags)
 {
+       struct pcb *pcb;
        struct trapframe *tp;
 
+       pcb = td->td_pcb;
        tp = td->td_frame;
        PROC_LOCK(curthread->td_proc);
        mcp->mc_onstack = sigonstack(tp->tf_rsp);
@@ -2035,8 +2043,8 @@ get_mcontext(struct thread *td, mcontext
        mcp->mc_flags = tp->tf_flags;
        mcp->mc_len = sizeof(*mcp);
        get_fpcontext(td, mcp);
-       mcp->mc_fsbase = td->td_pcb->pcb_fsbase;
-       mcp->mc_gsbase = td->td_pcb->pcb_gsbase;
+       mcp->mc_fsbase = pcb->pcb_fsbase;
+       mcp->mc_gsbase = pcb->pcb_gsbase;
        return (0);
 }
 
@@ -2049,10 +2057,12 @@ get_mcontext(struct thread *td, mcontext
 int
 set_mcontext(struct thread *td, const mcontext_t *mcp)
 {
+       struct pcb *pcb;
        struct trapframe *tp;
        long rflags;
        int ret;
 
+       pcb = td->td_pcb;
        tp = td->td_frame;
        if (mcp->mc_len != sizeof(*mcp) ||
            (mcp->mc_flags & ~_MC_FLAG_MASK) != 0)
@@ -2089,10 +2099,10 @@ set_mcontext(struct thread *td, const mc
                tp->tf_gs = mcp->mc_gs;
        }
        if (mcp->mc_flags & _MC_HASBASES) {
-               td->td_pcb->pcb_fsbase = mcp->mc_fsbase;
-               td->td_pcb->pcb_gsbase = mcp->mc_gsbase;
+               pcb->pcb_fsbase = mcp->mc_fsbase;
+               pcb->pcb_gsbase = mcp->mc_gsbase;
        }
-       td->td_pcb->pcb_full_iret = 1;
+       set_pcb_flags(pcb, PCB_FULL_IRET);
        return (0);
 }
 
@@ -2146,8 +2156,8 @@ fpstate_drop(struct thread *td)
         * sendsig() is the only caller of fpugetuserregs()... perhaps we just
         * have too many layers.
         */
-       curthread->td_pcb->pcb_flags &= ~(PCB_FPUINITDONE |
-           PCB_USERFPUINITDONE);
+       clear_pcb_flags(curthread->td_pcb,
+           PCB_FPUINITDONE | PCB_USERFPUINITDONE);
        critical_exit();
 }
 
@@ -2261,7 +2271,7 @@ set_dbregs(struct thread *td, struct dbr
                pcb->pcb_dr6 = dbregs->dr[6];
                pcb->pcb_dr7 = dbregs->dr[7];
 
-               pcb->pcb_flags |= PCB_DBREGS;
+               set_pcb_flags(pcb, PCB_DBREGS);
        }
 
        return (0);

Modified: head/sys/amd64/amd64/sys_machdep.c
==============================================================================
--- head/sys/amd64/amd64/sys_machdep.c  Tue Dec 21 23:15:40 2010        
(r216633)
+++ head/sys/amd64/amd64/sys_machdep.c  Wed Dec 22 00:18:42 2010        
(r216634)
@@ -103,7 +103,7 @@ sysarch_ldt(struct thread *td, struct sy
                error = amd64_get_ldt(td, largs);
                break;
        case I386_SET_LDT:
-               td->td_pcb->pcb_full_iret = 1;
+               set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
                if (largs->descs != NULL) {
                        lp = (struct user_segment_descriptor *)
                            kmem_alloc(kernel_map, largs->num *
@@ -133,7 +133,7 @@ update_gdt_gsbase(struct thread *td, uin
 
        if (td != curthread)
                return;
-       td->td_pcb->pcb_full_iret = 1;
+       set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
        critical_enter();
        sd = PCPU_GET(gs32p);
        sd->sd_lobase = base & 0xffffff;
@@ -148,7 +148,7 @@ update_gdt_fsbase(struct thread *td, uin
 
        if (td != curthread)
                return;
-       td->td_pcb->pcb_full_iret = 1;
+       set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
        critical_enter();
        sd = PCPU_GET(fs32p);
        sd->sd_lobase = base & 0xffffff;
@@ -204,7 +204,7 @@ sysarch(td, uap)
                if (!error) {
                        pcb->pcb_fsbase = i386base;
                        td->td_frame->tf_fs = _ufssel;
-                       pcb->pcb_full_iret = 1;
+                       set_pcb_flags(pcb, PCB_FULL_IRET);
                        update_gdt_fsbase(td, i386base);
                }
                break;
@@ -216,7 +216,7 @@ sysarch(td, uap)
                error = copyin(uap->parms, &i386base, sizeof(i386base));
                if (!error) {
                        pcb->pcb_gsbase = i386base;
-                       pcb->pcb_full_iret = 1;
+                       set_pcb_flags(pcb, PCB_FULL_IRET);
                        td->td_frame->tf_gs = _ugssel;
                        update_gdt_gsbase(td, i386base);
                }
@@ -230,7 +230,7 @@ sysarch(td, uap)
                if (!error) {
                        if (a64base < VM_MAXUSER_ADDRESS) {
                                pcb->pcb_fsbase = a64base;
-                               pcb->pcb_full_iret = 1;
+                               set_pcb_flags(pcb, PCB_FULL_IRET);
                                td->td_frame->tf_fs = _ufssel;
                        } else
                                error = EINVAL;
@@ -246,7 +246,7 @@ sysarch(td, uap)
                if (!error) {
                        if (a64base < VM_MAXUSER_ADDRESS) {
                                pcb->pcb_gsbase = a64base;
-                               pcb->pcb_full_iret = 1;
+                               set_pcb_flags(pcb, PCB_FULL_IRET);
                                td->td_frame->tf_gs = _ugssel;
                        } else
                                error = EINVAL;
@@ -533,7 +533,7 @@ amd64_set_ldt(td, uap, descs)
            uap->start, uap->num, (void *)uap->descs);
 #endif
 
-       td->td_pcb->pcb_full_iret = 1;
+       set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
        p = td->td_proc;
        if (descs == NULL) {
                /* Free descriptors */

Modified: head/sys/amd64/amd64/vm_machdep.c
==============================================================================
--- head/sys/amd64/amd64/vm_machdep.c   Tue Dec 21 23:15:40 2010        
(r216633)
+++ head/sys/amd64/amd64/vm_machdep.c   Wed Dec 22 00:18:42 2010        
(r216634)
@@ -190,7 +190,7 @@ cpu_fork(td1, p2, td2, flags)
        pcb2->pcb_tssp = NULL;
 
        /* New segment registers. */
-       pcb2->pcb_full_iret = 1;
+       set_pcb_flags(pcb2, PCB_FULL_IRET);
 
        /* Copy the LDT, if necessary. */
        mdp1 = &td1->td_proc->p_md;
@@ -275,7 +275,7 @@ cpu_thread_exit(struct thread *td)
        /* Disable any hardware breakpoints. */
        if (pcb->pcb_flags & PCB_DBREGS) {
                reset_dbregs();
-               pcb->pcb_flags &= ~PCB_DBREGS;
+               clear_pcb_flags(pcb, PCB_DBREGS);
        }
 }
 
@@ -385,9 +385,9 @@ cpu_set_upcall(struct thread *td, struct
         * values here.
         */
        bcopy(td0->td_pcb, pcb2, sizeof(*pcb2));
-       pcb2->pcb_flags &= ~(PCB_FPUINITDONE | PCB_USERFPUINITDONE);
+       clear_pcb_flags(pcb2, PCB_FPUINITDONE | PCB_USERFPUINITDONE);
        pcb2->pcb_save = &pcb2->pcb_user_save;
-       pcb2->pcb_full_iret = 1;
+       set_pcb_flags(pcb2, PCB_FULL_IRET);
 
        /*
         * Create a new fresh stack for the new thread.
@@ -491,18 +491,20 @@ cpu_set_upcall_kse(struct thread *td, vo
 int
 cpu_set_user_tls(struct thread *td, void *tls_base)
 {
+       struct pcb *pcb;
 
        if ((u_int64_t)tls_base >= VM_MAXUSER_ADDRESS)
                return (EINVAL);
 
+       pcb = td->td_pcb;
 #ifdef COMPAT_FREEBSD32
        if (td->td_proc->p_sysent->sv_flags & SV_ILP32) {
-               td->td_pcb->pcb_gsbase = (register_t)tls_base;
+               pcb->pcb_gsbase = (register_t)tls_base;
                return (0);
        }
 #endif
-       td->td_pcb->pcb_fsbase = (register_t)tls_base;
-       td->td_pcb->pcb_full_iret = 1;
+       pcb->pcb_fsbase = (register_t)tls_base;
+       set_pcb_flags(pcb, PCB_FULL_IRET);
        return (0);
 }
 

Modified: head/sys/amd64/ia32/ia32_reg.c
==============================================================================
--- head/sys/amd64/ia32/ia32_reg.c      Tue Dec 21 23:15:40 2010        
(r216633)
+++ head/sys/amd64/ia32/ia32_reg.c      Wed Dec 22 00:18:42 2010        
(r216634)
@@ -125,7 +125,7 @@ set_regs32(struct thread *td, struct reg
        tp->tf_fs = regs->r_fs;
        tp->tf_es = regs->r_es;
        tp->tf_ds = regs->r_ds;
-       td->td_pcb->pcb_full_iret = 1;
+       set_pcb_flags(pcb, PCB_FULL_IRET);
        tp->tf_flags = TF_HASSEGS;
        tp->tf_rdi = regs->r_edi;
        tp->tf_rsi = regs->r_esi;

Modified: head/sys/amd64/ia32/ia32_signal.c
==============================================================================
--- head/sys/amd64/ia32/ia32_signal.c   Tue Dec 21 23:15:40 2010        
(r216633)
+++ head/sys/amd64/ia32/ia32_signal.c   Wed Dec 22 00:18:42 2010        
(r216634)
@@ -130,8 +130,10 @@ ia32_set_fpcontext(struct thread *td, co
 static int
 ia32_get_mcontext(struct thread *td, struct ia32_mcontext *mcp, int flags)
 {
+       struct pcb *pcb;
        struct trapframe *tp;
 
+       pcb = td->td_pcb;
        tp = td->td_frame;
 
        PROC_LOCK(curthread->td_proc);
@@ -163,9 +165,9 @@ ia32_get_mcontext(struct thread *td, str
        mcp->mc_ss = tp->tf_ss;
        mcp->mc_len = sizeof(*mcp);
        ia32_get_fpcontext(td, mcp);
-       mcp->mc_fsbase = td->td_pcb->pcb_fsbase;
-       mcp->mc_gsbase = td->td_pcb->pcb_gsbase;
-       td->td_pcb->pcb_full_iret = 1;
+       mcp->mc_fsbase = pcb->pcb_fsbase;
+       mcp->mc_gsbase = pcb->pcb_gsbase;
+       set_pcb_flags(pcb, PCB_FULL_IRET);
        return (0);
 }
 
@@ -207,7 +209,7 @@ ia32_set_mcontext(struct thread *td, con
        tp->tf_rflags = rflags;
        tp->tf_rsp = mcp->mc_esp;
        tp->tf_ss = mcp->mc_ss;
-       td->td_pcb->pcb_full_iret = 1;
+       set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
        return (0);
 }
 
@@ -397,7 +399,7 @@ freebsd4_ia32_sendsig(sig_t catcher, ksi
        regs->tf_ss = _udatasel;
        regs->tf_ds = _udatasel;
        regs->tf_es = _udatasel;
-       td->td_pcb->pcb_full_iret = 1;
+       set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
        /* leave user %fs and %gs untouched */
        PROC_LOCK(p);
        mtx_lock(&psp->ps_mtx);
@@ -518,7 +520,7 @@ ia32_sendsig(sig_t catcher, ksiginfo_t *
        regs->tf_ss = _udatasel;
        regs->tf_ds = _udatasel;
        regs->tf_es = _udatasel;
-       td->td_pcb->pcb_full_iret = 1;
+       set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
        /* XXXKIB leave user %fs and %gs untouched */
        PROC_LOCK(p);
        mtx_lock(&psp->ps_mtx);
@@ -613,7 +615,7 @@ freebsd4_freebsd32_sigreturn(td, uap)
        regs->tf_gs = ucp->uc_mcontext.mc_gs;
 
        kern_sigprocmask(td, SIG_SETMASK, &ucp->uc_sigmask, NULL, 0);
-       td->td_pcb->pcb_full_iret = 1;
+       set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
        return (EJUSTRETURN);
 }
 #endif /* COMPAT_FREEBSD4 */
@@ -702,7 +704,7 @@ freebsd32_sigreturn(td, uap)
        regs->tf_flags = TF_HASSEGS;
 
        kern_sigprocmask(td, SIG_SETMASK, &ucp->uc_sigmask, NULL, 0);
-       td->td_pcb->pcb_full_iret = 1;
+       set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
        return (EJUSTRETURN);
 }
 
@@ -742,8 +744,7 @@ ia32_setregs(struct thread *td, struct i
        fpstate_drop(td);
 
        /* Return via doreti so that we can change to a different %cs */
-       pcb->pcb_flags |= PCB_32BIT;
-       pcb->pcb_flags &= ~PCB_GS32BIT;
-       td->td_pcb->pcb_full_iret = 1;
+       set_pcb_flags(pcb, PCB_32BIT | PCB_FULL_IRET);
+       clear_pcb_flags(pcb, PCB_GS32BIT);
        td->td_retval[1] = 0;
 }

Modified: head/sys/amd64/include/pcb.h
==============================================================================
--- head/sys/amd64/include/pcb.h        Tue Dec 21 23:15:40 2010        
(r216633)
+++ head/sys/amd64/include/pcb.h        Wed Dec 22 00:18:42 2010        
(r216634)
@@ -66,7 +66,13 @@ struct pcb {
        register_t      pcb_dr6;
        register_t      pcb_dr7;
 
-       u_long          pcb_flags;
+       struct region_descriptor pcb_gdt;
+       struct region_descriptor pcb_idt;
+       struct region_descriptor pcb_ldt;
+       uint16_t        pcb_tr;
+
+       u_char          pcb_flags;
+#define        PCB_FULL_IRET   0x01    /* full iret is required */
 #define        PCB_DBREGS      0x02    /* process using debug registers */
 #define        PCB_KERNFPU     0x04    /* kernel uses fpu */
 #define        PCB_FPUINITDONE 0x08    /* fpu state is initialized */
@@ -76,26 +82,52 @@ struct pcb {
 
        uint16_t        pcb_initial_fpucw;
 
-       caddr_t         pcb_onfault; /* copyin/out fault recovery */
+       /* copyin/out fault recovery */
+       caddr_t         pcb_onfault;
 
        /* 32-bit segment descriptor */
        struct user_segment_descriptor pcb_gs32sd;
+
        /* local tss, with i/o bitmap; NULL for common */
        struct amd64tss *pcb_tssp;
-       struct  savefpu *pcb_save;
-       char            pcb_full_iret;
 
-       struct region_descriptor pcb_gdt;
-       struct region_descriptor pcb_idt;
-       struct region_descriptor pcb_ldt;
-       uint16_t        pcb_tr;
-
-       struct  savefpu pcb_user_save;
+       struct savefpu  *pcb_save;
+       struct savefpu  pcb_user_save;
 };
 
 #ifdef _KERNEL
 struct trapframe;
 
+/*
+ * The pcb_flags is only modified by current thread, or by other threads
+ * when current thread is stopped.  However, current thread may change it
+ * from the interrupt context in cpu_switch(), or in the trap handler.
+ * When we read-modify-write pcb_flags from C sources, compiler may generate
+ * code that is not atomic regarding the interrupt handler.  If a trap or
+ * interrupt happens and any flag is modified from the handler, it can be
+ * clobbered with the cached value later.  Therefore, we implement setting
+ * and clearing flags with single-instruction functions, which do not race
+ * with possible modification of the flags from the trap or interrupt context,
+ * because traps and interrupts are executed only on instruction boundary.
+ */
+static __inline void
+set_pcb_flags(struct pcb *pcb, const u_char flags)
+{
+
+       __asm __volatile("orb %b1,%0"
+           : "=m" (pcb->pcb_flags) : "iq" (flags), "m" (pcb->pcb_flags)
+           : "cc");
+}
+
+static __inline void
+clear_pcb_flags(struct pcb *pcb, const u_char flags)
+{
+
+       __asm __volatile("andb %b1,%0"
+           : "=m" (pcb->pcb_flags) : "iq" (~flags), "m" (pcb->pcb_flags)
+           : "cc");
+}
+
 void   makectx(struct trapframe *, struct pcb *);
 int    savectx(struct pcb *);
 #endif

Modified: head/sys/amd64/linux32/linux32_machdep.c
==============================================================================
--- head/sys/amd64/linux32/linux32_machdep.c    Tue Dec 21 23:15:40 2010        
(r216633)
+++ head/sys/amd64/linux32/linux32_machdep.c    Wed Dec 22 00:18:42 2010        
(r216634)
@@ -590,6 +590,7 @@ linux_clone(struct thread *td, struct li
        if (args->flags & LINUX_CLONE_SETTLS) {
                struct user_segment_descriptor sd;
                struct l_user_desc info;
+               struct pcb *pcb;
                int a[2];
 
                error = copyin((void *)td->td_frame->tf_rsi, &info,
@@ -619,10 +620,11 @@ linux_clone(struct thread *td, struct li
                                    sd.sd_type, sd.sd_dpl, sd.sd_p, sd.sd_xx,
                                    sd.sd_long, sd.sd_def32, sd.sd_gran);
 #endif
-                       td2->td_pcb->pcb_gsbase = (register_t)info.base_addr;
-/* XXXKIB              td2->td_pcb->pcb_gs32sd = sd; */
+                       pcb = td2->td_pcb;
+                       pcb->pcb_gsbase = (register_t)info.base_addr;
+/* XXXKIB              pcb->pcb_gs32sd = sd; */
                        td2->td_frame->tf_gs = GSEL(GUGS32_SEL, SEL_UPL);
-                       td2->td_pcb->pcb_flags |= PCB_GS32BIT | PCB_32BIT;
+                       set_pcb_flags(pcb, PCB_GS32BIT | PCB_32BIT);
                }
        }
 
@@ -1169,6 +1171,7 @@ linux_set_thread_area(struct thread *td,
 {
        struct l_user_desc info;
        struct user_segment_descriptor sd;
+       struct pcb *pcb;
        int a[2];
        int error;
 
@@ -1257,8 +1260,9 @@ linux_set_thread_area(struct thread *td,
                    sd.sd_gran);
 #endif
 
-       td->td_pcb->pcb_gsbase = (register_t)info.base_addr;
-       td->td_pcb->pcb_flags |= PCB_32BIT | PCB_GS32BIT;
+       pcb = td->td_pcb;
+       pcb->pcb_gsbase = (register_t)info.base_addr;
+       set_pcb_flags(pcb, PCB_32BIT | PCB_GS32BIT);
        update_gdt_gsbase(td, info.base_addr);
 
        return (0);

Modified: head/sys/amd64/linux32/linux32_sysvec.c
==============================================================================
--- head/sys/amd64/linux32/linux32_sysvec.c     Tue Dec 21 23:15:40 2010        
(r216633)
+++ head/sys/amd64/linux32/linux32_sysvec.c     Wed Dec 22 00:18:42 2010        
(r216634)
@@ -422,7 +422,7 @@ linux_rt_sendsig(sig_t catcher, ksiginfo
        regs->tf_fs = _ufssel;
        regs->tf_gs = _ugssel;
        regs->tf_flags = TF_HASSEGS;
-       td->td_pcb->pcb_full_iret = 1;
+       set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
        PROC_LOCK(p);
        mtx_lock(&psp->ps_mtx);
 }
@@ -545,7 +545,7 @@ linux_sendsig(sig_t catcher, ksiginfo_t 
        regs->tf_fs = _ufssel;
        regs->tf_gs = _ugssel;
        regs->tf_flags = TF_HASSEGS;
-       td->td_pcb->pcb_full_iret = 1;
+       set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
        PROC_LOCK(p);
        mtx_lock(&psp->ps_mtx);
 }
@@ -643,7 +643,7 @@ linux_sigreturn(struct thread *td, struc
        regs->tf_rflags = eflags;
        regs->tf_rsp    = frame.sf_sc.sc_esp_at_signal;
        regs->tf_ss     = frame.sf_sc.sc_ss;
-       td->td_pcb->pcb_full_iret = 1;
+       set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
 
        return (EJUSTRETURN);
 }
@@ -742,7 +742,7 @@ linux_rt_sigreturn(struct thread *td, st
        regs->tf_rflags = eflags;
        regs->tf_rsp    = context->sc_esp_at_signal;
        regs->tf_ss     = context->sc_ss;
-       td->td_pcb->pcb_full_iret = 1;
+       set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
 
        /*
         * call sigaltstack & ignore results..
@@ -869,9 +869,8 @@ exec_linux_setregs(struct thread *td, st
        fpstate_drop(td);
 
        /* Do full restore on return so that we can change to a different %cs */
-       pcb->pcb_flags |= PCB_32BIT;
-       pcb->pcb_flags &= ~PCB_GS32BIT;
-       pcb->pcb_full_iret = 1;
+       set_pcb_flags(pcb, PCB_32BIT | PCB_FULL_IRET);
+       clear_pcb_flags(pcb, PCB_GS32BIT);
        td->td_retval[1] = 0;
 }
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to