Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 22 Dec 2010 00:18:42 +0000 (UTC)
From:      Jung-uk Kim <jkim@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r216634 - in head/sys/amd64: amd64 ia32 include linux32
Message-ID:  <201012220018.oBM0IgOg079632@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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;
 }
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201012220018.oBM0IgOg079632>