aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFenghua Yu <fenghua.yu@intel.com>2014-05-29 14:12:44 -0400
committerH. Peter Anvin <hpa@linux.intel.com>2014-05-29 17:33:09 -0400
commit7496d6458fe3219d63848ce4a9afbd86245cab22 (patch)
treee2f8a6a442d153b0708893aedc893469f6a0262d
parent7e7ce87f6ad4e1730364e5e76628b43c5759b700 (diff)
Define kernel API to get address of each state in xsave area
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>
-rw-r--r--arch/x86/include/asm/xsave.h3
-rw-r--r--arch/x86/kernel/process.c1
-rw-r--r--arch/x86/kernel/xsave.c64
3 files changed, 68 insertions, 0 deletions
diff --git a/arch/x86/include/asm/xsave.h b/arch/x86/include/asm/xsave.h
index aa3ff0cca9a1..1ba577c670ad 100644
--- a/arch/x86/include/asm/xsave.h
+++ b/arch/x86/include/asm/xsave.h
@@ -255,4 +255,7 @@ static inline int xrestore_user(struct xsave_struct __user *buf, u64 mask)
255 return err; 255 return err;
256} 256}
257 257
258void *get_xsave_addr(struct xsave_struct *xsave, int xstate);
259void setup_xstate_comp(void);
260
258#endif 261#endif
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 4505e2a950d8..f804dc935d2a 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -93,6 +93,7 @@ void arch_task_cache_init(void)
93 kmem_cache_create("task_xstate", xstate_size, 93 kmem_cache_create("task_xstate", xstate_size,
94 __alignof__(union thread_xstate), 94 __alignof__(union thread_xstate),
95 SLAB_PANIC | SLAB_NOTRACK, NULL); 95 SLAB_PANIC | SLAB_NOTRACK, NULL);
96 setup_xstate_comp();
96} 97}
97 98
98/* 99/*
diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c
index f930f8ab92d1..a6cb8233f628 100644
--- a/arch/x86/kernel/xsave.c
+++ b/arch/x86/kernel/xsave.c
@@ -482,6 +482,47 @@ static void __init setup_xstate_features(void)
482} 482}
483 483
484/* 484/*
485 * This function sets up offsets and sizes of all extended states in
486 * xsave area. This supports both standard format and compacted format
487 * of the xsave aread.
488 *
489 * Input: void
490 * Output: void
491 */
492void setup_xstate_comp(void)
493{
494 int i;
495
496 xstate_comp_offsets = kmalloc(xstate_features * sizeof(int),
497 GFP_KERNEL);
498 xstate_comp_sizes = kmalloc(xstate_features * sizeof(int), GFP_KERNEL);
499
500 if (!cpu_has_xsaves) {
501 for (i = 2; i < xstate_features; i++) {
502 if (test_bit(i, (unsigned long *)&pcntxt_mask)) {
503 xstate_comp_offsets[i] = xstate_offsets[i];
504 xstate_comp_sizes[i] = xstate_sizes[i];
505 }
506 }
507 return;
508 }
509
510 xstate_comp_offsets[2] = FXSAVE_SIZE + XSAVE_HDR_SIZE;
511
512 for (i = 2; i < xstate_features; i++) {
513 if (test_bit(i, (unsigned long *)&pcntxt_mask))
514 xstate_comp_sizes[i] = xstate_sizes[i];
515 else
516 xstate_comp_sizes[i] = 0;
517
518 if (i > 2)
519 xstate_comp_offsets[i] = xstate_comp_offsets[i-1]
520 + xstate_comp_sizes[i-1];
521
522 }
523}
524
525/*
485 * setup the xstate image representing the init state 526 * setup the xstate image representing the init state
486 */ 527 */
487static void __init setup_init_fpu_buf(void) 528static void __init setup_init_fpu_buf(void)
@@ -668,3 +709,26 @@ void eager_fpu_init(void)
668 else 709 else
669 fxrstor_checking(&init_xstate_buf->i387); 710 fxrstor_checking(&init_xstate_buf->i387);
670} 711}
712
713/*
714 * Given the xsave area and a state inside, this function returns the
715 * address of the state.
716 *
717 * This is the API that is called to get xstate address in either
718 * standard format or compacted format of xsave area.
719 *
720 * Inputs:
721 * xsave: base address of the xsave area;
722 * xstate: state which is defined in xsave.h (e.g. XSTATE_FP, XSTATE_SSE,
723 * etc.)
724 * Output:
725 * address of the state in the xsave area.
726 */
727void *get_xsave_addr(struct xsave_struct *xsave, int xstate)
728{
729 int feature = fls64(xstate) - 1;
730 if (!test_bit(feature, (unsigned long *)&pcntxt_mask))
731 return NULL;
732
733 return (void *)xsave + xstate_comp_offsets[feature];
734}