Define kernel API to get address of each state in xsave area
authorFenghua Yu <fenghua.yu@intel.com>
Thu, 29 May 2014 18:12:44 +0000 (11:12 -0700)
committerH. Peter Anvin <hpa@linux.intel.com>
Thu, 29 May 2014 21:33:09 +0000 (14:33 -0700)
In standard form, each state is saved in the xsave area in fixed offset.
But in compacted form, offset of each saved state only can be calculated during
run time because some xstates may not be enabled and saved.

We define kernel API get_xsave_addr() returns address of a given state saved in a xsave area.

It can be called in kernel to get address of each xstate in xsave area in
either standard format or compacted format.

It's useful when kernel wants to directly access each state in xsave area.

Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
Link: http://lkml.kernel.org/r/1401387164-43416-17-git-send-email-fenghua.yu@intel.com
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
arch/x86/include/asm/xsave.h
arch/x86/kernel/process.c
arch/x86/kernel/xsave.c

index aa3ff0cca9a100bf1f1ee3e7a2e04a9a1c99ab67..1ba577c670ad110a2ced566757e23b35096f3258 100644 (file)
@@ -255,4 +255,7 @@ static inline int xrestore_user(struct xsave_struct __user *buf, u64 mask)
        return err;
 }
 
+void *get_xsave_addr(struct xsave_struct *xsave, int xstate);
+void setup_xstate_comp(void);
+
 #endif
index 4505e2a950d81f479663df20ce787dbad5f293b0..f804dc935d2adffb37f587d34de9c4cd10ce70a3 100644 (file)
@@ -93,6 +93,7 @@ void arch_task_cache_init(void)
                kmem_cache_create("task_xstate", xstate_size,
                                  __alignof__(union thread_xstate),
                                  SLAB_PANIC | SLAB_NOTRACK, NULL);
+       setup_xstate_comp();
 }
 
 /*
index f930f8ab92d1025d7e72db3223f08154f5898b00..a6cb8233f628f99905030f230cab3d72d177d95f 100644 (file)
@@ -481,6 +481,47 @@ static void __init setup_xstate_features(void)
        } while (1);
 }
 
+/*
+ * This function sets up offsets and sizes of all extended states in
+ * xsave area. This supports both standard format and compacted format
+ * of the xsave aread.
+ *
+ * Input: void
+ * Output: void
+ */
+void setup_xstate_comp(void)
+{
+       int i;
+
+       xstate_comp_offsets = kmalloc(xstate_features * sizeof(int),
+                                     GFP_KERNEL);
+       xstate_comp_sizes = kmalloc(xstate_features * sizeof(int), GFP_KERNEL);
+
+       if (!cpu_has_xsaves) {
+               for (i = 2; i < xstate_features; i++) {
+                       if (test_bit(i, (unsigned long *)&pcntxt_mask)) {
+                               xstate_comp_offsets[i] = xstate_offsets[i];
+                               xstate_comp_sizes[i] = xstate_sizes[i];
+                       }
+               }
+               return;
+       }
+
+       xstate_comp_offsets[2] = FXSAVE_SIZE + XSAVE_HDR_SIZE;
+
+       for (i = 2; i < xstate_features; i++) {
+               if (test_bit(i, (unsigned long *)&pcntxt_mask))
+                       xstate_comp_sizes[i] = xstate_sizes[i];
+               else
+                       xstate_comp_sizes[i] = 0;
+
+               if (i > 2)
+                       xstate_comp_offsets[i] = xstate_comp_offsets[i-1]
+                                       + xstate_comp_sizes[i-1];
+
+       }
+}
+
 /*
  * setup the xstate image representing the init state
  */
@@ -668,3 +709,26 @@ void eager_fpu_init(void)
        else
                fxrstor_checking(&init_xstate_buf->i387);
 }
+
+/*
+ * Given the xsave area and a state inside, this function returns the
+ * address of the state.
+ *
+ * This is the API that is called to get xstate address in either
+ * standard format or compacted format of xsave area.
+ *
+ * Inputs:
+ *     xsave: base address of the xsave area;
+ *     xstate: state which is defined in xsave.h (e.g. XSTATE_FP, XSTATE_SSE,
+ *     etc.)
+ * Output:
+ *     address of the state in the xsave area.
+ */
+void *get_xsave_addr(struct xsave_struct *xsave, int xstate)
+{
+       int feature = fls64(xstate) - 1;
+       if (!test_bit(feature, (unsigned long *)&pcntxt_mask))
+               return NULL;
+
+       return (void *)xsave + xstate_comp_offsets[feature];
+}