summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjkim <jkim@FreeBSD.org>2010-12-22 00:18:42 +0000
committerjkim <jkim@FreeBSD.org>2010-12-22 00:18:42 +0000
commit24b08bca030970592bc5241517b0462f603b05b1 (patch)
tree38bd55300c4f19ade4f88947688e903fcf6ef97c
parentf4e75b41ae7145e275808cc561d4cacf0f9a51a7 (diff)
downloadFreeBSD-src-24b08bca030970592bc5241517b0462f603b05b1.zip
FreeBSD-src-24b08bca030970592bc5241517b0462f603b05b1.tar.gz
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
-rw-r--r--sys/amd64/amd64/cpu_switch.S6
-rw-r--r--sys/amd64/amd64/exception.S14
-rw-r--r--sys/amd64/amd64/fpu.c36
-rw-r--r--sys/amd64/amd64/genassym.c12
-rw-r--r--sys/amd64/amd64/machdep.c48
-rw-r--r--sys/amd64/amd64/sys_machdep.c16
-rw-r--r--sys/amd64/amd64/vm_machdep.c16
-rw-r--r--sys/amd64/ia32/ia32_reg.c2
-rw-r--r--sys/amd64/ia32/ia32_signal.c23
-rw-r--r--sys/amd64/include/pcb.h52
-rw-r--r--sys/amd64/linux32/linux32_machdep.c14
-rw-r--r--sys/amd64/linux32/linux32_sysvec.c13
12 files changed, 152 insertions, 100 deletions
diff --git a/sys/amd64/amd64/cpu_switch.S b/sys/amd64/amd64/cpu_switch.S
index 3ad0ef7..8161fa4 100644
--- a/sys/amd64/amd64/cpu_switch.S
+++ b/sys/amd64/amd64/cpu_switch.S
@@ -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:
diff --git a/sys/amd64/amd64/exception.S b/sys/amd64/amd64/exception.S
index 7ffa7a9..2d6f97a 100644
--- a/sys/amd64/amd64/exception.S
+++ b/sys/amd64/amd64/exception.S
@@ -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
diff --git a/sys/amd64/amd64/fpu.c b/sys/amd64/amd64/fpu.c
index 1b493b4..08e5e57 100644
--- a/sys/amd64/amd64/fpu.c
+++ b/sys/amd64/amd64/fpu.c
@@ -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 savefpu *addr)
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 fpu_kern_ctx *ctx, u_int flags)
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 fpu_kern_ctx *ctx)
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);
}
diff --git a/sys/amd64/amd64/genassym.c b/sys/amd64/amd64/genassym.c
index bc30174..585f274 100644
--- a/sys/amd64/amd64/genassym.c
+++ b/sys/amd64/amd64/genassym.c
@@ -145,22 +145,22 @@ ASSYM(PCB_DR2, offsetof(struct pcb, pcb_dr2));
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));
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index 5661a84..6c946e6 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -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, sigset_t *mask)
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, sigset_t *mask)
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, sigset_t *mask)
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 image_params *imgp, u_long stack)
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 image_params *imgp, u_long stack)
*/
reset_dbregs();
}
- pcb->pcb_flags &= ~PCB_DBREGS;
+ clear_pcb_flags(pcb, PCB_DBREGS);
}
/*
@@ -1904,7 +1910,7 @@ set_regs(struct thread *td, struct reg *regs)
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 fpreg *fpregs)
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_t *mcp, int flags)
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_t *mcp, int flags)
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 mcontext_t *mcp)
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 dbreg *dbregs)
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);
diff --git a/sys/amd64/amd64/sys_machdep.c b/sys/amd64/amd64/sys_machdep.c
index bb81664..74a4924 100644
--- a/sys/amd64/amd64/sys_machdep.c
+++ b/sys/amd64/amd64/sys_machdep.c
@@ -103,7 +103,7 @@ sysarch_ldt(struct thread *td, struct sysarch_args *uap, int uap_space)
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, uint32_t base)
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, uint32_t base)
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 */
diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c
index b966393..8e8d0c1 100644
--- a/sys/amd64/amd64/vm_machdep.c
+++ b/sys/amd64/amd64/vm_machdep.c
@@ -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 thread *td0)
* 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, void (*entry)(void *), void *arg,
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);
}
diff --git a/sys/amd64/ia32/ia32_reg.c b/sys/amd64/ia32/ia32_reg.c
index da6eb0f..279df9a 100644
--- a/sys/amd64/ia32/ia32_reg.c
+++ b/sys/amd64/ia32/ia32_reg.c
@@ -125,7 +125,7 @@ set_regs32(struct thread *td, struct reg32 *regs)
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;
diff --git a/sys/amd64/ia32/ia32_signal.c b/sys/amd64/ia32/ia32_signal.c
index e0f30e2..808790b 100644
--- a/sys/amd64/ia32/ia32_signal.c
+++ b/sys/amd64/ia32/ia32_signal.c
@@ -130,8 +130,10 @@ ia32_set_fpcontext(struct thread *td, const struct ia32_mcontext *mcp)
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, struct ia32_mcontext *mcp, int flags)
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, const struct ia32_mcontext *mcp)
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, ksiginfo_t *ksi, sigset_t *mask)
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 *ksi, sigset_t *mask)
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 image_params *imgp, u_long stack)
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;
}
diff --git a/sys/amd64/include/pcb.h b/sys/amd64/include/pcb.h
index e226379..2a2c8cd 100644
--- a/sys/amd64/include/pcb.h
+++ b/sys/amd64/include/pcb.h
@@ -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
diff --git a/sys/amd64/linux32/linux32_machdep.c b/sys/amd64/linux32/linux32_machdep.c
index be0acb3..8d4050e 100644
--- a/sys/amd64/linux32/linux32_machdep.c
+++ b/sys/amd64/linux32/linux32_machdep.c
@@ -590,6 +590,7 @@ linux_clone(struct thread *td, struct linux_clone_args *args)
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 linux_clone_args *args)
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);
diff --git a/sys/amd64/linux32/linux32_sysvec.c b/sys/amd64/linux32/linux32_sysvec.c
index 3ebb980..674a286e 100644
--- a/sys/amd64/linux32/linux32_sysvec.c
+++ b/sys/amd64/linux32/linux32_sysvec.c
@@ -422,7 +422,7 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
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 *ksi, sigset_t *mask)
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, struct linux_sigreturn_args *args)
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, struct linux_rt_sigreturn_args *args)
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, struct image_params *imgp, u_long stack)
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;
}
OpenPOWER on IntegriCloud