Skip to content

Commit a6662c3

Browse files
Shawn Anastasiochmeeedalf
Shawn Anastasio
authored andcommitted
powerpc: Implement fpu_kern_enter/fpu_kern_leave
Summary: Provide an implementation of fpu_kern_enter/fpu_kern_leave for PPC to enable FPU, VSX, and Altivec usage in-kernel. The functions currently only support FPU_KERN_NOCTX, but this is sufficient for ossl(1) and many other users of the API. This patchset has been tested on powerpc64le using a modified version of the in-tree tools/tools/crypto/cryptocheck.c tool to check for FPU/Vec register clobbering along with a follow-up patch to enable ossl(4) on powerpc64*. Reviewed by: jhibbits MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D41540
1 parent 67a2773 commit a6662c3

File tree

8 files changed

+199
-17
lines changed

8 files changed

+199
-17
lines changed

share/man/man9/fpu_kern.9

+4-1
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,8 @@ and false otherwise.
185185
.Sh NOTES
186186
The
187187
.Nm
188-
is currently implemented only for the i386, amd64, and arm64 architectures.
188+
is currently implemented only for the i386, amd64, arm64, and powerpc
189+
architectures.
189190
.Pp
190191
There is no way to handle floating point exceptions raised from
191192
kernel mode.
@@ -205,6 +206,8 @@ facitily and this manual page were written by
205206
.An Konstantin Belousov Aq Mt [email protected] .
206207
The arm64 support was added by
207208
.An Andrew Turner Aq Mt [email protected] .
209+
The powerpc support was added by
210+
.An Shawn Anastasio Aq Mt [email protected] .
208211
.Sh BUGS
209212
.Fn fpu_kern_leave
210213
should probably have type

sys/powerpc/include/altivec.h

+2
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,7 @@
3535
void enable_vec(struct thread *);
3636
void save_vec(struct thread *);
3737
void save_vec_nodrop(struct thread *);
38+
void enable_vec_kern(void);
39+
void disable_vec(struct thread *td);
3840

3941
#endif /* _MACHINE_ALTIVEC_H_ */

sys/powerpc/include/fpu.h

+20
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,26 @@ void save_fpu(struct thread *);
7676
void save_fpu_nodrop(struct thread *);
7777
void cleanup_fpscr(void);
7878
u_int get_fpu_exception(struct thread *);
79+
void enable_fpu_kern(void);
80+
void disable_fpu(struct thread *td);
81+
82+
/*
83+
* Flags for fpu_kern_alloc_ctx(), fpu_kern_enter() and fpu_kern_thread().
84+
*/
85+
#define FPU_KERN_NORMAL 0x0000
86+
#define FPU_KERN_NOWAIT 0x0001
87+
#define FPU_KERN_KTHR 0x0002
88+
#define FPU_KERN_NOCTX 0x0004
89+
90+
struct fpu_kern_ctx;
91+
92+
struct fpu_kern_ctx *fpu_kern_alloc_ctx(u_int flags);
93+
void fpu_kern_free_ctx(struct fpu_kern_ctx *ctx);
94+
void fpu_kern_enter(struct thread *td, struct fpu_kern_ctx *ctx,
95+
u_int flags);
96+
int fpu_kern_leave(struct thread *td, struct fpu_kern_ctx *ctx);
97+
int fpu_kern_thread(u_int flags);
98+
int is_fpu_kern_thread(u_int flags);
7999

80100
#endif /* _KERNEL */
81101

sys/powerpc/include/pcb.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -48,19 +48,22 @@ struct pcb {
4848
register_t pcb_toc; /* toc pointer */
4949
register_t pcb_lr; /* link register */
5050
register_t pcb_dscr; /* dscr value */
51-
register_t pcb_fscr;
51+
register_t pcb_fscr;
5252
register_t pcb_tar;
5353
struct pmap *pcb_pm; /* pmap of our vmspace */
5454
jmp_buf *pcb_onfault; /* For use during
5555
copyin/copyout */
5656
int pcb_flags;
5757
#define PCB_FPU 0x1 /* Process uses FPU */
5858
#define PCB_FPREGS 0x2 /* Process had FPU registers initialized */
59-
#define PCB_VEC 0x4 /* Process had Altivec initialized */
59+
#define PCB_VEC 0x4 /* Process uses Altivec */
6060
#define PCB_VSX 0x8 /* Process had VSX initialized */
6161
#define PCB_CDSCR 0x10 /* Process had Custom DSCR initialized */
6262
#define PCB_HTM 0x20 /* Process had HTM initialized */
6363
#define PCB_CFSCR 0x40 /* Process had FSCR updated */
64+
#define PCB_KERN_FPU 0x80 /* Kernel is using FPU/Vector unit */
65+
#define PCB_KERN_FPU_NOSAVE 0x100 /* FPU/Vec state not saved for kernel use */
66+
#define PCB_VECREGS 0x200 /* Process had Altivec registers initialized */
6467
struct fpu {
6568
union {
6669
#if _BYTE_ORDER == _BIG_ENDIAN

sys/powerpc/powerpc/altivec.c

+32-2
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,11 @@ enable_vec(struct thread *td)
105105
* the thread, initialise the vector registers and VSCR to 0, and
106106
* set the flag to indicate that the vector unit is in use.
107107
*/
108+
pcb->pcb_flags |= PCB_VEC;
108109
tf->srr1 |= PSL_VEC;
109-
if (!(pcb->pcb_flags & PCB_VEC)) {
110+
if (!(pcb->pcb_flags & PCB_VECREGS)) {
110111
memset(&pcb->pcb_vec, 0, sizeof pcb->pcb_vec);
111-
pcb->pcb_flags |= PCB_VEC;
112+
pcb->pcb_flags |= PCB_VECREGS;
112113
}
113114

114115
/*
@@ -170,3 +171,32 @@ save_vec_nodrop(struct thread *td)
170171
if (td == PCPU_GET(vecthread))
171172
save_vec_int(td);
172173
}
174+
175+
void
176+
enable_vec_kern(void)
177+
{
178+
mtmsr(mfmsr() | PSL_VEC);
179+
}
180+
181+
void
182+
disable_vec(struct thread *td)
183+
{
184+
register_t msr;
185+
struct pcb *pcb;
186+
struct trapframe *tf;
187+
188+
pcb = td->td_pcb;
189+
tf = trapframe(td);
190+
191+
/* Disable PSL_VEC in kernel (if enabled) */
192+
msr = mfmsr() & ~PSL_VEC;
193+
isync();
194+
mtmsr(msr);
195+
196+
/*
197+
* Disable PSL_VEC in userspace. It will be re-enabled when
198+
* an Altivec instruction is executed.
199+
*/
200+
tf->srr1 &= ~PSL_VEC;
201+
pcb->pcb_flags &= ~PCB_VEC;
202+
}

sys/powerpc/powerpc/exec_machdep.c

+10-11
Original file line numberDiff line numberDiff line change
@@ -441,12 +441,14 @@ grab_mcontext(struct thread *td, mcontext_t *mcp, int flags)
441441
* Repeat for Altivec context
442442
*/
443443

444-
if (pcb->pcb_flags & PCB_VEC) {
445-
KASSERT(td == curthread,
446-
("get_mcontext: fp save not curthread"));
447-
critical_enter();
448-
save_vec(td);
449-
critical_exit();
444+
if (pcb->pcb_flags & PCB_VECREGS) {
445+
if (pcb->pcb_flags & PCB_VEC) {
446+
KASSERT(td == curthread,
447+
("get_mcontext: altivec save not curthread"));
448+
critical_enter();
449+
save_vec(td);
450+
critical_exit();
451+
}
450452
mcp->mc_flags |= _MC_AV_VALID;
451453
mcp->mc_vscr = pcb->pcb_vec.vscr;
452454
mcp->mc_vrsave = pcb->pcb_vec.vrsave;
@@ -543,11 +545,8 @@ set_mcontext(struct thread *td, mcontext_t *mcp)
543545
}
544546

545547
if (mcp->mc_flags & _MC_AV_VALID) {
546-
if ((pcb->pcb_flags & PCB_VEC) != PCB_VEC) {
547-
critical_enter();
548-
enable_vec(td);
549-
critical_exit();
550-
}
548+
/* enable_vec() will happen lazily on a fault */
549+
pcb->pcb_flags |= PCB_VECREGS;
551550
pcb->pcb_vec.vscr = mcp->mc_vscr;
552551
pcb->pcb_vec.vrsave = mcp->mc_vrsave;
553552
memcpy(pcb->pcb_vec.vr, mcp->mc_avec, sizeof(mcp->mc_avec));

sys/powerpc/powerpc/fpu.c

+125
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include <machine/fpu.h>
4343
#include <machine/pcb.h>
4444
#include <machine/psl.h>
45+
#include <machine/altivec.h>
4546

4647
static void
4748
save_fpu_int(struct thread *td)
@@ -259,3 +260,127 @@ get_fpu_exception(struct thread *td)
259260
return ucode;
260261
}
261262

263+
void
264+
enable_fpu_kern(void)
265+
{
266+
register_t msr;
267+
268+
msr = mfmsr() | PSL_FP;
269+
270+
if (cpu_features & PPC_FEATURE_HAS_VSX)
271+
msr |= PSL_VSX;
272+
273+
mtmsr(msr);
274+
}
275+
276+
void
277+
disable_fpu(struct thread *td)
278+
{
279+
register_t msr;
280+
struct pcb *pcb;
281+
struct trapframe *tf;
282+
283+
pcb = td->td_pcb;
284+
tf = trapframe(td);
285+
286+
/* Disable FPU in kernel (if enabled) */
287+
msr = mfmsr() & ~(PSL_FP | PSL_VSX);
288+
isync();
289+
mtmsr(msr);
290+
291+
/*
292+
* Disable FPU in userspace. It will be re-enabled when
293+
* an FP or VSX instruction is executed.
294+
*/
295+
tf->srr1 &= ~(PSL_FP | PSL_VSX);
296+
pcb->pcb_flags &= ~(PCB_FPU | PCB_VSX);
297+
}
298+
299+
#ifndef __SPE__
300+
/*
301+
* XXX: Implement fpu_kern_alloc_ctx/fpu_kern_free_ctx once fpu_kern_enter and
302+
* fpu_kern_leave can handle !FPU_KERN_NOCTX.
303+
*/
304+
struct fpu_kern_ctx {
305+
#define FPU_KERN_CTX_DUMMY 0x01 /* avoided save for the kern thread */
306+
#define FPU_KERN_CTX_INUSE 0x02
307+
uint32_t flags;
308+
};
309+
310+
void
311+
fpu_kern_enter(struct thread *td, struct fpu_kern_ctx *ctx, u_int flags)
312+
{
313+
struct pcb *pcb;
314+
315+
pcb = td->td_pcb;
316+
317+
KASSERT((flags & FPU_KERN_NOCTX) != 0 || ctx != NULL,
318+
("ctx is required when !FPU_KERN_NOCTX"));
319+
KASSERT(ctx == NULL || (ctx->flags & FPU_KERN_CTX_INUSE) == 0,
320+
("using inuse ctx"));
321+
KASSERT((pcb->pcb_flags & PCB_KERN_FPU_NOSAVE) == 0,
322+
("recursive fpu_kern_enter while in PCB_KERN_FPU_NOSAVE state"));
323+
324+
if ((flags & FPU_KERN_NOCTX) != 0) {
325+
critical_enter();
326+
327+
if (pcb->pcb_flags & PCB_FPU) {
328+
save_fpu(td);
329+
pcb->pcb_flags |= PCB_FPREGS;
330+
}
331+
enable_fpu_kern();
332+
333+
if (pcb->pcb_flags & PCB_VEC) {
334+
save_vec(td);
335+
pcb->pcb_flags |= PCB_VECREGS;
336+
}
337+
enable_vec_kern();
338+
339+
pcb->pcb_flags |= PCB_KERN_FPU | PCB_KERN_FPU_NOSAVE;
340+
return;
341+
}
342+
343+
KASSERT(0, ("fpu_kern_enter with !FPU_KERN_NOCTX not implemented!"));
344+
}
345+
346+
int
347+
fpu_kern_leave(struct thread *td, struct fpu_kern_ctx *ctx)
348+
{
349+
struct pcb *pcb;
350+
351+
pcb = td->td_pcb;
352+
353+
if ((pcb->pcb_flags & PCB_KERN_FPU_NOSAVE) != 0) {
354+
KASSERT(ctx == NULL, ("non-null ctx after FPU_KERN_NOCTX"));
355+
KASSERT(PCPU_GET(fpcurthread) == NULL,
356+
("non-NULL fpcurthread for PCB_FP_NOSAVE"));
357+
CRITICAL_ASSERT(td);
358+
359+
/* Disable FPU, VMX, and VSX */
360+
disable_fpu(td);
361+
disable_vec(td);
362+
363+
pcb->pcb_flags &= ~PCB_KERN_FPU_NOSAVE;
364+
365+
critical_exit();
366+
} else {
367+
KASSERT(0, ("fpu_kern_leave with !FPU_KERN_NOCTX not implemented!"));
368+
}
369+
370+
pcb->pcb_flags &= ~PCB_KERN_FPU;
371+
372+
return 0;
373+
}
374+
375+
int
376+
is_fpu_kern_thread(u_int flags __unused)
377+
{
378+
struct pcb *curpcb;
379+
380+
if ((curthread->td_pflags & TDP_KTHREAD) == 0)
381+
return (0);
382+
curpcb = curthread->td_pcb;
383+
return ((curpcb->pcb_flags & PCB_KERN_FPU) != 0);
384+
}
385+
386+
#endif /* !__SPE__ */

sys/sys/param.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
* cannot include sys/param.h and should only be updated here.
7676
*/
7777
#undef __FreeBSD_version
78-
#define __FreeBSD_version 1500000
78+
#define __FreeBSD_version 1500001
7979

8080
/*
8181
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,

0 commit comments

Comments
 (0)