On Thu, 2023-12-21 at 09:02 -0500, Yang Weijiang wrote: > Use fpu_guest_cfg to calculate guest fpstate settings, open code for > __fpstate_reset() to avoid using kernel FPU config. > > Below configuration steps are currently enforced to get guest fpstate: > 1) Kernel sets up guest FPU settings in fpu__init_system_xstate(). > 2) User space sets vCPU thread group xstate permits via arch_prctl(). > 3) User space creates guest fpstate via __fpu_alloc_init_guest_fpstate() > for vcpu thread. > 4) User space enables guest dynamic xfeatures and re-allocate guest > fpstate. > > By adding kernel dynamic xfeatures in above #1 and #2, guest xstate area > size is expanded to hold (fpu_kernel_cfg.default_features | kernel dynamic > xfeatures | user dynamic xfeatures), then host xsaves/xrstors can operate > for all guest xfeatures. > > The user_* fields remain unchanged for compatibility with KVM uAPIs. > > Signed-off-by: Yang Weijiang <weijiang.yang@xxxxxxxxx> > --- > arch/x86/kernel/fpu/core.c | 47 ++++++++++++++++++++++++++++++-------- > 1 file changed, 37 insertions(+), 10 deletions(-) > > diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c > index 976f519721e2..0e0bf151418f 100644 > --- a/arch/x86/kernel/fpu/core.c > +++ b/arch/x86/kernel/fpu/core.c > @@ -250,8 +250,6 @@ void fpu_reset_from_exception_fixup(void) > } > > #if IS_ENABLED(CONFIG_KVM) > -static void __fpstate_reset(struct fpstate *fpstate, u64 xfd); > - > static void fpu_init_guest_permissions(struct fpu_guest *gfpu) > { > struct fpu_state_perm *fpuperm; > @@ -272,25 +270,54 @@ static void fpu_init_guest_permissions(struct fpu_guest *gfpu) > gfpu->perm = perm & ~FPU_GUEST_PERM_LOCKED; > } > > -bool fpu_alloc_guest_fpstate(struct fpu_guest *gfpu) > +static struct fpstate *__fpu_alloc_init_guest_fpstate(struct fpu_guest *gfpu) > { > + bool compacted = cpu_feature_enabled(X86_FEATURE_XCOMPACTED); > + unsigned int gfpstate_size, size; > struct fpstate *fpstate; > - unsigned int size; > > - size = fpu_user_cfg.default_size + ALIGN(offsetof(struct fpstate, regs), 64); > + /* > + * fpu_guest_cfg.default_size is initialized to hold all enabled > + * xfeatures except the user dynamic xfeatures. If the user dynamic > + * xfeatures are enabled, the guest fpstate will be re-allocated to > + * hold all guest enabled xfeatures, so omit user dynamic xfeatures > + * here. > + */ > + size = fpu_guest_cfg.default_size + > + ALIGN(offsetof(struct fpstate, regs), 64); > + > fpstate = vzalloc(size); > if (!fpstate) > - return false; > + return NULL; > + /* > + * Initialize sizes and feature masks, use fpu_user_cfg.* > + * for user_* settings for compatibility of exiting uAPIs. > + */ > + fpstate->size = gfpstate_size; > + fpstate->xfeatures = fpu_guest_cfg.default_features; > + fpstate->user_size = fpu_user_cfg.default_size; > + fpstate->user_xfeatures = fpu_user_cfg.default_features; > + fpstate->xfd = 0; > > - /* Leave xfd to 0 (the reset value defined by spec) */ > - __fpstate_reset(fpstate, 0); > fpstate_init_user(fpstate); > fpstate->is_valloc = true; > fpstate->is_guest = true; > > gfpu->fpstate = fpstate; > - gfpu->xfeatures = fpu_user_cfg.default_features; > - gfpu->perm = fpu_user_cfg.default_features; > + gfpu->xfeatures = fpu_guest_cfg.default_features; > + gfpu->perm = fpu_guest_cfg.default_features; > + > + return fpstate; > +} > + > +bool fpu_alloc_guest_fpstate(struct fpu_guest *gfpu) > +{ > + struct fpstate *fpstate; > + > + fpstate = __fpu_alloc_init_guest_fpstate(gfpu); > + > + if (!fpstate) > + return false; > > /* > * KVM sets the FP+SSE bits in the XSAVE header when copying FPU state Reviewed-by: Maxim Levitsky <mlevitsk@xxxxxxxxxx> Best regards, Maxim Levitsky