From owner-svn-src-head@FreeBSD.ORG Wed Dec 22 00:18:42 2010 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id D27EE1065670; Wed, 22 Dec 2010 00:18:42 +0000 (UTC) (envelope-from jkim@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id BFC6C8FC08; Wed, 22 Dec 2010 00:18:42 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id oBM0IgXv079645; Wed, 22 Dec 2010 00:18:42 GMT (envelope-from jkim@svn.freebsd.org) Received: (from jkim@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id oBM0IgOg079632; Wed, 22 Dec 2010 00:18:42 GMT (envelope-from jkim@svn.freebsd.org) Message-Id: <201012220018.oBM0IgOg079632@svn.freebsd.org> From: Jung-uk Kim Date: Wed, 22 Dec 2010 00:18:42 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r216634 - in head/sys/amd64: amd64 ia32 include linux32 X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 22 Dec 2010 00:18:42 -0000 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; }