From a2d16bc5417b9c39d12fd9eace1fd3bb0297e4ae Mon Sep 17 00:00:00 2001 From: Andrew Turner Date: Tue, 18 Jul 2017 16:36:32 +0000 Subject: [PATCH] Add support for passing FPU_KERN_NOCTX to fpu_kern_enter on arm64. This will be used to call into UEFI from the kernel. Sponsored by: DARPA, AFRL --- sys/arm64/arm64/vfp.c | 55 ++++++++++++++++++++++++++++++++--------- sys/arm64/include/pcb.h | 1 + sys/arm64/include/vfp.h | 1 + 3 files changed, 45 insertions(+), 12 deletions(-) diff --git a/sys/arm64/arm64/vfp.c b/sys/arm64/arm64/vfp.c index e901ea7b27cf..a98000384e85 100644 --- a/sys/arm64/arm64/vfp.c +++ b/sys/arm64/arm64/vfp.c @@ -262,8 +262,28 @@ fpu_kern_enter(struct thread *td, struct fpu_kern_ctx *ctx, u_int flags) struct pcb *pcb; pcb = td->td_pcb; + KASSERT((flags & FPU_KERN_NOCTX) != 0 || ctx != NULL, + ("ctx is required when !FPU_KERN_NOCTX")); KASSERT(ctx == NULL || (ctx->flags & FPU_KERN_CTX_INUSE) == 0, ("using inuse ctx")); + KASSERT((pcb->pcb_fpflags & PCB_FP_NOSAVE) == 0, + ("recursive fpu_kern_enter while in PCB_FP_NOSAVE state")); + + if ((flags & FPU_KERN_NOCTX) != 0) { + critical_enter(); + if (curthread == PCPU_GET(fpcurthread)) { + vfp_save_state(curthread, pcb); + PCPU_SET(fpcurthread, NULL); + } else { + KASSERT(PCPU_GET(fpcurthread) == NULL, + ("invalid fpcurthread")); + } + + vfp_enable(); + pcb->pcb_fpflags |= PCB_FP_KERN | PCB_FP_NOSAVE | + PCB_FP_STARTED; + return (0); + } if ((flags & FPU_KERN_KTHR) != 0 && is_fpu_kern_thread(0)) { ctx->flags = FPU_KERN_CTX_DUMMY | FPU_KERN_CTX_INUSE; @@ -293,19 +313,30 @@ fpu_kern_leave(struct thread *td, struct fpu_kern_ctx *ctx) pcb = td->td_pcb; - KASSERT((ctx->flags & FPU_KERN_CTX_INUSE) != 0, - ("FPU context not inuse")); - ctx->flags &= ~FPU_KERN_CTX_INUSE; + if ((pcb->pcb_fpflags & PCB_FP_NOSAVE) != 0) { + KASSERT(ctx == NULL, ("non-null ctx after FPU_KERN_NOCTX")); + KASSERT(PCPU_GET(fpcurthread) == NULL, + ("non-NULL fpcurthread for PCB_FP_NOSAVE")); + CRITICAL_ASSERT(td); - if (is_fpu_kern_thread(0) && - (ctx->flags & FPU_KERN_CTX_DUMMY) != 0) - return (0); - KASSERT((ctx->flags & FPU_KERN_CTX_DUMMY) == 0, ("dummy ctx")); - critical_enter(); - vfp_discard(td); - critical_exit(); - pcb->pcb_fpflags &= ~PCB_FP_STARTED; - pcb->pcb_fpusaved = ctx->prev; + vfp_disable(); + pcb->pcb_fpflags &= ~(PCB_FP_NOSAVE | PCB_FP_STARTED); + critical_exit(); + } else { + KASSERT((ctx->flags & FPU_KERN_CTX_INUSE) != 0, + ("FPU context not inuse")); + ctx->flags &= ~FPU_KERN_CTX_INUSE; + + if (is_fpu_kern_thread(0) && + (ctx->flags & FPU_KERN_CTX_DUMMY) != 0) + return (0); + KASSERT((ctx->flags & FPU_KERN_CTX_DUMMY) == 0, ("dummy ctx")); + critical_enter(); + vfp_discard(td); + critical_exit(); + pcb->pcb_fpflags &= ~PCB_FP_STARTED; + pcb->pcb_fpusaved = ctx->prev; + } if (pcb->pcb_fpusaved == &pcb->pcb_fpustate) { pcb->pcb_fpflags &= ~PCB_FP_KERN; diff --git a/sys/arm64/include/pcb.h b/sys/arm64/include/pcb.h index e28f8f00f071..602c0d6f8248 100644 --- a/sys/arm64/include/pcb.h +++ b/sys/arm64/include/pcb.h @@ -56,6 +56,7 @@ struct pcb { int pcb_fpflags; #define PCB_FP_STARTED 0x01 #define PCB_FP_KERN 0x02 +#define PCB_FP_NOSAVE 0x04 /* The bits passed to userspace in get_fpcontext */ #define PCB_FP_USERMASK (PCB_FP_STARTED) u_int pcb_vfpcpu; /* Last cpu this thread ran VFP code */ diff --git a/sys/arm64/include/vfp.h b/sys/arm64/include/vfp.h index b4943d436b4e..318ad02a1b6e 100644 --- a/sys/arm64/include/vfp.h +++ b/sys/arm64/include/vfp.h @@ -56,6 +56,7 @@ struct fpu_kern_ctx; #define FPU_KERN_NORMAL 0x0000 #define FPU_KERN_NOWAIT 0x0001 #define FPU_KERN_KTHR 0x0002 +#define FPU_KERN_NOCTX 0x0004 struct fpu_kern_ctx *fpu_kern_alloc_ctx(u_int); void fpu_kern_free_ctx(struct fpu_kern_ctx *);