svn commit: r219187 - in stable/8/sys/amd64: amd64 ia32 include
linux32
Jung-uk Kim
jkim at FreeBSD.org
Wed Mar 2 19:09:50 UTC 2011
Author: jkim
Date: Wed Mar 2 19:09:49 2011
New Revision: 219187
URL: http://svn.freebsd.org/changeset/base/219187
Log:
MFC: r216634, r216673
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_int(9) and atomic_clear_int(9) but without unnecessary LOCK
prefix for SMP. Add comments about the rationale. 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 four bytes. Fix some style(9) nits in pcb.h while I am in
the neighborhood.
Modified:
stable/8/sys/amd64/amd64/cpu_switch.S
stable/8/sys/amd64/amd64/exception.S
stable/8/sys/amd64/amd64/fpu.c
stable/8/sys/amd64/amd64/genassym.c
stable/8/sys/amd64/amd64/machdep.c
stable/8/sys/amd64/amd64/sys_machdep.c
stable/8/sys/amd64/amd64/vm_machdep.c
stable/8/sys/amd64/ia32/ia32_reg.c
stable/8/sys/amd64/ia32/ia32_signal.c
stable/8/sys/amd64/include/pcb.h
stable/8/sys/amd64/linux32/linux32_machdep.c
stable/8/sys/amd64/linux32/linux32_sysvec.c
Directory Properties:
stable/8/sys/ (props changed)
stable/8/sys/amd64/include/xen/ (props changed)
stable/8/sys/cddl/contrib/opensolaris/ (props changed)
stable/8/sys/contrib/dev/acpica/ (props changed)
stable/8/sys/contrib/pf/ (props changed)
Modified: stable/8/sys/amd64/amd64/cpu_switch.S
==============================================================================
--- stable/8/sys/amd64/amd64/cpu_switch.S Wed Mar 2 18:53:12 2011 (r219186)
+++ stable/8/sys/amd64/amd64/cpu_switch.S Wed Mar 2 19:09:49 2011 (r219187)
@@ -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)
+ orl $PCB_FULL_IRET,PCB_FLAGS(%r8)
movq (%rsp),%rax /* Hardware registers */
movq %r15,PCB_R15(%r8)
Modified: stable/8/sys/amd64/amd64/exception.S
==============================================================================
--- stable/8/sys/amd64/amd64/exception.S Wed Mar 2 18:53:12 2011 (r219186)
+++ stable/8/sys/amd64/amd64/exception.S Wed Mar 2 19:09:49 2011 (r219187)
@@ -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)
+ andl $~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)
+ andl $~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)
+ andl $~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 */
+ orl $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)
+ andl $~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
+ testl $PCB_FULL_IRET,PCB_FLAGS(%r8)
+ jz ld_regs
testl $TF_HASSEGS,TF_FLAGS(%rsp)
je set_segs
Modified: stable/8/sys/amd64/amd64/fpu.c
==============================================================================
--- stable/8/sys/amd64/amd64/fpu.c Wed Mar 2 18:53:12 2011 (r219186)
+++ stable/8/sys/amd64/amd64/fpu.c Wed Mar 2 19:09:49 2011 (r219187)
@@ -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: stable/8/sys/amd64/amd64/genassym.c
==============================================================================
--- stable/8/sys/amd64/amd64/genassym.c Wed Mar 2 18:53:12 2011 (r219186)
+++ stable/8/sys/amd64/amd64/genassym.c Wed Mar 2 19:09:49 2011 (r219187)
@@ -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: stable/8/sys/amd64/amd64/machdep.c
==============================================================================
--- stable/8/sys/amd64/amd64/machdep.c Wed Mar 2 18:53:12 2011 (r219186)
+++ stable/8/sys/amd64/amd64/machdep.c Wed Mar 2 19:09:49 2011 (r219187)
@@ -300,6 +300,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;
@@ -309,6 +310,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;
@@ -328,8 +330,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;
bzero(sf.sf_uc.uc_mcontext.mc_spare,
sizeof(sf.sf_uc.uc_mcontext.mc_spare));
bzero(sf.sf_uc.__spare__, sizeof(sf.sf_uc.__spare__));
@@ -393,7 +395,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);
}
@@ -417,13 +419,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",
@@ -482,8 +488,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)
@@ -493,7 +499,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);
}
@@ -862,9 +868,9 @@ exec_setregs(td, entry, stack, ps_string
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 = entry;
@@ -899,7 +905,7 @@ exec_setregs(td, entry, stack, ps_string
*/
reset_dbregs();
}
- pcb->pcb_flags &= ~PCB_DBREGS;
+ clear_pcb_flags(pcb, PCB_DBREGS);
}
/*
@@ -1912,7 +1918,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);
}
@@ -2004,8 +2010,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);
@@ -2043,8 +2051,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;
bzero(mcp->mc_spare, sizeof(mcp->mc_spare));
return (0);
}
@@ -2058,10 +2066,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)
@@ -2098,10 +2108,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);
}
@@ -2155,8 +2165,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();
}
@@ -2270,7 +2280,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: stable/8/sys/amd64/amd64/sys_machdep.c
==============================================================================
--- stable/8/sys/amd64/amd64/sys_machdep.c Wed Mar 2 18:53:12 2011 (r219186)
+++ stable/8/sys/amd64/amd64/sys_machdep.c Wed Mar 2 19:09:49 2011 (r219187)
@@ -119,7 +119,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 = malloc(largs->num * sizeof(struct
user_segment_descriptor), M_TEMP, M_WAITOK);
@@ -143,7 +143,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;
@@ -158,7 +158,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;
@@ -214,7 +214,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;
@@ -226,7 +226,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);
}
@@ -240,7 +240,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;
@@ -256,7 +256,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;
@@ -543,7 +543,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: stable/8/sys/amd64/amd64/vm_machdep.c
==============================================================================
--- stable/8/sys/amd64/amd64/vm_machdep.c Wed Mar 2 18:53:12 2011 (r219186)
+++ stable/8/sys/amd64/amd64/vm_machdep.c Wed Mar 2 19:09:49 2011 (r219187)
@@ -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 (SV_PROC_FLAG(td->td_proc, 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: stable/8/sys/amd64/ia32/ia32_reg.c
==============================================================================
--- stable/8/sys/amd64/ia32/ia32_reg.c Wed Mar 2 18:53:12 2011 (r219186)
+++ stable/8/sys/amd64/ia32/ia32_reg.c Wed Mar 2 19:09:49 2011 (r219187)
@@ -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: stable/8/sys/amd64/ia32/ia32_signal.c
==============================================================================
--- stable/8/sys/amd64/ia32/ia32_signal.c Wed Mar 2 18:53:12 2011 (r219186)
+++ stable/8/sys/amd64/ia32/ia32_signal.c Wed Mar 2 19:09:49 2011 (r219187)
@@ -129,8 +129,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);
@@ -162,11 +164,11 @@ 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;
+ mcp->mc_fsbase = pcb->pcb_fsbase;
+ mcp->mc_gsbase = pcb->pcb_gsbase;
bzero(mcp->mc_spare1, sizeof(mcp->mc_spare1));
bzero(mcp->mc_spare2, sizeof(mcp->mc_spare2));
- td->td_pcb->pcb_full_iret = 1;
+ set_pcb_flags(pcb, PCB_FULL_IRET);
return (0);
}
@@ -208,7 +210,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);
}
@@ -405,7 +407,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);
@@ -528,7 +530,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);
@@ -623,7 +625,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 */
@@ -712,7 +714,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);
}
@@ -755,8 +757,7 @@ ia32_setregs(td, entry, stack, ps_string
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: stable/8/sys/amd64/include/pcb.h
==============================================================================
--- stable/8/sys/amd64/include/pcb.h Wed Mar 2 18:53:12 2011 (r219186)
+++ stable/8/sys/amd64/include/pcb.h Wed Mar 2 19:09:49 2011 (r219187)
@@ -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_int 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_int flags)
+{
+
+ __asm __volatile("orl %1,%0"
+ : "=m" (pcb->pcb_flags) : "ir" (flags), "m" (pcb->pcb_flags)
+ : "cc");
+}
+
+static __inline void
+clear_pcb_flags(struct pcb *pcb, const u_int flags)
+{
+
+ __asm __volatile("andl %1,%0"
+ : "=m" (pcb->pcb_flags) : "ir" (~flags), "m" (pcb->pcb_flags)
+ : "cc");
+}
+
void makectx(struct trapframe *, struct pcb *);
int savectx(struct pcb *);
#endif
Modified: stable/8/sys/amd64/linux32/linux32_machdep.c
==============================================================================
--- stable/8/sys/amd64/linux32/linux32_machdep.c Wed Mar 2 18:53:12 2011 (r219186)
+++ stable/8/sys/amd64/linux32/linux32_machdep.c Wed Mar 2 19:09:49 2011 (r219187)
@@ -616,6 +616,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,
@@ -645,10 +646,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);
}
}
@@ -1178,6 +1180,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;
@@ -1266,8 +1269,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: stable/8/sys/amd64/linux32/linux32_sysvec.c
==============================================================================
--- stable/8/sys/amd64/linux32/linux32_sysvec.c Wed Mar 2 18:53:12 2011 (r219186)
+++ stable/8/sys/amd64/linux32/linux32_sysvec.c Wed Mar 2 19:09:49 2011 (r219187)
@@ -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..
@@ -879,9 +879,8 @@ exec_linux_setregs(td, entry, stack, ps_
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;
}
More information about the svn-src-stable
mailing list