You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
/* * Enable the extended processor state save/restore feature. * Called once per CPU onlining. */voidfpu__init_cpu_xstate(void)
{
if (!boot_cpu_has(X86_FEATURE_XSAVE) || !fpu_kernel_cfg.max_features)
return;
cr4_set_bits(X86_CR4_OSXSAVE);
/* * Must happen after CR4 setup and before xsetbv() to allow KVM * lazy passthrough. Write independent of the dynamic state static * key as that does not work on the boot CPU. This also ensures * that any stale state is wiped out from XFD. */if (cpu_feature_enabled(X86_FEATURE_XFD))
wrmsrl(MSR_IA32_XFD, init_fpstate.xfd);
/* * XCR_XFEATURE_ENABLED_MASK (aka. XCR0) sets user features * managed by XSAVE{C, OPT, S} and XRSTOR{S}. Only XSAVE user * states can be set here. */xsetbv(XCR_XFEATURE_ENABLED_MASK, fpu_user_cfg.max_features);
/* * MSR_IA32_XSS sets supervisor states managed by XSAVES. */if (boot_cpu_has(X86_FEATURE_XSAVES)) {
wrmsrl(MSR_IA32_XSS, xfeatures_mask_supervisor() |
xfeatures_mask_independent());
}
}
staticboolhandle_xfd_event(structpt_regs*regs)
{
u64xfd_err;
interr;
if (!IS_ENABLED(CONFIG_X86_64) || !cpu_feature_enabled(X86_FEATURE_XFD))
return false;
//当 MSR_IA32_XFD_ERR 为 0 时说明不是 XFD 引起的事件rdmsrl(MSR_IA32_XFD_ERR, xfd_err);
if (!xfd_err)
return false;
//清除 MSR_IA32_XFD_ERR,让下回 #NM 异常使用wrmsrl(MSR_IA32_XFD_ERR, 0);
//只有用户态引发 #NM/* Die if that happens in kernel space */if (WARN_ON(!user_mode(regs)))
return false;
local_irq_enable();
//使能改进程的 XFD feature,包括 xsave 空间的分配err=xfd_enable_feature(xfd_err);
//如有权限问题或者使能时发生错误,杀死触发 #NM 的进程switch (err) {
case-EPERM:
force_sig_fault(SIGILL, ILL_ILLOPC, error_get_trap_addr(regs));
break;
case-EFAULT:
force_sig(SIGSEGV);
break;
}
local_irq_disable();
return true;
}
DEFINE_IDTENTRY(exc_device_not_available)
{
unsigned longcr0=read_cr0();
if (handle_xfd_event(regs))
return;
...
/* This should not happen. */if (WARN(cr0&X86_CR0_TS, "CR0.TS was set")) {
/* Try to fix it up and carry on. */write_cr0(cr0& ~X86_CR0_TS);
} else {
/* * Something terrible happened, and we're better off trying * to kill the task than getting stuck in a never-ending * loop of #NM faults. */die("unexpected #NM exception", regs, 0);
}
}
arch/x86/kernel/fpu/xstate.c
int__xfd_enable_feature(u64xfd_err, structfpu_guest*guest_fpu)
{
u64xfd_event=xfd_err&XFEATURE_MASK_USER_DYNAMIC;
structfpu_state_perm*perm;
unsigned intksize, usize;
structfpu*fpu;
if (!xfd_event) {
if (!guest_fpu)
pr_err_once("XFD: Invalid xfd error: %016llx\n", xfd_err);
return0;
}
//防止并发使能/* Protect against concurrent modifications */spin_lock_irq(¤t->sighand->siglock);
//如果进程组没有相关 XFD 特性的权限,让它死吧/* If not permitted let it die */if ((xstate_get_group_perm(!!guest_fpu) &xfd_event) !=xfd_event) {
spin_unlock_irq(¤t->sighand->siglock);
return-EPERM;
}
//获取进程相关的 fpu 信息,从这里可以看到它在 task_struct 的位置fpu=¤t->group_leader->thread.fpu;
perm=guest_fpu ? &fpu->guest_perm : &fpu->perm;
ksize=perm->__state_size;
usize=perm->__user_state_size;
/* * The feature is permitted. State size is sufficient. Dropping * the lock is safe here even if more features are added from * another task, the retrieved buffer sizes are valid for the * currently requested feature(s). */spin_unlock_irq(¤t->sighand->siglock);
//给 xsave 区域分配 per 进程的空间/* * Try to allocate a new fpstate. If that fails there is no way * out. */if (fpstate_realloc(xfd_event, ksize, usize, guest_fpu))
return-EFAULT;
return0;
}
/* * Save the FPU register state in fpu->fpstate->regs. The register state is * preserved. * * Must be called with fpregs_lock() held. * * The legacy FNSAVE instruction clears all FPU state unconditionally, so * register state has to be reloaded. That might be a pointless exercise * when the FPU is going to be used by another task right after that. But * this only affects 20+ years old 32bit systems and avoids conditionals all * over the place. * * FXSAVE and all XSAVE variants preserve the FPU register state. */voidsave_fpregs_to_fpstate(structfpu*fpu)
{
if (likely(use_xsave())) {
os_xsave(fpu->fpstate);
update_avx_timestamp(fpu);
return;
}
if (likely(use_fxsr())) {
fxsave(&fpu->fpstate->regs.fxsave);
return;
}
/* * Legacy FPU register saving, FNSAVE always clears FPU registers, * so we have to reload them from the memory state. */
asm volatile("fnsave %[fp]; fwait" : [fp] "=m" (fpu->fpstate->regs.fsave));
frstor(&fpu->fpstate->regs.fsave);
}
arch/x86/kernel/fpu/xstate.h
/* * Save processor xstate to xsave area. * * Uses either XSAVE or XSAVEOPT or XSAVES depending on the CPU features * and command line options. The choice is permanent until the next reboot. */staticinlinevoidos_xsave(structfpstate*fpstate)
{
u64mask=fpstate->xfeatures;
u32lmask=mask;
u32hmask=mask >> 32;
interr;
WARN_ON_FPU(!alternatives_patched);
xfd_validate_state(fpstate, mask, false);
XSTATE_XSAVE(&fpstate->regs.xsave, lmask, hmask, err);
/* We should never fault when copying to a kernel buffer: */WARN_ON_FPU(err);
}