Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
[linux-2.6-microblaze.git] / arch / x86 / kernel / process_64.c
index 40a9638..ec0d836 100644 (file)
@@ -340,6 +340,29 @@ static __always_inline void load_seg_legacy(unsigned short prev_index,
        }
 }
 
+/*
+ * Store prev's PKRU value and load next's PKRU value if they differ. PKRU
+ * is not XSTATE managed on context switch because that would require a
+ * lookup in the task's FPU xsave buffer and require to keep that updated
+ * in various places.
+ */
+static __always_inline void x86_pkru_load(struct thread_struct *prev,
+                                         struct thread_struct *next)
+{
+       if (!cpu_feature_enabled(X86_FEATURE_OSPKE))
+               return;
+
+       /* Stash the prev task's value: */
+       prev->pkru = rdpkru();
+
+       /*
+        * PKRU writes are slightly expensive.  Avoid them when not
+        * strictly necessary:
+        */
+       if (prev->pkru != next->pkru)
+               wrpkru(next->pkru);
+}
+
 static __always_inline void x86_fsgsbase_load(struct thread_struct *prev,
                                              struct thread_struct *next)
 {
@@ -589,6 +612,8 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
 
        x86_fsgsbase_load(prev, next);
 
+       x86_pkru_load(prev, next);
+
        /*
         * Switch the PDA and FPU contexts.
         */