Changeset View
Changeset View
Standalone View
Standalone View
head/sys/amd64/amd64/fpu.c
Show First 20 Lines • Show All 910 Lines • ▼ Show 20 Lines | |||||
DRIVER_MODULE(fpupnp, acpi, fpupnp_driver, fpupnp_devclass, 0, 0); | DRIVER_MODULE(fpupnp, acpi, fpupnp_driver, fpupnp_devclass, 0, 0); | ||||
#endif /* DEV_ISA */ | #endif /* DEV_ISA */ | ||||
static MALLOC_DEFINE(M_FPUKERN_CTX, "fpukern_ctx", | static MALLOC_DEFINE(M_FPUKERN_CTX, "fpukern_ctx", | ||||
"Kernel contexts for FPU state"); | "Kernel contexts for FPU state"); | ||||
#define FPU_KERN_CTX_FPUINITDONE 0x01 | #define FPU_KERN_CTX_FPUINITDONE 0x01 | ||||
#define FPU_KERN_CTX_DUMMY 0x02 /* avoided save for the kern thread */ | #define FPU_KERN_CTX_DUMMY 0x02 /* avoided save for the kern thread */ | ||||
#define FPU_KERN_CTX_INUSE 0x04 | |||||
struct fpu_kern_ctx { | struct fpu_kern_ctx { | ||||
struct savefpu *prev; | struct savefpu *prev; | ||||
uint32_t flags; | uint32_t flags; | ||||
char hwstate1[]; | char hwstate1[]; | ||||
}; | }; | ||||
struct fpu_kern_ctx * | struct fpu_kern_ctx * | ||||
fpu_kern_alloc_ctx(u_int flags) | fpu_kern_alloc_ctx(u_int flags) | ||||
{ | { | ||||
struct fpu_kern_ctx *res; | struct fpu_kern_ctx *res; | ||||
size_t sz; | size_t sz; | ||||
sz = sizeof(struct fpu_kern_ctx) + XSAVE_AREA_ALIGN + | sz = sizeof(struct fpu_kern_ctx) + XSAVE_AREA_ALIGN + | ||||
cpu_max_ext_state_size; | cpu_max_ext_state_size; | ||||
res = malloc(sz, M_FPUKERN_CTX, ((flags & FPU_KERN_NOWAIT) ? | res = malloc(sz, M_FPUKERN_CTX, ((flags & FPU_KERN_NOWAIT) ? | ||||
M_NOWAIT : M_WAITOK) | M_ZERO); | M_NOWAIT : M_WAITOK) | M_ZERO); | ||||
return (res); | return (res); | ||||
} | } | ||||
void | void | ||||
fpu_kern_free_ctx(struct fpu_kern_ctx *ctx) | fpu_kern_free_ctx(struct fpu_kern_ctx *ctx) | ||||
{ | { | ||||
KASSERT((ctx->flags & FPU_KERN_CTX_INUSE) == 0, ("free'ing inuse ctx")); | |||||
/* XXXKIB clear the memory ? */ | /* XXXKIB clear the memory ? */ | ||||
free(ctx, M_FPUKERN_CTX); | free(ctx, M_FPUKERN_CTX); | ||||
} | } | ||||
static struct savefpu * | static struct savefpu * | ||||
fpu_kern_ctx_savefpu(struct fpu_kern_ctx *ctx) | fpu_kern_ctx_savefpu(struct fpu_kern_ctx *ctx) | ||||
{ | { | ||||
vm_offset_t p; | vm_offset_t p; | ||||
p = (vm_offset_t)&ctx->hwstate1; | p = (vm_offset_t)&ctx->hwstate1; | ||||
p = roundup2(p, XSAVE_AREA_ALIGN); | p = roundup2(p, XSAVE_AREA_ALIGN); | ||||
return ((struct savefpu *)p); | return ((struct savefpu *)p); | ||||
} | } | ||||
int | int | ||||
fpu_kern_enter(struct thread *td, struct fpu_kern_ctx *ctx, u_int flags) | fpu_kern_enter(struct thread *td, struct fpu_kern_ctx *ctx, u_int flags) | ||||
{ | { | ||||
struct pcb *pcb; | struct pcb *pcb; | ||||
KASSERT((ctx->flags & FPU_KERN_CTX_INUSE) == 0, ("using inuse ctx")); | |||||
if ((flags & FPU_KERN_KTHR) != 0 && is_fpu_kern_thread(0)) { | if ((flags & FPU_KERN_KTHR) != 0 && is_fpu_kern_thread(0)) { | ||||
ctx->flags = FPU_KERN_CTX_DUMMY; | ctx->flags = FPU_KERN_CTX_DUMMY | FPU_KERN_CTX_INUSE; | ||||
return (0); | return (0); | ||||
} | } | ||||
pcb = td->td_pcb; | pcb = td->td_pcb; | ||||
KASSERT(!PCB_USER_FPU(pcb) || pcb->pcb_save == | KASSERT(!PCB_USER_FPU(pcb) || pcb->pcb_save == | ||||
get_pcb_user_save_pcb(pcb), ("mangled pcb_save")); | get_pcb_user_save_pcb(pcb), ("mangled pcb_save")); | ||||
ctx->flags = 0; | ctx->flags = FPU_KERN_CTX_INUSE; | ||||
if ((pcb->pcb_flags & PCB_FPUINITDONE) != 0) | if ((pcb->pcb_flags & PCB_FPUINITDONE) != 0) | ||||
ctx->flags |= FPU_KERN_CTX_FPUINITDONE; | ctx->flags |= FPU_KERN_CTX_FPUINITDONE; | ||||
fpuexit(td); | fpuexit(td); | ||||
ctx->prev = pcb->pcb_save; | ctx->prev = pcb->pcb_save; | ||||
pcb->pcb_save = fpu_kern_ctx_savefpu(ctx); | pcb->pcb_save = fpu_kern_ctx_savefpu(ctx); | ||||
set_pcb_flags(pcb, PCB_KERNFPU); | set_pcb_flags(pcb, PCB_KERNFPU); | ||||
clear_pcb_flags(pcb, PCB_FPUINITDONE); | clear_pcb_flags(pcb, PCB_FPUINITDONE); | ||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
fpu_kern_leave(struct thread *td, struct fpu_kern_ctx *ctx) | fpu_kern_leave(struct thread *td, struct fpu_kern_ctx *ctx) | ||||
{ | { | ||||
struct pcb *pcb; | struct pcb *pcb; | ||||
KASSERT((ctx->flags & FPU_KERN_CTX_INUSE) != 0, | |||||
("leaving not inuse ctx")); | |||||
ctx->flags &= ~FPU_KERN_CTX_INUSE; | |||||
if (is_fpu_kern_thread(0) && (ctx->flags & FPU_KERN_CTX_DUMMY) != 0) | if (is_fpu_kern_thread(0) && (ctx->flags & FPU_KERN_CTX_DUMMY) != 0) | ||||
return (0); | return (0); | ||||
KASSERT((ctx->flags & FPU_KERN_CTX_DUMMY) == 0, ("dummy ctx")); | KASSERT((ctx->flags & FPU_KERN_CTX_DUMMY) == 0, ("dummy ctx")); | ||||
pcb = td->td_pcb; | pcb = td->td_pcb; | ||||
critical_enter(); | critical_enter(); | ||||
if (curthread == PCPU_GET(fpcurthread)) | if (curthread == PCPU_GET(fpcurthread)) | ||||
fpudrop(); | fpudrop(); | ||||
▲ Show 20 Lines • Show All 64 Lines • Show Last 20 Lines |