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:
parent
6e4e1c18e4
commit
e6c006d96a
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=216634
@ -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:
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user