diff options
author | Suresh Siddha <suresh.b.siddha@intel.com> | 2010-07-19 19:05:49 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2010-07-19 20:51:30 -0400 |
commit | 29104e101d710dd152f807978884643a52eca8b7 (patch) | |
tree | 03ab625528d91ad13d60a817c7885591fea197b3 /arch/x86/kernel/i387.c | |
parent | a1488f8bf4d72ad724700f6e982469a1240e4264 (diff) |
x86, xsave: Sync xsave memory layout with its header for user handling
With xsaveopt, if a processor implementation discern that a processor state
component is in its initialized state it may modify the corresponding bit in
the xsave_hdr.xstate_bv as '0', with out modifying the corresponding memory
layout. Hence wHile presenting the xstate information to the user, we always
ensure that the memory layout of a feature will be in the init state if the
corresponding header bit is zero. This ensures the consistency and avoids the
condition of the user seeing some some stale state in the memory layout during
signal handling, debugging etc.
Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
LKML-Reference: <20100719230205.351459480@sbs-t61.sc.intel.com>
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch/x86/kernel/i387.c')
-rw-r--r-- | arch/x86/kernel/i387.c | 11 |
1 files changed, 11 insertions, 0 deletions
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c index 86cef6b32253..6106af9fd129 100644 --- a/arch/x86/kernel/i387.c +++ b/arch/x86/kernel/i387.c | |||
@@ -190,6 +190,8 @@ int xfpregs_get(struct task_struct *target, const struct user_regset *regset, | |||
190 | if (ret) | 190 | if (ret) |
191 | return ret; | 191 | return ret; |
192 | 192 | ||
193 | sanitize_i387_state(target); | ||
194 | |||
193 | return user_regset_copyout(&pos, &count, &kbuf, &ubuf, | 195 | return user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
194 | &target->thread.fpu.state->fxsave, 0, -1); | 196 | &target->thread.fpu.state->fxsave, 0, -1); |
195 | } | 197 | } |
@@ -207,6 +209,8 @@ int xfpregs_set(struct task_struct *target, const struct user_regset *regset, | |||
207 | if (ret) | 209 | if (ret) |
208 | return ret; | 210 | return ret; |
209 | 211 | ||
212 | sanitize_i387_state(target); | ||
213 | |||
210 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | 214 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, |
211 | &target->thread.fpu.state->fxsave, 0, -1); | 215 | &target->thread.fpu.state->fxsave, 0, -1); |
212 | 216 | ||
@@ -446,6 +450,8 @@ int fpregs_get(struct task_struct *target, const struct user_regset *regset, | |||
446 | -1); | 450 | -1); |
447 | } | 451 | } |
448 | 452 | ||
453 | sanitize_i387_state(target); | ||
454 | |||
449 | if (kbuf && pos == 0 && count == sizeof(env)) { | 455 | if (kbuf && pos == 0 && count == sizeof(env)) { |
450 | convert_from_fxsr(kbuf, target); | 456 | convert_from_fxsr(kbuf, target); |
451 | return 0; | 457 | return 0; |
@@ -467,6 +473,8 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset, | |||
467 | if (ret) | 473 | if (ret) |
468 | return ret; | 474 | return ret; |
469 | 475 | ||
476 | sanitize_i387_state(target); | ||
477 | |||
470 | if (!HAVE_HWFP) | 478 | if (!HAVE_HWFP) |
471 | return fpregs_soft_set(target, regset, pos, count, kbuf, ubuf); | 479 | return fpregs_soft_set(target, regset, pos, count, kbuf, ubuf); |
472 | 480 | ||
@@ -533,6 +541,9 @@ static int save_i387_xsave(void __user *buf) | |||
533 | struct _fpstate_ia32 __user *fx = buf; | 541 | struct _fpstate_ia32 __user *fx = buf; |
534 | int err = 0; | 542 | int err = 0; |
535 | 543 | ||
544 | |||
545 | sanitize_i387_state(tsk); | ||
546 | |||
536 | /* | 547 | /* |
537 | * For legacy compatible, we always set FP/SSE bits in the bit | 548 | * For legacy compatible, we always set FP/SSE bits in the bit |
538 | * vector while saving the state to the user context. | 549 | * vector while saving the state to the user context. |