1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-01-12 14:29:28 +00:00

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
This commit is contained in:
Jung-uk Kim 2010-12-22 00:18:42 +00:00
parent 6e4e1c18e4
commit e6c006d96a
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=216634
12 changed files with 152 additions and 100 deletions

View File

@ -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:

View File

@ -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

View File

@ -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);
}

View File

@ -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));

View File

@ -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);

View File

@ -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 */

View File

@ -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);
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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;
}