Fix for mis-interpretation of PCB_KERNFPU.

RIght now PCB_KERNFPU is used both as indication that kernel prepared
hardware FPU context to use and that the thread is fpu-kern
thread.  This also breaks fpu_kern_enter(FPU_KERN_NOCTX), since
fpu_kern_leave() then clears PCB_KERNFPU.

Introduce new flag PCB_KERNFPU_THR which indicates that the thread is
fpu-kern.  Do not clear PCB_KERNFPU if fpu-kern thread leaves noctx
fpu region.

Reported and tested by:	jhb (amd64)
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
Differential revision:	https://reviews.freebsd.org/D25511
This commit is contained in:
Konstantin Belousov 2020-10-14 23:01:41 +00:00
parent d3ba71b2b1
commit e406235000
4 changed files with 14 additions and 10 deletions

View File

@ -1230,8 +1230,9 @@ fpu_kern_leave(struct thread *td, struct fpu_kern_ctx *ctx)
if (pcb->pcb_save == get_pcb_user_save_pcb(pcb)) {
if ((pcb->pcb_flags & PCB_USERFPUINITDONE) != 0) {
set_pcb_flags(pcb, PCB_FPUINITDONE);
clear_pcb_flags(pcb, PCB_KERNFPU);
} else
if ((pcb->pcb_flags & PCB_KERNFPU_THR) == 0)
clear_pcb_flags(pcb, PCB_KERNFPU);
} else if ((pcb->pcb_flags & PCB_KERNFPU_THR) == 0)
clear_pcb_flags(pcb, PCB_FPUINITDONE | PCB_KERNFPU);
} else {
if ((ctx->flags & FPU_KERN_CTX_FPUINITDONE) != 0)
@ -1254,7 +1255,7 @@ fpu_kern_thread(u_int flags)
("mangled pcb_save"));
KASSERT(PCB_USER_FPU(curpcb), ("recursive call"));
set_pcb_flags(curpcb, PCB_KERNFPU);
set_pcb_flags(curpcb, PCB_KERNFPU | PCB_KERNFPU_THR);
return (0);
}
@ -1264,7 +1265,7 @@ is_fpu_kern_thread(u_int flags)
if ((curthread->td_pflags & TDP_KTHREAD) == 0)
return (0);
return ((curpcb->pcb_flags & PCB_KERNFPU) != 0);
return ((curpcb->pcb_flags & PCB_KERNFPU_THR) != 0);
}
/*

View File

@ -84,6 +84,7 @@ struct pcb {
#define PCB_KERNFPU 0x04 /* kernel uses fpu */
#define PCB_FPUINITDONE 0x08 /* fpu state is initialized */
#define PCB_USERFPUINITDONE 0x10 /* fpu user state is initialized */
#define PCB_KERNFPU_THR 0x20 /* fpu_kern_thread() */
#define PCB_32BIT 0x40 /* process has 32 bit context (segs etc) */
#define PCB_FPUNOSAVE 0x80 /* no save area for current FPU ctx */

View File

@ -1472,11 +1472,12 @@ fpu_kern_leave(struct thread *td, struct fpu_kern_ctx *ctx)
}
if (pcb->pcb_save == get_pcb_user_save_pcb(pcb)) {
if ((pcb->pcb_flags & PCB_NPXUSERINITDONE) != 0)
if ((pcb->pcb_flags & PCB_NPXUSERINITDONE) != 0) {
pcb->pcb_flags |= PCB_NPXINITDONE;
else
pcb->pcb_flags &= ~PCB_NPXINITDONE;
pcb->pcb_flags &= ~PCB_KERNNPX;
if ((pcb->pcb_flags & PCB_KERNNPX_THR) == 0)
pcb->pcb_flags |= ~PCB_KERNNPX;
} else if ((pcb->pcb_flags & PCB_KERNNPX_THR) == 0)
pcb->pcb_flags &= ~(PCB_NPXINITDONE | PCB_KERNNPX);
} else {
if ((ctx->flags & FPU_KERN_CTX_NPXINITDONE) != 0)
pcb->pcb_flags |= PCB_NPXINITDONE;
@ -1498,7 +1499,7 @@ fpu_kern_thread(u_int flags)
("mangled pcb_save"));
KASSERT(PCB_USER_FPU(curpcb), ("recursive call"));
curpcb->pcb_flags |= PCB_KERNNPX;
curpcb->pcb_flags |= PCB_KERNNPX | PCB_KERNNPX_THR;
return (0);
}
@ -1508,7 +1509,7 @@ is_fpu_kern_thread(u_int flags)
if ((curthread->td_pflags & TDP_KTHREAD) == 0)
return (0);
return ((curpcb->pcb_flags & PCB_KERNNPX) != 0);
return ((curpcb->pcb_flags & PCB_KERNNPX_THR) != 0);
}
/*

View File

@ -82,6 +82,7 @@ struct pcb {
u_int pcb_flags;
#define PCB_DBREGS 0x02 /* process using debug registers */
#define PCB_KERNNPX_THR 0x04 /* fpu_kern_thread() */
#define PCB_NPXINITDONE 0x08 /* fpu state is initialized */
#define PCB_VM86CALL 0x10 /* in vm86 call */
#define PCB_NPXUSERINITDONE 0x20 /* user fpu state is initialized */