x86/fpu: Prepare guest FPU for dynamically enabled FPU features
authorThomas Gleixner <tglx@linutronix.de>
Wed, 5 Jan 2022 12:35:13 +0000 (04:35 -0800)
committerPaolo Bonzini <pbonzini@redhat.com>
Fri, 7 Jan 2022 18:33:03 +0000 (13:33 -0500)
To support dynamically enabled FPU features for guests prepare the guest
pseudo FPU container to keep track of the currently enabled xfeatures and
the guest permissions.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Jing Liu <jing2.liu@intel.com>
Signed-off-by: Yang Zhong <yang.zhong@intel.com>
Message-Id: <20220105123532.12586-3-yang.zhong@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/include/asm/fpu/types.h
arch/x86/kernel/fpu/core.c

index 6ddf806..c752d0a 100644 (file)
@@ -505,6 +505,19 @@ struct fpu {
  */
 struct fpu_guest {
        /*
+        * @xfeatures:                  xfeature bitmap of features which are
+        *                              currently enabled for the guest vCPU.
+        */
+       u64                             xfeatures;
+
+       /*
+        * @perm:                       xfeature bitmap of features which are
+        *                              permitted to be enabled for the guest
+        *                              vCPU.
+        */
+       u64                             perm;
+
+       /*
         * @fpstate:                    Pointer to the allocated guest fpstate
         */
        struct fpstate                  *fpstate;
index ab19b3d..eddeeb4 100644 (file)
@@ -201,6 +201,26 @@ void fpu_reset_from_exception_fixup(void)
 #if IS_ENABLED(CONFIG_KVM)
 static void __fpstate_reset(struct fpstate *fpstate);
 
+static void fpu_init_guest_permissions(struct fpu_guest *gfpu)
+{
+       struct fpu_state_perm *fpuperm;
+       u64 perm;
+
+       if (!IS_ENABLED(CONFIG_X86_64))
+               return;
+
+       spin_lock_irq(&current->sighand->siglock);
+       fpuperm = &current->group_leader->thread.fpu.guest_perm;
+       perm = fpuperm->__state_perm;
+
+       /* First fpstate allocation locks down permissions. */
+       WRITE_ONCE(fpuperm->__state_perm, perm | FPU_GUEST_PERM_LOCKED);
+
+       spin_unlock_irq(&current->sighand->siglock);
+
+       gfpu->perm = perm & ~FPU_GUEST_PERM_LOCKED;
+}
+
 bool fpu_alloc_guest_fpstate(struct fpu_guest *gfpu)
 {
        struct fpstate *fpstate;
@@ -216,7 +236,11 @@ bool fpu_alloc_guest_fpstate(struct fpu_guest *gfpu)
        fpstate->is_valloc      = true;
        fpstate->is_guest       = true;
 
-       gfpu->fpstate = fpstate;
+       gfpu->fpstate           = fpstate;
+       gfpu->xfeatures         = fpu_user_cfg.default_features;
+       gfpu->perm              = fpu_user_cfg.default_features;
+       fpu_init_guest_permissions(gfpu);
+
        return true;
 }
 EXPORT_SYMBOL_GPL(fpu_alloc_guest_fpstate);