x86/fpu: copy MXCSR & MXCSR_FLAGS with SSE/YMM state
Subsystems (4)
PATCH v2 1/1 x86/fpu: copy MXCSR & MXCSR_FLAGS with SSE/YMM state
On Skylake CPUs I noticed that XRSTOR is unable to deal with xsave areas created by copyout_from_xsaves if the xstate has only SSE/YMM state, but no FP state. That is, xfeatures had XFEATURE_MASK_SSE set, but not XFEATURE_MASK_FP.
The reason is that part of the SSE/YMM state lives in the MXCSR and MXCSR_FLAGS fields of the FP area.
Ensure that whenever we copy SSE or YMM state around, the MXCSR and MXCSR_FLAGS fields are also copied around.
--- arch/x86/kernel/fpu/xstate.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+)
arch/x86/kernel/fpu/xstate.c +44 -0
@@ -920,6 +920,23 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,#endif /* ! CONFIG_ARCH_HAS_PKEYS */ /* +* Weird legacy quirk: SSE and YMM states store information in the +* MXCSR and MXCSR_FLAGS fields of the FP area. That means if the FP +* area is marked as unused in the xfeatures header, we need to copy +* MXCSR and MXCSR_FLAGS if either SSE or YMM are in use. +*/ +static inline bool xfeatures_need_mxcsr_copy (u64 xfeatures) +{ +if (!(xfeatures & (XFEATURE_MASK_SSE |XFEATURE_MASK_YMM ))) +return 0 ; + +if (xfeatures &XFEATURE_MASK_FP ) +return 0 ; + +return 1 ; +} + +/* * This is similar to user_regset_copyout(), but will not add offset to * the source data pointer or increment pos, count, kbuf, and ubuf. */
@@ -987,6 +1004,13 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int of } +if (xfeatures_need_mxcsr_copy (header.xfeatures)) { + offset = offsetof(struct fxregs_state , mxcsr); + size =sizeof (u64);// copy mxcsr & mxcsr_flags +__copy_xstate_to_kernel (kbuf, &xsave->i387.mxcsr, offset, + size, size_total); + } +/* * Fill xsave->i387.sw_reserved value for ptrace frame: */
@@ -1069,6 +1093,13 @@ int copy_xstate_to_user(void __user *ubuf, struct xregs_state *xsave, unsigned i } +if (xfeatures_need_mxcsr_copy (header.xfeatures)) { + offset = offsetof(struct fxregs_state , mxcsr); + size =sizeof (u64);// copy mxcsr & mxcsr_flags +__copy_xstate_to_user (ubuf, &xsave->i387.mxcsr, offset, + size, size_total); + } +/* * Fill xsave->i387.sw_reserved value for ptrace frame: */
@@ -1121,6 +1152,12 @@ int copy_kernel_to_xstate(struct xregs_state *xsave, const void *kbuf) } } +if (xfeatures_need_mxcsr_copy (xfeatures)) { + offset = offsetof(struct fxregs_state , mxcsr); + size =sizeof (u64);// copy mxcsr & mxcsr_flags +memcpy (&xsave->i387.mxcsr, kbuf + offset, size); + } +/* * The state that came in from userspace was user-state only. * Mask all the user states out of 'xfeatures':
@@ -1176,6 +1213,13 @@ int copy_user_to_xstate(struct xregs_state *xsave, const void __user *ubuf) } } +if (xfeatures_need_mxcsr_copy (xfeatures)) { + offset = offsetof(struct fxregs_state , mxcsr); + size =sizeof (u64);// copy mxcsr & mxcsr_flags +if (__copy_from_user (&xsave->i387.mxcsr, ubuf + offset, size)) +return -EFAULT ; + } +/* * The state that came in from userspace was user-state only. * Mask all the user states out of 'xfeatures':
Quoted 15 lines · Rik van Riel
On Skylake CPUs I noticed that XRSTOR is unable to deal with xsave areas created by
copyout_from_xsavesif the xstate has only SSE/YMM state, but no FP state. That is, xfeatures hadXFEATURE_MASK_SSEset, but notXFEATURE_MASK_FP.The reason is that part of the SSE/YMM state lives in the MXCSR and
MXCSR_FLAGSfields of the FP area.Ensure that whenever we copy SSE or YMM state around, the MXCSR and
MXCSR_FLAGSfields are also copied around.Signed-off-by Rik van Riel <[email protected]>--- arch/x86/kernel/fpu/xstate.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+)
...
arch/x86/kernel/fpu/xstate.c int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int of · line 1009
Quoted 7 lines
arch/x86/kernel/fpu/xstate.c +3
-0@@ -987,6 +1004,13 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int of } +if (xfeatures_need_mxcsr_copy (header.xfeatures)) { + offset = offsetof(struct fxregs_state , mxcsr); + size =sizeof (u64);// copy mxcsr & mxcsr_flags
^^^^^^^^^^^^^^^^^^^^^^^^^^^
We don't do // comments, do we?
And side-line comments are always impairing the readability of the code unless it is a struct's members or asm or so ...
Signature · 5 lines
Regards/Gruss,
Boris.
SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg)
-- Quoted 33 lines · Borislav Petkov
Quoted 18 lines · Rik van Riel
On Skylake CPUs I noticed that XRSTOR is unable to deal with xsave areas
created bycopyout_from_xsavesif the xstate has only SSE/YMM state, but
no FP state. That is, xfeatures hadXFEATURE_MASK_SSEset, but notXFEATURE_MASK_FP.The reason is that part of the SSE/YMM state lives in the MXCSR and
MXCSR_FLAGSfields of the FP area.Ensure that whenever we copy SSE or YMM state around, the MXCSR and
MXCSR_FLAGSfields are also copied around.Signed-off-by Rik van Riel <[email protected]>---
arch/x86/kernel/fpu/xstate.c | 44
++++++++++++++++++++++++++++++++++++++++++++1 file changed, 44 insertions(+)...
arch/x86/kernel/fpu/xstate.c int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int of · line 1009
Quoted 8 lines
(quoted diff) +0
-0@@ -987,6 +1004,13 @@ int copy_xstate_to_kernel(void *kbuf, struct
xregs_state*xsave, unsigned int of
}arch/x86/kernel/fpu/xstate.c +3
-0+if (xfeatures_need_mxcsr_copy (header.xfeatures)) { + offset = offsetof(struct fxregs_state , mxcsr); + size =sizeof (u64);// copy mxcsr & mxcsr_flags ^^^^^^^^^^^^^^^^^^^^^^^^^^^
Quoted 5 lines
We don't do // comments, do we?
And side-line comments are always impairing the readability of the code
unless it is a struct's members or asm or so ...
Good point. OTOH, I don't really want to add an extra line to each of these blocks of code, either...
Ingo, how would you like me to do these comments?
Or should I have a magic #define with comment somewhere, like this?
/* Copy both mxcsr & mxcsr_flags */
#define MXCSR_AND_FLAGS_SIZE sizeof(u64)
Quoted 43 lines · Rik van Riel
Quoted 33 lines · Borislav Petkov
Quoted 18 lines · Rik van Riel
On Skylake CPUs I noticed that XRSTOR is unable to deal with xsave areas
created bycopyout_from_xsavesif the xstate has only SSE/YMM state, but
no FP state. That is, xfeatures hadXFEATURE_MASK_SSEset, but notXFEATURE_MASK_FP.The reason is that part of the SSE/YMM state lives in the MXCSR and
MXCSR_FLAGSfields of the FP area.Ensure that whenever we copy SSE or YMM state around, the MXCSR and
MXCSR_FLAGSfields are also copied around.Signed-off-by Rik van Riel <[email protected]>---
arch/x86/kernel/fpu/xstate.c | 44
++++++++++++++++++++++++++++++++++++++++++++1 file changed, 44 insertions(+)...
arch/x86/kernel/fpu/xstate.c int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int of · line 1009
Quoted 8 lines
(quoted diff) +0
-0@@ -987,6 +1004,13 @@ int copy_xstate_to_kernel(void *kbuf, struct
xregs_state*xsave, unsigned int of
}arch/x86/kernel/fpu/xstate.c +3
-0+if (xfeatures_need_mxcsr_copy (header.xfeatures)) { + offset = offsetof(struct fxregs_state , mxcsr); + size =sizeof (u64);// copy mxcsr & mxcsr_flags ^^^^^^^^^^^^^^^^^^^^^^^^^^^Quoted 5 lines
We don't do // comments, do we?
And side-line comments are always impairing the readability of the code
unless it is a struct's members or asm or so ...Good point. OTOH, I don't really want to add an extra line to each of these blocks of code, either...
Quoted 7 lines
Ingo, how would you like me to do these comments?
Or should I have a magic #define with comment somewhere, like this?
/* Copy both mxcsr &
mxcsr_flags*/
#defineMXCSR_AND_FLAGS_SIZEsizeof(u64)
Yeah, that define would make it pretty clear what's going on. Please make it a bit more vebose:
/* Copy both mxcsr & mxcsr_flags with a single u64 memcpy: */ #define MXCSR_AND_FLAGS_SIZE sizeof(u64)
As for same-line comments, it can be the usual comment form:
size = sizeof(u64); /* Copy mxcsr & mxcsr_flags */
But MXCSR_AND_FLAGS_SIZE is more expressive.
BTW., you can also use a separate comment line in such cases:
/* Copy mxcsr & mxcsr_flags in one u64 step: */ size = sizeof(u64);
... as readability is more important than brevity.
It's the C++ comment style that is frowned upon, as it looks weird in Linux kernel code.
Thanks,
Ingo
PATCH v3 1/1 x86/fpu: copy MXCSR & MXCSR_FLAGS with SSE/YMM state
Quoted 8 lines · On Fri, 10 Feb 2017 09:00:54 +0100 Ingo Molnar <[email protected]> wrote:
Quoted 2 lines
/* Copy both mxcsr &
mxcsr_flags*/
#defineMXCSR_AND_FLAGS_SIZEsizeof(u64)Yeah, that define would make it pretty clear what's going on. Please make it a bit more vebose:
/* Copy both mxcsr & mxcsr_flags with a single u64 memcpy: */ #define MXCSR_AND_FLAGS_SIZE sizeof(u64)
OK, here it is :)
---8<---
Subject: x86/fpu: copy MXCSR & MXCSR_FLAGS with SSE/YMM state
On Skylake CPUs I noticed that XRSTOR is unable to deal with states created by copyout_from_xsaves if the xstate has only SSE/YMM state, and no FP state. That is, xfeatures had XFEATURE_MASK_SSE set, but not XFEATURE_MASK_FP.
The reason is that part of the SSE/YMM state lives in the MXCSR and MXCSR_FLAGS fields of the FP state.
Ensure that whenever we copy SSE or YMM state around, the MXCSR and MXCSR_FLAGS fields are also copied around.
--- arch/x86/include/asm/fpu/types.h | 3 +++ arch/x86/kernel/fpu/xstate.c | 44 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+)
arch/x86/include/asm/fpu/types.h +3 -0
@@ -68,6 +68,9 @@ struct fxregs_state {/* Default value for fxregs_state.mxcsr: */ #define MXCSR_DEFAULT 0x1f80 +/* Copy both mxcsr & mxcsr_flags with a single u64 memcpy: */ +#define MXCSR_AND_FLAGS_SIZE sizeof(u64) +/* * Software based FPU emulation state. This is arbitrary really, * it matches the x87 format to make it easier to understand:
arch/x86/kernel/fpu/xstate.c +44 -0
74 lines not on this page · raw message
Ingo Molnar
AppliedQuoted 6 lines · Rik van Riel
/*
+ * Weird legacy quirk: SSE and YMM states store information in the
+ * MXCSR andMXCSR_FLAGSfields of the FP area. That means if the FP
+ * area is marked is unused in the xfeatures header, we need to copy
+ * MXCSR andMXCSR_FLAGSif either SSE or YMM are in use.
+ */
Review
Quoted 10 lines
(quoted diff) +10
-0+static inline bool xfeatures_need_mxcsr_copy(u64 xfeatures) +{ + if (!(xfeatures & (XFEATURE_MASK_SSE|XFEATURE_MASK_YMM))) + return 0; + + if (xfeatures & XFEATURE_MASK_FP) + return 0; + + return 1; +}
Applied to tip:WIP.x86/fpu and will try to get that branch into final shape ASAP, thanks Rik!
BTW., a different approach: could we also implement this quirk via setting the xfeatures bits accordingly? In particular, we could set FP to 1 if we see that XFEATURE_MASK_SSE or XFEATURE_MASK_YMM are set.
I.e. instead of:
header.xfeatures = xsave->header.xfeatures;
We could do something like:
header.xfeatures = xfeatures_quirk(xsave->header.xfeatures);
?
xfeatures_quirk() would do the obvious:
static u64 xfeatures_mxcsr_quirk(u64 xfeatures)
{
if (xfeatures & (XFEATURE_MASK_SSE|XFEATURE_MASK_YMM))
return xfeatures | XFEATURE_MASK_FP;
return xfeatures;
}This means we'd copy the whole FP area, not just the MXCSR* fields, but I think overall it's a cleaner and easier to maintain approach - assuming it works and I'm missing something.
Such as us then sticking that enabled FP bit into the hardware and it could get confused or reject the state if other FP fields have random values?
In any case I've applied your fix with minor edits: I fixed a typo, renamed the quirk function which was a bit long, removed marginal linebreaks and twiddled the changelog. Edited version is attached below.
BTW., would you be interested in adding your FPU user ABI tests to tools/tests/selftests/x86? If there's many tests then I wouldn't mind if it got a new, separate subdirectory, under tools/tests/selftests/x86/fpu/ or so.
Thanks,
Ingo
==========================>
Quoted 1 line
From
85fb989d3a58cb9c7904bb7dd8264be61e18b185Mon Sep 17 00:00:00 2001
From: Rik van Riel <[email protected]>
Date: Fri, 10 Feb 2017 08:54:45 -0500
Subject: [PATCH] x86/fpu: Add FPU state copying quirk to handle XRSTOR failure on Intel Skylake CPUs
On Skylake CPUs I noticed that XRSTOR is unable to deal with states created by copyout_from_xsaves() if the xstate has only SSE/YMM state, and no FP state. That is, xfeatures had XFEATURE_MASK_SSE set, but not XFEATURE_MASK_FP.
The reason is that part of the SSE/YMM state lives in the MXCSR and MXCSR_FLAGS fields of the FP state.
Ensure that whenever we copy SSE or YMM state around, the MXCSR and MXCSR_FLAGS fields are also copied around.
--- arch/x86/include/asm/fpu/types.h | 3 +++ arch/x86/kernel/fpu/xstate.c | 42 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+)
arch/x86/include/asm/fpu/types.h +3 -0
@@ -68,6 +68,9 @@ struct fxregs_state {/* Default value for fxregs_state.mxcsr: */ #define MXCSR_DEFAULT 0x1f80 +/* Copy both mxcsr & mxcsr_flags with a single u64 memcpy: */ +#define MXCSR_AND_FLAGS_SIZE sizeof(u64) +/* * Software based FPU emulation state. This is arbitrary really, * it matches the x87 format to make it easier to understand:
arch/x86/kernel/fpu/xstate.c +42 -0
72 lines not on this page · raw message
tip-bot for Rik van Riel
merge bot[tip:perf/core] x86/fpu: Add FPU state copying quirk to handle XRSTOR failure on Intel Skylake CPUs
In reply to Rik van Rielx86/fpu: Add FPU state copying quirk to handle XRSTOR failure on Intel Skylake CPUs
Commit-ID: 85fb989d3a58cb9c7904bb7dd8264be61e18b185 Gitweb: http://git.kernel.org/tip/85fb989d3a58cb9c7904bb7dd8264be61e18b185 Author: Rik van Riel <[email protected]> AuthorDate: Fri, 10 Feb 2017 08:54:45 -0500 Committer: Ingo Molnar <[email protected]> CommitDate: Sat, 11 Feb 2017 11:00:22 +0100
x86/fpu: Add FPU state copying quirk to handle XRSTOR failure on Intel Skylake CPUs
On Skylake CPUs I noticed that XRSTOR is unable to deal with states created by copyout_from_xsaves() if the xstate has only SSE/YMM state, and no FP state. That is, xfeatures had XFEATURE_MASK_SSE set, but not XFEATURE_MASK_FP.
The reason is that part of the SSE/YMM state lives in the MXCSR and MXCSR_FLAGS fields of the FP state.
Ensure that whenever we copy SSE or YMM state around, the MXCSR and MXCSR_FLAGS fields are also copied around.
--- arch/x86/include/asm/fpu/types.h | 3 +++ arch/x86/kernel/fpu/xstate.c | 42 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+)
arch/x86/include/asm/fpu/types.h +3 -0
@@ -68,6 +68,9 @@ struct fxregs_state {/* Default value for fxregs_state.mxcsr: */ #define MXCSR_DEFAULT 0x1f80 +/* Copy both mxcsr & mxcsr_flags with a single u64 memcpy: */ +#define MXCSR_AND_FLAGS_SIZE sizeof(u64) +/* * Software based FPU emulation state. This is arbitrary really, * it matches the x87 format to make it easier to understand:
arch/x86/kernel/fpu/xstate.c +42 -0
72 lines not on this page · raw message
Quoted 6 lines · Rik van Riel
/*
+ * Weird legacy quirk: SSE and YMM states store information in the
+ * MXCSR andMXCSR_FLAGSfields of the FP area. That means if the FP
+ * area is marked as unused in the xfeatures header, we need to copy
+ * MXCSR andMXCSR_FLAGSif either SSE or YMM are in use.
+ */
arch/x86/kernel/fpu/xstate.c int arch_set_user_pkey_access(struct task_struct *tsk, int pkey, · line 937
Quoted 10 lines
arch/x86/kernel/fpu/xstate.c +10
-0+static inline bool xfeatures_need_mxcsr_copy (u64 xfeatures) +{ +if (!(xfeatures & (XFEATURE_MASK_SSE |XFEATURE_MASK_YMM ))) +return 0 ; + +if (xfeatures &XFEATURE_MASK_FP ) +return 0 ; + +return 1 ; +}
Would you consider separating MXCSR & MXCSR_FLAGS from XFEATURE_MASK_FP. Here we assume if both xstate[0] and xstate[1] are being copied, then there is no need to copy MXCSR/MXCSR_FLAGS again. What if only xstate[0] is copied and MXCSR/MXCSR_FLAGS is invalid?
Yu-cheng
Quoted 17 lines · Yu-cheng Yu
Quoted 16 lines · Rik van Riel
/*
+ * Weird legacy quirk: SSE and YMM states store information in the
+ * MXCSR andMXCSR_FLAGSfields of the FP area. That means if the FP
+ * area is marked as unused in the xfeatures header, we need to copy
+ * MXCSR andMXCSR_FLAGSif either SSE or YMM are in use.
+ */arch/x86/kernel/fpu/xstate.c +8
-0+static inline bool xfeatures_need_mxcsr_copy (u64 xfeatures) +{ +if (!(xfeatures & (XFEATURE_MASK_SSE |XFEATURE_MASK_YMM ))) +return 0 ; + +if (xfeatures &XFEATURE_MASK_FP ) +return 0 ; +
Quoted 8 lines
arch/x86/kernel/fpu/xstate.c int arch_set_user_pkey_access(struct task_struct *tsk, int pkey, · line 937
Quoted 2 lines
arch/x86/kernel/fpu/xstate.c +2
-0+return 1 ; +}Would you consider separating MXCSR &
MXCSR_FLAGSfrom XFEATURE_MASK_FP. Here we assume if both xstate[0] and xstate[1] are being copied, then there is no need to copy MXCSR/MXCSR_FLAGS again. What if only xstate[0] is copied and MXCSR/MXCSR_FLAGS is invalid?
Surely then the CPU would ignore the contents of
MXCSR/MXCSR_FLAGS because the SSE and YMM bits in
the xfeatures header are clear?
What am I missing?
Quoted 27 lines · Rik van Riel
Quoted 17 lines · Yu-cheng Yu
Quoted 16 lines · Rik van Riel
/*
+ * Weird legacy quirk: SSE and YMM states store information in the
+ * MXCSR andMXCSR_FLAGSfields of the FP area. That means if the FP
+ * area is marked as unused in the xfeatures header, we need to copy
+ * MXCSR andMXCSR_FLAGSif either SSE or YMM are in use.
+ */arch/x86/kernel/fpu/xstate.c +8
-0+static inline bool xfeatures_need_mxcsr_copy (u64 xfeatures) +{ +if (!(xfeatures & (XFEATURE_MASK_SSE |XFEATURE_MASK_YMM ))) +return 0 ; + +if (xfeatures &XFEATURE_MASK_FP ) +return 0 ; +Quoted 8 lines
arch/x86/kernel/fpu/xstate.c int arch_set_user_pkey_access(struct task_struct *tsk, int pkey, · line 937
Quoted 2 lines
arch/x86/kernel/fpu/xstate.c +2
-0+return 1 ; +}Would you consider separating MXCSR &
MXCSR_FLAGSfrom XFEATURE_MASK_FP. Here we assume if both xstate[0] and xstate[1] are being copied, then there is no need to copy MXCSR/MXCSR_FLAGS again. What if only xstate[0] is copied and MXCSR/MXCSR_FLAGS is invalid?
Quoted 5 lines
Surely then the CPU would ignore the contents of
MXCSR/MXCSR_FLAGS because the SSE and YMM bits in
the xfeatures header are clear?What am I missing?
For example in copy_user_to_xstate(), is it possible that only xstate[0] is copied in, but in fact the task already has a valid xstate[1] and MXCSR is overwritten? We can think about this as a separate patch.
Thanks,
Yu-cheng
kbuild test robot
build bot[tip:WIP.x86/fpu 31/31] arch/x86/kernel/fpu/xstate.c:931:9-10: WARNING: return of 0/1 in function 'xfeatures_mxcsr_quirk' with return type bool
coccinelle warnings: (new ones prefixed by >>)
tree: https://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git WIP.x86/fpu head: 85fb989d3a58cb9c7904bb7dd8264be61e18b185 commit: 85fb989d3a58cb9c7904bb7dd8264be61e18b185 [31/31] x86/fpu: Add FPU state copying quirk to handle XRSTOR failure on Intel Skylake CPUs
coccinelle warnings: (new ones prefixed by >>)
>> arch/x86/kernel/fpu/xstate.c:931:9-10: WARNING: return of 0/1 in function 'xfeatures_mxcsr_quirk' with return type bool
Please review and possibly fold the followup patch.
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
kbuild test robot
build bot[PATCH] x86/fpu: fix boolreturn.cocci warnings
arch/x86/kernel/fpu/xstate.c:931:9-10: WARNING: return of 0/1 in function 'xfeatures_mxcsr_quirk' with return type bool
arch/x86/kernel/fpu/xstate.c:931:9-10: WARNING: return of 0/1 in function 'xfeatures_mxcsr_quirk' with return type bool
Return statements in functions returning bool should use true/false instead of 1/0.
Generated by: scripts/coccinelle/misc/boolreturn.cocci
---
xstate.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
arch/x86/kernel/fpu/xstate.c +3 -3
@@ -928,12 +928,12 @@ int arch_set_user_pkey_access(struct tasstatic inline bool xfeatures_mxcsr_quirk (u64 xfeatures) {if (!(xfeatures & (XFEATURE_MASK_SSE |XFEATURE_MASK_YMM ))) -return 0 ; +return false;if (xfeatures &XFEATURE_MASK_FP ) -return 0 ; +return false; -return 1 ; +return true; }/*
Re: [PATCH] x86/fpu: fix boolreturn.cocci warnings
Quoted 4 lines · kbuild test robot
arch/x86/kernel/fpu/xstate.c:931:9-10: WARNING: return of 0/1 in function '
xfeatures_mxcsr_quirk' with return type boolReturn statements in functions returning bool should use true/false instead of 1/0.
Note that this is a totally bogus warning. I personally find a 0/1 return more readable than a textual 'true/false', even if bools are used, and nowhere does the kernel mandate the use of 0/1.
So NAK ...
Thanks,
Ingo
Re: [PATCH] x86/fpu: fix boolreturn.cocci warnings
Quoted 11 lines · Ingo Molnar
Quoted 4 lines · kbuild test robot
arch/x86/kernel/fpu/xstate.c:931:9-10: WARNING: return of 0/1 in function '
xfeatures_mxcsr_quirk' with return type boolReturn statements in functions returning bool should use true/false instead of 1/0.
Note that this is a totally bogus warning. I personally find a 0/1 return more readable than a textual 'true/false', even if bools are used, and nowhere does the kernel mandate the use of 0/1.
I disagree.
The fact that booleans have been brought retroactively into the C-Standard does and for compability reasons C still follows the approach "Boolean values are just integers" does not make it any better.
We had stupid bugs, where people returned -EINVAL from a boolean function and introduced silly and hard to understand bugs.
The canonical values assigned to booleans are 'true' and 'false' and not whatever people prefer. Can we please be consistent on that?
Thanks,
tglx
Re: [PATCH] x86/fpu: fix boolreturn.cocci warnings
(Linus and Andrew Cc:-ed)
Quoted 13 lines · Thomas Gleixner
Quoted 11 lines · Ingo Molnar
Quoted 4 lines · kbuild test robot
arch/x86/kernel/fpu/xstate.c:931:9-10: WARNING: return of 0/1 in function '
xfeatures_mxcsr_quirk' with return type boolReturn statements in functions returning bool should use true/false instead of 1/0.
Note that this is a totally bogus warning. I personally find a 0/1 return more readable than a textual 'true/false', even if bools are used, and nowhere does the kernel mandate the use of 0/1.
Quoted 8 lines
I disagree.
The fact that booleans have been brought retroactively into the C-Standard does and for compability reasons C still follows the approach "Boolean values are just integers" does not make it any better.
We had stupid bugs, where people returned
-EINVALfrom a boolean function and introduced silly and hard to understand bugs.
But this function is not using -EINVAL, it's using 0 and 1 which is both correct and unambiguous!
I mean, if the Cocci script warned about -EINVAL then it would have found a clear bug. Now it's warning about the use of 0/1 literals with bool types which is perfectly legal, readable, clear C code!
Quoted 2 lines
The canonical values assigned to booleans are 'true' and 'false' and not whatever people prefer. Can we please be consistent on that?
I think that's backwards, because 1/0 is just as canonical for true/false, and to me personally it's in fact easier to read as well.
I would really like higher level buy-in for that principle (I've Cc:-ed Linus and Andrew), and if indeed the consensus is that '0/1' cannot be used with 'bool' then I'll remove all uses of 'bool' from my patches and from code I care about and use 'int' instead. Please update Documentation/CodingStyle accordingly as well.
To me a lexical 'true/false' instead of '1/0' is a step backwards in readability in many cases - using the slightly wider 'int' type is the lesser evil.
Thanks,
Ingo
Re: [PATCH] x86/fpu: fix boolreturn.cocci warnings
Quoted 2 lines · Ingo Molnar
To me a lexical 'true/false' instead of '1/0' is a step backwards in readability in many cases
What cases are those to you?
I can't think of any case where 1/0 for true/false is "more readable" for boolean returns to me.
tip-bot for kbuild test robot
build bot[tip:perf/core] x86/fpu: Fix boolreturn.cocci warnings
In reply to kbuild test robotx86/fpu: Fix boolreturn.cocci warnings
Commit-ID: 9908f0103652690a7a17f3da415859320e88edc3 Gitweb: http://git.kernel.org/tip/9908f0103652690a7a17f3da415859320e88edc3 Author: kbuild test robot <[email protected]> AuthorDate: Mon, 6 Mar 2017 08:45:53 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Mon, 6 Mar 2017 11:52:47 +0100
x86/fpu: Fix boolreturn.cocci warnings
arch/x86/kernel/fpu/xstate.c:931:9-10: WARNING: return of 0/1 in function 'xfeatures_mxcsr_quirk' with return type bool
Return statements in functions returning bool should use true/false instead of 1/0.
Generated by: scripts/coccinelle/misc/boolreturn.cocci
--- arch/x86/kernel/fpu/xstate.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
arch/x86/kernel/fpu/xstate.c +3 -3
@@ -928,12 +928,12 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,static inline bool xfeatures_mxcsr_quirk (u64 xfeatures) {if (!(xfeatures & (XFEATURE_MASK_SSE |XFEATURE_MASK_YMM ))) -return 0 ; +return false;if (xfeatures &XFEATURE_MASK_FP ) -return 0 ; +return false; -return 1 ; +return true; }/*
PATCH 1/1 x86/fpu: Turn WARN_ON in context switch into WARN_ON_FPU
From: Andi Kleen <[email protected]>
copy_xregs_to_kernel checks if the alternatives have been already patched.
This WARN_ON is always executed in every context switch.
All the other checks in fpu internal.h are WARN_ON_FPU, but this one is plain WARN_ON. I assume it was forgotten to switch it.
So switch it to WARN_ON_FPU too to avoid some unnecessary code in the context switch, and a potentially expensive cache line miss for the global variable.
(or could be removed since if it hasn't triggered by now it probably never will)
--- arch/x86/include/asm/fpu/internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/include/asm/fpu/internal.h +1 -1
@@ -340,7 +340,7 @@ static inline void copy_xregs_to_kernel(struct xregs_state *xstate)u32 hmask = mask >>32 ;int err; -WARN_ON (!alternatives_patched); +WARN_ON_FPU (!alternatives_patched);XSTATE_XSAVE (xstate, lmask, hmask, err);
Signature · 1 line
2.9.3
tip-bot for Andi Kleen
merge bot[tip:perf/core] x86/fpu: Turn WARN_ON() in context switch into WARN_ON_FPU()
x86/fpu: Turn WARN_ON() in context switch into WARN_ON_FPU()
Commit-ID: 6061efb6ee6fc891498a23994a4d0a5e2a52c059 Gitweb: http://git.kernel.org/tip/6061efb6ee6fc891498a23994a4d0a5e2a52c059 Author: Andi Kleen <[email protected]> AuthorDate: Tue, 28 Mar 2017 23:26:05 -0700 Committer: Ingo Molnar <[email protected]> CommitDate: Fri, 31 Mar 2017 11:20:05 +0200
x86/fpu: Turn WARN_ON() in context switch into WARN_ON_FPU()
copy_xregs_to_kernel checks if the alternatives have been already patched.
This WARN_ON() is always executed in every context switch.
All the other checks in fpu internal.h are WARN_ON_FPU(), but this one is plain WARN_ON(). I assume it was forgotten to switch it.
So switch it to WARN_ON_FPU() too to avoid some unnecessary code in the context switch, and a potentially expensive cache line miss for the global variable.
--- arch/x86/include/asm/fpu/internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/include/asm/fpu/internal.h +1 -1
@@ -350,7 +350,7 @@ static inline void copy_xregs_to_kernel(struct xregs_state *xstate)u32 hmask = mask >>32 ;int err; -WARN_ON (!alternatives_patched); +WARN_ON_FPU (!alternatives_patched);XSTATE_XSAVE (xstate, lmask, hmask, err);
v4 cover x86/fpu: prevent leaking FPU registers via invalid FPU state
From: Eric Biggers <[email protected]>
This series fixes the bug found by syzkaller where the ptrace syscall can be used to set invalid bits in a task's FPU state. I also found that an equivalent bug was reachable using the sigreturn syscall, so the first patch fixes the bug in both cases.
The other two patches start validating the other parts of the xstate_header and make it so that invalid FPU states can no longer be abused to leak the FPU registers of other processes.
Changes since v3:
- Rebase onto tip/master
Changes since v2:
- Use an exception handler to handle invalid FPU states (suggested by Andy Lutomirski)
- Check the size of xstate_header.reserved at build time (suggested by Dave Hansen)
Eric Biggers (3):
x86/fpu: don't let userspace set bogus xcomp_bv x86/fpu: tighten validation of user-supplied xstate_header x86/fpu: reinitialize FPU registers if restoring FPU state fails
arch/x86/include/asm/fpu/internal.h | 51 +++++++++++------------------------- arch/x86/include/asm/fpu/xstate.h | 25 ++++++++++++++++++ arch/x86/kernel/fpu/regset.c | 17 +++++------- arch/x86/kernel/fpu/signal.c | 18 ++++++++----- arch/x86/kernel/fpu/xstate.c | 52 ++++++++++++++----------------------- arch/x86/mm/extable.c | 24 +++++++++++++++++ 6 files changed, 102 insertions(+), 85 deletions(-)
Signature · 1 line
2.14.1.821.g8fa685d3b7-goog
PATCH v4 1/3 x86/fpu: don't let userspace set bogus xcomp_bv
From: Eric Biggers <[email protected]>
On x86, userspace can use the ptrace() or rt_sigreturn() system calls to set a task's extended state (xstate) or "FPU" registers. ptrace() can set them for another task using the PTRACE_SETREGSET request with NT_X86_XSTATE, while rt_sigreturn() can set them for the current task. In either case, registers can be set to any value, but the kernel assumes that the XSAVE area itself remains valid in the sense that the CPU can restore it.
However, in the case where the kernel is using the uncompacted xstate format (which it does whenever the XSAVES instruction is unavailable), it was possible for userspace to set the xcomp_bv field in the xstate_header to an arbitrary value. However, all bits in that field are reserved in the uncompacted case, so when switching to a task with nonzero xcomp_bv, the XRSTOR instruction failed with a #GP fault. This caused the WARN_ON_FPU(err) in copy_kernel_to_xregs() to be hit. In addition, since the error is otherwise ignored, the FPU registers from the task previously executing on the CPU were leaked.
Fix the bug by checking that the user-supplied value of xcomp_bv is 0 in the uncompacted case, and returning an error otherwise.
The reason for validating xcomp_bv rather than simply overwriting it with 0 is that we want userspace to see an error if it (incorrectly) provides an XSAVE area in compacted format rather than in uncompacted format.
Note that as before, in case of error we clear the task's FPU state. This is perhaps non-ideal, especially for PTRACE_SETREGSET; it might be better to return an error before changing anything. But it seems the "clear on error" behavior is fine for now, and it's a little tricky to do otherwise because it would mean we couldn't simply copy the full userspace state into kernel memory in one __copy_from_user().
This bug was found by syzkaller, which hit the above-mentioned WARN_ON_FPU():
WARNING: CPU: 1 PID: 0 at ./arch/x86/include/asm/fpu/internal.h:373 __switch_to+0x5b5/0x5d0
CPU: 1 PID: 0 Comm: swapper/1 Not tainted 4.13.0 #453
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
task: ffff9ba2bc8e42c0 task.stack: ffffa78cc036c000
RIP: 0010:__switch_to+0x5b5/0x5d0
RSP: 0000:ffffa78cc08bbb88 EFLAGS: 00010082
RAX: 00000000fffffffe RBX: ffff9ba2b8bf2180 RCX: 00000000c0000100
RDX: 00000000ffffffff RSI: 000000005cb10700 RDI: ffff9ba2b8bf36c0
RBP: ffffa78cc08bbbd0 R08: 00000000929fdf46 R09: 0000000000000001
R10: 0000000000000000 R11: 0000000000000000 R12: ffff9ba2bc8e42c0
R13: 0000000000000000 R14: ffff9ba2b8bf3680 R15: ffff9ba2bf5d7b40
FS: 00007f7e5cb10700(0000) GS:ffff9ba2bf400000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00000000004005cc CR3: 0000000079fd5000 CR4: 00000000001406e0
Call Trace:
Code: 84 00 00 00 00 00 e9 11 fd ff ff 0f ff 66 0f 1f 84 00 00 00 00 00 e9 e7 fa ff ff 0f ff 66 0f 1f 84 00 00 00 00 00 e9 c2 fa ff ff <0f> ff 66 0f 1f 84 00 00 00 00 00 e9 d4 fc ff ff 66 66 2e 0f 1fHere is a C reproducer. The expected behavior is that the program spin forever with no output. However, on a buggy kernel running on a processor with the "xsave" feature but without the "xsaves" feature (e.g. Sandy Bridge through Broadwell for Intel), within a second or two the program reports that the xmm registers were corrupted, i.e. were not restored correctly. With CONFIG_X86_DEBUG_FPU=y it also hits the above kernel warning.
#define _GNU_SOURCE
#include <stdbool.h>
#include <inttypes.h>
#include <linux/elf.h>
#include <stdio.h>
#include <sys/ptrace.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void)
{
int pid = fork();
uint64_t xstate[512];
struct iovec iov = { .iov_base = xstate, .iov_len = sizeof(xstate) };
if (pid == 0) {
bool tracee = true;
for (int i = 0; i < sysconf(_SC_NPROCESSORS_ONLN) && tracee; i++)
tracee = (fork() != 0);
uint32_t xmm0[4] = { [0 ... 3] = tracee ? 0x00000000 : 0xDEADBEEF };
asm volatile(" movdqu %0, %%xmm0\n"
" mov %0, %%rbx\n"
"1: movdqu %%xmm0, %0\n"
" mov %0, %%rax\n"
" cmp %%rax, %%rbx\n"
" je 1b\n"
: "+m" (xmm0) : : "rax", "rbx", "xmm0");
printf("BUG: xmm registers corrupted! tracee=%d, xmm0=%08X%08X%08X%08X\n",
tracee, xmm0[0], xmm0[1], xmm0[2], xmm0[3]);
} else {
usleep(100000);
ptrace(PTRACE_ATTACH, pid, 0, 0);
wait(NULL);
ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov);
xstate[65] = -1;
ptrace(PTRACE_SETREGSET, pid, NT_X86_XSTATE, &iov);
ptrace(PTRACE_CONT, pid, 0, 0);
wait(NULL);
}
return 1;
}Note: the program only tests for the bug using the ptrace() system call. The bug can also be reproduced using the rt_sigreturn() system call, but only when called from a 32-bit program, since for 64-bit programs the kernel restores the FPU state from the signal frame by doing XRSTOR directly from userspace memory (with proper error checking).
--- arch/x86/kernel/fpu/regset.c | 4 ++++ arch/x86/kernel/fpu/signal.c | 9 +++++++-- 2 files changed, 11 insertions(+), 2 deletions(-)
arch/x86/kernel/fpu/regset.c +4 -0
@@ -141,6 +141,10 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset, ret =copy_user_to_xstate (xsave, ubuf); }else { ret =user_regset_copyin (&pos, &count, &kbuf, &ubuf, xsave,0 ,-1 ); + +/* xcomp_bv must be 0 when using uncompacted format */ +if (!ret && xsave->header.xcomp_bv) + ret = -EINVAL ; }/*
arch/x86/kernel/fpu/signal.c +7 -2
@@ -324,11 +324,16 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)*/ fpu__drop (fpu); -if (using_compacted_format ()) +if (using_compacted_format ()) { err =copy_user_to_xstate (&fpu->state.xsave, buf_fx); -else + }else { err =__copy_from_user (&fpu->state.xsave, buf_fx, state_size); +/* xcomp_bv must be 0 when using uncompacted format */ +if (!err && fpu->state.xsave.header.xcomp_bv) + err = -EINVAL ; + } +if (err ||__copy_from_user (&env, buf,sizeof (env))) {fpstate_init (&fpu->state);trace_x86_fpu_init_state (fpu);
Signature · 1 line
2.14.1.821.g8fa685d3b7-goog
PATCH v4 2/3 x86/fpu: tighten validation of user-supplied xstate_header
In reply to Eric BiggersFrom: Eric Biggers <[email protected]>
Move validation of user-supplied xstate_headers into a helper function and call it from both the ptrace and sigreturn syscall paths. The new function also considers it to be an error if *any* reserved bits are set, whereas before we were just clearing most of them.
This should reduce the chance of bugs that fail to correctly validate user-supplied XSAVE areas. It also will expose any broken userspace programs that set the other reserved bits; this is desirable because such programs will lose compatibility with future CPUs and kernels if those bits are ever used for anything. (There shouldn't be any such programs, and in fact in the case where the compacted format is in use we were already validating xfeatures. But you never know...)
--- arch/x86/include/asm/fpu/xstate.h | 25 +++++++++++++++++++ arch/x86/kernel/fpu/regset.c | 21 ++++++---------- arch/x86/kernel/fpu/signal.c | 17 +++++++------ arch/x86/kernel/fpu/xstate.c | 52 ++++++++++++++------------------------- 4 files changed, 60 insertions(+), 55 deletions(-)
arch/x86/include/asm/fpu/xstate.h +25 -0
@@ -52,4 +52,29 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int ofint copy_xstate_to_user (void __user *ubuf,struct xregs_state *xsave,unsigned int offset,unsigned int size);int copy_kernel_to_xstate (struct xregs_state *xsave,const void *kbuf);int copy_user_to_xstate (struct xregs_state *xsave,const void __user *ubuf); + +/* Validate an xstate header supplied by userspace (ptrace or sigreturn) */ +static inline int validate_xstate_header (const struct xstate_header *hdr) +{ +/* No unknown or supervisor features may be set */ +if (hdr->xfeatures & (~xfeatures_mask |XFEATURE_MASK_SUPERVISOR )) +return -EINVAL ; + +/* Userspace must use the uncompacted format */ +if (hdr->xcomp_bv) +return -EINVAL ; + +/* +* If 'reserved' is shrunken to add a new field, make sure to validate +* that new field here! +*/ +BUILD_BUG_ON (sizeof (hdr->reserved) !=48 ); + +/* No reserved bits may be set */ +if (memchr_inv (hdr->reserved,0 ,sizeof (hdr->reserved))) +return -EINVAL ; + +return 0 ; +} +#endif
arch/x86/kernel/fpu/regset.c +7 -14
@@ -134,34 +134,27 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset,fpu__activate_fpstate_write (fpu); -if (boot_cpu_has (X86_FEATURE_XSAVES )) { +if (using_compacted_format ()) {if (kbuf) ret =copy_kernel_to_xstate (xsave, kbuf);else ret =copy_user_to_xstate (xsave, ubuf); }else { ret =user_regset_copyin (&pos, &count, &kbuf, &ubuf, xsave,0 ,-1 ); - -/* xcomp_bv must be 0 when using uncompacted format */ -if (!ret && xsave->header.xcomp_bv) - ret = -EINVAL ; +if (!ret) + ret =validate_xstate_header (&xsave->header); } -/* -* In case of failure, mark all states as init: -*/ -if (ret) -fpstate_init (&fpu->state); -/* * mxcsr reserved bits must be masked to zero for security reasons. */ xsave->i387.mxcsr &= mxcsr_feature_mask; - xsave->header.xfeatures &= xfeatures_mask; +/* -* These bits must be zero. +* In case of failure, mark all states as init: */ -memset (&xsave->header.reserved,0 ,48 ); +if (ret) +fpstate_init (&fpu->state);return ret; }
arch/x86/kernel/fpu/signal.c +9 -8
@@ -214,8 +214,11 @@ sanitize_restored_xstate(struct task_struct *tsk,struct xstate_header *header = &xsave->header;if (use_xsave ()) { -/* These bits must be zero. */ -memset (header->reserved,0 ,48 ); +/* +* Note: we don't need to zero the reserved bits in the +* xstate_header here because we either didn't copy them at all, +* or we checked earlier that they aren't set. +*/ /* * Init the state that is not present in the memory
@@ -224,7 +227,7 @@ sanitize_restored_xstate(struct task_struct *tsk,if (fx_only) header->xfeatures =XFEATURE_MASK_FPSSE ;else - header->xfeatures &= (xfeatures_mask & xfeatures); + header->xfeatures &= xfeatures; }if (use_fxsr ()) {
@@ -308,7 +311,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)/* * For 32-bit frames with fxstate, copy the user state to the * thread's fpu state, reconstruct fxstate from the fsave -* header. Sanitize the copied state etc. +* header. Validate and sanitize the copied state. */ struct fpu *fpu = &tsk->thread.fpu;struct user_i387_ia32_struct env;
@@ -328,10 +331,8 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) err =copy_user_to_xstate (&fpu->state.xsave, buf_fx); }else { err =__copy_from_user (&fpu->state.xsave, buf_fx, state_size); - -/* xcomp_bv must be 0 when using uncompacted format */ -if (!err && fpu->state.xsave.header.xcomp_bv) - err = -EINVAL ; +if (!err) + err =validate_xstate_header (&fpu->state.xsave.header); }if (err ||__copy_from_user (&env, buf,sizeof (env))) {
arch/x86/kernel/fpu/xstate.c +19 -33
116 lines not on this page · raw message
Signature · 1 line
2.14.1.821.g8fa685d3b7-goog
PATCH v4 3/3 x86/fpu: reinitialize FPU registers if restoring FPU state fails
In reply to Eric BiggersFrom: Eric Biggers <[email protected]>
Userspace can change the FPU state of a task using the ptrace() or rt_sigreturn() system calls. Because reserved bits in the FPU state can cause the XRSTOR instruction to fail, the kernel has to carefully validate that no reserved bits or other invalid values are being set.
Unfortunately, there have been bugs in this validation code. For example, we were not checking that the 'xcomp_bv' field in the xstate_header was 0. As-is, such bugs are exploitable to read the FPU registers of other processes on the system. To do so, an attacker can create a task, assign to it an invalid FPU state, then spin in a loop and monitor the values of the FPU registers. Because the task's FPU registers are not being restored, sometimes the FPU registers will have the values from another process.
This is likely to continue to be a problem in the future because the validation done by the CPU instructions like XRSTOR is not immediately visible to kernel developers. Nor will invalid FPU states ever be encountered during ordinary use --- they will only be seen during fuzzing or exploits. There can even be reserved bits outside the xstate_header which are easy to forget about. For example, the MXCSR register contains reserved bits, which were not validated by the KVM_SET_XSAVE ioctl until commit a575813bfe4b ("KVM: x86: Fix load damaged SSEx MXCSR register").
Therefore, mitigate this class of vulnerability by restoring the FPU registers from init_fpstate if restoring from the task's state fails.
We actually used to do this, but it was (perhaps unwisely) removed by commit 9ccc27a5d297 ("x86/fpu: Remove error return values from copy_kernel_to_*regs() functions"). This new patch is also a bit different. First, it only clears the registers, not also the bad in-memory state; this is simpler and makes it easier to make the mitigation cover all callers of __copy_kernel_to_fpregs(). Second, it does the register clearing in an exception handler so that no extra instructions are added to context switches. In fact, we *remove* instructions, since previously we were always zeroing the register containing 'err' even if CONFIG_X86_DEBUG_FPU was disabled.
--- arch/x86/include/asm/fpu/internal.h | 51 +++++++++++-------------------------- arch/x86/mm/extable.c | 24 +++++++++++++++++ 2 files changed, 39 insertions(+), 36 deletions(-)
arch/x86/include/asm/fpu/internal.h +15 -36
@@ -120,20 +120,11 @@ extern void fpstate_sanitize_xstate(struct fpu *fpu); err; \ }) -#define check_insn(insn, output, input...) \ -({ \ - int err; \ +#define kernel_insn(insn, output, input...) \ asm volatile("1:" #insn "\n\t" \ "2:\n" \ - ".section .fixup,\"ax\"\n" \ - "3: movl $-1,%[err]\n" \ - " jmp 2b\n" \ - ".previous\n" \ - _ASM_EXTABLE(1b, 3b) \ - : [err] "=r" (err), output \ - : "0"(0), input); \ - err; \ -}) + _ASM_EXTABLE_HANDLE(1b, 2b, ex_handler_fprestore) \ + : output : input)static inline int copy_fregs_to_user (struct fregs_state __user *fx) {
@@ -153,20 +144,16 @@ static inline int copy_fxregs_to_user(struct fxregs_state __user *fx)static inline void copy_kernel_to_fxregs (struct fxregs_state *fx) { -int err; -if (IS_ENABLED (CONFIG_X86_32 )) { - err = check_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx)); + kernel_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx)); }else {if (IS_ENABLED (CONFIG_AS_FXSAVEQ )) { - err = check_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx)); + kernel_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx)); }else {/* See comment in copy_fxregs_to_kernel() below. */ - err = check_insn(rex64/fxrstor (%[fx]), "=m" (*fx), [fx] "R" (fx), "m" (*fx)); + kernel_insn(rex64/fxrstor (%[fx]), "=m" (*fx), [fx] "R" (fx), "m" (*fx)); } } -/* Copying from a kernel buffer to FPU registers should never fail: */ -WARN_ON_FPU (err); }static inline int copy_user_to_fxregs (struct fxregs_state __user *fx)
@@ -183,9 +170,7 @@ static inline int copy_user_to_fxregs(struct fxregs_state __user *fx)static inline void copy_kernel_to_fregs (struct fregs_state *fx) { - int err = check_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx)); - -WARN_ON_FPU (err); + kernel_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx)); }static inline int copy_user_to_fregs (struct fregs_state __user *fx)
@@ -281,18 +266,13 @@ static inline void copy_fxregs_to_kernel(struct fpu *fpu)* Use XRSTORS to restore context if it is enabled. XRSTORS supports compact * XSAVE area format. */ -#define XSTATE_XRESTORE (st, lmask, hmask, err) \ +#define XSTATE_XRESTORE (st, lmask, hmask) \ asm volatile(ALTERNATIVE(XRSTOR, \ XRSTORS, X86_FEATURE_XSAVES) \ "\n" \ - "xor %[err], %[err]\n" \ "3:\n" \ - ".pushsection .fixup,\"ax\"\n" \ - "4: movl $-2, %[err]\n" \ - "jmp 3b\n" \ - ".popsection\n" \ - _ASM_EXTABLE(661b, 4b) \ - : [err] "=r" (err) \ + _ASM_EXTABLE_HANDLE(661b, 3b, ex_handler_fprestore)\ + : \ : "D" (st), "m" (*st), "a" (lmask), "d" (hmask) \ : "memory")
@@ -336,7 +316,10 @@ static inline void copy_kernel_to_xregs_booting(struct xregs_state *xstate)else XSTATE_OP (XRSTOR , xstate, lmask, hmask, err); -/* We should never fault when copying from a kernel buffer: */ +/* +* We should never fault when copying from a kernel buffer, and the FPU +* state we set at boot time should be valid. +*/ WARN_ON_FPU (err); }
@@ -365,12 +348,8 @@ static inline void copy_kernel_to_xregs(struct xregs_state *xstate, u64 mask) {u32 lmask = mask;u32 hmask = mask >>32 ; -int err; - -XSTATE_XRESTORE (xstate, lmask, hmask, err); -/* We should never fault when copying from a kernel buffer: */ -WARN_ON_FPU (err); +XSTATE_XRESTORE (xstate, lmask, hmask); }/*
arch/x86/mm/extable.c +24 -0
@@ -2,6 +2,7 @@#include <linux/uaccess.h> #include <linux/sched/debug.h> +#include <asm/fpu/internal.h> #include <asm/traps.h> #include <asm/kdebug.h>
@@ -78,6 +79,29 @@ bool ex_handler_refcount(const struct exception_table_entry *fixup, }EXPORT_SYMBOL_GPL (ex_handler_refcount); +/* +* Handler for when we fail to restore a task's FPU state. We should never get +* here because the FPU state of a task using the FPU (task->thread.fpu.state) +* should always be valid. However, past bugs have allowed userspace to set +* reserved bits in the XSAVE area using PTRACE_SETREGSET or sys_rt_sigreturn(). +* These caused XRSTOR to fail when switching to the task, leaking the FPU +* registers of the task previously executing on the CPU. Mitigate this class +* of vulnerability by restoring from the initial state (essentially, zeroing +* out all the FPU registers) if we can't restore from the task's FPU state. +*/ +bool ex_handler_fprestore (const struct exception_table_entry *fixup, +struct pt_regs *regs,int trapnr) +{ + regs->ip =ex_fixup_addr (fixup); + +WARN_ONCE (1 ,"Bad FPU state detected at %pB, reinitializing FPU registers." , + (void *)instruction_pointer (regs)); + +__copy_kernel_to_fpregs (&init_fpstate,-1 ); +return true; +} +EXPORT_SYMBOL_GPL (ex_handler_fprestore); +bool ex_handler_ext (const struct exception_table_entry *fixup,struct pt_regs *regs,int trapnr) {
Signature · 1 line
2.14.1.821.g8fa685d3b7-goog
Re: [PATCH v4 0/3] x86/fpu: prevent leaking FPU registers via invalid FPU state
In reply to Eric BiggersQuoted 25 lines · Eric Biggers
From: Eric Biggers <[email protected]>
This series fixes the bug found by syzkaller where the ptrace syscall can be used to set invalid bits in a task's FPU state. I also found that an equivalent bug was reachable using the sigreturn syscall, so the first patch fixes the bug in both cases.
The other two patches start validating the other parts of the
xstate_headerand make it so that invalid FPU states can no longer be abused to leak the FPU registers of other processes.Changes since v3:
- Rebase onto tip/masterChanges since v2:
- Use an exception handler to handle invalid FPU states (suggested by Andy Lutomirski)
- Check the size of xstate_header.reserved at build time (suggested by Dave Hansen)Eric Biggers (3):
x86/fpu: don't let userspace set bogusxcomp_bvx86/fpu: tighten validation of user-suppliedxstate_headerx86/fpu: reinitialize FPU registers if restoring FPU state fails
Quoted 7 lines
arch/x86/include/asm/fpu/internal.h | 51 +++++++++++------------------------- arch/x86/include/asm/fpu/xstate.h | 25 ++++++++++++++++++ arch/x86/kernel/fpu/regset.c | 17 +++++------- arch/x86/kernel/fpu/signal.c | 18 ++++++++----- arch/x86/kernel/fpu/xstate.c | 52 ++++++++++++++----------------------- arch/x86/mm/extable.c | 24 +++++++++++++++++ 6 files changed, 102 insertions(+), 85 deletions(-)
Thank you Eric - I've applied them and will push it all out together with the other pending bits in WIP.x86/fpu.
Ingo
cover x86 FPU fixes and cleanups for v4.14
So I'd like to push these changes to Linus tomorrow-ish as an RFC pull request in 1-2 days, because there's now 4 fixes depending on these changes, and because the result will be more maintainable for the LTS v4.14 kernel.
The biggest changes from the earlier iterations is the fixes from Eric Biggers for information leaks, plus more cleanups. I have also removed the change that Peter Zijlstra and others felt uneasy about, the ::last_cpu -> ::fpregs_cached change to the state machine. This should make the changes uncontroversial.
Due to taking out that patch I had to rebase the changes, most of which have accrued months of testing in linux-next. So I'm pretty confident about the overall stability of it. (Famous last words.)
Thanks,
Ingo
===============>
Andi Kleen (1):
x86/fpu: Turn WARN_ON() in context switch into WARN_ON_FPU()
Eric Biggers (3):
x86/fpu: Don't let userspace set bogus xcomp_bv x86/fpu: Tighten validation of user-supplied xstate_header x86/fpu: Reinitialize FPU registers if restoring FPU state fails
Ingo Molnar (27):
x86/fpu: Rename copyin_to_xsaves()/copyout_from_xsaves() to copy_user_to_xstate()/copy_xstate_to_user() x86/fpu: Split copy_xstate_to_user() into copy_xstate_to_kernel() & copy_xstate_to_user() x86/fpu: Remove 'ubuf' parameter from the copy_xstate_to_kernel() APIs
x86/fpu: Remove 'kbuf' parameter from the copy_xstate_to_user() APIs
x86/fpu: Clean up parameter order in the copy_xstate_to_*() APIs
x86/fpu: Clean up the parameter definitions of copy_xstate_to_*()
x86/fpu: Remove the 'start_pos' parameter from the __copy_xstate_to_*() functions x86/fpu: Clarify parameter names in the copy_xstate_to_*() methods
x86/fpu: Change 'size_total' parameter to unsigned and standardize the size checks in copy_xstate_to_*() x86/fpu: Simplify __copy_xstate_to_kernel() return values
x86/fpu: Split copy_user_to_xstate() into copy_kernel_to_xstate() & copy_user_to_xstate() x86/fpu: Remove 'ubuf' parameter from the copy_kernel_to_xstate() API
x86/fpu: Remove 'kbuf' parameter from the copy_user_to_xstate() API
x86/fpu: Flip the parameter order in copy_*_to_xstate()
x86/fpu: Simplify fpu->fpregs_active use
x86/fpu: Make the fpu state change in fpu__clear() scheduler-atomic
x86/fpu: Split the state handling in fpu__drop()
x86/fpu: Change fpu->fpregs_active users to fpu->fpstate_active
x86/fpu: Decouple fpregs_activate()/fpregs_deactivate() from fpu->fpregs_active x86/fpu: Remove struct fpu::fpregs_active
x86/fpu: Simplify fpu__activate_fpstate_read()
x86/fpu: Remove fpu__current_fpstate_write_begin/end()
x86/fpu: Rename fpu::fpstate_active to fpu::initialized
x86/fpu: Fix stale comments about lazy FPU logic
x86/fpu: Simplify and speed up fpu__copy()
x86/fpu: Rename fpu__activate_curr() to fpu__initialize()
x86/fpu: Rename fpu__activate_fpstate_read/write() to fpu__read/write()
Rik van Riel (1):
x86/fpu: Add FPU state copying quirk to handle XRSTOR failure on Intel Skylake CPUs
kbuild test robot (1):
x86/fpu: Fix boolreturn.cocci warnings
arch/x86/ia32/ia32_signal.c | 2 +- arch/x86/include/asm/fpu/internal.h | 90 ++++++--------------- arch/x86/include/asm/fpu/types.h | 32 ++------ arch/x86/include/asm/fpu/xstate.h | 33 +++++++- arch/x86/include/asm/trace/fpu.h | 11 +-- arch/x86/kernel/fpu/core.c | 158 +++++++++---------------------------- arch/x86/kernel/fpu/init.c | 2 +- arch/x86/kernel/fpu/regset.c | 48 ++++++------ arch/x86/kernel/fpu/signal.c | 36 +++++---- arch/x86/kernel/fpu/xstate.c | 240 ++++++++++++++++++++++++++++++++++++++++++++------------ arch/x86/kernel/signal.c | 6 +- arch/x86/kvm/x86.c | 2 +- arch/x86/math-emu/fpu_entry.c | 2 +- arch/x86/mm/extable.c | 24 ++++++ arch/x86/mm/pkeys.c | 3 +- 15 files changed, 367 insertions(+), 322 deletions(-)
Signature · 1 line
2.11.0
PATCH 1/33 x86/fpu: Rename copyin_to_xsaves()/copyout_from_xsaves() to copy_user_to_xstate()/copy_xstate_to_user()
The 'copyin/copyout' nomenclature needlessly departs from what the modern FPU code uses, which is:
copy_fpregs_to_fpstate()
copy_fpstate_to_sigframe()
copy_fregs_to_user()
copy_fxregs_to_kernel()
copy_fxregs_to_user()
copy_kernel_to_fpregs()
copy_kernel_to_fregs()
copy_kernel_to_fxregs()
copy_kernel_to_xregs()
copy_user_to_fregs()
copy_user_to_fxregs()
copy_user_to_xregs()
copy_xregs_to_kernel()
copy_xregs_to_user()
I.e. according to this pattern, the following rename should be done:
copyin_to_xsaves() -> copy_user_to_xstate()
copyout_from_xsaves() -> copy_xstate_to_user()
or, if we want to be pedantic, denote that that the user-space format is ptrace:
copyin_to_xsaves() -> copy_user_ptrace_to_xstate()
copyout_from_xsaves() -> copy_xstate_to_user_ptrace()
But I'd suggest the shorter, non-pedantic name.
--- arch/x86/include/asm/fpu/xstate.h | 4 ++-- arch/x86/kernel/fpu/regset.c | 4 ++-- arch/x86/kernel/fpu/signal.c | 2 +- arch/x86/kernel/fpu/xstate.c | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-)
arch/x86/include/asm/fpu/xstate.h +2 -2
@@ -48,8 +48,8 @@ void fpu__xstate_clear_all_cpu_caps(void);void *get_xsave_addr (struct xregs_state *xsave,int xstate);const void *get_xsave_field_ptr (int xstate_field);int using_compacted_format (void ); -int copyout_from_xsaves (unsigned int pos,unsigned int count,void *kbuf, +int copy_xstate_to_user (unsigned int pos,unsigned int count,void *kbuf,void __user *ubuf,struct xregs_state *xsave); -int copyin_to_xsaves (const void *kbuf,const void __user *ubuf, +int copy_user_to_xstate (const void *kbuf,const void __user *ubuf,struct xregs_state *xsave);#endif
arch/x86/kernel/fpu/regset.c +2 -2
@@ -92,7 +92,7 @@ int xstateregs_get(struct task_struct *target, const struct user_regset *regset,fpu__activate_fpstate_read (fpu);if (using_compacted_format ()) { - ret =copyout_from_xsaves (pos, count, kbuf, ubuf, xsave); + ret =copy_xstate_to_user (pos, count, kbuf, ubuf, xsave); }else {fpstate_sanitize_xstate (fpu);/*
@@ -132,7 +132,7 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset,fpu__activate_fpstate_write (fpu);if (boot_cpu_has (X86_FEATURE_XSAVES )) - ret =copyin_to_xsaves (kbuf, ubuf, xsave); + ret =copy_user_to_xstate (kbuf, ubuf, xsave);else ret =user_regset_copyin (&pos, &count, &kbuf, &ubuf, xsave,0 ,-1 );
arch/x86/kernel/fpu/signal.c +1 -1
@@ -324,7 +324,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)fpu__drop (fpu);if (using_compacted_format ()) { - err =copyin_to_xsaves (NULL , buf_fx, + err =copy_user_to_xstate (NULL , buf_fx, &fpu->state.xsave); }else { err = __copy_from_user(&fpu->state.xsave,
arch/x86/kernel/fpu/xstate.c +2 -2
@@ -951,7 +951,7 @@ static inline int xstate_copyout(unsigned int pos, unsigned int count,* zero. This is called from xstateregs_get() and there we check the CPU * has XSAVES. */ -int copyout_from_xsaves (unsigned int pos,unsigned int count,void *kbuf, +int copy_xstate_to_user (unsigned int pos,unsigned int count,void *kbuf,void __user *ubuf,struct xregs_state *xsave) {unsigned int offset, size;
@@ -1023,7 +1023,7 @@ int copyout_from_xsaves(unsigned int pos, unsigned int count, void *kbuf,* there we check the CPU has XSAVES and a whole standard-sized buffer * exists. */ -int copyin_to_xsaves (const void *kbuf,const void __user *ubuf, +int copy_user_to_xstate (const void *kbuf,const void __user *ubuf,struct xregs_state *xsave) {unsigned int offset, size;
Signature · 1 line
2.11.0
tip-bot for Ingo Molnar
merge bot[tip:x86/fpu] x86/fpu: Rename copyin_to_xsaves()/copyout_from_xsaves() to copy_user_to_xstate()/copy_xstate_to_user()
x86/fpu: Rename copyin_to_xsaves()/copyout_from_xsaves() to copy_user_to_xstate()/copy_xstate_to_user()
Commit-ID: 656f083116a4799d8c0194976b8a2d66bf306538 Gitweb: http://git.kernel.org/tip/656f083116a4799d8c0194976b8a2d66bf306538 Author: Ingo Molnar <[email protected]> AuthorDate: Sat, 23 Sep 2017 14:59:44 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Sun, 24 Sep 2017 13:04:30 +0200
x86/fpu: Rename copyin_to_xsaves()/copyout_from_xsaves() to copy_user_to_xstate()/copy_xstate_to_user()
The 'copyin/copyout' nomenclature needlessly departs from what the modern FPU code uses, which is:
copy_fpregs_to_fpstate()
copy_fpstate_to_sigframe()
copy_fregs_to_user()
copy_fxregs_to_kernel()
copy_fxregs_to_user()
copy_kernel_to_fpregs()
copy_kernel_to_fregs()
copy_kernel_to_fxregs()
copy_kernel_to_xregs()
copy_user_to_fregs()
copy_user_to_fxregs()
copy_user_to_xregs()
copy_xregs_to_kernel()
copy_xregs_to_user()
I.e. according to this pattern, the following rename should be done:
copyin_to_xsaves() -> copy_user_to_xstate()
copyout_from_xsaves() -> copy_xstate_to_user()
or, if we want to be pedantic, denote that that the user-space format is ptrace:
copyin_to_xsaves() -> copy_user_ptrace_to_xstate()
copyout_from_xsaves() -> copy_xstate_to_user_ptrace()
But I'd suggest the shorter, non-pedantic name.
--- arch/x86/include/asm/fpu/xstate.h | 4 ++-- arch/x86/kernel/fpu/regset.c | 4 ++-- arch/x86/kernel/fpu/signal.c | 2 +- arch/x86/kernel/fpu/xstate.c | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-)
arch/x86/include/asm/fpu/xstate.h +2 -2
@@ -48,8 +48,8 @@ void fpu__xstate_clear_all_cpu_caps(void);void *get_xsave_addr (struct xregs_state *xsave,int xstate);const void *get_xsave_field_ptr (int xstate_field);int using_compacted_format (void ); -int copyout_from_xsaves (unsigned int pos,unsigned int count,void *kbuf, +int copy_xstate_to_user (unsigned int pos,unsigned int count,void *kbuf,void __user *ubuf,struct xregs_state *xsave); -int copyin_to_xsaves (const void *kbuf,const void __user *ubuf, +int copy_user_to_xstate (const void *kbuf,const void __user *ubuf,struct xregs_state *xsave);#endif
arch/x86/kernel/fpu/regset.c +2 -2
@@ -92,7 +92,7 @@ int xstateregs_get(struct task_struct *target, const struct user_regset *regset,fpu__activate_fpstate_read (fpu);if (using_compacted_format ()) { - ret =copyout_from_xsaves (pos, count, kbuf, ubuf, xsave); + ret =copy_xstate_to_user (pos, count, kbuf, ubuf, xsave); }else {fpstate_sanitize_xstate (fpu);/*
@@ -132,7 +132,7 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset,fpu__activate_fpstate_write (fpu);if (boot_cpu_has (X86_FEATURE_XSAVES )) - ret =copyin_to_xsaves (kbuf, ubuf, xsave); + ret =copy_user_to_xstate (kbuf, ubuf, xsave);else ret =user_regset_copyin (&pos, &count, &kbuf, &ubuf, xsave,0 ,-1 );
arch/x86/kernel/fpu/signal.c +1 -1
@@ -324,7 +324,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)fpu__drop (fpu);if (using_compacted_format ()) { - err =copyin_to_xsaves (NULL , buf_fx, + err =copy_user_to_xstate (NULL , buf_fx, &fpu->state.xsave); }else { err = __copy_from_user(&fpu->state.xsave,
arch/x86/kernel/fpu/xstate.c +2 -2
@@ -951,7 +951,7 @@ static inline int xstate_copyout(unsigned int pos, unsigned int count,* zero. This is called from xstateregs_get() and there we check the CPU * has XSAVES. */ -int copyout_from_xsaves (unsigned int pos,unsigned int count,void *kbuf, +int copy_xstate_to_user (unsigned int pos,unsigned int count,void *kbuf,void __user *ubuf,struct xregs_state *xsave) {unsigned int offset, size;
@@ -1023,7 +1023,7 @@ int copyout_from_xsaves(unsigned int pos, unsigned int count, void *kbuf,* there we check the CPU has XSAVES and a whole standard-sized buffer * exists. */ -int copyin_to_xsaves (const void *kbuf,const void __user *ubuf, +int copy_user_to_xstate (const void *kbuf,const void __user *ubuf,struct xregs_state *xsave) {unsigned int offset, size;
PATCH 2/33 x86/fpu: Split copy_xstate_to_user() into copy_xstate_to_kernel() & copy_xstate_to_user()
In reply to Ingo Molnarcopy_xstate_to_user() is a weird API - in part due to a bad API inherited from the regset APIs.
But don't propagate that bad API choice into the FPU code - so as a first step split the API into kernel and user buffer handling routines.
(Also split the xstate_copyout() internal helper.)
The split API is a dumb duplication that should be obviously correct, the real splitting will be done in the next patch.
--- arch/x86/include/asm/fpu/xstate.h | 4 +-- arch/x86/kernel/fpu/regset.c | 5 ++- arch/x86/kernel/fpu/xstate.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 109 insertions(+), 10 deletions(-)
arch/x86/include/asm/fpu/xstate.h +2 -2
@@ -48,8 +48,8 @@ void fpu__xstate_clear_all_cpu_caps(void);void *get_xsave_addr (struct xregs_state *xsave,int xstate);const void *get_xsave_field_ptr (int xstate_field);int using_compacted_format (void ); -int copy_xstate_to_user (unsigned int pos,unsigned int count,void *kbuf, -void __user *ubuf,struct xregs_state *xsave); +int copy_xstate_to_kernel (unsigned int pos,unsigned int count,void *kbuf,void __user *ubuf,struct xregs_state *xsave); +int copy_xstate_to_user (unsigned int pos,unsigned int count,void *kbuf,void __user *ubuf,struct xregs_state *xsave);int copy_user_to_xstate (const void *kbuf,const void __user *ubuf,struct xregs_state *xsave);#endif
arch/x86/kernel/fpu/regset.c +4 -1
@@ -92,7 +92,10 @@ int xstateregs_get(struct task_struct *target, const struct user_regset *regset,fpu__activate_fpstate_read (fpu);if (using_compacted_format ()) { - ret =copy_xstate_to_user (pos, count, kbuf, ubuf, xsave); +if (kbuf) + ret =copy_xstate_to_kernel (pos, count, kbuf, ubuf, xsave); +else + ret =copy_xstate_to_user (pos, count, kbuf, ubuf, xsave); }else {fpstate_sanitize_xstate (fpu);/*
arch/x86/kernel/fpu/xstate.c +103 -7
134 lines not on this page · raw message
Signature · 1 line
2.11.0
tip-bot for Ingo Molnar
merge bot[tip:x86/fpu] x86/fpu: Split copy_xstate_to_user() into copy_xstate_to_kernel() & copy_xstate_to_user()
x86/fpu: Split copy_xstate_to_user() into copy_xstate_to_kernel() & copy_xstate_to_user()
Commit-ID: f0d4f30a7fd299587840a028655285a87f334904 Gitweb: http://git.kernel.org/tip/f0d4f30a7fd299587840a028655285a87f334904 Author: Ingo Molnar <[email protected]> AuthorDate: Sat, 23 Sep 2017 14:59:45 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Sun, 24 Sep 2017 13:04:30 +0200
x86/fpu: Split copy_xstate_to_user() into copy_xstate_to_kernel() & copy_xstate_to_user()
copy_xstate_to_user() is a weird API - in part due to a bad API inherited from the regset APIs.
But don't propagate that bad API choice into the FPU code - so as a first step split the API into kernel and user buffer handling routines.
(Also split the xstate_copyout() internal helper.)
The split API is a dumb duplication that should be obviously correct, the real splitting will be done in the next patch.
--- arch/x86/include/asm/fpu/xstate.h | 4 +- arch/x86/kernel/fpu/regset.c | 5 +- arch/x86/kernel/fpu/xstate.c | 110 +++++++++++++++++++++++++++++++++++--- 3 files changed, 109 insertions(+), 10 deletions(-)
arch/x86/include/asm/fpu/xstate.h +2 -2
@@ -48,8 +48,8 @@ void fpu__xstate_clear_all_cpu_caps(void);void *get_xsave_addr (struct xregs_state *xsave,int xstate);const void *get_xsave_field_ptr (int xstate_field);int using_compacted_format (void ); -int copy_xstate_to_user (unsigned int pos,unsigned int count,void *kbuf, -void __user *ubuf,struct xregs_state *xsave); +int copy_xstate_to_kernel (unsigned int pos,unsigned int count,void *kbuf,void __user *ubuf,struct xregs_state *xsave); +int copy_xstate_to_user (unsigned int pos,unsigned int count,void *kbuf,void __user *ubuf,struct xregs_state *xsave);int copy_user_to_xstate (const void *kbuf,const void __user *ubuf,struct xregs_state *xsave);#endif
arch/x86/kernel/fpu/regset.c +4 -1
@@ -92,7 +92,10 @@ int xstateregs_get(struct task_struct *target, const struct user_regset *regset,fpu__activate_fpstate_read (fpu);if (using_compacted_format ()) { - ret =copy_xstate_to_user (pos, count, kbuf, ubuf, xsave); +if (kbuf) + ret =copy_xstate_to_kernel (pos, count, kbuf, ubuf, xsave); +else + ret =copy_xstate_to_user (pos, count, kbuf, ubuf, xsave); }else {fpstate_sanitize_xstate (fpu);/*
arch/x86/kernel/fpu/xstate.c +103 -7
134 lines not on this page · raw message
PATCH 3/33 x86/fpu: Remove 'ubuf' parameter from the copy_xstate_to_kernel() APIs
In reply to Ingo MolnarThe 'ubuf' parameter is unused in the _kernel() side of the API, remove it.
This simplifies the code and makes it easier to think about.
--- arch/x86/include/asm/fpu/xstate.h | 2 +- arch/x86/kernel/fpu/regset.c | 2 +- arch/x86/kernel/fpu/xstate.c | 21 ++++++--------------- 3 files changed, 8 insertions(+), 17 deletions(-)
arch/x86/include/asm/fpu/xstate.h +1 -1
@@ -48,7 +48,7 @@ void fpu__xstate_clear_all_cpu_caps(void);void *get_xsave_addr (struct xregs_state *xsave,int xstate);const void *get_xsave_field_ptr (int xstate_field);int using_compacted_format (void ); -int copy_xstate_to_kernel (unsigned int pos,unsigned int count,void *kbuf,void __user *ubuf,struct xregs_state *xsave); +int copy_xstate_to_kernel (unsigned int pos,unsigned int count,void *kbuf,struct xregs_state *xsave);int copy_xstate_to_user (unsigned int pos,unsigned int count,void *kbuf,void __user *ubuf,struct xregs_state *xsave);int copy_user_to_xstate (const void *kbuf,const void __user *ubuf,struct xregs_state *xsave);
arch/x86/kernel/fpu/regset.c +1 -1
@@ -93,7 +93,7 @@ int xstateregs_get(struct task_struct *target, const struct user_regset *regset,if (using_compacted_format ()) {if (kbuf) - ret =copy_xstate_to_kernel (pos, count, kbuf, ubuf, xsave); + ret =copy_xstate_to_kernel (pos, count, kbuf, xsave);else ret =copy_xstate_to_user (pos, count, kbuf, ubuf, xsave); }else {
arch/x86/kernel/fpu/xstate.c +6 -15
@@ -926,7 +926,7 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,*/ static inline int __copy_xstate_to_kernel (unsigned int pos,unsigned int count, -void *kbuf,void __user *ubuf, +void *kbuf,const void *data,const int start_pos,const int end_pos) {
@@ -936,12 +936,7 @@ __copy_xstate_to_kernel(unsigned int pos, unsigned int count,if (end_pos <0 || pos < end_pos) {unsigned int copy = (end_pos <0 ? count :min (count, end_pos - pos)); -if (kbuf) { -memcpy (kbuf + pos, data, copy); - }else { -if (__copy_to_user (ubuf + pos, data, copy)) -return -EFAULT ; - } +memcpy (kbuf + pos, data, copy); }return 0 ; }
@@ -953,8 +948,7 @@ __copy_xstate_to_kernel(unsigned int pos, unsigned int count,* It supports partial copy but pos always starts from zero. This is called * from xstateregs_get() and there we check the CPU has XSAVES. */ -int copy_xstate_to_kernel (unsigned int pos,unsigned int count,void *kbuf, -void __user *ubuf,struct xregs_state *xsave) +int copy_xstate_to_kernel (unsigned int pos,unsigned int count,void *kbuf,struct xregs_state *xsave) {unsigned int offset, size;int ret, i;
@@ -979,8 +973,7 @@ int copy_xstate_to_kernel(unsigned int pos, unsigned int count, void *kbuf, offset = offsetof(struct xregs_state , header); size =sizeof (header); - ret =__copy_xstate_to_kernel (offset, size, kbuf, ubuf, &header,0 , count); - + ret =__copy_xstate_to_kernel (offset, size, kbuf, &header,0 , count);if (ret)return ret;
@@ -994,8 +987,7 @@ int copy_xstate_to_kernel(unsigned int pos, unsigned int count, void *kbuf, offset = xstate_offsets[i]; size = xstate_sizes[i]; - ret =__copy_xstate_to_kernel (offset, size, kbuf, ubuf, src,0 , count); - + ret =__copy_xstate_to_kernel (offset, size, kbuf, src,0 , count);if (ret)return ret;
@@ -1011,8 +1003,7 @@ int copy_xstate_to_kernel(unsigned int pos, unsigned int count, void *kbuf, offset = offsetof(struct fxregs_state , sw_reserved); size =sizeof (xstate_fx_sw_bytes); - ret =__copy_xstate_to_kernel (offset, size, kbuf, ubuf, xstate_fx_sw_bytes,0 , count); - + ret =__copy_xstate_to_kernel (offset, size, kbuf, xstate_fx_sw_bytes,0 , count);if (ret)return ret;
Signature · 1 line
2.11.0
tip-bot for Ingo Molnar
merge bot[tip:x86/fpu] x86/fpu: Remove 'ubuf' parameter from the copy_xstate_to_kernel() APIs
x86/fpu: Remove 'ubuf' parameter from the copy_xstate_to_kernel() APIs
Commit-ID: 4d981cf2d96f29cdfa7d4972c8b377fe7baa9c4c Gitweb: http://git.kernel.org/tip/4d981cf2d96f29cdfa7d4972c8b377fe7baa9c4c Author: Ingo Molnar <[email protected]> AuthorDate: Sat, 23 Sep 2017 14:59:46 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Sun, 24 Sep 2017 13:04:31 +0200
x86/fpu: Remove 'ubuf' parameter from the copy_xstate_to_kernel() APIs
The 'ubuf' parameter is unused in the _kernel() side of the API, remove it.
This simplifies the code and makes it easier to think about.
--- arch/x86/include/asm/fpu/xstate.h | 2 +- arch/x86/kernel/fpu/regset.c | 2 +- arch/x86/kernel/fpu/xstate.c | 21 ++++++--------------- 3 files changed, 8 insertions(+), 17 deletions(-)
arch/x86/include/asm/fpu/xstate.h +1 -1
@@ -48,7 +48,7 @@ void fpu__xstate_clear_all_cpu_caps(void);void *get_xsave_addr (struct xregs_state *xsave,int xstate);const void *get_xsave_field_ptr (int xstate_field);int using_compacted_format (void ); -int copy_xstate_to_kernel (unsigned int pos,unsigned int count,void *kbuf,void __user *ubuf,struct xregs_state *xsave); +int copy_xstate_to_kernel (unsigned int pos,unsigned int count,void *kbuf,struct xregs_state *xsave);int copy_xstate_to_user (unsigned int pos,unsigned int count,void *kbuf,void __user *ubuf,struct xregs_state *xsave);int copy_user_to_xstate (const void *kbuf,const void __user *ubuf,struct xregs_state *xsave);
arch/x86/kernel/fpu/regset.c +1 -1
@@ -93,7 +93,7 @@ int xstateregs_get(struct task_struct *target, const struct user_regset *regset,if (using_compacted_format ()) {if (kbuf) - ret =copy_xstate_to_kernel (pos, count, kbuf, ubuf, xsave); + ret =copy_xstate_to_kernel (pos, count, kbuf, xsave);else ret =copy_xstate_to_user (pos, count, kbuf, ubuf, xsave); }else {
arch/x86/kernel/fpu/xstate.c +6 -15
@@ -926,7 +926,7 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,*/ static inline int __copy_xstate_to_kernel (unsigned int pos,unsigned int count, -void *kbuf,void __user *ubuf, +void *kbuf,const void *data,const int start_pos,const int end_pos) {
@@ -936,12 +936,7 @@ __copy_xstate_to_kernel(unsigned int pos, unsigned int count,if (end_pos <0 || pos < end_pos) {unsigned int copy = (end_pos <0 ? count :min (count, end_pos - pos)); -if (kbuf) { -memcpy (kbuf + pos, data, copy); - }else { -if (__copy_to_user (ubuf + pos, data, copy)) -return -EFAULT ; - } +memcpy (kbuf + pos, data, copy); }return 0 ; }
@@ -953,8 +948,7 @@ __copy_xstate_to_kernel(unsigned int pos, unsigned int count,* It supports partial copy but pos always starts from zero. This is called * from xstateregs_get() and there we check the CPU has XSAVES. */ -int copy_xstate_to_kernel (unsigned int pos,unsigned int count,void *kbuf, -void __user *ubuf,struct xregs_state *xsave) +int copy_xstate_to_kernel (unsigned int pos,unsigned int count,void *kbuf,struct xregs_state *xsave) {unsigned int offset, size;int ret, i;
@@ -979,8 +973,7 @@ int copy_xstate_to_kernel(unsigned int pos, unsigned int count, void *kbuf, offset = offsetof(struct xregs_state , header); size =sizeof (header); - ret =__copy_xstate_to_kernel (offset, size, kbuf, ubuf, &header,0 , count); - + ret =__copy_xstate_to_kernel (offset, size, kbuf, &header,0 , count);if (ret)return ret;
@@ -994,8 +987,7 @@ int copy_xstate_to_kernel(unsigned int pos, unsigned int count, void *kbuf, offset = xstate_offsets[i]; size = xstate_sizes[i]; - ret =__copy_xstate_to_kernel (offset, size, kbuf, ubuf, src,0 , count); - + ret =__copy_xstate_to_kernel (offset, size, kbuf, src,0 , count);if (ret)return ret;
@@ -1011,8 +1003,7 @@ int copy_xstate_to_kernel(unsigned int pos, unsigned int count, void *kbuf, offset = offsetof(struct fxregs_state , sw_reserved); size =sizeof (xstate_fx_sw_bytes); - ret =__copy_xstate_to_kernel (offset, size, kbuf, ubuf, xstate_fx_sw_bytes,0 , count); - + ret =__copy_xstate_to_kernel (offset, size, kbuf, xstate_fx_sw_bytes,0 , count);if (ret)return ret;
PATCH 4/33 x86/fpu: Remove 'kbuf' parameter from the copy_xstate_to_user() APIs
In reply to Ingo MolnarThe 'kbuf' parameter is unused in the _user() side of the API, remove it.
This simplifies the code and makes it easier to think about.
--- arch/x86/include/asm/fpu/xstate.h | 2 +- arch/x86/kernel/fpu/regset.c | 2 +- arch/x86/kernel/fpu/xstate.c | 25 +++++++------------------ 3 files changed, 9 insertions(+), 20 deletions(-)
arch/x86/include/asm/fpu/xstate.h +1 -1
@@ -49,7 +49,7 @@ void *get_xsave_addr(struct xregs_state *xsave, int xstate);const void *get_xsave_field_ptr (int xstate_field);int using_compacted_format (void );int copy_xstate_to_kernel (unsigned int pos,unsigned int count,void *kbuf,struct xregs_state *xsave); -int copy_xstate_to_user (unsigned int pos,unsigned int count,void *kbuf,void __user *ubuf,struct xregs_state *xsave); +int copy_xstate_to_user (unsigned int pos,unsigned int count,void __user *ubuf,struct xregs_state *xsave);int copy_user_to_xstate (const void *kbuf,const void __user *ubuf,struct xregs_state *xsave);#endif
arch/x86/kernel/fpu/regset.c +1 -1
@@ -95,7 +95,7 @@ int xstateregs_get(struct task_struct *target, const struct user_regset *regset,if (kbuf) ret =copy_xstate_to_kernel (pos, count, kbuf, xsave);else - ret =copy_xstate_to_user (pos, count, kbuf, ubuf, xsave); + ret =copy_xstate_to_user (pos, count, ubuf, xsave); }else {fpstate_sanitize_xstate (fpu);/*
arch/x86/kernel/fpu/xstate.c +7 -18
@@ -1011,10 +1011,7 @@ int copy_xstate_to_kernel(unsigned int pos, unsigned int count, void *kbuf, stru }static inline int -__copy_xstate_to_user (unsigned int pos,unsigned int count, -void *kbuf,void __user *ubuf, -const void *data,const int start_pos, -const int end_pos) +__copy_xstate_to_user (unsigned int pos,unsigned int count,void __user *ubuf,const void *data,const int start_pos,const int end_pos) {if ((count ==0 ) || (pos < start_pos))return 0 ;
@@ -1022,12 +1019,8 @@ __copy_xstate_to_user(unsigned int pos, unsigned int count,if (end_pos <0 || pos < end_pos) {unsigned int copy = (end_pos <0 ? count :min (count, end_pos - pos)); -if (kbuf) { -memcpy (kbuf + pos, data, copy); - }else { -if (__copy_to_user (ubuf + pos, data, copy)) -return -EFAULT ; - } +if (__copy_to_user (ubuf + pos, data, copy)) +return -EFAULT ; }return 0 ; }
@@ -1038,8 +1031,7 @@ __copy_xstate_to_user(unsigned int pos, unsigned int count,* zero. This is called from xstateregs_get() and there we check the CPU * has XSAVES. */ -int copy_xstate_to_user (unsigned int pos,unsigned int count,void *kbuf, -void __user *ubuf,struct xregs_state *xsave) +int copy_xstate_to_user (unsigned int pos,unsigned int count,void __user *ubuf,struct xregs_state *xsave) {unsigned int offset, size;int ret, i;
@@ -1064,8 +1056,7 @@ int copy_xstate_to_user(unsigned int pos, unsigned int count, void *kbuf, offset = offsetof(struct xregs_state , header); size =sizeof (header); - ret =__copy_xstate_to_user (offset, size, kbuf, ubuf, &header,0 , count); - + ret =__copy_xstate_to_user (offset, size, ubuf, &header,0 , count);if (ret)return ret;
@@ -1079,8 +1070,7 @@ int copy_xstate_to_user(unsigned int pos, unsigned int count, void *kbuf, offset = xstate_offsets[i]; size = xstate_sizes[i]; - ret =__copy_xstate_to_user (offset, size, kbuf, ubuf, src,0 , count); - + ret =__copy_xstate_to_user (offset, size, ubuf, src,0 , count);if (ret)return ret;
@@ -1096,8 +1086,7 @@ int copy_xstate_to_user(unsigned int pos, unsigned int count, void *kbuf, offset = offsetof(struct fxregs_state , sw_reserved); size =sizeof (xstate_fx_sw_bytes); - ret =__copy_xstate_to_user (offset, size, kbuf, ubuf, xstate_fx_sw_bytes,0 , count); - + ret =__copy_xstate_to_user (offset, size, ubuf, xstate_fx_sw_bytes,0 , count);if (ret)return ret;
Signature · 1 line
2.11.0
tip-bot for Ingo Molnar
merge bot[tip:x86/fpu] x86/fpu: Remove 'kbuf' parameter from the copy_xstate_to_user() APIs
x86/fpu: Remove 'kbuf' parameter from the copy_xstate_to_user() APIs
Commit-ID: a69c158fb3e7a91220f55029bf222a4e678d16e9 Gitweb: http://git.kernel.org/tip/a69c158fb3e7a91220f55029bf222a4e678d16e9 Author: Ingo Molnar <[email protected]> AuthorDate: Sat, 23 Sep 2017 14:59:47 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Sun, 24 Sep 2017 13:04:31 +0200
x86/fpu: Remove 'kbuf' parameter from the copy_xstate_to_user() APIs
The 'kbuf' parameter is unused in the _user() side of the API, remove it.
This simplifies the code and makes it easier to think about.
--- arch/x86/include/asm/fpu/xstate.h | 2 +- arch/x86/kernel/fpu/regset.c | 2 +- arch/x86/kernel/fpu/xstate.c | 25 +++++++------------------ 3 files changed, 9 insertions(+), 20 deletions(-)
arch/x86/include/asm/fpu/xstate.h +1 -1
@@ -49,7 +49,7 @@ void *get_xsave_addr(struct xregs_state *xsave, int xstate);const void *get_xsave_field_ptr (int xstate_field);int using_compacted_format (void );int copy_xstate_to_kernel (unsigned int pos,unsigned int count,void *kbuf,struct xregs_state *xsave); -int copy_xstate_to_user (unsigned int pos,unsigned int count,void *kbuf,void __user *ubuf,struct xregs_state *xsave); +int copy_xstate_to_user (unsigned int pos,unsigned int count,void __user *ubuf,struct xregs_state *xsave);int copy_user_to_xstate (const void *kbuf,const void __user *ubuf,struct xregs_state *xsave);#endif
arch/x86/kernel/fpu/regset.c +1 -1
@@ -95,7 +95,7 @@ int xstateregs_get(struct task_struct *target, const struct user_regset *regset,if (kbuf) ret =copy_xstate_to_kernel (pos, count, kbuf, xsave);else - ret =copy_xstate_to_user (pos, count, kbuf, ubuf, xsave); + ret =copy_xstate_to_user (pos, count, ubuf, xsave); }else {fpstate_sanitize_xstate (fpu);/*
arch/x86/kernel/fpu/xstate.c +7 -18
@@ -1011,10 +1011,7 @@ int copy_xstate_to_kernel(unsigned int pos, unsigned int count, void *kbuf, stru }static inline int -__copy_xstate_to_user (unsigned int pos,unsigned int count, -void *kbuf,void __user *ubuf, -const void *data,const int start_pos, -const int end_pos) +__copy_xstate_to_user (unsigned int pos,unsigned int count,void __user *ubuf,const void *data,const int start_pos,const int end_pos) {if ((count ==0 ) || (pos < start_pos))return 0 ;
@@ -1022,12 +1019,8 @@ __copy_xstate_to_user(unsigned int pos, unsigned int count,if (end_pos <0 || pos < end_pos) {unsigned int copy = (end_pos <0 ? count :min (count, end_pos - pos)); -if (kbuf) { -memcpy (kbuf + pos, data, copy); - }else { -if (__copy_to_user (ubuf + pos, data, copy)) -return -EFAULT ; - } +if (__copy_to_user (ubuf + pos, data, copy)) +return -EFAULT ; }return 0 ; }
@@ -1038,8 +1031,7 @@ __copy_xstate_to_user(unsigned int pos, unsigned int count,* zero. This is called from xstateregs_get() and there we check the CPU * has XSAVES. */ -int copy_xstate_to_user (unsigned int pos,unsigned int count,void *kbuf, -void __user *ubuf,struct xregs_state *xsave) +int copy_xstate_to_user (unsigned int pos,unsigned int count,void __user *ubuf,struct xregs_state *xsave) {unsigned int offset, size;int ret, i;
@@ -1064,8 +1056,7 @@ int copy_xstate_to_user(unsigned int pos, unsigned int count, void *kbuf, offset = offsetof(struct xregs_state , header); size =sizeof (header); - ret =__copy_xstate_to_user (offset, size, kbuf, ubuf, &header,0 , count); - + ret =__copy_xstate_to_user (offset, size, ubuf, &header,0 , count);if (ret)return ret;
@@ -1079,8 +1070,7 @@ int copy_xstate_to_user(unsigned int pos, unsigned int count, void *kbuf, offset = xstate_offsets[i]; size = xstate_sizes[i]; - ret =__copy_xstate_to_user (offset, size, kbuf, ubuf, src,0 , count); - + ret =__copy_xstate_to_user (offset, size, ubuf, src,0 , count);if (ret)return ret;
@@ -1096,8 +1086,7 @@ int copy_xstate_to_user(unsigned int pos, unsigned int count, void *kbuf, offset = offsetof(struct fxregs_state , sw_reserved); size =sizeof (xstate_fx_sw_bytes); - ret =__copy_xstate_to_user (offset, size, kbuf, ubuf, xstate_fx_sw_bytes,0 , count); - + ret =__copy_xstate_to_user (offset, size, ubuf, xstate_fx_sw_bytes,0 , count);if (ret)return ret;
PATCH 5/33 x86/fpu: Clean up parameter order in the copy_xstate_to_*() APIs
In reply to Ingo MolnarParameter ordering is weird:
int copy_xstate_to_kernel(unsigned int pos, unsigned int count, void *kbuf, struct xregs_state *xsave); int copy_xstate_to_user(unsigned int pos, unsigned int count, void __user *ubuf, struct xregs_state *xsave);
'pos' and 'count', which are attributes of the destination buffer, are listed before the destination buffer itself ...
List them after the primary arguments instead.
This makes the code more similar to regular memcpy() variant APIs.
No change in functionality.
--- arch/x86/include/asm/fpu/xstate.h | 4 ++-- arch/x86/kernel/fpu/regset.c | 4 ++-- arch/x86/kernel/fpu/xstate.c | 25 ++++++++++++------------- 3 files changed, 16 insertions(+), 17 deletions(-)
arch/x86/include/asm/fpu/xstate.h +2 -2
@@ -48,8 +48,8 @@ void fpu__xstate_clear_all_cpu_caps(void);void *get_xsave_addr (struct xregs_state *xsave,int xstate);const void *get_xsave_field_ptr (int xstate_field);int using_compacted_format (void ); -int copy_xstate_to_kernel (unsigned int pos,unsigned int count,void *kbuf,struct xregs_state *xsave); -int copy_xstate_to_user (unsigned int pos,unsigned int count,void __user *ubuf,struct xregs_state *xsave); +int copy_xstate_to_kernel (void *kbuf,struct xregs_state *xsave,unsigned int pos,unsigned int count); +int copy_xstate_to_user (void __user *ubuf,struct xregs_state *xsave,unsigned int pos,unsigned int count);int copy_user_to_xstate (const void *kbuf,const void __user *ubuf,struct xregs_state *xsave);#endif
arch/x86/kernel/fpu/regset.c +2 -2
@@ -93,9 +93,9 @@ int xstateregs_get(struct task_struct *target, const struct user_regset *regset,if (using_compacted_format ()) {if (kbuf) - ret =copy_xstate_to_kernel (pos, count, kbuf, xsave); + ret =copy_xstate_to_kernel (kbuf, xsave, pos, count);else - ret =copy_xstate_to_user (pos, count, ubuf, xsave); + ret =copy_xstate_to_user (ubuf, xsave, pos, count); }else {fpstate_sanitize_xstate (fpu);/*
arch/x86/kernel/fpu/xstate.c +12 -13
@@ -925,10 +925,9 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,* the source data pointer or increment pos, count, kbuf, and ubuf. */ static inline int -__copy_xstate_to_kernel (unsigned int pos,unsigned int count, -void *kbuf, -const void *data,const int start_pos, -const int end_pos) +__copy_xstate_to_kernel (void *kbuf, +const void *data, +unsigned int pos,unsigned int count,const int start_pos,const int end_pos) {if ((count ==0 ) || (pos < start_pos))return 0 ;
@@ -948,7 +947,7 @@ __copy_xstate_to_kernel(unsigned int pos, unsigned int count,* It supports partial copy but pos always starts from zero. This is called * from xstateregs_get() and there we check the CPU has XSAVES. */ -int copy_xstate_to_kernel (unsigned int pos,unsigned int count,void *kbuf,struct xregs_state *xsave) +int copy_xstate_to_kernel (void *kbuf,struct xregs_state *xsave,unsigned int pos,unsigned int count) {unsigned int offset, size;int ret, i;
@@ -973,7 +972,7 @@ int copy_xstate_to_kernel(unsigned int pos, unsigned int count, void *kbuf, stru offset = offsetof(struct xregs_state , header); size =sizeof (header); - ret =__copy_xstate_to_kernel (offset, size, kbuf, &header,0 , count); + ret =__copy_xstate_to_kernel (kbuf, &header, offset, size,0 , count);if (ret)return ret;
@@ -987,7 +986,7 @@ int copy_xstate_to_kernel(unsigned int pos, unsigned int count, void *kbuf, stru offset = xstate_offsets[i]; size = xstate_sizes[i]; - ret =__copy_xstate_to_kernel (offset, size, kbuf, src,0 , count); + ret =__copy_xstate_to_kernel (kbuf, src, offset, size,0 , count);if (ret)return ret;
@@ -1003,7 +1002,7 @@ int copy_xstate_to_kernel(unsigned int pos, unsigned int count, void *kbuf, stru offset = offsetof(struct fxregs_state , sw_reserved); size =sizeof (xstate_fx_sw_bytes); - ret =__copy_xstate_to_kernel (offset, size, kbuf, xstate_fx_sw_bytes,0 , count); + ret =__copy_xstate_to_kernel (kbuf, xstate_fx_sw_bytes, offset, size,0 , count);if (ret)return ret;
@@ -1011,7 +1010,7 @@ int copy_xstate_to_kernel(unsigned int pos, unsigned int count, void *kbuf, stru }static inline int -__copy_xstate_to_user (unsigned int pos,unsigned int count,void __user *ubuf,const void *data,const int start_pos,const int end_pos) +__copy_xstate_to_user (void __user *ubuf,const void *data,unsigned int pos,unsigned int count,const int start_pos,const int end_pos) {if ((count ==0 ) || (pos < start_pos))return 0 ;
@@ -1031,7 +1030,7 @@ __copy_xstate_to_user(unsigned int pos, unsigned int count, void __user *ubuf, c* zero. This is called from xstateregs_get() and there we check the CPU * has XSAVES. */ -int copy_xstate_to_user (unsigned int pos,unsigned int count,void __user *ubuf,struct xregs_state *xsave) +int copy_xstate_to_user (void __user *ubuf,struct xregs_state *xsave,unsigned int pos,unsigned int count) {unsigned int offset, size;int ret, i;
@@ -1056,7 +1055,7 @@ int copy_xstate_to_user(unsigned int pos, unsigned int count, void __user *ubuf, offset = offsetof(struct xregs_state , header); size =sizeof (header); - ret =__copy_xstate_to_user (offset, size, ubuf, &header,0 , count); + ret =__copy_xstate_to_user (ubuf, &header, offset, size,0 , count);if (ret)return ret;
@@ -1070,7 +1069,7 @@ int copy_xstate_to_user(unsigned int pos, unsigned int count, void __user *ubuf, offset = xstate_offsets[i]; size = xstate_sizes[i]; - ret =__copy_xstate_to_user (offset, size, ubuf, src,0 , count); + ret =__copy_xstate_to_user (ubuf, src, offset, size,0 , count);if (ret)return ret;
@@ -1086,7 +1085,7 @@ int copy_xstate_to_user(unsigned int pos, unsigned int count, void __user *ubuf, offset = offsetof(struct fxregs_state , sw_reserved); size =sizeof (xstate_fx_sw_bytes); - ret =__copy_xstate_to_user (offset, size, ubuf, xstate_fx_sw_bytes,0 , count); + ret =__copy_xstate_to_user (ubuf, xstate_fx_sw_bytes, offset, size,0 , count);if (ret)return ret;
Signature · 1 line
2.11.0
tip-bot for Ingo Molnar
merge bot[tip:x86/fpu] x86/fpu: Clean up parameter order in the copy_xstate_to_*() APIs
x86/fpu: Clean up parameter order in the copy_xstate_to_*() APIs
Commit-ID: d7eda6c99cc75f1c41d67abf988f37a10045a370 Gitweb: http://git.kernel.org/tip/d7eda6c99cc75f1c41d67abf988f37a10045a370 Author: Ingo Molnar <[email protected]> AuthorDate: Sat, 23 Sep 2017 14:59:48 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Sun, 24 Sep 2017 13:04:31 +0200
x86/fpu: Clean up parameter order in the copy_xstate_to_*() APIs
Parameter ordering is weird:
int copy_xstate_to_kernel(unsigned int pos, unsigned int count, void *kbuf, struct xregs_state *xsave); int copy_xstate_to_user(unsigned int pos, unsigned int count, void __user *ubuf, struct xregs_state *xsave);
'pos' and 'count', which are attributes of the destination buffer, are listed before the destination buffer itself ...
List them after the primary arguments instead.
This makes the code more similar to regular memcpy() variant APIs.
No change in functionality.
--- arch/x86/include/asm/fpu/xstate.h | 4 ++-- arch/x86/kernel/fpu/regset.c | 4 ++-- arch/x86/kernel/fpu/xstate.c | 25 ++++++++++++------------- 3 files changed, 16 insertions(+), 17 deletions(-)
arch/x86/include/asm/fpu/xstate.h +2 -2
@@ -48,8 +48,8 @@ void fpu__xstate_clear_all_cpu_caps(void);void *get_xsave_addr (struct xregs_state *xsave,int xstate);const void *get_xsave_field_ptr (int xstate_field);int using_compacted_format (void ); -int copy_xstate_to_kernel (unsigned int pos,unsigned int count,void *kbuf,struct xregs_state *xsave); -int copy_xstate_to_user (unsigned int pos,unsigned int count,void __user *ubuf,struct xregs_state *xsave); +int copy_xstate_to_kernel (void *kbuf,struct xregs_state *xsave,unsigned int pos,unsigned int count); +int copy_xstate_to_user (void __user *ubuf,struct xregs_state *xsave,unsigned int pos,unsigned int count);int copy_user_to_xstate (const void *kbuf,const void __user *ubuf,struct xregs_state *xsave);#endif
arch/x86/kernel/fpu/regset.c +2 -2
@@ -93,9 +93,9 @@ int xstateregs_get(struct task_struct *target, const struct user_regset *regset,if (using_compacted_format ()) {if (kbuf) - ret =copy_xstate_to_kernel (pos, count, kbuf, xsave); + ret =copy_xstate_to_kernel (kbuf, xsave, pos, count);else - ret =copy_xstate_to_user (pos, count, ubuf, xsave); + ret =copy_xstate_to_user (ubuf, xsave, pos, count); }else {fpstate_sanitize_xstate (fpu);/*
arch/x86/kernel/fpu/xstate.c +12 -13
@@ -925,10 +925,9 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,* the source data pointer or increment pos, count, kbuf, and ubuf. */ static inline int -__copy_xstate_to_kernel (unsigned int pos,unsigned int count, -void *kbuf, -const void *data,const int start_pos, -const int end_pos) +__copy_xstate_to_kernel (void *kbuf, +const void *data, +unsigned int pos,unsigned int count,const int start_pos,const int end_pos) {if ((count ==0 ) || (pos < start_pos))return 0 ;
@@ -948,7 +947,7 @@ __copy_xstate_to_kernel(unsigned int pos, unsigned int count,* It supports partial copy but pos always starts from zero. This is called * from xstateregs_get() and there we check the CPU has XSAVES. */ -int copy_xstate_to_kernel (unsigned int pos,unsigned int count,void *kbuf,struct xregs_state *xsave) +int copy_xstate_to_kernel (void *kbuf,struct xregs_state *xsave,unsigned int pos,unsigned int count) {unsigned int offset, size;int ret, i;
@@ -973,7 +972,7 @@ int copy_xstate_to_kernel(unsigned int pos, unsigned int count, void *kbuf, stru offset = offsetof(struct xregs_state , header); size =sizeof (header); - ret =__copy_xstate_to_kernel (offset, size, kbuf, &header,0 , count); + ret =__copy_xstate_to_kernel (kbuf, &header, offset, size,0 , count);if (ret)return ret;
@@ -987,7 +986,7 @@ int copy_xstate_to_kernel(unsigned int pos, unsigned int count, void *kbuf, stru offset = xstate_offsets[i]; size = xstate_sizes[i]; - ret =__copy_xstate_to_kernel (offset, size, kbuf, src,0 , count); + ret =__copy_xstate_to_kernel (kbuf, src, offset, size,0 , count);if (ret)return ret;
@@ -1003,7 +1002,7 @@ int copy_xstate_to_kernel(unsigned int pos, unsigned int count, void *kbuf, stru offset = offsetof(struct fxregs_state , sw_reserved); size =sizeof (xstate_fx_sw_bytes); - ret =__copy_xstate_to_kernel (offset, size, kbuf, xstate_fx_sw_bytes,0 , count); + ret =__copy_xstate_to_kernel (kbuf, xstate_fx_sw_bytes, offset, size,0 , count);if (ret)return ret;
@@ -1011,7 +1010,7 @@ int copy_xstate_to_kernel(unsigned int pos, unsigned int count, void *kbuf, stru }static inline int -__copy_xstate_to_user (unsigned int pos,unsigned int count,void __user *ubuf,const void *data,const int start_pos,const int end_pos) +__copy_xstate_to_user (void __user *ubuf,const void *data,unsigned int pos,unsigned int count,const int start_pos,const int end_pos) {if ((count ==0 ) || (pos < start_pos))return 0 ;
@@ -1031,7 +1030,7 @@ __copy_xstate_to_user(unsigned int pos, unsigned int count, void __user *ubuf, c* zero. This is called from xstateregs_get() and there we check the CPU * has XSAVES. */ -int copy_xstate_to_user (unsigned int pos,unsigned int count,void __user *ubuf,struct xregs_state *xsave) +int copy_xstate_to_user (void __user *ubuf,struct xregs_state *xsave,unsigned int pos,unsigned int count) {unsigned int offset, size;int ret, i;
@@ -1056,7 +1055,7 @@ int copy_xstate_to_user(unsigned int pos, unsigned int count, void __user *ubuf, offset = offsetof(struct xregs_state , header); size =sizeof (header); - ret =__copy_xstate_to_user (offset, size, ubuf, &header,0 , count); + ret =__copy_xstate_to_user (ubuf, &header, offset, size,0 , count);if (ret)return ret;
@@ -1070,7 +1069,7 @@ int copy_xstate_to_user(unsigned int pos, unsigned int count, void __user *ubuf, offset = xstate_offsets[i]; size = xstate_sizes[i]; - ret =__copy_xstate_to_user (offset, size, ubuf, src,0 , count); + ret =__copy_xstate_to_user (ubuf, src, offset, size,0 , count);if (ret)return ret;
@@ -1086,7 +1085,7 @@ int copy_xstate_to_user(unsigned int pos, unsigned int count, void __user *ubuf, offset = offsetof(struct fxregs_state , sw_reserved); size =sizeof (xstate_fx_sw_bytes); - ret =__copy_xstate_to_user (offset, size, ubuf, xstate_fx_sw_bytes,0 , count); + ret =__copy_xstate_to_user (ubuf, xstate_fx_sw_bytes, offset, size,0 , count);if (ret)return ret;
PATCH 6/33 x86/fpu: Clean up the parameter definitions of copy_xstate_to_*()
In reply to Ingo MolnarRemove pointless 'const' of non-pointer input parameter.
Remove unnecessary parenthesis that shows uncertainty about arithmetic operator precedence.
Clarify copy_xstate_to_user() description.
No change in functionality.
--- arch/x86/kernel/fpu/xstate.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
arch/x86/kernel/fpu/xstate.c +5 -5
@@ -927,13 +927,13 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,static inline int __copy_xstate_to_kernel (void *kbuf,const void *data, -unsigned int pos,unsigned int count,const int start_pos,const int end_pos) +unsigned int pos,unsigned int count,int start_pos,int end_pos) {if ((count ==0 ) || (pos < start_pos))return 0 ;if (end_pos <0 || pos < end_pos) { -unsigned int copy = (end_pos <0 ? count :min (count, end_pos - pos)); +unsigned int copy = end_pos <0 ? count :min (count, end_pos - pos);memcpy (kbuf + pos, data, copy); }
@@ -1010,13 +1010,13 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int po }static inline int -__copy_xstate_to_user (void __user *ubuf,const void *data,unsigned int pos,unsigned int count,const int start_pos,const int end_pos) +__copy_xstate_to_user (void __user *ubuf,const void *data,unsigned int pos,unsigned int count,int start_pos,int end_pos) {if ((count ==0 ) || (pos < start_pos))return 0 ;if (end_pos <0 || pos < end_pos) { -unsigned int copy = (end_pos <0 ? count :min (count, end_pos - pos)); +unsigned int copy = end_pos <0 ? count :min (count, end_pos - pos);if (__copy_to_user (ubuf + pos, data, copy))return -EFAULT ;
@@ -1026,7 +1026,7 @@ __copy_xstate_to_user(void __user *ubuf, const void *data, unsigned int pos, uns/* * Convert from kernel XSAVES compacted format to standard format and copy -* to a ptrace buffer. It supports partial copy but pos always starts from +* to a user-space buffer. It supports partial copy but pos always starts from * zero. This is called from xstateregs_get() and there we check the CPU * has XSAVES. */
Signature · 1 line
2.11.0
tip-bot for Ingo Molnar
merge bot[tip:x86/fpu] x86/fpu: Clean up the parameter definitions of copy_xstate_to_*()
x86/fpu: Clean up the parameter definitions of copy_xstate_to_*()
Commit-ID: becb2bb72ff906cc0d2bac3ee9574f694364823b Gitweb: http://git.kernel.org/tip/becb2bb72ff906cc0d2bac3ee9574f694364823b Author: Ingo Molnar <[email protected]> AuthorDate: Sat, 23 Sep 2017 14:59:49 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Sun, 24 Sep 2017 13:04:31 +0200
x86/fpu: Clean up the parameter definitions of copy_xstate_to_*()
Remove pointless 'const' of non-pointer input parameter.
Remove unnecessary parenthesis that shows uncertainty about arithmetic operator precedence.
Clarify copy_xstate_to_user() description.
No change in functionality.
--- arch/x86/kernel/fpu/xstate.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
arch/x86/kernel/fpu/xstate.c +5 -5
@@ -927,13 +927,13 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,static inline int __copy_xstate_to_kernel (void *kbuf,const void *data, -unsigned int pos,unsigned int count,const int start_pos,const int end_pos) +unsigned int pos,unsigned int count,int start_pos,int end_pos) {if ((count ==0 ) || (pos < start_pos))return 0 ;if (end_pos <0 || pos < end_pos) { -unsigned int copy = (end_pos <0 ? count :min (count, end_pos - pos)); +unsigned int copy = end_pos <0 ? count :min (count, end_pos - pos);memcpy (kbuf + pos, data, copy); }
@@ -1010,13 +1010,13 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int po }static inline int -__copy_xstate_to_user (void __user *ubuf,const void *data,unsigned int pos,unsigned int count,const int start_pos,const int end_pos) +__copy_xstate_to_user (void __user *ubuf,const void *data,unsigned int pos,unsigned int count,int start_pos,int end_pos) {if ((count ==0 ) || (pos < start_pos))return 0 ;if (end_pos <0 || pos < end_pos) { -unsigned int copy = (end_pos <0 ? count :min (count, end_pos - pos)); +unsigned int copy = end_pos <0 ? count :min (count, end_pos - pos);if (__copy_to_user (ubuf + pos, data, copy))return -EFAULT ;
@@ -1026,7 +1026,7 @@ __copy_xstate_to_user(void __user *ubuf, const void *data, unsigned int pos, uns/* * Convert from kernel XSAVES compacted format to standard format and copy -* to a ptrace buffer. It supports partial copy but pos always starts from +* to a user-space buffer. It supports partial copy but pos always starts from * zero. This is called from xstateregs_get() and there we check the CPU * has XSAVES. */
PATCH 7/33 x86/fpu: Remove the 'start_pos' parameter from the __copy_xstate_to_*() functions
In reply to Ingo Molnar'start_pos' is always 0, so remove it and remove the pointless check of 'pos < 0' which can not ever be true as 'pos' is unsigned ...
No change in functionality.
--- arch/x86/kernel/fpu/xstate.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-)
arch/x86/kernel/fpu/xstate.c +10 -10
@@ -927,9 +927,9 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,static inline int __copy_xstate_to_kernel (void *kbuf,const void *data, -unsigned int pos,unsigned int count,int start_pos,int end_pos) +unsigned int pos,unsigned int count,int end_pos) { -if ((count ==0 ) || (pos < start_pos)) +if (!count)return 0 ;if (end_pos <0 || pos < end_pos) {
@@ -972,7 +972,7 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int po offset = offsetof(struct xregs_state , header); size =sizeof (header); - ret =__copy_xstate_to_kernel (kbuf, &header, offset, size,0 , count); + ret =__copy_xstate_to_kernel (kbuf, &header, offset, size, count);if (ret)return ret;
@@ -986,7 +986,7 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int po offset = xstate_offsets[i]; size = xstate_sizes[i]; - ret =__copy_xstate_to_kernel (kbuf, src, offset, size,0 , count); + ret =__copy_xstate_to_kernel (kbuf, src, offset, size, count);if (ret)return ret;
@@ -1002,7 +1002,7 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int po offset = offsetof(struct fxregs_state , sw_reserved); size =sizeof (xstate_fx_sw_bytes); - ret =__copy_xstate_to_kernel (kbuf, xstate_fx_sw_bytes, offset, size,0 , count); + ret =__copy_xstate_to_kernel (kbuf, xstate_fx_sw_bytes, offset, size, count);if (ret)return ret;
@@ -1010,9 +1010,9 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int po }static inline int -__copy_xstate_to_user (void __user *ubuf,const void *data,unsigned int pos,unsigned int count,int start_pos,int end_pos) +__copy_xstate_to_user (void __user *ubuf,const void *data,unsigned int pos,unsigned int count,int end_pos) { -if ((count ==0 ) || (pos < start_pos)) +if (!count)return 0 ;if (end_pos <0 || pos < end_pos) {
@@ -1055,7 +1055,7 @@ int copy_xstate_to_user(void __user *ubuf, struct xregs_state *xsave, unsigned i offset = offsetof(struct xregs_state , header); size =sizeof (header); - ret =__copy_xstate_to_user (ubuf, &header, offset, size,0 , count); + ret =__copy_xstate_to_user (ubuf, &header, offset, size, count);if (ret)return ret;
@@ -1069,7 +1069,7 @@ int copy_xstate_to_user(void __user *ubuf, struct xregs_state *xsave, unsigned i offset = xstate_offsets[i]; size = xstate_sizes[i]; - ret =__copy_xstate_to_user (ubuf, src, offset, size,0 , count); + ret =__copy_xstate_to_user (ubuf, src, offset, size, count);if (ret)return ret;
@@ -1085,7 +1085,7 @@ int copy_xstate_to_user(void __user *ubuf, struct xregs_state *xsave, unsigned i offset = offsetof(struct fxregs_state , sw_reserved); size =sizeof (xstate_fx_sw_bytes); - ret =__copy_xstate_to_user (ubuf, xstate_fx_sw_bytes, offset, size,0 , count); + ret =__copy_xstate_to_user (ubuf, xstate_fx_sw_bytes, offset, size, count);if (ret)return ret;
Signature · 1 line
2.11.0
tip-bot for Ingo Molnar
merge bot[tip:x86/fpu] x86/fpu: Remove the 'start_pos' parameter from the __copy_xstate_to_*() functions
x86/fpu: Remove the 'start_pos' parameter from the __copy_xstate_to_*() functions
Commit-ID: 8a5b731889cbf004b406d988dc591c8a7aac773e Gitweb: http://git.kernel.org/tip/8a5b731889cbf004b406d988dc591c8a7aac773e Author: Ingo Molnar <[email protected]> AuthorDate: Sat, 23 Sep 2017 14:59:50 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Sun, 24 Sep 2017 13:04:31 +0200
x86/fpu: Remove the 'start_pos' parameter from the __copy_xstate_to_*() functions
'start_pos' is always 0, so remove it and remove the pointless check of 'pos < 0' which can not ever be true as 'pos' is unsigned ...
No change in functionality.
--- arch/x86/kernel/fpu/xstate.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-)
arch/x86/kernel/fpu/xstate.c +10 -10
@@ -927,9 +927,9 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,static inline int __copy_xstate_to_kernel (void *kbuf,const void *data, -unsigned int pos,unsigned int count,int start_pos,int end_pos) +unsigned int pos,unsigned int count,int end_pos) { -if ((count ==0 ) || (pos < start_pos)) +if (!count)return 0 ;if (end_pos <0 || pos < end_pos) {
@@ -972,7 +972,7 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int po offset = offsetof(struct xregs_state , header); size =sizeof (header); - ret =__copy_xstate_to_kernel (kbuf, &header, offset, size,0 , count); + ret =__copy_xstate_to_kernel (kbuf, &header, offset, size, count);if (ret)return ret;
@@ -986,7 +986,7 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int po offset = xstate_offsets[i]; size = xstate_sizes[i]; - ret =__copy_xstate_to_kernel (kbuf, src, offset, size,0 , count); + ret =__copy_xstate_to_kernel (kbuf, src, offset, size, count);if (ret)return ret;
@@ -1002,7 +1002,7 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int po offset = offsetof(struct fxregs_state , sw_reserved); size =sizeof (xstate_fx_sw_bytes); - ret =__copy_xstate_to_kernel (kbuf, xstate_fx_sw_bytes, offset, size,0 , count); + ret =__copy_xstate_to_kernel (kbuf, xstate_fx_sw_bytes, offset, size, count);if (ret)return ret;
@@ -1010,9 +1010,9 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int po }static inline int -__copy_xstate_to_user (void __user *ubuf,const void *data,unsigned int pos,unsigned int count,int start_pos,int end_pos) +__copy_xstate_to_user (void __user *ubuf,const void *data,unsigned int pos,unsigned int count,int end_pos) { -if ((count ==0 ) || (pos < start_pos)) +if (!count)return 0 ;if (end_pos <0 || pos < end_pos) {
@@ -1055,7 +1055,7 @@ int copy_xstate_to_user(void __user *ubuf, struct xregs_state *xsave, unsigned i offset = offsetof(struct xregs_state , header); size =sizeof (header); - ret =__copy_xstate_to_user (ubuf, &header, offset, size,0 , count); + ret =__copy_xstate_to_user (ubuf, &header, offset, size, count);if (ret)return ret;
@@ -1069,7 +1069,7 @@ int copy_xstate_to_user(void __user *ubuf, struct xregs_state *xsave, unsigned i offset = xstate_offsets[i]; size = xstate_sizes[i]; - ret =__copy_xstate_to_user (ubuf, src, offset, size,0 , count); + ret =__copy_xstate_to_user (ubuf, src, offset, size, count);if (ret)return ret;
@@ -1085,7 +1085,7 @@ int copy_xstate_to_user(void __user *ubuf, struct xregs_state *xsave, unsigned i offset = offsetof(struct fxregs_state , sw_reserved); size =sizeof (xstate_fx_sw_bytes); - ret =__copy_xstate_to_user (ubuf, xstate_fx_sw_bytes, offset, size,0 , count); + ret =__copy_xstate_to_user (ubuf, xstate_fx_sw_bytes, offset, size, count);if (ret)return ret;
PATCH 8/33 x86/fpu: Clarify parameter names in the copy_xstate_to_*() methods
In reply to Ingo MolnarRight now there's a confusing mixture of 'offset' and 'size' parameters:
- __copy_xstate_to_*() input parameter 'end_pos' not not really an offset, but the full size of the copy to be performed.
- input parameter 'count' to copy_xstate_to_*() shadows that of __copy_xstate_to_*()'s 'count' parameter name - but the roles are different: the first one is the total number of bytes to be copied, while the second one is a partial copy size.
To unconfuse all this, use a consistent set of parameter names:
- 'size' is the partial copy size within a single xstate component
- 'size_total' is the total copy requested
- 'offset_start' is the requested starting offset.
- 'offset' is the offset within an xstate component.
No change in functionality.
--- arch/x86/include/asm/fpu/xstate.h | 4 ++-- arch/x86/kernel/fpu/xstate.c | 44 ++++++++++++++++++++++---------------------- 2 files changed, 24 insertions(+), 24 deletions(-)
arch/x86/include/asm/fpu/xstate.h +2 -2
@@ -48,8 +48,8 @@ void fpu__xstate_clear_all_cpu_caps(void);void *get_xsave_addr (struct xregs_state *xsave,int xstate);const void *get_xsave_field_ptr (int xstate_field);int using_compacted_format (void ); -int copy_xstate_to_kernel (void *kbuf,struct xregs_state *xsave,unsigned int pos,unsigned int count); -int copy_xstate_to_user (void __user *ubuf,struct xregs_state *xsave,unsigned int pos,unsigned int count); +int copy_xstate_to_kernel (void *kbuf,struct xregs_state *xsave,unsigned int offset,unsigned int size); +int copy_xstate_to_user (void __user *ubuf,struct xregs_state *xsave,unsigned int offset,unsigned int size);int copy_user_to_xstate (const void *kbuf,const void __user *ubuf,struct xregs_state *xsave);#endif
arch/x86/kernel/fpu/xstate.c +22 -22
130 lines not on this page · raw message
Signature · 1 line
2.11.0
Re: [PATCH 08/33] x86/fpu: Clarify parameter names in the copy_xstate_to_*() methods
arch/x86/kernel/fpu/xstate.c int arch_set_user_pkey_access(struct task_struct *tsk, int pkey, · line 930
Quoted 5 lines · Ingo Molnar
static inline int
__copy_xstate_to_kernel(void *kbuf,arch/x86/kernel/fpu/xstate.c +1
-1const void *data, - unsigned int pos, unsigned int count, int end_pos) + unsigned int offset, unsigned int size, int size_total)
Why is size_total int?
arch/x86/kernel/fpu/xstate.c int arch_set_user_pkey_access(struct task_struct *tsk, int pkey, · line 935
Quoted 8 lines
{
arch/x86/kernel/fpu/xstate.c +2
-3-if (!count) +if (!size)return 0 ; -if (end_pos <0 || pos < end_pos) { -unsigned int copy = end_pos <0 ? count :min (count, end_pos - pos); +if (size_total <0 || offset < size_total) {
And why would it be < 0? The call sites of this inline are all inside of:
int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave,
unsigned int offset_start, int size_total)
and hand in size_total completely unmodified. copy_xstate_to_kernel() itself has a single callsite:
int xstateregs_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf)
and that hands in count unmodified.
The same issue is with the to_user() variant which is even more obvious. All callers are inside of copy_xstate_to_user() where size_total is an unsigned int argument which is handed in unmodified.
This signed/unsigned mismatch is confusing at best.
Thanks,
tglx
Re: [PATCH 08/33] x86/fpu: Clarify parameter names in the copy_xstate_to_*() methods
Quoted 2 lines · Thomas Gleixner
This signed/unsigned mismatch is confusing at best.
Bah, should have read the next patch before staring at the code ....
Thanks,
tglx
tip-bot for Ingo Molnar
merge bot[tip:x86/fpu] x86/fpu: Clarify parameter names in the copy_xstate_to_*() methods
In reply to Ingo Molnarx86/fpu: Clarify parameter names in the copy_xstate_to_*() methods
Commit-ID: 56583c9a1400fe1935edd55b24b4fbbc779b59cb Gitweb: http://git.kernel.org/tip/56583c9a1400fe1935edd55b24b4fbbc779b59cb Author: Ingo Molnar <[email protected]> AuthorDate: Sat, 23 Sep 2017 14:59:51 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Sun, 24 Sep 2017 13:04:32 +0200
x86/fpu: Clarify parameter names in the copy_xstate_to_*() methods
Right now there's a confusing mixture of 'offset' and 'size' parameters:
- __copy_xstate_to_*() input parameter 'end_pos' not not really an offset, but the full size of the copy to be performed.
- input parameter 'count' to copy_xstate_to_*() shadows that of __copy_xstate_to_*()'s 'count' parameter name - but the roles are different: the first one is the total number of bytes to be copied, while the second one is a partial copy size.
To unconfuse all this, use a consistent set of parameter names:
- 'size' is the partial copy size within a single xstate component
- 'size_total' is the total copy requested
- 'offset_start' is the requested starting offset.
- 'offset' is the offset within an xstate component.
No change in functionality.
--- arch/x86/include/asm/fpu/xstate.h | 4 ++-- arch/x86/kernel/fpu/xstate.c | 44 +++++++++++++++++++-------------------- 2 files changed, 24 insertions(+), 24 deletions(-)
arch/x86/include/asm/fpu/xstate.h +2 -2
@@ -48,8 +48,8 @@ void fpu__xstate_clear_all_cpu_caps(void);void *get_xsave_addr (struct xregs_state *xsave,int xstate);const void *get_xsave_field_ptr (int xstate_field);int using_compacted_format (void ); -int copy_xstate_to_kernel (void *kbuf,struct xregs_state *xsave,unsigned int pos,unsigned int count); -int copy_xstate_to_user (void __user *ubuf,struct xregs_state *xsave,unsigned int pos,unsigned int count); +int copy_xstate_to_kernel (void *kbuf,struct xregs_state *xsave,unsigned int offset,unsigned int size); +int copy_xstate_to_user (void __user *ubuf,struct xregs_state *xsave,unsigned int offset,unsigned int size);int copy_user_to_xstate (const void *kbuf,const void __user *ubuf,struct xregs_state *xsave);#endif
arch/x86/kernel/fpu/xstate.c +22 -22
130 lines not on this page · raw message
PATCH 9/33 x86/fpu: Change 'size_total' parameter to unsigned and standardize the size checks in copy_xstate_to_*()
In reply to Ingo Molnar'size_total' is derived from an unsigned input parameter - and then converted to 'int' and checked for negative ranges:
if (size_total < 0 || offset < size_total) {This conversion and the checks are unnecessary obfuscation, reject overly large requested copy sizes outright and simplify the underlying code.
--- arch/x86/kernel/fpu/xstate.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-)
arch/x86/kernel/fpu/xstate.c +15 -17
@@ -925,15 +925,11 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,* the source data pointer or increment pos, count, kbuf, and ubuf. */ static inline int -__copy_xstate_to_kernel (void *kbuf, -const void *data, -unsigned int offset,unsigned int size,int size_total) +__copy_xstate_to_kernel (void *kbuf,const void *data, +unsigned int offset,unsigned int size,unsigned int size_total) { -if (!size) -return 0 ; - -if (size_total <0 || offset < size_total) { -unsigned int copy = size_total <0 ? size :min (size, size_total - offset); +if (offset < size_total) { +unsigned int copy =min (size, size_total - offset);memcpy (kbuf + offset, data, copy); }
@@ -986,12 +982,13 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int of offset = xstate_offsets[i]; size = xstate_sizes[i]; +/* The next component has to fit fully into the output buffer: */ +if (offset + size > size_total) +break ; + ret =__copy_xstate_to_kernel (kbuf, src, offset, size, size_total);if (ret)return ret; - -if (offset + size >= size_total) -break ; } }
@@ -1010,13 +1007,13 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int of }static inline int -__copy_xstate_to_user (void __user *ubuf,const void *data,unsigned int offset,unsigned int size,int size_total) +__copy_xstate_to_user (void __user *ubuf,const void *data,unsigned int offset,unsigned int size,unsigned int size_total) {if (!size)return 0 ; -if (size_total <0 || offset < size_total) { -unsigned int copy = size_total <0 ? size :min (size, size_total - offset); +if (offset < size_total) { +unsigned int copy =min (size, size_total - offset);if (__copy_to_user (ubuf + offset, data, copy))return -EFAULT ;
@@ -1069,12 +1066,13 @@ int copy_xstate_to_user(void __user *ubuf, struct xregs_state *xsave, unsigned i offset = xstate_offsets[i]; size = xstate_sizes[i]; +/* The next component has to fit fully into the output buffer: */ +if (offset + size > size_total) +break ; + ret =__copy_xstate_to_user (ubuf, src, offset, size, size_total);if (ret)return ret; - -if (offset + size >= size_total) -break ; } }
Signature · 1 line
2.11.0
tip-bot for Ingo Molnar
merge bot[tip:x86/fpu] x86/fpu: Change 'size_total' parameter to unsigned and standardize the size checks in copy_xstate_to_*()
x86/fpu: Change 'size_total' parameter to unsigned and standardize the size checks in copy_xstate_to_*()
Commit-ID: 6ff15f8db7eaf29ef5ead6afbec9b25485fe8703 Gitweb: http://git.kernel.org/tip/6ff15f8db7eaf29ef5ead6afbec9b25485fe8703 Author: Ingo Molnar <[email protected]> AuthorDate: Sat, 23 Sep 2017 14:59:52 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Sun, 24 Sep 2017 13:04:32 +0200
x86/fpu: Change 'size_total' parameter to unsigned and standardize the size checks in copy_xstate_to_*()
'size_total' is derived from an unsigned input parameter - and then converted to 'int' and checked for negative ranges:
if (size_total < 0 || offset < size_total) {This conversion and the checks are unnecessary obfuscation, reject overly large requested copy sizes outright and simplify the underlying code.
--- arch/x86/kernel/fpu/xstate.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-)
arch/x86/kernel/fpu/xstate.c +15 -17
@@ -925,15 +925,11 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,* the source data pointer or increment pos, count, kbuf, and ubuf. */ static inline int -__copy_xstate_to_kernel (void *kbuf, -const void *data, -unsigned int offset,unsigned int size,int size_total) +__copy_xstate_to_kernel (void *kbuf,const void *data, +unsigned int offset,unsigned int size,unsigned int size_total) { -if (!size) -return 0 ; - -if (size_total <0 || offset < size_total) { -unsigned int copy = size_total <0 ? size :min (size, size_total - offset); +if (offset < size_total) { +unsigned int copy =min (size, size_total - offset);memcpy (kbuf + offset, data, copy); }
@@ -986,12 +982,13 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int of offset = xstate_offsets[i]; size = xstate_sizes[i]; +/* The next component has to fit fully into the output buffer: */ +if (offset + size > size_total) +break ; + ret =__copy_xstate_to_kernel (kbuf, src, offset, size, size_total);if (ret)return ret; - -if (offset + size >= size_total) -break ; } }
@@ -1010,13 +1007,13 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int of }static inline int -__copy_xstate_to_user (void __user *ubuf,const void *data,unsigned int offset,unsigned int size,int size_total) +__copy_xstate_to_user (void __user *ubuf,const void *data,unsigned int offset,unsigned int size,unsigned int size_total) {if (!size)return 0 ; -if (size_total <0 || offset < size_total) { -unsigned int copy = size_total <0 ? size :min (size, size_total - offset); +if (offset < size_total) { +unsigned int copy =min (size, size_total - offset);if (__copy_to_user (ubuf + offset, data, copy))return -EFAULT ;
@@ -1069,12 +1066,13 @@ int copy_xstate_to_user(void __user *ubuf, struct xregs_state *xsave, unsigned i offset = xstate_offsets[i]; size = xstate_sizes[i]; +/* The next component has to fit fully into the output buffer: */ +if (offset + size > size_total) +break ; + ret =__copy_xstate_to_user (ubuf, src, offset, size, size_total);if (ret)return ret; - -if (offset + size >= size_total) -break ; } }
PATCH 10/33 x86/fpu: Simplify __copy_xstate_to_kernel() return values
In reply to Ingo Molnar__copy_xstate_to_kernel() can only return 0 (because kernel copies cannot fail), simplify the code throughout.
No change in functionality.
--- arch/x86/kernel/fpu/xstate.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-)
arch/x86/kernel/fpu/xstate.c +5 -12
@@ -924,7 +924,7 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,* This is similar to user_regset_copyout(), but will not add offset to * the source data pointer or increment pos, count, kbuf, and ubuf. */ -static inline int +static inline void __copy_xstate_to_kernel (void *kbuf,const void *data,unsigned int offset,unsigned int size,unsigned int size_total) {
@@ -933,7 +933,6 @@ __copy_xstate_to_kernel(void *kbuf, const void *data,memcpy (kbuf + offset, data, copy); } -return 0 ; }/*
@@ -946,8 +945,8 @@ __copy_xstate_to_kernel(void *kbuf, const void *data,int copy_xstate_to_kernel (void *kbuf,struct xregs_state *xsave,unsigned int offset_start,unsigned int size_total) {unsigned int offset, size; -int ret, i;struct xstate_header header; +int i;/* * Currently copy_regset_to_user() starts from pos 0:
@@ -968,9 +967,7 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int of offset = offsetof(struct xregs_state , header); size =sizeof (header); - ret =__copy_xstate_to_kernel (kbuf, &header, offset, size, size_total); -if (ret) -return ret; +__copy_xstate_to_kernel (kbuf, &header, offset, size, size_total);for (i =0 ; i <XFEATURE_MAX ; i++) {/*
@@ -986,9 +983,7 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int ofif (offset + size > size_total)break ; - ret =__copy_xstate_to_kernel (kbuf, src, offset, size, size_total); -if (ret) -return ret; +__copy_xstate_to_kernel (kbuf, src, offset, size, size_total); } }
@@ -999,9 +994,7 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int of offset = offsetof(struct fxregs_state , sw_reserved); size =sizeof (xstate_fx_sw_bytes); - ret =__copy_xstate_to_kernel (kbuf, xstate_fx_sw_bytes, offset, size, size_total); -if (ret) -return ret; +__copy_xstate_to_kernel (kbuf, xstate_fx_sw_bytes, offset, size, size_total);return 0 ; }
Signature · 1 line
2.11.0
tip-bot for Ingo Molnar
merge bot[tip:x86/fpu] x86/fpu: Simplify __copy_xstate_to_kernel() return values
x86/fpu: Simplify __copy_xstate_to_kernel() return values
Commit-ID: 8c0817f4a3188ac5485ce14f96f12a175800b881 Gitweb: http://git.kernel.org/tip/8c0817f4a3188ac5485ce14f96f12a175800b881 Author: Ingo Molnar <[email protected]> AuthorDate: Sat, 23 Sep 2017 14:59:53 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Sun, 24 Sep 2017 13:04:32 +0200
x86/fpu: Simplify __copy_xstate_to_kernel() return values
__copy_xstate_to_kernel() can only return 0 (because kernel copies cannot fail), simplify the code throughout.
No change in functionality.
--- arch/x86/kernel/fpu/xstate.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-)
arch/x86/kernel/fpu/xstate.c +5 -12
@@ -924,7 +924,7 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,* This is similar to user_regset_copyout(), but will not add offset to * the source data pointer or increment pos, count, kbuf, and ubuf. */ -static inline int +static inline void __copy_xstate_to_kernel (void *kbuf,const void *data,unsigned int offset,unsigned int size,unsigned int size_total) {
@@ -933,7 +933,6 @@ __copy_xstate_to_kernel(void *kbuf, const void *data,memcpy (kbuf + offset, data, copy); } -return 0 ; }/*
@@ -946,8 +945,8 @@ __copy_xstate_to_kernel(void *kbuf, const void *data,int copy_xstate_to_kernel (void *kbuf,struct xregs_state *xsave,unsigned int offset_start,unsigned int size_total) {unsigned int offset, size; -int ret, i;struct xstate_header header; +int i;/* * Currently copy_regset_to_user() starts from pos 0:
@@ -968,9 +967,7 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int of offset = offsetof(struct xregs_state , header); size =sizeof (header); - ret =__copy_xstate_to_kernel (kbuf, &header, offset, size, size_total); -if (ret) -return ret; +__copy_xstate_to_kernel (kbuf, &header, offset, size, size_total);for (i =0 ; i <XFEATURE_MAX ; i++) {/*
@@ -986,9 +983,7 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int ofif (offset + size > size_total)break ; - ret =__copy_xstate_to_kernel (kbuf, src, offset, size, size_total); -if (ret) -return ret; +__copy_xstate_to_kernel (kbuf, src, offset, size, size_total); } }
@@ -999,9 +994,7 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int of offset = offsetof(struct fxregs_state , sw_reserved); size =sizeof (xstate_fx_sw_bytes); - ret =__copy_xstate_to_kernel (kbuf, xstate_fx_sw_bytes, offset, size, size_total); -if (ret) -return ret; +__copy_xstate_to_kernel (kbuf, xstate_fx_sw_bytes, offset, size, size_total);return 0 ; }
PATCH 11/33 x86/fpu: Split copy_user_to_xstate() into copy_kernel_to_xstate() & copy_user_to_xstate()
In reply to Ingo MolnarSimilar to:
x86/fpu: Split copy_xstate_to_user() into copy_xstate_to_kernel() & copy_xstate_to_user()
No change in functionality.
--- arch/x86/include/asm/fpu/xstate.h | 4 ++-- arch/x86/kernel/fpu/regset.c | 10 ++++++--- arch/x86/kernel/fpu/xstate.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 74 insertions(+), 6 deletions(-)
arch/x86/include/asm/fpu/xstate.h +2 -2
@@ -50,6 +50,6 @@ const void *get_xsave_field_ptr(int xstate_field);int using_compacted_format (void );int copy_xstate_to_kernel (void *kbuf,struct xregs_state *xsave,unsigned int offset,unsigned int size);int copy_xstate_to_user (void __user *ubuf,struct xregs_state *xsave,unsigned int offset,unsigned int size); -int copy_user_to_xstate (const void *kbuf,const void __user *ubuf, -struct xregs_state *xsave); +int copy_kernel_to_xstate (const void *kbuf,const void __user *ubuf,struct xregs_state *xsave); +int copy_user_to_xstate (const void *kbuf,const void __user *ubuf,struct xregs_state *xsave);#endif
arch/x86/kernel/fpu/regset.c +7 -3
@@ -134,10 +134,14 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset,fpu__activate_fpstate_write (fpu); -if (boot_cpu_has (X86_FEATURE_XSAVES )) - ret =copy_user_to_xstate (kbuf, ubuf, xsave); -else +if (boot_cpu_has (X86_FEATURE_XSAVES )) { +if (kbuf) + ret =copy_kernel_to_xstate (kbuf, ubuf, xsave); +else + ret =copy_user_to_xstate (kbuf, ubuf, xsave); + }else { ret =user_regset_copyin (&pos, &count, &kbuf, &ubuf, xsave,0 ,-1 ); + }/* * In case of failure, mark all states as init:
arch/x86/kernel/fpu/xstate.c +65 -1
72 lines not on this page · raw message
Signature · 1 line
2.11.0
tip-bot for Ingo Molnar
merge bot[tip:x86/fpu] x86/fpu: Split copy_user_to_xstate() into copy_kernel_to_xstate() & copy_user_to_xstate()
x86/fpu: Split copy_user_to_xstate() into copy_kernel_to_xstate() & copy_user_to_xstate()
Commit-ID: 79fecc2b7506f29fb91becc65e8788e5ae7eba9f Gitweb: http://git.kernel.org/tip/79fecc2b7506f29fb91becc65e8788e5ae7eba9f Author: Ingo Molnar <[email protected]> AuthorDate: Sat, 23 Sep 2017 14:59:54 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Sun, 24 Sep 2017 13:04:32 +0200
x86/fpu: Split copy_user_to_xstate() into copy_kernel_to_xstate() & copy_user_to_xstate()
Similar to:
x86/fpu: Split copy_xstate_to_user() into copy_xstate_to_kernel() & copy_xstate_to_user()
No change in functionality.
--- arch/x86/include/asm/fpu/xstate.h | 4 +-- arch/x86/kernel/fpu/regset.c | 10 ++++-- arch/x86/kernel/fpu/xstate.c | 66 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 74 insertions(+), 6 deletions(-)
arch/x86/include/asm/fpu/xstate.h +2 -2
@@ -50,6 +50,6 @@ const void *get_xsave_field_ptr(int xstate_field);int using_compacted_format (void );int copy_xstate_to_kernel (void *kbuf,struct xregs_state *xsave,unsigned int offset,unsigned int size);int copy_xstate_to_user (void __user *ubuf,struct xregs_state *xsave,unsigned int offset,unsigned int size); -int copy_user_to_xstate (const void *kbuf,const void __user *ubuf, -struct xregs_state *xsave); +int copy_kernel_to_xstate (const void *kbuf,const void __user *ubuf,struct xregs_state *xsave); +int copy_user_to_xstate (const void *kbuf,const void __user *ubuf,struct xregs_state *xsave);#endif
arch/x86/kernel/fpu/regset.c +7 -3
@@ -134,10 +134,14 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset,fpu__activate_fpstate_write (fpu); -if (boot_cpu_has (X86_FEATURE_XSAVES )) - ret =copy_user_to_xstate (kbuf, ubuf, xsave); -else +if (boot_cpu_has (X86_FEATURE_XSAVES )) { +if (kbuf) + ret =copy_kernel_to_xstate (kbuf, ubuf, xsave); +else + ret =copy_user_to_xstate (kbuf, ubuf, xsave); + }else { ret =user_regset_copyin (&pos, &count, &kbuf, &ubuf, xsave,0 ,-1 ); + }/* * In case of failure, mark all states as init:
arch/x86/kernel/fpu/xstate.c +65 -1
72 lines not on this page · raw message
PATCH 12/33 x86/fpu: Remove 'ubuf' parameter from the copy_kernel_to_xstate() API
In reply to Ingo MolnarNo change in functionality.
--- arch/x86/include/asm/fpu/xstate.h | 2 +- arch/x86/kernel/fpu/regset.c | 2 +- arch/x86/kernel/fpu/xstate.c | 17 +++-------------- 3 files changed, 5 insertions(+), 16 deletions(-)
arch/x86/include/asm/fpu/xstate.h +1 -1
@@ -50,6 +50,6 @@ const void *get_xsave_field_ptr(int xstate_field);int using_compacted_format (void );int copy_xstate_to_kernel (void *kbuf,struct xregs_state *xsave,unsigned int offset,unsigned int size);int copy_xstate_to_user (void __user *ubuf,struct xregs_state *xsave,unsigned int offset,unsigned int size); -int copy_kernel_to_xstate (const void *kbuf,const void __user *ubuf,struct xregs_state *xsave); +int copy_kernel_to_xstate (const void *kbuf,struct xregs_state *xsave);int copy_user_to_xstate (const void *kbuf,const void __user *ubuf,struct xregs_state *xsave);#endif
arch/x86/kernel/fpu/regset.c +1 -1
@@ -136,7 +136,7 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset,if (boot_cpu_has (X86_FEATURE_XSAVES )) {if (kbuf) - ret =copy_kernel_to_xstate (kbuf, ubuf, xsave); + ret =copy_kernel_to_xstate (kbuf, xsave);else ret =copy_user_to_xstate (kbuf, ubuf, xsave); }else {
arch/x86/kernel/fpu/xstate.c +3 -14
@@ -1089,8 +1089,7 @@ int copy_xstate_to_user(void __user *ubuf, struct xregs_state *xsave, unsigned i* there we check the CPU has XSAVES and a whole standard-sized buffer * exists. */ -int copy_kernel_to_xstate (const void *kbuf,const void __user *ubuf, -struct xregs_state *xsave) +int copy_kernel_to_xstate (const void *kbuf,struct xregs_state *xsave) {unsigned int offset, size;int i;
@@ -1100,12 +1099,7 @@ int copy_kernel_to_xstate(const void *kbuf, const void __user *ubuf, offset = offsetof(struct xregs_state , header); size =sizeof (xfeatures); -if (kbuf) { -memcpy (&xfeatures, kbuf + offset, size); - }else { -if (__copy_from_user (&xfeatures, ubuf + offset, size)) -return -EFAULT ; - } +memcpy (&xfeatures, kbuf + offset, size);/* * Reject if the user sets any disabled or supervisor features:
@@ -1124,12 +1118,7 @@ int copy_kernel_to_xstate(const void *kbuf, const void __user *ubuf, offset = xstate_offsets[i]; size = xstate_sizes[i]; -if (kbuf) { -memcpy (dst, kbuf + offset, size); - }else { -if (__copy_from_user (dst, ubuf + offset, size)) -return -EFAULT ; - } +memcpy (dst, kbuf + offset, size); } }
Signature · 1 line
2.11.0
tip-bot for Ingo Molnar
merge bot[tip:x86/fpu] x86/fpu: Remove 'ubuf' parameter from the copy_kernel_to_xstate() API
x86/fpu: Remove 'ubuf' parameter from the copy_kernel_to_xstate() API
Commit-ID: 59dffa4edba1f15b2bfdbe608aca1efe664c674c Gitweb: http://git.kernel.org/tip/59dffa4edba1f15b2bfdbe608aca1efe664c674c Author: Ingo Molnar <[email protected]> AuthorDate: Sat, 23 Sep 2017 14:59:55 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Sun, 24 Sep 2017 13:04:33 +0200
x86/fpu: Remove 'ubuf' parameter from the copy_kernel_to_xstate() API
No change in functionality.
--- arch/x86/include/asm/fpu/xstate.h | 2 +- arch/x86/kernel/fpu/regset.c | 2 +- arch/x86/kernel/fpu/xstate.c | 17 +++-------------- 3 files changed, 5 insertions(+), 16 deletions(-)
arch/x86/include/asm/fpu/xstate.h +1 -1
@@ -50,6 +50,6 @@ const void *get_xsave_field_ptr(int xstate_field);int using_compacted_format (void );int copy_xstate_to_kernel (void *kbuf,struct xregs_state *xsave,unsigned int offset,unsigned int size);int copy_xstate_to_user (void __user *ubuf,struct xregs_state *xsave,unsigned int offset,unsigned int size); -int copy_kernel_to_xstate (const void *kbuf,const void __user *ubuf,struct xregs_state *xsave); +int copy_kernel_to_xstate (const void *kbuf,struct xregs_state *xsave);int copy_user_to_xstate (const void *kbuf,const void __user *ubuf,struct xregs_state *xsave);#endif
arch/x86/kernel/fpu/regset.c +1 -1
@@ -136,7 +136,7 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset,if (boot_cpu_has (X86_FEATURE_XSAVES )) {if (kbuf) - ret =copy_kernel_to_xstate (kbuf, ubuf, xsave); + ret =copy_kernel_to_xstate (kbuf, xsave);else ret =copy_user_to_xstate (kbuf, ubuf, xsave); }else {
arch/x86/kernel/fpu/xstate.c +3 -14
@@ -1089,8 +1089,7 @@ int copy_xstate_to_user(void __user *ubuf, struct xregs_state *xsave, unsigned i* there we check the CPU has XSAVES and a whole standard-sized buffer * exists. */ -int copy_kernel_to_xstate (const void *kbuf,const void __user *ubuf, -struct xregs_state *xsave) +int copy_kernel_to_xstate (const void *kbuf,struct xregs_state *xsave) {unsigned int offset, size;int i;
@@ -1100,12 +1099,7 @@ int copy_kernel_to_xstate(const void *kbuf, const void __user *ubuf, offset = offsetof(struct xregs_state , header); size =sizeof (xfeatures); -if (kbuf) { -memcpy (&xfeatures, kbuf + offset, size); - }else { -if (__copy_from_user (&xfeatures, ubuf + offset, size)) -return -EFAULT ; - } +memcpy (&xfeatures, kbuf + offset, size);/* * Reject if the user sets any disabled or supervisor features:
@@ -1124,12 +1118,7 @@ int copy_kernel_to_xstate(const void *kbuf, const void __user *ubuf, offset = xstate_offsets[i]; size = xstate_sizes[i]; -if (kbuf) { -memcpy (dst, kbuf + offset, size); - }else { -if (__copy_from_user (dst, ubuf + offset, size)) -return -EFAULT ; - } +memcpy (dst, kbuf + offset, size); } }
PATCH 13/33 x86/fpu: Remove 'kbuf' parameter from the copy_user_to_xstate() API
In reply to Ingo MolnarNo change in functionality.
--- arch/x86/include/asm/fpu/xstate.h | 2 +- arch/x86/kernel/fpu/regset.c | 2 +- arch/x86/kernel/fpu/signal.c | 11 ++++------- arch/x86/kernel/fpu/xstate.c | 19 +++++-------------- 4 files changed, 11 insertions(+), 23 deletions(-)
arch/x86/include/asm/fpu/xstate.h +1 -1
@@ -51,5 +51,5 @@ int using_compacted_format(void);int copy_xstate_to_kernel (void *kbuf,struct xregs_state *xsave,unsigned int offset,unsigned int size);int copy_xstate_to_user (void __user *ubuf,struct xregs_state *xsave,unsigned int offset,unsigned int size);int copy_kernel_to_xstate (const void *kbuf,struct xregs_state *xsave); -int copy_user_to_xstate (const void *kbuf,const void __user *ubuf,struct xregs_state *xsave); +int copy_user_to_xstate (const void __user *ubuf,struct xregs_state *xsave);#endif
arch/x86/kernel/fpu/regset.c +1 -1
@@ -138,7 +138,7 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset,if (kbuf) ret =copy_kernel_to_xstate (kbuf, xsave);else - ret =copy_user_to_xstate (kbuf, ubuf, xsave); + ret =copy_user_to_xstate (ubuf, xsave); }else { ret =user_regset_copyin (&pos, &count, &kbuf, &ubuf, xsave,0 ,-1 ); }
arch/x86/kernel/fpu/signal.c +4 -7
@@ -323,13 +323,10 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)*/ fpu__drop (fpu); -if (using_compacted_format ()) { - err =copy_user_to_xstate (NULL , buf_fx, - &fpu->state.xsave); - }else { - err =__copy_from_user (&fpu->state.xsave, - buf_fx, state_size); - } +if (using_compacted_format ()) + err =copy_user_to_xstate (buf_fx, &fpu->state.xsave); +else + err =__copy_from_user (&fpu->state.xsave, buf_fx, state_size);if (err ||__copy_from_user (&env, buf,sizeof (env))) {fpstate_init (&fpu->state);
arch/x86/kernel/fpu/xstate.c +5 -14
@@ -1142,8 +1142,7 @@ int copy_kernel_to_xstate(const void *kbuf, struct xregs_state *xsave)* there we check the CPU has XSAVES and a whole standard-sized buffer * exists. */ -int copy_user_to_xstate (const void *kbuf,const void __user *ubuf, -struct xregs_state *xsave) +int copy_user_to_xstate (const void __user *ubuf,struct xregs_state *xsave) {unsigned int offset, size;int i;
@@ -1153,12 +1152,8 @@ int copy_user_to_xstate(const void *kbuf, const void __user *ubuf, offset = offsetof(struct xregs_state , header); size =sizeof (xfeatures); -if (kbuf) { -memcpy (&xfeatures, kbuf + offset, size); - }else { -if (__copy_from_user (&xfeatures, ubuf + offset, size)) -return -EFAULT ; - } +if (__copy_from_user (&xfeatures, ubuf + offset, size)) +return -EFAULT ;/* * Reject if the user sets any disabled or supervisor features:
@@ -1177,12 +1172,8 @@ int copy_user_to_xstate(const void *kbuf, const void __user *ubuf, offset = xstate_offsets[i]; size = xstate_sizes[i]; -if (kbuf) { -memcpy (dst, kbuf + offset, size); - }else { -if (__copy_from_user (dst, ubuf + offset, size)) -return -EFAULT ; - } +if (__copy_from_user (dst, ubuf + offset, size)) +return -EFAULT ; } }
Signature · 1 line
2.11.0
tip-bot for Ingo Molnar
merge bot[tip:x86/fpu] x86/fpu: Remove 'kbuf' parameter from the copy_user_to_xstate() API
x86/fpu: Remove 'kbuf' parameter from the copy_user_to_xstate() API
Commit-ID: 7b9094c688f807c110a2dab6f6edc5876bfa7b0b Gitweb: http://git.kernel.org/tip/7b9094c688f807c110a2dab6f6edc5876bfa7b0b Author: Ingo Molnar <[email protected]> AuthorDate: Sat, 23 Sep 2017 14:59:56 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Sun, 24 Sep 2017 13:04:33 +0200
x86/fpu: Remove 'kbuf' parameter from the copy_user_to_xstate() API
No change in functionality.
--- arch/x86/include/asm/fpu/xstate.h | 2 +- arch/x86/kernel/fpu/regset.c | 2 +- arch/x86/kernel/fpu/signal.c | 11 ++++------- arch/x86/kernel/fpu/xstate.c | 19 +++++-------------- 4 files changed, 11 insertions(+), 23 deletions(-)
arch/x86/include/asm/fpu/xstate.h +1 -1
@@ -51,5 +51,5 @@ int using_compacted_format(void);int copy_xstate_to_kernel (void *kbuf,struct xregs_state *xsave,unsigned int offset,unsigned int size);int copy_xstate_to_user (void __user *ubuf,struct xregs_state *xsave,unsigned int offset,unsigned int size);int copy_kernel_to_xstate (const void *kbuf,struct xregs_state *xsave); -int copy_user_to_xstate (const void *kbuf,const void __user *ubuf,struct xregs_state *xsave); +int copy_user_to_xstate (const void __user *ubuf,struct xregs_state *xsave);#endif
arch/x86/kernel/fpu/regset.c +1 -1
@@ -138,7 +138,7 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset,if (kbuf) ret =copy_kernel_to_xstate (kbuf, xsave);else - ret =copy_user_to_xstate (kbuf, ubuf, xsave); + ret =copy_user_to_xstate (ubuf, xsave); }else { ret =user_regset_copyin (&pos, &count, &kbuf, &ubuf, xsave,0 ,-1 ); }
arch/x86/kernel/fpu/signal.c +4 -7
@@ -323,13 +323,10 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)*/ fpu__drop (fpu); -if (using_compacted_format ()) { - err =copy_user_to_xstate (NULL , buf_fx, - &fpu->state.xsave); - }else { - err =__copy_from_user (&fpu->state.xsave, - buf_fx, state_size); - } +if (using_compacted_format ()) + err =copy_user_to_xstate (buf_fx, &fpu->state.xsave); +else + err =__copy_from_user (&fpu->state.xsave, buf_fx, state_size);if (err ||__copy_from_user (&env, buf,sizeof (env))) {fpstate_init (&fpu->state);
arch/x86/kernel/fpu/xstate.c +5 -14
@@ -1142,8 +1142,7 @@ int copy_kernel_to_xstate(const void *kbuf, struct xregs_state *xsave)* there we check the CPU has XSAVES and a whole standard-sized buffer * exists. */ -int copy_user_to_xstate (const void *kbuf,const void __user *ubuf, -struct xregs_state *xsave) +int copy_user_to_xstate (const void __user *ubuf,struct xregs_state *xsave) {unsigned int offset, size;int i;
@@ -1153,12 +1152,8 @@ int copy_user_to_xstate(const void *kbuf, const void __user *ubuf, offset = offsetof(struct xregs_state , header); size =sizeof (xfeatures); -if (kbuf) { -memcpy (&xfeatures, kbuf + offset, size); - }else { -if (__copy_from_user (&xfeatures, ubuf + offset, size)) -return -EFAULT ; - } +if (__copy_from_user (&xfeatures, ubuf + offset, size)) +return -EFAULT ;/* * Reject if the user sets any disabled or supervisor features:
@@ -1177,12 +1172,8 @@ int copy_user_to_xstate(const void *kbuf, const void __user *ubuf, offset = xstate_offsets[i]; size = xstate_sizes[i]; -if (kbuf) { -memcpy (dst, kbuf + offset, size); - }else { -if (__copy_from_user (dst, ubuf + offset, size)) -return -EFAULT ; - } +if (__copy_from_user (dst, ubuf + offset, size)) +return -EFAULT ; } }
PATCH 14/33 x86/fpu: Flip the parameter order in copy_*_to_xstate()
In reply to Ingo MolnarMake it more consistent with regular memcpy() semantics, where the destination argument comes first.
No change in functionality.
--- arch/x86/include/asm/fpu/xstate.h | 4 ++-- arch/x86/kernel/fpu/regset.c | 4 ++-- arch/x86/kernel/fpu/signal.c | 2 +- arch/x86/kernel/fpu/xstate.c | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-)
arch/x86/include/asm/fpu/xstate.h +2 -2
@@ -50,6 +50,6 @@ const void *get_xsave_field_ptr(int xstate_field);int using_compacted_format (void );int copy_xstate_to_kernel (void *kbuf,struct xregs_state *xsave,unsigned int offset,unsigned int size);int copy_xstate_to_user (void __user *ubuf,struct xregs_state *xsave,unsigned int offset,unsigned int size); -int copy_kernel_to_xstate (const void *kbuf,struct xregs_state *xsave); -int copy_user_to_xstate (const void __user *ubuf,struct xregs_state *xsave); +int copy_kernel_to_xstate (struct xregs_state *xsave,const void *kbuf); +int copy_user_to_xstate (struct xregs_state *xsave,const void __user *ubuf);#endif
arch/x86/kernel/fpu/regset.c +2 -2
@@ -136,9 +136,9 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset,if (boot_cpu_has (X86_FEATURE_XSAVES )) {if (kbuf) - ret =copy_kernel_to_xstate (kbuf, xsave); + ret =copy_kernel_to_xstate (xsave, kbuf);else - ret =copy_user_to_xstate (ubuf, xsave); + ret =copy_user_to_xstate (xsave, ubuf); }else { ret =user_regset_copyin (&pos, &count, &kbuf, &ubuf, xsave,0 ,-1 ); }
arch/x86/kernel/fpu/signal.c +1 -1
@@ -324,7 +324,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)fpu__drop (fpu);if (using_compacted_format ()) - err =copy_user_to_xstate (buf_fx, &fpu->state.xsave); + err =copy_user_to_xstate (&fpu->state.xsave, buf_fx);else err =__copy_from_user (&fpu->state.xsave, buf_fx, state_size);
arch/x86/kernel/fpu/xstate.c +2 -2
@@ -1089,7 +1089,7 @@ int copy_xstate_to_user(void __user *ubuf, struct xregs_state *xsave, unsigned i* there we check the CPU has XSAVES and a whole standard-sized buffer * exists. */ -int copy_kernel_to_xstate (const void *kbuf,struct xregs_state *xsave) +int copy_kernel_to_xstate (struct xregs_state *xsave,const void *kbuf) {unsigned int offset, size;int i;
@@ -1142,7 +1142,7 @@ int copy_kernel_to_xstate(const void *kbuf, struct xregs_state *xsave)* there we check the CPU has XSAVES and a whole standard-sized buffer * exists. */ -int copy_user_to_xstate (const void __user *ubuf,struct xregs_state *xsave) +int copy_user_to_xstate (struct xregs_state *xsave,const void __user *ubuf) {unsigned int offset, size;int i;
Signature · 1 line
2.11.0
tip-bot for Ingo Molnar
merge bot[tip:x86/fpu] x86/fpu: Flip the parameter order in copy_*_to_xstate()
x86/fpu: Flip the parameter order in copy_*_to_xstate()
Commit-ID: 6d7f7da5533a3f841eeb1d9657257c9367924274 Gitweb: http://git.kernel.org/tip/6d7f7da5533a3f841eeb1d9657257c9367924274 Author: Ingo Molnar <[email protected]> AuthorDate: Sat, 23 Sep 2017 14:59:57 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Sun, 24 Sep 2017 13:04:33 +0200
x86/fpu: Flip the parameter order in copy_*_to_xstate()
Make it more consistent with regular memcpy() semantics, where the destination argument comes first.
No change in functionality.
--- arch/x86/include/asm/fpu/xstate.h | 4 ++-- arch/x86/kernel/fpu/regset.c | 4 ++-- arch/x86/kernel/fpu/signal.c | 2 +- arch/x86/kernel/fpu/xstate.c | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-)
arch/x86/include/asm/fpu/xstate.h +2 -2
@@ -50,6 +50,6 @@ const void *get_xsave_field_ptr(int xstate_field);int using_compacted_format (void );int copy_xstate_to_kernel (void *kbuf,struct xregs_state *xsave,unsigned int offset,unsigned int size);int copy_xstate_to_user (void __user *ubuf,struct xregs_state *xsave,unsigned int offset,unsigned int size); -int copy_kernel_to_xstate (const void *kbuf,struct xregs_state *xsave); -int copy_user_to_xstate (const void __user *ubuf,struct xregs_state *xsave); +int copy_kernel_to_xstate (struct xregs_state *xsave,const void *kbuf); +int copy_user_to_xstate (struct xregs_state *xsave,const void __user *ubuf);#endif
arch/x86/kernel/fpu/regset.c +2 -2
@@ -136,9 +136,9 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset,if (boot_cpu_has (X86_FEATURE_XSAVES )) {if (kbuf) - ret =copy_kernel_to_xstate (kbuf, xsave); + ret =copy_kernel_to_xstate (xsave, kbuf);else - ret =copy_user_to_xstate (ubuf, xsave); + ret =copy_user_to_xstate (xsave, ubuf); }else { ret =user_regset_copyin (&pos, &count, &kbuf, &ubuf, xsave,0 ,-1 ); }
arch/x86/kernel/fpu/signal.c +1 -1
@@ -324,7 +324,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)fpu__drop (fpu);if (using_compacted_format ()) - err =copy_user_to_xstate (buf_fx, &fpu->state.xsave); + err =copy_user_to_xstate (&fpu->state.xsave, buf_fx);else err =__copy_from_user (&fpu->state.xsave, buf_fx, state_size);
arch/x86/kernel/fpu/xstate.c +2 -2
@@ -1089,7 +1089,7 @@ int copy_xstate_to_user(void __user *ubuf, struct xregs_state *xsave, unsigned i* there we check the CPU has XSAVES and a whole standard-sized buffer * exists. */ -int copy_kernel_to_xstate (const void *kbuf,struct xregs_state *xsave) +int copy_kernel_to_xstate (struct xregs_state *xsave,const void *kbuf) {unsigned int offset, size;int i;
@@ -1142,7 +1142,7 @@ int copy_kernel_to_xstate(const void *kbuf, struct xregs_state *xsave)* there we check the CPU has XSAVES and a whole standard-sized buffer * exists. */ -int copy_user_to_xstate (const void __user *ubuf,struct xregs_state *xsave) +int copy_user_to_xstate (struct xregs_state *xsave,const void __user *ubuf) {unsigned int offset, size;int i;
PATCH 15/33 x86/fpu: Simplify fpu->fpregs_active use
In reply to Ingo MolnarThe fpregs_active() inline function is pretty pointless - in almost all the callsites it can be replaced with a direct fpu->fpregs_active access.
Do so and eliminate the extra layer of obfuscation.
--- arch/x86/include/asm/fpu/internal.h | 17 +---------------- arch/x86/kernel/fpu/core.c | 2 +- arch/x86/kernel/fpu/signal.c | 9 +++++---- arch/x86/mm/pkeys.c | 2 +- 4 files changed, 8 insertions(+), 22 deletions(-)
arch/x86/include/asm/fpu/internal.h +1 -16
@@ -543,21 +543,6 @@ static inline void fpregs_activate(struct fpu *fpu) }/* -* The question "does this thread have fpu access?" -* is slightly racy, since preemption could come in -* and revoke it immediately after the test. -* -* However, even in that very unlikely scenario, -* we can just assume we have FPU access - typically -* to save the FP state - we'll just take a #NM -* fault and get the FPU access back. -*/ -static inline int fpregs_active (void ) -{ -return current->thread.fpu.fpregs_active; -} - -/* * FPU state switching for scheduling. * * This is a two-stage process:
@@ -617,7 +602,7 @@ static inline void user_fpu_begin(void)struct fpu *fpu = ¤t->thread.fpu;preempt_disable (); -if (!fpregs_active ()) +if (!fpu->fpregs_active)fpregs_activate (fpu);preempt_enable (); }
arch/x86/kernel/fpu/core.c +1 -1
@@ -367,7 +367,7 @@ void fpu__current_fpstate_write_end(void)* registers may still be out of date. Update them with * an XRSTOR if they are active. */ -if (fpregs_active ()) +if (fpu->fpregs_active)copy_kernel_to_fpregs (&fpu->state);/*
arch/x86/kernel/fpu/signal.c +5 -4
@@ -155,7 +155,8 @@ static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf)*/ int copy_fpstate_to_sigframe (void __user *buf,void __user *buf_fx,int size) { -struct xregs_state *xsave = ¤t->thread.fpu.state.xsave; +struct fpu *fpu = ¤t->thread.fpu; +struct xregs_state *xsave = &fpu->state.xsave;struct task_struct *tsk = current;int ia32_fxstate = (buf != buf_fx);
@@ -170,13 +171,13 @@ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)sizeof (struct user_i387_ia32_struct ),NULL , (struct _fpstate_32 __user *) buf) ? -1 : 1; -if (fpregs_active () ||using_compacted_format ()) { +if (fpu->fpregs_active ||using_compacted_format ()) {/* Save the live register state to the user directly. */ if (copy_fpregs_to_sigframe (buf_fx))return -1 ;/* Update the thread's fxstate to save the fsave header. */ if (ia32_fxstate) -copy_fxregs_to_kernel (&tsk->thread.fpu); +copy_fxregs_to_kernel (fpu); }else {/* * It is a *bug* if kernel uses compacted-format for xsave
@@ -189,7 +190,7 @@ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)return -1 ; } -fpstate_sanitize_xstate (&tsk->thread.fpu); +fpstate_sanitize_xstate (fpu);if (__copy_to_user (buf_fx, xsave, fpu_user_xstate_size))return -1 ; }
arch/x86/mm/pkeys.c +1 -1
@@ -45,7 +45,7 @@ int __execute_only_pkey(struct mm_struct *mm)*/ preempt_disable ();if (!need_to_set_mm_pkey && -fpregs_active () && + current->thread.fpu.fpregs_active && !__pkru_allows_read (read_pkru (), execute_only_pkey)) {preempt_enable ();return execute_only_pkey;
Signature · 1 line
2.11.0
tip-bot for Ingo Molnar
merge bot[tip:x86/fpu] x86/fpu: Simplify fpu->fpregs_active use
x86/fpu: Simplify fpu->fpregs_active use
Commit-ID: b3a163081c28d1a4d1ad76259a9d93b34a82f1da Gitweb: http://git.kernel.org/tip/b3a163081c28d1a4d1ad76259a9d93b34a82f1da Author: Ingo Molnar <[email protected]> AuthorDate: Sat, 23 Sep 2017 14:59:58 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Sun, 24 Sep 2017 13:04:33 +0200
x86/fpu: Simplify fpu->fpregs_active use
The fpregs_active() inline function is pretty pointless - in almost all the callsites it can be replaced with a direct fpu->fpregs_active access.
Do so and eliminate the extra layer of obfuscation.
--- arch/x86/include/asm/fpu/internal.h | 17 +---------------- arch/x86/kernel/fpu/core.c | 2 +- arch/x86/kernel/fpu/signal.c | 9 +++++---- arch/x86/mm/pkeys.c | 2 +- 4 files changed, 8 insertions(+), 22 deletions(-)
arch/x86/include/asm/fpu/internal.h +1 -16
@@ -543,21 +543,6 @@ static inline void fpregs_activate(struct fpu *fpu) }/* -* The question "does this thread have fpu access?" -* is slightly racy, since preemption could come in -* and revoke it immediately after the test. -* -* However, even in that very unlikely scenario, -* we can just assume we have FPU access - typically -* to save the FP state - we'll just take a #NM -* fault and get the FPU access back. -*/ -static inline int fpregs_active (void ) -{ -return current->thread.fpu.fpregs_active; -} - -/* * FPU state switching for scheduling. * * This is a two-stage process:
@@ -617,7 +602,7 @@ static inline void user_fpu_begin(void)struct fpu *fpu = ¤t->thread.fpu;preempt_disable (); -if (!fpregs_active ()) +if (!fpu->fpregs_active)fpregs_activate (fpu);preempt_enable (); }
arch/x86/kernel/fpu/core.c +1 -1
@@ -367,7 +367,7 @@ void fpu__current_fpstate_write_end(void)* registers may still be out of date. Update them with * an XRSTOR if they are active. */ -if (fpregs_active ()) +if (fpu->fpregs_active)copy_kernel_to_fpregs (&fpu->state);/*
arch/x86/kernel/fpu/signal.c +5 -4
@@ -155,7 +155,8 @@ static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf)*/ int copy_fpstate_to_sigframe (void __user *buf,void __user *buf_fx,int size) { -struct xregs_state *xsave = ¤t->thread.fpu.state.xsave; +struct fpu *fpu = ¤t->thread.fpu; +struct xregs_state *xsave = &fpu->state.xsave;struct task_struct *tsk = current;int ia32_fxstate = (buf != buf_fx);
@@ -170,13 +171,13 @@ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)sizeof (struct user_i387_ia32_struct ),NULL , (struct _fpstate_32 __user *) buf) ? -1 : 1; -if (fpregs_active () ||using_compacted_format ()) { +if (fpu->fpregs_active ||using_compacted_format ()) {/* Save the live register state to the user directly. */ if (copy_fpregs_to_sigframe (buf_fx))return -1 ;/* Update the thread's fxstate to save the fsave header. */ if (ia32_fxstate) -copy_fxregs_to_kernel (&tsk->thread.fpu); +copy_fxregs_to_kernel (fpu); }else {/* * It is a *bug* if kernel uses compacted-format for xsave
@@ -189,7 +190,7 @@ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)return -1 ; } -fpstate_sanitize_xstate (&tsk->thread.fpu); +fpstate_sanitize_xstate (fpu);if (__copy_to_user (buf_fx, xsave, fpu_user_xstate_size))return -1 ; }
arch/x86/mm/pkeys.c +1 -1
@@ -45,7 +45,7 @@ int __execute_only_pkey(struct mm_struct *mm)*/ preempt_disable ();if (!need_to_set_mm_pkey && -fpregs_active () && + current->thread.fpu.fpregs_active && !__pkru_allows_read (read_pkru (), execute_only_pkey)) {preempt_enable ();return execute_only_pkey;
PATCH 16/33 x86/fpu: Make the fpu state change in fpu__clear() scheduler-atomic
In reply to Ingo MolnarDo this temporarily only, to make it easier to change the FPU state machine, in particular this change couples the fpu->fpregs_active and fpu->fpstate_active
states: they are only set/cleared together (as far as the scheduler sees them).
This will be removed by later patches.
--- arch/x86/kernel/fpu/core.c | 2 ++ 1 file changed, 2 insertions(+)
arch/x86/kernel/fpu/core.c +2 -0
@@ -462,9 +462,11 @@ void fpu__clear(struct fpu *fpu)* Make sure fpstate is cleared and initialized. */ if (static_cpu_has (X86_FEATURE_FPU )) { +preempt_disable ();fpu__activate_curr (fpu);user_fpu_begin ();copy_init_fpstate_to_fpregs (); +preempt_enable (); } }
Signature · 1 line
2.11.0
tip-bot for Ingo Molnar
merge bot[tip:x86/fpu] x86/fpu: Make the fpu state change in fpu__clear() scheduler-atomic
x86/fpu: Make the fpu state change in fpu__clear() scheduler-atomic
Commit-ID: a10b6a16cdad88170f546d008c77453cddf918e6 Gitweb: http://git.kernel.org/tip/a10b6a16cdad88170f546d008c77453cddf918e6 Author: Ingo Molnar <[email protected]> AuthorDate: Sat, 23 Sep 2017 14:59:59 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Sun, 24 Sep 2017 13:04:33 +0200
x86/fpu: Make the fpu state change in fpu__clear() scheduler-atomic
Do this temporarily only, to make it easier to change the FPU state machine, in particular this change couples the fpu->fpregs_active and fpu->fpstate_active
states: they are only set/cleared together (as far as the scheduler sees them).
This will be removed by later patches.
--- arch/x86/kernel/fpu/core.c | 2 ++ 1 file changed, 2 insertions(+)
arch/x86/kernel/fpu/core.c +2 -0
@@ -462,9 +462,11 @@ void fpu__clear(struct fpu *fpu)* Make sure fpstate is cleared and initialized. */ if (static_cpu_has (X86_FEATURE_FPU )) { +preempt_disable ();fpu__activate_curr (fpu);user_fpu_begin ();copy_init_fpstate_to_fpregs (); +preempt_enable (); } }
PATCH 17/33 x86/fpu: Split the state handling in fpu__drop()
In reply to Ingo MolnarPrepare fpu__drop() to use fpu->fpregs_active.
There are two distinct usecases for fpu__drop() in this context:exit_thread() when called for 'current' in exit(), and when called for another task in fork().
This patch does not change behavior, it only adds a couple of debug checks and structures the code to make the ->fpregs_active change more obviously correct.
All the complications will be removed later on.
--- arch/x86/kernel/fpu/core.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-)
arch/x86/kernel/fpu/core.c +13 -6
@@ -414,12 +414,19 @@ void fpu__drop(struct fpu *fpu) {preempt_disable (); -if (fpu->fpregs_active) { -/* Ignore delayed exceptions from user space */ - asmvolatile ("1: fwait\n" -"2:\n" - _ASM_EXTABLE(1b, 2b)); -fpregs_deactivate (fpu); +if (fpu == ¤t->thread.fpu) { +WARN_ON_FPU (fpu->fpstate_active != fpu->fpregs_active); + +if (fpu->fpregs_active) { +/* Ignore delayed exceptions from user space */ + asmvolatile ("1: fwait\n" +"2:\n" + _ASM_EXTABLE(1b, 2b)); +if (fpu->fpregs_active) +fpregs_deactivate (fpu); + } + }else { +WARN_ON_FPU (fpu->fpregs_active); } fpu->fpstate_active =0 ;
Signature · 1 line
2.11.0
tip-bot for Ingo Molnar
merge bot[tip:x86/fpu] x86/fpu: Split the state handling in fpu__drop()
x86/fpu: Split the state handling in fpu__drop()
Commit-ID: b6aa85558d7e7b18fc3470d2bc1731d2205dd275 Gitweb: http://git.kernel.org/tip/b6aa85558d7e7b18fc3470d2bc1731d2205dd275 Author: Ingo Molnar <[email protected]> AuthorDate: Sat, 23 Sep 2017 15:00:00 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Sun, 24 Sep 2017 13:04:34 +0200
x86/fpu: Split the state handling in fpu__drop()
Prepare fpu__drop() to use fpu->fpregs_active.
There are two distinct usecases for fpu__drop() in this context:exit_thread() when called for 'current' in exit(), and when called for another task in fork().
This patch does not change behavior, it only adds a couple of debug checks and structures the code to make the ->fpregs_active change more obviously correct.
All the complications will be removed later on.
--- arch/x86/kernel/fpu/core.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-)
arch/x86/kernel/fpu/core.c +13 -6
@@ -414,12 +414,19 @@ void fpu__drop(struct fpu *fpu) {preempt_disable (); -if (fpu->fpregs_active) { -/* Ignore delayed exceptions from user space */ - asmvolatile ("1: fwait\n" -"2:\n" - _ASM_EXTABLE(1b, 2b)); -fpregs_deactivate (fpu); +if (fpu == ¤t->thread.fpu) { +WARN_ON_FPU (fpu->fpstate_active != fpu->fpregs_active); + +if (fpu->fpregs_active) { +/* Ignore delayed exceptions from user space */ + asmvolatile ("1: fwait\n" +"2:\n" + _ASM_EXTABLE(1b, 2b)); +if (fpu->fpregs_active) +fpregs_deactivate (fpu); + } + }else { +WARN_ON_FPU (fpu->fpregs_active); } fpu->fpstate_active =0 ;
PATCH 18/33 x86/fpu: Change fpu->fpregs_active users to fpu->fpstate_active
In reply to Ingo MolnarWe want to simplify the FPU state machine by eliminating fpu->fpregs_active, and we can do that because the two state flags (::fpregs_active and ::fpstate_active) are set essentially together.
The old lazy FPU switching code used to make a distinction - but there's no lazy switching code anymore, we always switch in an 'eager' fashion.
Do this by first changing all substantial uses of fpu->fpregs_active to fpu->fpstate_active and adding a few debug checks to double check our assumption is correct.
--- arch/x86/include/asm/fpu/internal.h | 4 +++- arch/x86/kernel/fpu/core.c | 16 ++++++++++------ arch/x86/kernel/fpu/signal.c | 4 +++- arch/x86/mm/pkeys.c | 3 +-- 4 files changed, 17 insertions(+), 10 deletions(-)
arch/x86/include/asm/fpu/internal.h +3 -1
@@ -556,7 +556,9 @@ static inline void fpregs_activate(struct fpu *fpu)static inline void switch_fpu_prepare (struct fpu *old_fpu,int cpu) { -if (old_fpu->fpregs_active) { +WARN_ON_FPU (old_fpu->fpregs_active != old_fpu->fpstate_active); + +if (old_fpu->fpstate_active) {if (!copy_fpregs_to_fpstate (old_fpu)) old_fpu->last_cpu =-1 ;else
arch/x86/kernel/fpu/core.c +10 -6
@@ -100,7 +100,7 @@ void __kernel_fpu_begin(void)kernel_fpu_disable (); -if (fpu->fpregs_active) { +if (fpu->fpstate_active) {/* * Ignore return value -- we don't care if reg state * is clobbered.
@@ -116,7 +116,7 @@ void __kernel_fpu_end(void) {struct fpu *fpu = ¤t->thread.fpu; -if (fpu->fpregs_active) +if (fpu->fpstate_active)copy_kernel_to_fpregs (&fpu->state);kernel_fpu_enable ();
@@ -147,8 +147,10 @@ void fpu__save(struct fpu *fpu)WARN_ON_FPU (fpu != ¤t->thread.fpu);preempt_disable (); +WARN_ON_FPU (fpu->fpstate_active != fpu->fpregs_active); +trace_x86_fpu_before_save (fpu); -if (fpu->fpregs_active) { +if (fpu->fpstate_active) {if (!copy_fpregs_to_fpstate (fpu)) {copy_kernel_to_fpregs (&fpu->state); }
@@ -262,11 +264,12 @@ EXPORT_SYMBOL_GPL(fpu__activate_curr);*/ void fpu__activate_fpstate_read (struct fpu *fpu) { +WARN_ON_FPU (fpu->fpstate_active != fpu->fpregs_active);/* * If fpregs are active (in the current CPU), then * copy them to the fpstate: */ -if (fpu->fpregs_active) { +if (fpu->fpstate_active) {fpu__save (fpu); }else {if (!fpu->fpstate_active) {
@@ -362,12 +365,13 @@ void fpu__current_fpstate_write_end(void) {struct fpu *fpu = ¤t->thread.fpu; +WARN_ON_FPU (fpu->fpstate_active != fpu->fpregs_active);/* * 'fpu' now has an updated copy of the state, but the * registers may still be out of date. Update them with * an XRSTOR if they are active. */ -if (fpu->fpregs_active) +if (fpu->fpstate_active)copy_kernel_to_fpregs (&fpu->state);/*
@@ -417,7 +421,7 @@ void fpu__drop(struct fpu *fpu)if (fpu == ¤t->thread.fpu) {WARN_ON_FPU (fpu->fpstate_active != fpu->fpregs_active); -if (fpu->fpregs_active) { +if (fpu->fpstate_active) {/* Ignore delayed exceptions from user space */ asmvolatile ("1: fwait\n" "2:\n"
arch/x86/kernel/fpu/signal.c +3 -1
@@ -171,7 +171,9 @@ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)sizeof (struct user_i387_ia32_struct ),NULL , (struct _fpstate_32 __user *) buf) ? -1 : 1; -if (fpu->fpregs_active ||using_compacted_format ()) { +WARN_ON_FPU (fpu->fpstate_active != fpu->fpregs_active); + +if (fpu->fpstate_active ||using_compacted_format ()) {/* Save the live register state to the user directly. */ if (copy_fpregs_to_sigframe (buf_fx))return -1 ;
arch/x86/mm/pkeys.c +1 -2
@@ -18,7 +18,6 @@#include <asm/cpufeature.h> /* boot_cpu_has, ... */ #include <asm/mmu_context.h> /* vma_pkey() */ -#include <asm/fpu/internal.h> /* fpregs_active() */ int __execute_only_pkey (struct mm_struct *mm) {
@@ -45,7 +44,7 @@ int __execute_only_pkey(struct mm_struct *mm)*/ preempt_disable ();if (!need_to_set_mm_pkey && - current->thread.fpu.fpregs_active && + current->thread.fpu.fpstate_active && !__pkru_allows_read (read_pkru (), execute_only_pkey)) {preempt_enable ();return execute_only_pkey;
Signature · 1 line
2.11.0
tip-bot for Ingo Molnar
merge bot[tip:x86/fpu] x86/fpu: Change fpu->fpregs_active users to fpu->fpstate_active
x86/fpu: Change fpu->fpregs_active users to fpu->fpstate_active
Commit-ID: f1c8cd0176078c7bcafdc89cac447cab672a0b5e Gitweb: http://git.kernel.org/tip/f1c8cd0176078c7bcafdc89cac447cab672a0b5e Author: Ingo Molnar <[email protected]> AuthorDate: Sat, 23 Sep 2017 15:00:01 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Sun, 24 Sep 2017 13:04:34 +0200
x86/fpu: Change fpu->fpregs_active users to fpu->fpstate_active
We want to simplify the FPU state machine by eliminating fpu->fpregs_active, and we can do that because the two state flags (::fpregs_active and ::fpstate_active) are set essentially together.
The old lazy FPU switching code used to make a distinction - but there's no lazy switching code anymore, we always switch in an 'eager' fashion.
Do this by first changing all substantial uses of fpu->fpregs_active to fpu->fpstate_active and adding a few debug checks to double check our assumption is correct.
--- arch/x86/include/asm/fpu/internal.h | 4 +++- arch/x86/kernel/fpu/core.c | 16 ++++++++++------ arch/x86/kernel/fpu/signal.c | 4 +++- arch/x86/mm/pkeys.c | 3 +-- 4 files changed, 17 insertions(+), 10 deletions(-)
arch/x86/include/asm/fpu/internal.h +3 -1
@@ -556,7 +556,9 @@ static inline void fpregs_activate(struct fpu *fpu)static inline void switch_fpu_prepare (struct fpu *old_fpu,int cpu) { -if (old_fpu->fpregs_active) { +WARN_ON_FPU (old_fpu->fpregs_active != old_fpu->fpstate_active); + +if (old_fpu->fpstate_active) {if (!copy_fpregs_to_fpstate (old_fpu)) old_fpu->last_cpu =-1 ;else
arch/x86/kernel/fpu/core.c +10 -6
@@ -100,7 +100,7 @@ void __kernel_fpu_begin(void)kernel_fpu_disable (); -if (fpu->fpregs_active) { +if (fpu->fpstate_active) {/* * Ignore return value -- we don't care if reg state * is clobbered.
@@ -116,7 +116,7 @@ void __kernel_fpu_end(void) {struct fpu *fpu = ¤t->thread.fpu; -if (fpu->fpregs_active) +if (fpu->fpstate_active)copy_kernel_to_fpregs (&fpu->state);kernel_fpu_enable ();
@@ -147,8 +147,10 @@ void fpu__save(struct fpu *fpu)WARN_ON_FPU (fpu != ¤t->thread.fpu);preempt_disable (); +WARN_ON_FPU (fpu->fpstate_active != fpu->fpregs_active); +trace_x86_fpu_before_save (fpu); -if (fpu->fpregs_active) { +if (fpu->fpstate_active) {if (!copy_fpregs_to_fpstate (fpu)) {copy_kernel_to_fpregs (&fpu->state); }
@@ -262,11 +264,12 @@ EXPORT_SYMBOL_GPL(fpu__activate_curr);*/ void fpu__activate_fpstate_read (struct fpu *fpu) { +WARN_ON_FPU (fpu->fpstate_active != fpu->fpregs_active);/* * If fpregs are active (in the current CPU), then * copy them to the fpstate: */ -if (fpu->fpregs_active) { +if (fpu->fpstate_active) {fpu__save (fpu); }else {if (!fpu->fpstate_active) {
@@ -362,12 +365,13 @@ void fpu__current_fpstate_write_end(void) {struct fpu *fpu = ¤t->thread.fpu; +WARN_ON_FPU (fpu->fpstate_active != fpu->fpregs_active);/* * 'fpu' now has an updated copy of the state, but the * registers may still be out of date. Update them with * an XRSTOR if they are active. */ -if (fpu->fpregs_active) +if (fpu->fpstate_active)copy_kernel_to_fpregs (&fpu->state);/*
@@ -417,7 +421,7 @@ void fpu__drop(struct fpu *fpu)if (fpu == ¤t->thread.fpu) {WARN_ON_FPU (fpu->fpstate_active != fpu->fpregs_active); -if (fpu->fpregs_active) { +if (fpu->fpstate_active) {/* Ignore delayed exceptions from user space */ asmvolatile ("1: fwait\n" "2:\n"
arch/x86/kernel/fpu/signal.c +3 -1
@@ -171,7 +171,9 @@ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)sizeof (struct user_i387_ia32_struct ),NULL , (struct _fpstate_32 __user *) buf) ? -1 : 1; -if (fpu->fpregs_active ||using_compacted_format ()) { +WARN_ON_FPU (fpu->fpstate_active != fpu->fpregs_active); + +if (fpu->fpstate_active ||using_compacted_format ()) {/* Save the live register state to the user directly. */ if (copy_fpregs_to_sigframe (buf_fx))return -1 ;
arch/x86/mm/pkeys.c +1 -2
@@ -18,7 +18,6 @@#include <asm/cpufeature.h> /* boot_cpu_has, ... */ #include <asm/mmu_context.h> /* vma_pkey() */ -#include <asm/fpu/internal.h> /* fpregs_active() */ int __execute_only_pkey (struct mm_struct *mm) {
@@ -45,7 +44,7 @@ int __execute_only_pkey(struct mm_struct *mm)*/ preempt_disable ();if (!need_to_set_mm_pkey && - current->thread.fpu.fpregs_active && + current->thread.fpu.fpstate_active && !__pkru_allows_read (read_pkru (), execute_only_pkey)) {preempt_enable ();return execute_only_pkey;
Re: [PATCH 00/33] x86 FPU fixes and cleanups for v4.14
In reply to Ingo MolnarQuoted 11 lines · Ingo Molnar
So I'd like to push these changes to Linus tomorrow-ish as an RFC pull request in 1-2 days, because there's now 4 fixes depending on these changes, and because the result will be more maintainable for the LTS v4.14 kernel.
The biggest changes from the earlier iterations is the fixes from Eric Biggers for information leaks, plus more cleanups. I have also removed the change that Peter Zijlstra and others felt uneasy about, the ::last_cpu -> ::fpregs_cached change to the state machine. This should make the changes uncontroversial.
Quoted 3 lines
Due to taking out that patch I had to rebase the changes, most of which have accrued months of testing in linux-next. So I'm pretty confident about the overall stability of it. (Famous last words.)
I forgot to mention that these changes are also available in tip:master (and tip:WIP.x86/fpu), at:
git git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip.git master
Thanks,
Ingo
Re: [PATCH 00/33] x86 FPU fixes and cleanups for v4.14
Quoted 14 lines · Ingo Molnar
Quoted 11 lines · Ingo Molnar
So I'd like to push these changes to Linus tomorrow-ish as an RFC pull request in 1-2 days, because there's now 4 fixes depending on these changes, and because the result will be more maintainable for the LTS v4.14 kernel.
The biggest changes from the earlier iterations is the fixes from Eric Biggers for information leaks, plus more cleanups. I have also removed the change that Peter Zijlstra and others felt uneasy about, the ::last_cpu -> ::fpregs_cached change to the state machine. This should make the changes uncontroversial.
Quoted 8 lines
Quoted 3 lines
Due to taking out that patch I had to rebase the changes, most of which have accrued months of testing in linux-next. So I'm pretty confident about the overall stability of it. (Famous last words.)
I forgot to mention that these changes are also available in tip:master (and tip:WIP.x86/fpu), at:
git
git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip.gitmaster
Really? Did you hijack the Xen tree? :-)
Juergen
Re: [PATCH 00/33] x86 FPU fixes and cleanups for v4.14
Quoted 19 lines · Juergen Gross
Quoted 18 lines · Ingo Molnar
Quoted 14 lines · Ingo Molnar
So I'd like to push these changes to Linus tomorrow-ish as an RFC pull request in 1-2 days, because there's now 4 fixes depending on these changes, and because the result will be more maintainable for the LTS v4.14 kernel.
The biggest changes from the earlier iterations is the fixes from Eric Biggers for information leaks, plus more cleanups. I have also removed the change that Peter Zijlstra and others felt uneasy about, the ::last_cpu -> ::fpregs_cached change to the state machine. This should make the changes uncontroversial.
Due to taking out that patch I had to rebase the changes, most of which have accrued months of testing in linux-next. So I'm pretty confident about the overall stability of it. (Famous last words.)
Quoted 6 lines
Quoted 4 lines
I forgot to mention that these changes are also available in tip:master (and tip:WIP.x86/fpu), at:
git
git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip.gitmasterReally? Did you hijack the Xen tree? :-)
Lol, copy & paste error ;-) Should be:
git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git master
Thanks,
Ingo
PATCH 19/33 x86/fpu: Decouple fpregs_activate()/fpregs_deactivate() from fpu->fpregs_active
In reply to Ingo MolnarThe fpregs_activate()/fpregs_deactivate() are currently called in such a pattern:
if (!fpu->fpregs_active) fpregs_activate(fpu); ... if (fpu->fpregs_active) fpregs_deactivate(fpu);
But note that it's actually safe to call them without checking the flag first.
This further decouples the fpu->fpregs_active flag from actual FPU logic.
--- arch/x86/include/asm/fpu/internal.h | 7 +------ arch/x86/kernel/fpu/core.c | 3 +-- 2 files changed, 2 insertions(+), 8 deletions(-)
arch/x86/include/asm/fpu/internal.h +1 -6
@@ -526,8 +526,6 @@ static inline int fpregs_state_valid(struct fpu *fpu, unsigned int cpu)*/ static inline void fpregs_deactivate (struct fpu *fpu) { -WARN_ON_FPU (!fpu->fpregs_active); - fpu->fpregs_active =0 ;this_cpu_write (fpu_fpregs_owner_ctx,NULL );trace_x86_fpu_regs_deactivated (fpu);
@@ -535,8 +533,6 @@ static inline void fpregs_deactivate(struct fpu *fpu)static inline void fpregs_activate (struct fpu *fpu) { -WARN_ON_FPU (fpu->fpregs_active); - fpu->fpregs_active =1 ;this_cpu_write (fpu_fpregs_owner_ctx, fpu);trace_x86_fpu_regs_activated (fpu);
@@ -604,8 +600,7 @@ static inline void user_fpu_begin(void)struct fpu *fpu = ¤t->thread.fpu;preempt_disable (); -if (!fpu->fpregs_active) -fpregs_activate (fpu); +fpregs_activate (fpu);preempt_enable (); }
arch/x86/kernel/fpu/core.c +1 -2
@@ -426,8 +426,7 @@ void fpu__drop(struct fpu *fpu) asmvolatile ("1: fwait\n" "2:\n" _ASM_EXTABLE(1b, 2b)); -if (fpu->fpregs_active) -fpregs_deactivate (fpu); +fpregs_deactivate (fpu); } }else {WARN_ON_FPU (fpu->fpregs_active);
Signature · 1 line
2.11.0
tip-bot for Ingo Molnar
merge bot[tip:x86/fpu] x86/fpu: Decouple fpregs_activate()/fpregs_deactivate() from fpu->fpregs_active
x86/fpu: Decouple fpregs_activate()/fpregs_deactivate() from fpu->fpregs_active
Commit-ID: 6cf4edbe0526db311a28734609da888fdfcb3604 Gitweb: http://git.kernel.org/tip/6cf4edbe0526db311a28734609da888fdfcb3604 Author: Ingo Molnar <[email protected]> AuthorDate: Sat, 23 Sep 2017 15:00:02 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Sun, 24 Sep 2017 13:04:34 +0200
x86/fpu: Decouple fpregs_activate()/fpregs_deactivate() from fpu->fpregs_active
The fpregs_activate()/fpregs_deactivate() are currently called in such a pattern:
if (!fpu->fpregs_active) fpregs_activate(fpu); ... if (fpu->fpregs_active) fpregs_deactivate(fpu);
But note that it's actually safe to call them without checking the flag first.
This further decouples the fpu->fpregs_active flag from actual FPU logic.
--- arch/x86/include/asm/fpu/internal.h | 7 +------ arch/x86/kernel/fpu/core.c | 3 +-- 2 files changed, 2 insertions(+), 8 deletions(-)
arch/x86/include/asm/fpu/internal.h +1 -6
@@ -526,8 +526,6 @@ static inline int fpregs_state_valid(struct fpu *fpu, unsigned int cpu)*/ static inline void fpregs_deactivate (struct fpu *fpu) { -WARN_ON_FPU (!fpu->fpregs_active); - fpu->fpregs_active =0 ;this_cpu_write (fpu_fpregs_owner_ctx,NULL );trace_x86_fpu_regs_deactivated (fpu);
@@ -535,8 +533,6 @@ static inline void fpregs_deactivate(struct fpu *fpu)static inline void fpregs_activate (struct fpu *fpu) { -WARN_ON_FPU (fpu->fpregs_active); - fpu->fpregs_active =1 ;this_cpu_write (fpu_fpregs_owner_ctx, fpu);trace_x86_fpu_regs_activated (fpu);
@@ -604,8 +600,7 @@ static inline void user_fpu_begin(void)struct fpu *fpu = ¤t->thread.fpu;preempt_disable (); -if (!fpu->fpregs_active) -fpregs_activate (fpu); +fpregs_activate (fpu);preempt_enable (); }
arch/x86/kernel/fpu/core.c +1 -2
@@ -426,8 +426,7 @@ void fpu__drop(struct fpu *fpu) asmvolatile ("1: fwait\n" "2:\n" _ASM_EXTABLE(1b, 2b)); -if (fpu->fpregs_active) -fpregs_deactivate (fpu); +fpregs_deactivate (fpu); } }else {WARN_ON_FPU (fpu->fpregs_active);
PATCH 20/33 x86/fpu: Remove struct fpu::fpregs_active
In reply to Ingo MolnarThe previous changes paved the way for the removal of the fpu::fpregs_active state flag - we now only have the fpu::fpstate_active and fpu::last_cpu fields left.
--- arch/x86/include/asm/fpu/internal.h | 5 ----- arch/x86/include/asm/fpu/types.h | 23 ----------------------- arch/x86/include/asm/trace/fpu.h | 5 +---- arch/x86/kernel/fpu/core.c | 9 --------- arch/x86/kernel/fpu/signal.c | 2 -- 5 files changed, 1 insertion(+), 43 deletions(-)
arch/x86/include/asm/fpu/internal.h +0 -5
@@ -526,14 +526,12 @@ static inline int fpregs_state_valid(struct fpu *fpu, unsigned int cpu)*/ static inline void fpregs_deactivate (struct fpu *fpu) { - fpu->fpregs_active =0 ;this_cpu_write (fpu_fpregs_owner_ctx,NULL );trace_x86_fpu_regs_deactivated (fpu); }static inline void fpregs_activate (struct fpu *fpu) { - fpu->fpregs_active =1 ;this_cpu_write (fpu_fpregs_owner_ctx, fpu);trace_x86_fpu_regs_activated (fpu); }
@@ -552,8 +550,6 @@ static inline void fpregs_activate(struct fpu *fpu)static inline void switch_fpu_prepare (struct fpu *old_fpu,int cpu) { -WARN_ON_FPU (old_fpu->fpregs_active != old_fpu->fpstate_active); -if (old_fpu->fpstate_active) {if (!copy_fpregs_to_fpstate (old_fpu)) old_fpu->last_cpu =-1 ;
@@ -561,7 +557,6 @@ switch_fpu_prepare(struct fpu *old_fpu, int cpu) old_fpu->last_cpu = cpu;/* But leave fpu_fpregs_owner_ctx! */ - old_fpu->fpregs_active =0 ;trace_x86_fpu_regs_deactivated (old_fpu); }else old_fpu->last_cpu =-1 ;
arch/x86/include/asm/fpu/types.h +0 -23
@@ -299,29 +299,6 @@ struct fpu {unsigned char fpstate_active;/* -* @fpregs_active: -* -* This flag determines whether a given context is actively -* loaded into the FPU's registers and that those registers -* represent the task's current FPU state. -* -* Note the interaction with fpstate_active: -* -* # task does not use the FPU: -* fpstate_active == 0 -* -* # task uses the FPU and regs are active: -* fpstate_active == 1 && fpregs_active == 1 -* -* # the regs are inactive but still match fpstate: -* fpstate_active == 1 && fpregs_active == 0 && fpregs_owner == fpu -* -* The third state is what we use for the lazy restore optimization -* on lazy-switching CPUs. -*/ -unsigned char fpregs_active; - -/* * @state: * * In-memory copy of all FPU registers that we save/restore
arch/x86/include/asm/trace/fpu.h +1 -4
@@ -12,7 +12,6 @@ DECLARE_EVENT_CLASS(x86_fpu,TP_STRUCT__entry (__field (struct fpu *,fpu ) -__field (bool, fpregs_active)__field (bool, fpstate_active)__field (u64, xfeatures) __field(u64, xcomp_bv)
@@ -20,16 +19,14 @@ DECLARE_EVENT_CLASS(x86_fpu,TP_fast_assign ( __entry->fpu = fpu; - __entry->fpregs_active = fpu->fpregs_active; __entry->fpstate_active = fpu->fpstate_active;if (boot_cpu_has (X86_FEATURE_OSXSAVE )) { __entry->xfeatures = fpu->state.xsave.header.xfeatures; __entry->xcomp_bv = fpu->state.xsave.header.xcomp_bv; } ), -TP_printk ("x86/fpu: %p fpregs_active: %d fpstate_active: %d xfeatures: %llx xcomp_bv: %llx" , +TP_printk ("x86/fpu: %p fpstate_active: %d xfeatures: %llx xcomp_bv: %llx" , __entry->fpu, - __entry->fpregs_active, __entry->fpstate_active, __entry->xfeatures, __entry->xcomp_bv
arch/x86/kernel/fpu/core.c +0 -9
@@ -147,8 +147,6 @@ void fpu__save(struct fpu *fpu)WARN_ON_FPU (fpu != ¤t->thread.fpu);preempt_disable (); -WARN_ON_FPU (fpu->fpstate_active != fpu->fpregs_active); -trace_x86_fpu_before_save (fpu);if (fpu->fpstate_active) {if (!copy_fpregs_to_fpstate (fpu)) {
@@ -191,7 +189,6 @@ EXPORT_SYMBOL_GPL(fpstate_init);int fpu__copy (struct fpu *dst_fpu,struct fpu *src_fpu) { - dst_fpu->fpregs_active =0 ; dst_fpu->last_cpu =-1 ;if (!src_fpu->fpstate_active || !static_cpu_has (X86_FEATURE_FPU ))
@@ -264,7 +261,6 @@ EXPORT_SYMBOL_GPL(fpu__activate_curr);*/ void fpu__activate_fpstate_read (struct fpu *fpu) { -WARN_ON_FPU (fpu->fpstate_active != fpu->fpregs_active);/* * If fpregs are active (in the current CPU), then * copy them to the fpstate:
@@ -365,7 +361,6 @@ void fpu__current_fpstate_write_end(void) {struct fpu *fpu = ¤t->thread.fpu; -WARN_ON_FPU (fpu->fpstate_active != fpu->fpregs_active);/* * 'fpu' now has an updated copy of the state, but the * registers may still be out of date. Update them with
@@ -419,8 +414,6 @@ void fpu__drop(struct fpu *fpu)preempt_disable ();if (fpu == ¤t->thread.fpu) { -WARN_ON_FPU (fpu->fpstate_active != fpu->fpregs_active); -if (fpu->fpstate_active) {/* Ignore delayed exceptions from user space */ asm volatile("1: fwait\n"
@@ -428,8 +421,6 @@ void fpu__drop(struct fpu *fpu) _ASM_EXTABLE(1b, 2b));fpregs_deactivate (fpu); } - }else { -WARN_ON_FPU (fpu->fpregs_active); } fpu->fpstate_active =0 ;
arch/x86/kernel/fpu/signal.c +0 -2
@@ -171,8 +171,6 @@ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)sizeof (struct user_i387_ia32_struct ),NULL , (struct _fpstate_32 __user *) buf) ? -1 : 1; -WARN_ON_FPU (fpu->fpstate_active != fpu->fpregs_active); -if (fpu->fpstate_active ||using_compacted_format ()) {/* Save the live register state to the user directly. */ if (copy_fpregs_to_sigframe (buf_fx))
Signature · 1 line
2.11.0
tip-bot for Ingo Molnar
merge bot[tip:x86/fpu] x86/fpu: Remove struct fpu::fpregs_active
x86/fpu: Remove struct fpu::fpregs_active
Commit-ID: 99dc26bda233ee722bbd370bddf20beece3ffb93 Gitweb: http://git.kernel.org/tip/99dc26bda233ee722bbd370bddf20beece3ffb93 Author: Ingo Molnar <[email protected]> AuthorDate: Sat, 23 Sep 2017 15:00:03 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Sun, 24 Sep 2017 13:04:34 +0200
x86/fpu: Remove struct fpu::fpregs_active
The previous changes paved the way for the removal of the fpu::fpregs_active state flag - we now only have the fpu::fpstate_active and fpu::last_cpu fields left.
--- arch/x86/include/asm/fpu/internal.h | 5 ----- arch/x86/include/asm/fpu/types.h | 23 ----------------------- arch/x86/include/asm/trace/fpu.h | 5 +---- arch/x86/kernel/fpu/core.c | 9 --------- arch/x86/kernel/fpu/signal.c | 2 -- 5 files changed, 1 insertion(+), 43 deletions(-)
arch/x86/include/asm/fpu/internal.h +0 -5
@@ -526,14 +526,12 @@ static inline int fpregs_state_valid(struct fpu *fpu, unsigned int cpu)*/ static inline void fpregs_deactivate (struct fpu *fpu) { - fpu->fpregs_active =0 ;this_cpu_write (fpu_fpregs_owner_ctx,NULL );trace_x86_fpu_regs_deactivated (fpu); }static inline void fpregs_activate (struct fpu *fpu) { - fpu->fpregs_active =1 ;this_cpu_write (fpu_fpregs_owner_ctx, fpu);trace_x86_fpu_regs_activated (fpu); }
@@ -552,8 +550,6 @@ static inline void fpregs_activate(struct fpu *fpu)static inline void switch_fpu_prepare (struct fpu *old_fpu,int cpu) { -WARN_ON_FPU (old_fpu->fpregs_active != old_fpu->fpstate_active); -if (old_fpu->fpstate_active) {if (!copy_fpregs_to_fpstate (old_fpu)) old_fpu->last_cpu =-1 ;
@@ -561,7 +557,6 @@ switch_fpu_prepare(struct fpu *old_fpu, int cpu) old_fpu->last_cpu = cpu;/* But leave fpu_fpregs_owner_ctx! */ - old_fpu->fpregs_active =0 ;trace_x86_fpu_regs_deactivated (old_fpu); }else old_fpu->last_cpu =-1 ;
arch/x86/include/asm/fpu/types.h +0 -23
@@ -299,29 +299,6 @@ struct fpu {unsigned char fpstate_active;/* -* @fpregs_active: -* -* This flag determines whether a given context is actively -* loaded into the FPU's registers and that those registers -* represent the task's current FPU state. -* -* Note the interaction with fpstate_active: -* -* # task does not use the FPU: -* fpstate_active == 0 -* -* # task uses the FPU and regs are active: -* fpstate_active == 1 && fpregs_active == 1 -* -* # the regs are inactive but still match fpstate: -* fpstate_active == 1 && fpregs_active == 0 && fpregs_owner == fpu -* -* The third state is what we use for the lazy restore optimization -* on lazy-switching CPUs. -*/ -unsigned char fpregs_active; - -/* * @state: * * In-memory copy of all FPU registers that we save/restore
arch/x86/include/asm/trace/fpu.h +1 -4
@@ -12,7 +12,6 @@ DECLARE_EVENT_CLASS(x86_fpu,TP_STRUCT__entry (__field (struct fpu *,fpu ) -__field (bool, fpregs_active)__field (bool, fpstate_active)__field (u64, xfeatures) __field(u64, xcomp_bv)
@@ -20,16 +19,14 @@ DECLARE_EVENT_CLASS(x86_fpu,TP_fast_assign ( __entry->fpu = fpu; - __entry->fpregs_active = fpu->fpregs_active; __entry->fpstate_active = fpu->fpstate_active;if (boot_cpu_has (X86_FEATURE_OSXSAVE )) { __entry->xfeatures = fpu->state.xsave.header.xfeatures; __entry->xcomp_bv = fpu->state.xsave.header.xcomp_bv; } ), -TP_printk ("x86/fpu: %p fpregs_active: %d fpstate_active: %d xfeatures: %llx xcomp_bv: %llx" , +TP_printk ("x86/fpu: %p fpstate_active: %d xfeatures: %llx xcomp_bv: %llx" , __entry->fpu, - __entry->fpregs_active, __entry->fpstate_active, __entry->xfeatures, __entry->xcomp_bv
arch/x86/kernel/fpu/core.c +0 -9
@@ -147,8 +147,6 @@ void fpu__save(struct fpu *fpu)WARN_ON_FPU (fpu != ¤t->thread.fpu);preempt_disable (); -WARN_ON_FPU (fpu->fpstate_active != fpu->fpregs_active); -trace_x86_fpu_before_save (fpu);if (fpu->fpstate_active) {if (!copy_fpregs_to_fpstate (fpu)) {
@@ -191,7 +189,6 @@ EXPORT_SYMBOL_GPL(fpstate_init);int fpu__copy (struct fpu *dst_fpu,struct fpu *src_fpu) { - dst_fpu->fpregs_active =0 ; dst_fpu->last_cpu =-1 ;if (!src_fpu->fpstate_active || !static_cpu_has (X86_FEATURE_FPU ))
@@ -264,7 +261,6 @@ EXPORT_SYMBOL_GPL(fpu__activate_curr);*/ void fpu__activate_fpstate_read (struct fpu *fpu) { -WARN_ON_FPU (fpu->fpstate_active != fpu->fpregs_active);/* * If fpregs are active (in the current CPU), then * copy them to the fpstate:
@@ -365,7 +361,6 @@ void fpu__current_fpstate_write_end(void) {struct fpu *fpu = ¤t->thread.fpu; -WARN_ON_FPU (fpu->fpstate_active != fpu->fpregs_active);/* * 'fpu' now has an updated copy of the state, but the * registers may still be out of date. Update them with
@@ -419,8 +414,6 @@ void fpu__drop(struct fpu *fpu)preempt_disable ();if (fpu == ¤t->thread.fpu) { -WARN_ON_FPU (fpu->fpstate_active != fpu->fpregs_active); -if (fpu->fpstate_active) {/* Ignore delayed exceptions from user space */ asm volatile("1: fwait\n"
@@ -428,8 +421,6 @@ void fpu__drop(struct fpu *fpu) _ASM_EXTABLE(1b, 2b));fpregs_deactivate (fpu); } - }else { -WARN_ON_FPU (fpu->fpregs_active); } fpu->fpstate_active =0 ;
arch/x86/kernel/fpu/signal.c +0 -2
@@ -171,8 +171,6 @@ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)sizeof (struct user_i387_ia32_struct ),NULL , (struct _fpstate_32 __user *) buf) ? -1 : 1; -WARN_ON_FPU (fpu->fpstate_active != fpu->fpregs_active); -if (fpu->fpstate_active ||using_compacted_format ()) {/* Save the live register state to the user directly. */ if (copy_fpregs_to_sigframe (buf_fx))
PATCH 21/33 x86/fpu: Add FPU state copying quirk to handle XRSTOR failure on Intel Skylake CPUs
In reply to Ingo MolnarFrom: Rik van Riel <[email protected]>
On Skylake CPUs I noticed that XRSTOR is unable to deal with states created by copyout_from_xsaves() if the xstate has only SSE/YMM state, and no FP state. That is, xfeatures had XFEATURE_MASK_SSE set, but not XFEATURE_MASK_FP.
The reason is that part of the SSE/YMM state lives in the MXCSR and MXCSR_FLAGS fields of the FP state.
Ensure that whenever we copy SSE or YMM state around, the MXCSR and MXCSR_FLAGS fields are also copied around.
--- arch/x86/include/asm/fpu/types.h | 3 +++ arch/x86/kernel/fpu/xstate.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+)
arch/x86/include/asm/fpu/types.h +3 -0
@@ -68,6 +68,9 @@ struct fxregs_state {/* Default value for fxregs_state.mxcsr: */ #define MXCSR_DEFAULT 0x1f80 +/* Copy both mxcsr & mxcsr_flags with a single u64 memcpy: */ +#define MXCSR_AND_FLAGS_SIZE sizeof(u64) +/* * Software based FPU emulation state. This is arbitrary really, * it matches the x87 format to make it easier to understand:
arch/x86/kernel/fpu/xstate.c +42 -0
72 lines not on this page · raw message
Signature · 1 line
2.11.0
tip-bot for Rik van Riel
merge bot[tip:x86/fpu] x86/fpu: Add FPU state copying quirk to handle XRSTOR failure on Intel Skylake CPUs
x86/fpu: Add FPU state copying quirk to handle XRSTOR failure on Intel Skylake CPUs
Commit-ID: 0852b374173bb57f870d78e6c6839c77b339be5f Gitweb: http://git.kernel.org/tip/0852b374173bb57f870d78e6c6839c77b339be5f Author: Rik van Riel <[email protected]> AuthorDate: Sat, 23 Sep 2017 15:00:04 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Sun, 24 Sep 2017 13:04:34 +0200
x86/fpu: Add FPU state copying quirk to handle XRSTOR failure on Intel Skylake CPUs
On Skylake CPUs I noticed that XRSTOR is unable to deal with states created by copyout_from_xsaves() if the xstate has only SSE/YMM state, and no FP state. That is, xfeatures had XFEATURE_MASK_SSE set, but not XFEATURE_MASK_FP.
The reason is that part of the SSE/YMM state lives in the MXCSR and MXCSR_FLAGS fields of the FP state.
Ensure that whenever we copy SSE or YMM state around, the MXCSR and MXCSR_FLAGS fields are also copied around.
--- arch/x86/include/asm/fpu/types.h | 3 +++ arch/x86/kernel/fpu/xstate.c | 42 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+)
arch/x86/include/asm/fpu/types.h +3 -0
@@ -68,6 +68,9 @@ struct fxregs_state {/* Default value for fxregs_state.mxcsr: */ #define MXCSR_DEFAULT 0x1f80 +/* Copy both mxcsr & mxcsr_flags with a single u64 memcpy: */ +#define MXCSR_AND_FLAGS_SIZE sizeof(u64) +/* * Software based FPU emulation state. This is arbitrary really, * it matches the x87 format to make it easier to understand:
arch/x86/kernel/fpu/xstate.c +42 -0
72 lines not on this page · raw message
PATCH 22/33 x86/fpu: Fix boolreturn.cocci warnings
In reply to Ingo MolnarFrom: kbuild test robot <[email protected]>
arch/x86/kernel/fpu/xstate.c:931:9-10: WARNING: return of 0/1 in function 'xfeatures_mxcsr_quirk' with return type bool
Return statements in functions returning bool should use true/false instead of 1/0.
Generated by: scripts/coccinelle/misc/boolreturn.cocci
--- arch/x86/kernel/fpu/xstate.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
arch/x86/kernel/fpu/xstate.c +3 -3
@@ -929,12 +929,12 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,static inline bool xfeatures_mxcsr_quirk (u64 xfeatures) {if (!(xfeatures & (XFEATURE_MASK_SSE |XFEATURE_MASK_YMM ))) -return 0 ; +return false;if (xfeatures &XFEATURE_MASK_FP ) -return 0 ; +return false; -return 1 ; +return true; }/*
Signature · 1 line
2.11.0
tip-bot for kbuild test robot
build bot[tip:x86/fpu] x86/fpu: Fix boolreturn.cocci warnings
x86/fpu: Fix boolreturn.cocci warnings
Commit-ID: 4f8cef59bad29344aca0e2e6b0ad18dadd078fd0 Gitweb: http://git.kernel.org/tip/4f8cef59bad29344aca0e2e6b0ad18dadd078fd0 Author: kbuild test robot <[email protected]> AuthorDate: Sat, 23 Sep 2017 15:00:05 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Sun, 24 Sep 2017 13:04:35 +0200
x86/fpu: Fix boolreturn.cocci warnings
arch/x86/kernel/fpu/xstate.c:931:9-10: WARNING: return of 0/1 in function 'xfeatures_mxcsr_quirk' with return type bool
Return statements in functions returning bool should use true/false instead of 1/0.
Generated by: scripts/coccinelle/misc/boolreturn.cocci
--- arch/x86/kernel/fpu/xstate.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
arch/x86/kernel/fpu/xstate.c +3 -3
@@ -929,12 +929,12 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,static inline bool xfeatures_mxcsr_quirk (u64 xfeatures) {if (!(xfeatures & (XFEATURE_MASK_SSE |XFEATURE_MASK_YMM ))) -return 0 ; +return false;if (xfeatures &XFEATURE_MASK_FP ) -return 0 ; +return false; -return 1 ; +return true; }/*
PATCH 23/33 x86/fpu: Turn WARN_ON() in context switch into WARN_ON_FPU()
In reply to Ingo MolnarFrom: Andi Kleen <[email protected]>
copy_xregs_to_kernel checks if the alternatives have been already patched.
This WARN_ON() is always executed in every context switch.
All the other checks in fpu internal.h are WARN_ON_FPU(), but this one is plain WARN_ON(). I assume it was forgotten to switch it.
So switch it to WARN_ON_FPU() too to avoid some unnecessary code in the context switch, and a potentially expensive cache line miss for the global variable.
--- arch/x86/include/asm/fpu/internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/include/asm/fpu/internal.h +1 -1
@@ -350,7 +350,7 @@ static inline void copy_xregs_to_kernel(struct xregs_state *xstate)u32 hmask = mask >>32 ;int err; -WARN_ON (!alternatives_patched); +WARN_ON_FPU (!alternatives_patched);XSTATE_XSAVE (xstate, lmask, hmask, err);
Signature · 1 line
2.11.0
tip-bot for Andi Kleen
merge bot[tip:x86/fpu] x86/fpu: Turn WARN_ON() in context switch into WARN_ON_FPU()
x86/fpu: Turn WARN_ON() in context switch into WARN_ON_FPU()
Commit-ID: 03eaec81ac09814817e9f0307d572ffe8365f980 Gitweb: http://git.kernel.org/tip/03eaec81ac09814817e9f0307d572ffe8365f980 Author: Andi Kleen <[email protected]> AuthorDate: Sat, 23 Sep 2017 15:00:06 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Sun, 24 Sep 2017 13:04:35 +0200
x86/fpu: Turn WARN_ON() in context switch into WARN_ON_FPU()
copy_xregs_to_kernel checks if the alternatives have been already patched.
This WARN_ON() is always executed in every context switch.
All the other checks in fpu internal.h are WARN_ON_FPU(), but this one is plain WARN_ON(). I assume it was forgotten to switch it.
So switch it to WARN_ON_FPU() too to avoid some unnecessary code in the context switch, and a potentially expensive cache line miss for the global variable.
--- arch/x86/include/asm/fpu/internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/include/asm/fpu/internal.h +1 -1
@@ -350,7 +350,7 @@ static inline void copy_xregs_to_kernel(struct xregs_state *xstate)u32 hmask = mask >>32 ;int err; -WARN_ON (!alternatives_patched); +WARN_ON_FPU (!alternatives_patched);XSTATE_XSAVE (xstate, lmask, hmask, err);
PATCH 24/33 x86/fpu: Don't let userspace set bogus xcomp_bv
In reply to Ingo MolnarFrom: Eric Biggers <[email protected]>
On x86, userspace can use the ptrace() or rt_sigreturn() system calls to set a task's extended state (xstate) or "FPU" registers. ptrace() can set them for another task using the PTRACE_SETREGSET request with NT_X86_XSTATE, while rt_sigreturn() can set them for the current task. In either case, registers can be set to any value, but the kernel assumes that the XSAVE area itself remains valid in the sense that the CPU can restore it.
However, in the case where the kernel is using the uncompacted xstate format (which it does whenever the XSAVES instruction is unavailable), it was possible for userspace to set the xcomp_bv field in the xstate_header to an arbitrary value. However, all bits in that field are reserved in the uncompacted case, so when switching to a task with nonzero xcomp_bv, the XRSTOR instruction failed with a #GP fault. This caused the WARN_ON_FPU(err) in copy_kernel_to_xregs() to be hit. In addition, since the error is otherwise ignored, the FPU registers from the task previously executing on the CPU were leaked.
Fix the bug by checking that the user-supplied value of xcomp_bv is 0 in the uncompacted case, and returning an error otherwise.
The reason for validating xcomp_bv rather than simply overwriting it with 0 is that we want userspace to see an error if it (incorrectly) provides an XSAVE area in compacted format rather than in uncompacted format.
Note that as before, in case of error we clear the task's FPU state. This is perhaps non-ideal, especially for PTRACE_SETREGSET; it might be better to return an error before changing anything. But it seems the "clear on error" behavior is fine for now, and it's a little tricky to do otherwise because it would mean we couldn't simply copy the full userspace state into kernel memory in one __copy_from_user().
This bug was found by syzkaller, which hit the above-mentioned WARN_ON_FPU():
WARNING: CPU: 1 PID: 0 at ./arch/x86/include/asm/fpu/internal.h:373 __switch_to+0x5b5/0x5d0
CPU: 1 PID: 0 Comm: swapper/1 Not tainted 4.13.0 #453
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
task: ffff9ba2bc8e42c0 task.stack: ffffa78cc036c000
RIP: 0010:__switch_to+0x5b5/0x5d0
RSP: 0000:ffffa78cc08bbb88 EFLAGS: 00010082
RAX: 00000000fffffffe RBX: ffff9ba2b8bf2180 RCX: 00000000c0000100
RDX: 00000000ffffffff RSI: 000000005cb10700 RDI: ffff9ba2b8bf36c0
RBP: ffffa78cc08bbbd0 R08: 00000000929fdf46 R09: 0000000000000001
R10: 0000000000000000 R11: 0000000000000000 R12: ffff9ba2bc8e42c0
R13: 0000000000000000 R14: ffff9ba2b8bf3680 R15: ffff9ba2bf5d7b40
FS: 00007f7e5cb10700(0000) GS:ffff9ba2bf400000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00000000004005cc CR3: 0000000079fd5000 CR4: 00000000001406e0
Call Trace:
Code: 84 00 00 00 00 00 e9 11 fd ff ff 0f ff 66 0f 1f 84 00 00 00 00 00 e9 e7 fa ff ff 0f ff 66 0f 1f 84 00 00 00 00 00 e9 c2 fa ff ff <0f> ff 66 0f 1f 84 00 00 00 00 00 e9 d4 fc ff ff 66 66 2e 0f 1fHere is a C reproducer. The expected behavior is that the program spin forever with no output. However, on a buggy kernel running on a processor with the "xsave" feature but without the "xsaves" feature (e.g. Sandy Bridge through Broadwell for Intel), within a second or two the program reports that the xmm registers were corrupted, i.e. were not restored correctly. With CONFIG_X86_DEBUG_FPU=y it also hits the above kernel warning.
#define _GNU_SOURCE
#include <stdbool.h>
#include <inttypes.h>
#include <linux/elf.h>
#include <stdio.h>
#include <sys/ptrace.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void)
{
int pid = fork();
uint64_t xstate[512];
struct iovec iov = { .iov_base = xstate, .iov_len = sizeof(xstate) };
if (pid == 0) {
bool tracee = true;
for (int i = 0; i < sysconf(_SC_NPROCESSORS_ONLN) && tracee; i++)
tracee = (fork() != 0);
uint32_t xmm0[4] = { [0 ... 3] = tracee ? 0x00000000 : 0xDEADBEEF };
asm volatile(" movdqu %0, %%xmm0\n"
" mov %0, %%rbx\n"
"1: movdqu %%xmm0, %0\n"
" mov %0, %%rax\n"
" cmp %%rax, %%rbx\n"
" je 1b\n"
: "+m" (xmm0) : : "rax", "rbx", "xmm0");
printf("BUG: xmm registers corrupted! tracee=%d, xmm0=%08X%08X%08X%08X\n",
tracee, xmm0[0], xmm0[1], xmm0[2], xmm0[3]);
} else {
usleep(100000);
ptrace(PTRACE_ATTACH, pid, 0, 0);
wait(NULL);
ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov);
xstate[65] = -1;
ptrace(PTRACE_SETREGSET, pid, NT_X86_XSTATE, &iov);
ptrace(PTRACE_CONT, pid, 0, 0);
wait(NULL);
}
return 1;
}Note: the program only tests for the bug using the ptrace() system call. The bug can also be reproduced using the rt_sigreturn() system call, but only when called from a 32-bit program, since for 64-bit programs the kernel restores the FPU state from the signal frame by doing XRSTOR directly from userspace memory (with proper error checking).
--- arch/x86/kernel/fpu/regset.c | 4 ++++ arch/x86/kernel/fpu/signal.c | 9 +++++++-- 2 files changed, 11 insertions(+), 2 deletions(-)
arch/x86/kernel/fpu/regset.c +4 -0
@@ -141,6 +141,10 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset, ret =copy_user_to_xstate (xsave, ubuf); }else { ret =user_regset_copyin (&pos, &count, &kbuf, &ubuf, xsave,0 ,-1 ); + +/* xcomp_bv must be 0 when using uncompacted format */ +if (!ret && xsave->header.xcomp_bv) + ret = -EINVAL ; }/*
arch/x86/kernel/fpu/signal.c +7 -2
@@ -324,11 +324,16 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)*/ fpu__drop (fpu); -if (using_compacted_format ()) +if (using_compacted_format ()) { err =copy_user_to_xstate (&fpu->state.xsave, buf_fx); -else + }else { err =__copy_from_user (&fpu->state.xsave, buf_fx, state_size); +/* xcomp_bv must be 0 when using uncompacted format */ +if (!err && fpu->state.xsave.header.xcomp_bv) + err = -EINVAL ; + } +if (err ||__copy_from_user (&env, buf,sizeof (env))) {fpstate_init (&fpu->state);trace_x86_fpu_init_state (fpu);
Signature · 1 line
2.11.0
tip-bot for Eric Biggers
merge bot[tip:x86/fpu] x86/fpu: Don't let userspace set bogus xcomp_bv
x86/fpu: Don't let userspace set bogus xcomp_bv
Commit-ID: 814fb7bb7db5433757d76f4c4502c96fc53b0b5e Gitweb: http://git.kernel.org/tip/814fb7bb7db5433757d76f4c4502c96fc53b0b5e Author: Eric Biggers <[email protected]> AuthorDate: Sat, 23 Sep 2017 15:00:07 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 25 Sep 2017 09:26:32 +0200
x86/fpu: Don't let userspace set bogus xcomp_bv
On x86, userspace can use the ptrace() or rt_sigreturn() system calls to set a task's extended state (xstate) or "FPU" registers. ptrace() can set them for another task using the PTRACE_SETREGSET request with NT_X86_XSTATE, while rt_sigreturn() can set them for the current task. In either case, registers can be set to any value, but the kernel assumes that the XSAVE area itself remains valid in the sense that the CPU can restore it.
However, in the case where the kernel is using the uncompacted xstate format (which it does whenever the XSAVES instruction is unavailable), it was possible for userspace to set the xcomp_bv field in the xstate_header to an arbitrary value. However, all bits in that field are reserved in the uncompacted case, so when switching to a task with nonzero xcomp_bv, the XRSTOR instruction failed with a #GP fault. This caused the WARN_ON_FPU(err) in copy_kernel_to_xregs() to be hit. In addition, since the error is otherwise ignored, the FPU registers from the task previously executing on the CPU were leaked.
Fix the bug by checking that the user-supplied value of xcomp_bv is 0 in the uncompacted case, and returning an error otherwise.
The reason for validating xcomp_bv rather than simply overwriting it with 0 is that we want userspace to see an error if it (incorrectly) provides an XSAVE area in compacted format rather than in uncompacted format.
Note that as before, in case of error we clear the task's FPU state. This is perhaps non-ideal, especially for PTRACE_SETREGSET; it might be better to return an error before changing anything. But it seems the "clear on error" behavior is fine for now, and it's a little tricky to do otherwise because it would mean we couldn't simply copy the full userspace state into kernel memory in one __copy_from_user().
This bug was found by syzkaller, which hit the above-mentioned WARN_ON_FPU():
WARNING: CPU: 1 PID: 0 at ./arch/x86/include/asm/fpu/internal.h:373 __switch_to+0x5b5/0x5d0
CPU: 1 PID: 0 Comm: swapper/1 Not tainted 4.13.0 #453
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
task: ffff9ba2bc8e42c0 task.stack: ffffa78cc036c000
RIP: 0010:__switch_to+0x5b5/0x5d0
RSP: 0000:ffffa78cc08bbb88 EFLAGS: 00010082
RAX: 00000000fffffffe RBX: ffff9ba2b8bf2180 RCX: 00000000c0000100
RDX: 00000000ffffffff RSI: 000000005cb10700 RDI: ffff9ba2b8bf36c0
RBP: ffffa78cc08bbbd0 R08: 00000000929fdf46 R09: 0000000000000001
R10: 0000000000000000 R11: 0000000000000000 R12: ffff9ba2bc8e42c0
R13: 0000000000000000 R14: ffff9ba2b8bf3680 R15: ffff9ba2bf5d7b40
FS: 00007f7e5cb10700(0000) GS:ffff9ba2bf400000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00000000004005cc CR3: 0000000079fd5000 CR4: 00000000001406e0
Call Trace:
Code: 84 00 00 00 00 00 e9 11 fd ff ff 0f ff 66 0f 1f 84 00 00 00 00 00 e9 e7 fa ff ff 0f ff 66 0f 1f 84 00 00 00 00 00 e9 c2 fa ff ff <0f> ff 66 0f 1f 84 00 00 00 00 00 e9 d4 fc ff ff 66 66 2e 0f 1fHere is a C reproducer. The expected behavior is that the program spin forever with no output. However, on a buggy kernel running on a processor with the "xsave" feature but without the "xsaves" feature (e.g. Sandy Bridge through Broadwell for Intel), within a second or two the program reports that the xmm registers were corrupted, i.e. were not restored correctly. With CONFIG_X86_DEBUG_FPU=y it also hits the above kernel warning.
#define _GNU_SOURCE
#include <stdbool.h>
#include <inttypes.h>
#include <linux/elf.h>
#include <stdio.h>
#include <sys/ptrace.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void)
{
int pid = fork();
uint64_t xstate[512];
struct iovec iov = { .iov_base = xstate, .iov_len = sizeof(xstate) };
if (pid == 0) {
bool tracee = true;
for (int i = 0; i < sysconf(_SC_NPROCESSORS_ONLN) && tracee; i++)
tracee = (fork() != 0);
uint32_t xmm0[4] = { [0 ... 3] = tracee ? 0x00000000 : 0xDEADBEEF };
asm volatile(" movdqu %0, %%xmm0\n"
" mov %0, %%rbx\n"
"1: movdqu %%xmm0, %0\n"
" mov %0, %%rax\n"
" cmp %%rax, %%rbx\n"
" je 1b\n"
: "+m" (xmm0) : : "rax", "rbx", "xmm0");
printf("BUG: xmm registers corrupted! tracee=%d, xmm0=%08X%08X%08X%08X\n",
tracee, xmm0[0], xmm0[1], xmm0[2], xmm0[3]);
} else {
usleep(100000);
ptrace(PTRACE_ATTACH, pid, 0, 0);
wait(NULL);
ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov);
xstate[65] = -1;
ptrace(PTRACE_SETREGSET, pid, NT_X86_XSTATE, &iov);
ptrace(PTRACE_CONT, pid, 0, 0);
wait(NULL);
}
return 1;
}Note: the program only tests for the bug using the ptrace() system call. The bug can also be reproduced using the rt_sigreturn() system call, but only when called from a 32-bit program, since for 64-bit programs the kernel restores the FPU state from the signal frame by doing XRSTOR directly from userspace memory (with proper error checking).
--- arch/x86/kernel/fpu/regset.c | 4 ++++ arch/x86/kernel/fpu/signal.c | 9 +++++++-- 2 files changed, 11 insertions(+), 2 deletions(-)
arch/x86/kernel/fpu/regset.c +4 -0
@@ -141,6 +141,10 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset, ret =copy_user_to_xstate (xsave, ubuf); }else { ret =user_regset_copyin (&pos, &count, &kbuf, &ubuf, xsave,0 ,-1 ); + +/* xcomp_bv must be 0 when using uncompacted format */ +if (!ret && xsave->header.xcomp_bv) + ret = -EINVAL ; }/*
arch/x86/kernel/fpu/signal.c +7 -2
@@ -324,11 +324,16 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)*/ fpu__drop (fpu); -if (using_compacted_format ()) +if (using_compacted_format ()) { err =copy_user_to_xstate (&fpu->state.xsave, buf_fx); -else + }else { err =__copy_from_user (&fpu->state.xsave, buf_fx, state_size); +/* xcomp_bv must be 0 when using uncompacted format */ +if (!err && state_size > offsetof(struct xregs_state , header) && fpu->state.xsave.header.xcomp_bv) + err = -EINVAL ; + } +if (err ||__copy_from_user (&env, buf,sizeof (env))) {fpstate_init (&fpu->state);trace_x86_fpu_init_state (fpu);
PATCH 25/33 x86/fpu: Tighten validation of user-supplied xstate_header
In reply to Ingo MolnarFrom: Eric Biggers <[email protected]>
Move validation of user-supplied xstate_headers into a helper function and call it from both the ptrace and sigreturn syscall paths. The new function also considers it to be an error if *any* reserved bits are set, whereas before we were just clearing most of them.
This should reduce the chance of bugs that fail to correctly validate user-supplied XSAVE areas. It also will expose any broken userspace programs that set the other reserved bits; this is desirable because such programs will lose compatibility with future CPUs and kernels if those bits are ever used for anything. (There shouldn't be any such programs, and in fact in the case where the compacted format is in use we were already validating xfeatures. But you never know...)
--- arch/x86/include/asm/fpu/xstate.h | 25 +++++++++++++++++++++++++ arch/x86/kernel/fpu/regset.c | 21 +++++++-------------- arch/x86/kernel/fpu/signal.c | 17 +++++++++-------- arch/x86/kernel/fpu/xstate.c | 52 +++++++++++++++++++--------------------------------- 4 files changed, 60 insertions(+), 55 deletions(-)
arch/x86/include/asm/fpu/xstate.h +25 -0
@@ -52,4 +52,29 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int ofint copy_xstate_to_user (void __user *ubuf,struct xregs_state *xsave,unsigned int offset,unsigned int size);int copy_kernel_to_xstate (struct xregs_state *xsave,const void *kbuf);int copy_user_to_xstate (struct xregs_state *xsave,const void __user *ubuf); + +/* Validate an xstate header supplied by userspace (ptrace or sigreturn) */ +static inline int validate_xstate_header (const struct xstate_header *hdr) +{ +/* No unknown or supervisor features may be set */ +if (hdr->xfeatures & (~xfeatures_mask |XFEATURE_MASK_SUPERVISOR )) +return -EINVAL ; + +/* Userspace must use the uncompacted format */ +if (hdr->xcomp_bv) +return -EINVAL ; + +/* +* If 'reserved' is shrunken to add a new field, make sure to validate +* that new field here! +*/ +BUILD_BUG_ON (sizeof (hdr->reserved) !=48 ); + +/* No reserved bits may be set */ +if (memchr_inv (hdr->reserved,0 ,sizeof (hdr->reserved))) +return -EINVAL ; + +return 0 ; +} +#endif
arch/x86/kernel/fpu/regset.c +7 -14
@@ -134,34 +134,27 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset,fpu__activate_fpstate_write (fpu); -if (boot_cpu_has (X86_FEATURE_XSAVES )) { +if (using_compacted_format ()) {if (kbuf) ret =copy_kernel_to_xstate (xsave, kbuf);else ret =copy_user_to_xstate (xsave, ubuf); }else { ret =user_regset_copyin (&pos, &count, &kbuf, &ubuf, xsave,0 ,-1 ); - -/* xcomp_bv must be 0 when using uncompacted format */ -if (!ret && xsave->header.xcomp_bv) - ret = -EINVAL ; +if (!ret) + ret =validate_xstate_header (&xsave->header); }/* -* In case of failure, mark all states as init: -*/ -if (ret) -fpstate_init (&fpu->state); - -/* * mxcsr reserved bits must be masked to zero for security reasons. */ xsave->i387.mxcsr &= mxcsr_feature_mask; - xsave->header.xfeatures &= xfeatures_mask; +/* -* These bits must be zero. +* In case of failure, mark all states as init: */ -memset (&xsave->header.reserved,0 ,48 ); +if (ret) +fpstate_init (&fpu->state);return ret; }
arch/x86/kernel/fpu/signal.c +9 -8
@@ -214,8 +214,11 @@ sanitize_restored_xstate(struct task_struct *tsk,struct xstate_header *header = &xsave->header;if (use_xsave ()) { -/* These bits must be zero. */ -memset (header->reserved,0 ,48 ); +/* +* Note: we don't need to zero the reserved bits in the +* xstate_header here because we either didn't copy them at all, +* or we checked earlier that they aren't set. +*/ /* * Init the state that is not present in the memory
@@ -224,7 +227,7 @@ sanitize_restored_xstate(struct task_struct *tsk,if (fx_only) header->xfeatures =XFEATURE_MASK_FPSSE ;else - header->xfeatures &= (xfeatures_mask & xfeatures); + header->xfeatures &= xfeatures; }if (use_fxsr ()) {
@@ -308,7 +311,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)/* * For 32-bit frames with fxstate, copy the user state to the * thread's fpu state, reconstruct fxstate from the fsave -* header. Sanitize the copied state etc. +* header. Validate and sanitize the copied state. */ struct fpu *fpu = &tsk->thread.fpu;struct user_i387_ia32_struct env;
@@ -328,10 +331,8 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) err =copy_user_to_xstate (&fpu->state.xsave, buf_fx); }else { err =__copy_from_user (&fpu->state.xsave, buf_fx, state_size); - -/* xcomp_bv must be 0 when using uncompacted format */ -if (!err && fpu->state.xsave.header.xcomp_bv) - err = -EINVAL ; +if (!err) + err =validate_xstate_header (&fpu->state.xsave.header); }if (err ||__copy_from_user (&env, buf,sizeof (env))) {
arch/x86/kernel/fpu/xstate.c +19 -33
116 lines not on this page · raw message
Signature · 1 line
2.11.0
PATCH 26/33 x86/fpu: Reinitialize FPU registers if restoring FPU state fails
In reply to Ingo MolnarFrom: Eric Biggers <[email protected]>
Userspace can change the FPU state of a task using the ptrace() or rt_sigreturn() system calls. Because reserved bits in the FPU state can cause the XRSTOR instruction to fail, the kernel has to carefully validate that no reserved bits or other invalid values are being set.
Unfortunately, there have been bugs in this validation code. For example, we were not checking that the 'xcomp_bv' field in the xstate_header was 0. As-is, such bugs are exploitable to read the FPU registers of other processes on the system. To do so, an attacker can create a task, assign to it an invalid FPU state, then spin in a loop and monitor the values of the FPU registers. Because the task's FPU registers are not being restored, sometimes the FPU registers will have the values from another process.
This is likely to continue to be a problem in the future because the validation done by the CPU instructions like XRSTOR is not immediately visible to kernel developers. Nor will invalid FPU states ever be encountered during ordinary use --- they will only be seen during fuzzing or exploits. There can even be reserved bits outside the xstate_header which are easy to forget about. For example, the MXCSR register contains reserved bits, which were not validated by the KVM_SET_XSAVE ioctl until commit a575813bfe4b ("KVM: x86: Fix load damaged SSEx MXCSR register").
Therefore, mitigate this class of vulnerability by restoring the FPU registers from init_fpstate if restoring from the task's state fails.
We actually used to do this, but it was (perhaps unwisely) removed by commit 9ccc27a5d297 ("x86/fpu: Remove error return values from copy_kernel_to_*regs() functions"). This new patch is also a bit different. First, it only clears the registers, not also the bad in-memory state; this is simpler and makes it easier to make the mitigation cover all callers of __copy_kernel_to_fpregs(). Second, it does the register clearing in an exception handler so that no extra instructions are added to context switches. In fact, we *remove* instructions, since previously we were always zeroing the register containing 'err' even if CONFIG_X86_DEBUG_FPU was disabled.
--- arch/x86/include/asm/fpu/internal.h | 51 +++++++++++++++------------------------------------ arch/x86/mm/extable.c | 24 ++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 36 deletions(-)
arch/x86/include/asm/fpu/internal.h +15 -36
@@ -120,20 +120,11 @@ extern void fpstate_sanitize_xstate(struct fpu *fpu); err; \ }) -#define check_insn(insn, output, input...) \ -({ \ - int err; \ +#define kernel_insn(insn, output, input...) \ asm volatile("1:" #insn "\n\t" \ "2:\n" \ - ".section .fixup,\"ax\"\n" \ - "3: movl $-1,%[err]\n" \ - " jmp 2b\n" \ - ".previous\n" \ - _ASM_EXTABLE(1b, 3b) \ - : [err] "=r" (err), output \ - : "0"(0), input); \ - err; \ -}) + _ASM_EXTABLE_HANDLE(1b, 2b, ex_handler_fprestore) \ + : output : input)static inline int copy_fregs_to_user (struct fregs_state __user *fx) {
@@ -153,20 +144,16 @@ static inline int copy_fxregs_to_user(struct fxregs_state __user *fx)static inline void copy_kernel_to_fxregs (struct fxregs_state *fx) { -int err; -if (IS_ENABLED (CONFIG_X86_32 )) { - err = check_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx)); + kernel_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx)); }else {if (IS_ENABLED (CONFIG_AS_FXSAVEQ )) { - err = check_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx)); + kernel_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx)); }else {/* See comment in copy_fxregs_to_kernel() below. */ - err = check_insn(rex64/fxrstor (%[fx]), "=m" (*fx), [fx] "R" (fx), "m" (*fx)); + kernel_insn(rex64/fxrstor (%[fx]), "=m" (*fx), [fx] "R" (fx), "m" (*fx)); } } -/* Copying from a kernel buffer to FPU registers should never fail: */ -WARN_ON_FPU (err); }static inline int copy_user_to_fxregs (struct fxregs_state __user *fx)
@@ -183,9 +170,7 @@ static inline int copy_user_to_fxregs(struct fxregs_state __user *fx)static inline void copy_kernel_to_fregs (struct fregs_state *fx) { - int err = check_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx)); - -WARN_ON_FPU (err); + kernel_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx)); }static inline int copy_user_to_fregs (struct fregs_state __user *fx)
@@ -281,18 +266,13 @@ static inline void copy_fxregs_to_kernel(struct fpu *fpu)* Use XRSTORS to restore context if it is enabled. XRSTORS supports compact * XSAVE area format. */ -#define XSTATE_XRESTORE (st, lmask, hmask, err) \ +#define XSTATE_XRESTORE (st, lmask, hmask) \ asm volatile(ALTERNATIVE(XRSTOR, \ XRSTORS, X86_FEATURE_XSAVES) \ "\n" \ - "xor %[err], %[err]\n" \ "3:\n" \ - ".pushsection .fixup,\"ax\"\n" \ - "4: movl $-2, %[err]\n" \ - "jmp 3b\n" \ - ".popsection\n" \ - _ASM_EXTABLE(661b, 4b) \ - : [err] "=r" (err) \ + _ASM_EXTABLE_HANDLE(661b, 3b, ex_handler_fprestore)\ + : \ : "D" (st), "m" (*st), "a" (lmask), "d" (hmask) \ : "memory")
@@ -336,7 +316,10 @@ static inline void copy_kernel_to_xregs_booting(struct xregs_state *xstate)else XSTATE_OP (XRSTOR , xstate, lmask, hmask, err); -/* We should never fault when copying from a kernel buffer: */ +/* +* We should never fault when copying from a kernel buffer, and the FPU +* state we set at boot time should be valid. +*/ WARN_ON_FPU (err); }
@@ -365,12 +348,8 @@ static inline void copy_kernel_to_xregs(struct xregs_state *xstate, u64 mask) {u32 lmask = mask;u32 hmask = mask >>32 ; -int err; - -XSTATE_XRESTORE (xstate, lmask, hmask, err); -/* We should never fault when copying from a kernel buffer: */ -WARN_ON_FPU (err); +XSTATE_XRESTORE (xstate, lmask, hmask); }/*
arch/x86/mm/extable.c +24 -0
@@ -2,6 +2,7 @@#include <linux/uaccess.h> #include <linux/sched/debug.h> +#include <asm/fpu/internal.h> #include <asm/traps.h> #include <asm/kdebug.h>
@@ -78,6 +79,29 @@ bool ex_handler_refcount(const struct exception_table_entry *fixup, }EXPORT_SYMBOL_GPL (ex_handler_refcount); +/* +* Handler for when we fail to restore a task's FPU state. We should never get +* here because the FPU state of a task using the FPU (task->thread.fpu.state) +* should always be valid. However, past bugs have allowed userspace to set +* reserved bits in the XSAVE area using PTRACE_SETREGSET or sys_rt_sigreturn(). +* These caused XRSTOR to fail when switching to the task, leaking the FPU +* registers of the task previously executing on the CPU. Mitigate this class +* of vulnerability by restoring from the initial state (essentially, zeroing +* out all the FPU registers) if we can't restore from the task's FPU state. +*/ +bool ex_handler_fprestore (const struct exception_table_entry *fixup, +struct pt_regs *regs,int trapnr) +{ + regs->ip =ex_fixup_addr (fixup); + +WARN_ONCE (1 ,"Bad FPU state detected at %pB, reinitializing FPU registers." , + (void *)instruction_pointer (regs)); + +__copy_kernel_to_fpregs (&init_fpstate,-1 ); +return true; +} +EXPORT_SYMBOL_GPL (ex_handler_fprestore); +bool ex_handler_ext (const struct exception_table_entry *fixup,struct pt_regs *regs,int trapnr) {
Signature · 1 line
2.11.0
tip-bot for Eric Biggers
merge bot[tip:x86/fpu] x86/fpu: Reinitialize FPU registers if restoring FPU state fails
x86/fpu: Reinitialize FPU registers if restoring FPU state fails
Commit-ID: d5c8028b4788f62b31fb79a331b3ad3e041fa366 Gitweb: http://git.kernel.org/tip/d5c8028b4788f62b31fb79a331b3ad3e041fa366 Author: Eric Biggers <[email protected]> AuthorDate: Sat, 23 Sep 2017 15:00:09 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 25 Sep 2017 09:26:38 +0200
x86/fpu: Reinitialize FPU registers if restoring FPU state fails
Userspace can change the FPU state of a task using the ptrace() or rt_sigreturn() system calls. Because reserved bits in the FPU state can cause the XRSTOR instruction to fail, the kernel has to carefully validate that no reserved bits or other invalid values are being set.
Unfortunately, there have been bugs in this validation code. For example, we were not checking that the 'xcomp_bv' field in the xstate_header was 0. As-is, such bugs are exploitable to read the FPU registers of other processes on the system. To do so, an attacker can create a task, assign to it an invalid FPU state, then spin in a loop and monitor the values of the FPU registers. Because the task's FPU registers are not being restored, sometimes the FPU registers will have the values from another process.
This is likely to continue to be a problem in the future because the validation done by the CPU instructions like XRSTOR is not immediately visible to kernel developers. Nor will invalid FPU states ever be encountered during ordinary use --- they will only be seen during fuzzing or exploits. There can even be reserved bits outside the xstate_header which are easy to forget about. For example, the MXCSR register contains reserved bits, which were not validated by the KVM_SET_XSAVE ioctl until commit a575813bfe4b ("KVM: x86: Fix load damaged SSEx MXCSR register").
Therefore, mitigate this class of vulnerability by restoring the FPU registers from init_fpstate if restoring from the task's state fails.
We actually used to do this, but it was (perhaps unwisely) removed by commit 9ccc27a5d297 ("x86/fpu: Remove error return values from copy_kernel_to_*regs() functions"). This new patch is also a bit different. First, it only clears the registers, not also the bad in-memory state; this is simpler and makes it easier to make the mitigation cover all callers of __copy_kernel_to_fpregs(). Second, it does the register clearing in an exception handler so that no extra instructions are added to context switches. In fact, we *remove* instructions, since previously we were always zeroing the register containing 'err' even if CONFIG_X86_DEBUG_FPU was disabled.
--- arch/x86/include/asm/fpu/internal.h | 51 +++++++++++-------------------------- arch/x86/mm/extable.c | 24 +++++++++++++++++ 2 files changed, 39 insertions(+), 36 deletions(-)
arch/x86/include/asm/fpu/internal.h +15 -36
@@ -120,20 +120,11 @@ extern void fpstate_sanitize_xstate(struct fpu *fpu); err; \ }) -#define check_insn(insn, output, input...) \ -({ \ - int err; \ +#define kernel_insn(insn, output, input...) \ asm volatile("1:" #insn "\n\t" \ "2:\n" \ - ".section .fixup,\"ax\"\n" \ - "3: movl $-1,%[err]\n" \ - " jmp 2b\n" \ - ".previous\n" \ - _ASM_EXTABLE(1b, 3b) \ - : [err] "=r" (err), output \ - : "0"(0), input); \ - err; \ -}) + _ASM_EXTABLE_HANDLE(1b, 2b, ex_handler_fprestore) \ + : output : input)static inline int copy_fregs_to_user (struct fregs_state __user *fx) {
@@ -153,20 +144,16 @@ static inline int copy_fxregs_to_user(struct fxregs_state __user *fx)static inline void copy_kernel_to_fxregs (struct fxregs_state *fx) { -int err; -if (IS_ENABLED (CONFIG_X86_32 )) { - err = check_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx)); + kernel_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx)); }else {if (IS_ENABLED (CONFIG_AS_FXSAVEQ )) { - err = check_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx)); + kernel_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx)); }else {/* See comment in copy_fxregs_to_kernel() below. */ - err = check_insn(rex64/fxrstor (%[fx]), "=m" (*fx), [fx] "R" (fx), "m" (*fx)); + kernel_insn(rex64/fxrstor (%[fx]), "=m" (*fx), [fx] "R" (fx), "m" (*fx)); } } -/* Copying from a kernel buffer to FPU registers should never fail: */ -WARN_ON_FPU (err); }static inline int copy_user_to_fxregs (struct fxregs_state __user *fx)
@@ -183,9 +170,7 @@ static inline int copy_user_to_fxregs(struct fxregs_state __user *fx)static inline void copy_kernel_to_fregs (struct fregs_state *fx) { - int err = check_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx)); - -WARN_ON_FPU (err); + kernel_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx)); }static inline int copy_user_to_fregs (struct fregs_state __user *fx)
@@ -281,18 +266,13 @@ static inline void copy_fxregs_to_kernel(struct fpu *fpu)* Use XRSTORS to restore context if it is enabled. XRSTORS supports compact * XSAVE area format. */ -#define XSTATE_XRESTORE (st, lmask, hmask, err) \ +#define XSTATE_XRESTORE (st, lmask, hmask) \ asm volatile(ALTERNATIVE(XRSTOR, \ XRSTORS, X86_FEATURE_XSAVES) \ "\n" \ - "xor %[err], %[err]\n" \ "3:\n" \ - ".pushsection .fixup,\"ax\"\n" \ - "4: movl $-2, %[err]\n" \ - "jmp 3b\n" \ - ".popsection\n" \ - _ASM_EXTABLE(661b, 4b) \ - : [err] "=r" (err) \ + _ASM_EXTABLE_HANDLE(661b, 3b, ex_handler_fprestore)\ + : \ : "D" (st), "m" (*st), "a" (lmask), "d" (hmask) \ : "memory")
@@ -336,7 +316,10 @@ static inline void copy_kernel_to_xregs_booting(struct xregs_state *xstate)else XSTATE_OP (XRSTOR , xstate, lmask, hmask, err); -/* We should never fault when copying from a kernel buffer: */ +/* +* We should never fault when copying from a kernel buffer, and the FPU +* state we set at boot time should be valid. +*/ WARN_ON_FPU (err); }
@@ -365,12 +348,8 @@ static inline void copy_kernel_to_xregs(struct xregs_state *xstate, u64 mask) {u32 lmask = mask;u32 hmask = mask >>32 ; -int err; - -XSTATE_XRESTORE (xstate, lmask, hmask, err); -/* We should never fault when copying from a kernel buffer: */ -WARN_ON_FPU (err); +XSTATE_XRESTORE (xstate, lmask, hmask); }/*
arch/x86/mm/extable.c +24 -0
@@ -2,6 +2,7 @@#include <linux/uaccess.h> #include <linux/sched/debug.h> +#include <asm/fpu/internal.h> #include <asm/traps.h> #include <asm/kdebug.h>
@@ -78,6 +79,29 @@ bool ex_handler_refcount(const struct exception_table_entry *fixup, }EXPORT_SYMBOL_GPL (ex_handler_refcount); +/* +* Handler for when we fail to restore a task's FPU state. We should never get +* here because the FPU state of a task using the FPU (task->thread.fpu.state) +* should always be valid. However, past bugs have allowed userspace to set +* reserved bits in the XSAVE area using PTRACE_SETREGSET or sys_rt_sigreturn(). +* These caused XRSTOR to fail when switching to the task, leaking the FPU +* registers of the task previously executing on the CPU. Mitigate this class +* of vulnerability by restoring from the initial state (essentially, zeroing +* out all the FPU registers) if we can't restore from the task's FPU state. +*/ +bool ex_handler_fprestore (const struct exception_table_entry *fixup, +struct pt_regs *regs,int trapnr) +{ + regs->ip =ex_fixup_addr (fixup); + +WARN_ONCE (1 ,"Bad FPU state detected at %pB, reinitializing FPU registers." , + (void *)instruction_pointer (regs)); + +__copy_kernel_to_fpregs (&init_fpstate,-1 ); +return true; +} +EXPORT_SYMBOL_GPL (ex_handler_fprestore); +bool ex_handler_ext (const struct exception_table_entry *fixup,struct pt_regs *regs,int trapnr) {
PATCH 27/33 x86/fpu: Simplify fpu__activate_fpstate_read()
In reply to Ingo Molnarfpu__activate_fpstate_read() can only ever be called for a non-current, non-executing (stopped) task - so make sure this is checked via a warning and remove the current-task logic.
This also fixes an incorrect (but harmless) warning introduced by one of the earlier patches.
--- arch/x86/kernel/fpu/core.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-)
arch/x86/kernel/fpu/core.c +8 -16
@@ -256,26 +256,18 @@ EXPORT_SYMBOL_GPL(fpu__activate_curr);* * If the task has not used the FPU before then initialize its * fpstate. -* -* If the task has used the FPU before then save it. */ void fpu__activate_fpstate_read (struct fpu *fpu) { -/* -* If fpregs are active (in the current CPU), then -* copy them to the fpstate: -*/ -if (fpu->fpstate_active) { -fpu__save (fpu); - }else { -if (!fpu->fpstate_active) { -fpstate_init (&fpu->state); -trace_x86_fpu_init_state (fpu); +WARN_ON_FPU (fpu == ¤t->thread.fpu); -trace_x86_fpu_activate_state (fpu); -/* Safe to do for current and for stopped child tasks: */ - fpu->fpstate_active =1 ; - } +if (!fpu->fpstate_active) { +fpstate_init (&fpu->state); +trace_x86_fpu_init_state (fpu); + +trace_x86_fpu_activate_state (fpu); +/* Safe to do for current and for stopped child tasks: */ + fpu->fpstate_active =1 ; } }
Signature · 1 line
2.11.0
tip-bot for Ingo Molnar
merge bot[tip:x86/fpu] x86/fpu: Fix fpu__activate_fpstate_read() and update comments
x86/fpu: Fix fpu__activate_fpstate_read() and update comments
Commit-ID: 4618e90965f272fe522f2af2523a60d0d4bc78f3 Gitweb: http://git.kernel.org/tip/4618e90965f272fe522f2af2523a60d0d4bc78f3 Author: Ingo Molnar <[email protected]> AuthorDate: Sat, 23 Sep 2017 15:00:10 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 26 Sep 2017 09:41:09 +0200
x86/fpu: Fix fpu__activate_fpstate_read() and update comments
fpu__activate_fpstate_read() can be called for the current task when coredumping - or for stopped tasks when ptrace-ing.
Implement this properly in the code and update the comments.
This also fixes an incorrect (but harmless) warning introduced by one of the earlier patches.
--- arch/x86/kernel/fpu/core.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-)
arch/x86/kernel/fpu/core.c +10 -7
@@ -254,18 +254,21 @@ EXPORT_SYMBOL_GPL(fpu__activate_curr);/* * This function must be called before we read a task's fpstate. * -* If the task has not used the FPU before then initialize its -* fpstate. +* There's two cases where this gets called: +* +* - for the current task (when coredumping), in which case we have +* to save the latest FPU registers into the fpstate, +* +* - or it's called for stopped tasks (ptrace), in which case the +* registers were already saved by the context-switch code when +* the task scheduled out - we only have to initialize the registers +* if they've never been initialized. * * If the task has used the FPU before then save it. */ void fpu__activate_fpstate_read (struct fpu *fpu) { -/* -* If fpregs are active (in the current CPU), then -* copy them to the fpstate: -*/ -if (fpu->fpstate_active) { +if (fpu == ¤t->thread.fpu) {fpu__save (fpu); }else {if (!fpu->fpstate_active) {
PATCH 28/33 x86/fpu: Remove fpu__current_fpstate_write_begin/end()
In reply to Ingo MolnarThese functions are not used anymore, so remove them.
--- arch/x86/include/asm/fpu/internal.h | 2 -- arch/x86/kernel/fpu/core.c | 63 --------------------------------------------------------- 2 files changed, 65 deletions(-)
arch/x86/include/asm/fpu/internal.h +0 -2
@@ -26,8 +26,6 @@extern void fpu__activate_curr (struct fpu *fpu);extern void fpu__activate_fpstate_read (struct fpu *fpu);extern void fpu__activate_fpstate_write (struct fpu *fpu); -extern void fpu__current_fpstate_write_begin (void ); -extern void fpu__current_fpstate_write_end (void );extern void fpu__save (struct fpu *fpu);extern void fpu__restore (struct fpu *fpu);extern int fpu__restore_sig (void __user *buf,int ia32_frame);
arch/x86/kernel/fpu/core.c +0 -63
69 lines not on this page · raw message
Signature · 1 line
2.11.0
tip-bot for Ingo Molnar
merge bot[tip:x86/fpu] x86/fpu: Remove fpu__current_fpstate_write_begin/end()
x86/fpu: Remove fpu__current_fpstate_write_begin/end()
Commit-ID: 685c930d6e58e31e251ec354f9dca3958a4c5040 Gitweb: http://git.kernel.org/tip/685c930d6e58e31e251ec354f9dca3958a4c5040 Author: Ingo Molnar <[email protected]> AuthorDate: Sat, 23 Sep 2017 15:00:11 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 26 Sep 2017 09:42:20 +0200
x86/fpu: Remove fpu__current_fpstate_write_begin/end()
These functions are not used anymore, so remove them.
--- arch/x86/include/asm/fpu/internal.h | 2 -- arch/x86/kernel/fpu/core.c | 63 ------------------------------------- 2 files changed, 65 deletions(-)
arch/x86/include/asm/fpu/internal.h +0 -2
@@ -26,8 +26,6 @@extern void fpu__activate_curr (struct fpu *fpu);extern void fpu__activate_fpstate_read (struct fpu *fpu);extern void fpu__activate_fpstate_write (struct fpu *fpu); -extern void fpu__current_fpstate_write_begin (void ); -extern void fpu__current_fpstate_write_end (void );extern void fpu__save (struct fpu *fpu);extern void fpu__restore (struct fpu *fpu);extern int fpu__restore_sig (void __user *buf,int ia32_frame);
arch/x86/kernel/fpu/core.c +0 -63
69 lines not on this page · raw message
PATCH 29/33 x86/fpu: Rename fpu::fpstate_active to fpu::initialized
In reply to Ingo MolnarThe x86 FPU code used to have a complex state machine where both the FPU registers and the FPU state context could be 'active' (or inactive) independently of each other - which enabled features like lazy FPU restore.
Much of this complexity is gone in the current code: now we basically can have FPU-less tasks (kernel threads) that don't use (and save/restore) FPU state at all, plus full FPU users that save/restore directly with no laziness whatsoever.
But the fpu::fpstate_active still carries bits of the old complexity - meanwhile this flag has become a simple flag that shows whether the FPU context saving area in the thread struct is initialized and used, or not.
Rename it to fpu::initialized to express this simplicity in the name as well.
--- arch/x86/ia32/ia32_signal.c | 2 +- arch/x86/include/asm/fpu/internal.h | 4 ++-- arch/x86/include/asm/fpu/types.h | 6 +++--- arch/x86/include/asm/trace/fpu.h | 8 ++++---- arch/x86/kernel/fpu/core.c | 24 ++++++++++++------------ arch/x86/kernel/fpu/init.c | 2 +- arch/x86/kernel/fpu/regset.c | 6 +++--- arch/x86/kernel/fpu/signal.c | 8 ++++---- arch/x86/kernel/fpu/xstate.c | 2 +- arch/x86/kernel/signal.c | 6 +++--- arch/x86/mm/pkeys.c | 2 +- 11 files changed, 35 insertions(+), 35 deletions(-)
arch/x86/ia32/ia32_signal.c +1 -1
@@ -231,7 +231,7 @@ static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, ksig->ka.sa.sa_restorer) sp = (unsigned long ) ksig->ka.sa.sa_restorer; -if (fpu->fpstate_active) { +if (fpu->initialized) {unsigned long fx_aligned, math_size; sp =fpu__alloc_mathframe (sp,1 , &fx_aligned, &math_size);
arch/x86/include/asm/fpu/internal.h +2 -2
@@ -527,7 +527,7 @@ static inline void fpregs_activate(struct fpu *fpu)static inline void switch_fpu_prepare (struct fpu *old_fpu,int cpu) { -if (old_fpu->fpstate_active) { +if (old_fpu->initialized) {if (!copy_fpregs_to_fpstate (old_fpu)) old_fpu->last_cpu =-1 ;else
@@ -550,7 +550,7 @@ switch_fpu_prepare(struct fpu *old_fpu, int cpu)static inline void switch_fpu_finish (struct fpu *new_fpu,int cpu) {bool preload =static_cpu_has (X86_FEATURE_FPU ) && - new_fpu->fpstate_active; + new_fpu->initialized;if (preload) {if (!fpregs_state_valid (new_fpu, cpu))
arch/x86/include/asm/fpu/types.h +3 -3
@@ -293,13 +293,13 @@ struct fpu {unsigned int last_cpu;/* -* @fpstate_active: +* @initialized: * -* This flag indicates whether this context is active: if the task +* This flag indicates whether this context is initialized: if the task * is not running then we can restore from this context, if the task * is running then we should save into this context. */ -unsigned char fpstate_active; +unsigned char initialized;/* * @state:
arch/x86/include/asm/trace/fpu.h +4 -4
@@ -12,22 +12,22 @@ DECLARE_EVENT_CLASS(x86_fpu,TP_STRUCT__entry (__field (struct fpu *,fpu ) -__field (bool, fpstate_active) +__field (bool, initialized)__field (u64, xfeatures)__field (u64, xcomp_bv) ),TP_fast_assign ( __entry->fpu = fpu; - __entry->fpstate_active = fpu->fpstate_active; + __entry->initialized = fpu->initialized;if (boot_cpu_has (X86_FEATURE_OSXSAVE )) { __entry->xfeatures = fpu->state.xsave.header.xfeatures; __entry->xcomp_bv = fpu->state.xsave.header.xcomp_bv; } ), -TP_printk ("x86/fpu: %p fpstate_active: %d xfeatures: %llx xcomp_bv: %llx" , +TP_printk ("x86/fpu: %p initialized: %d xfeatures: %llx xcomp_bv: %llx" , __entry->fpu, - __entry->fpstate_active, + __entry->initialized, __entry->xfeatures, __entry->xcomp_bv )
arch/x86/kernel/fpu/core.c +12 -12
@@ -100,7 +100,7 @@ void __kernel_fpu_begin(void)kernel_fpu_disable (); -if (fpu->fpstate_active) { +if (fpu->initialized) {/* * Ignore return value -- we don't care if reg state * is clobbered.
@@ -116,7 +116,7 @@ void __kernel_fpu_end(void) {struct fpu *fpu = ¤t->thread.fpu; -if (fpu->fpstate_active) +if (fpu->initialized)copy_kernel_to_fpregs (&fpu->state);kernel_fpu_enable ();
@@ -148,7 +148,7 @@ void fpu__save(struct fpu *fpu)preempt_disable ();trace_x86_fpu_before_save (fpu); -if (fpu->fpstate_active) { +if (fpu->initialized) {if (!copy_fpregs_to_fpstate (fpu)) {copy_kernel_to_fpregs (&fpu->state); }
@@ -191,7 +191,7 @@ int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu) { dst_fpu->last_cpu =-1 ; -if (!src_fpu->fpstate_active || !static_cpu_has (X86_FEATURE_FPU )) +if (!src_fpu->initialized || !static_cpu_has (X86_FEATURE_FPU ))return 0 ;WARN_ON_FPU (src_fpu != ¤t->thread.fpu);
@@ -240,13 +240,13 @@ void fpu__activate_curr(struct fpu *fpu) {WARN_ON_FPU (fpu != ¤t->thread.fpu); -if (!fpu->fpstate_active) { +if (!fpu->initialized) {fpstate_init (&fpu->state);trace_x86_fpu_init_state (fpu);trace_x86_fpu_activate_state (fpu);/* Safe to do for the current task: */ - fpu->fpstate_active =1 ; + fpu->initialized =1 ; } }EXPORT_SYMBOL_GPL (fpu__activate_curr);
@@ -261,13 +261,13 @@ void fpu__activate_fpstate_read(struct fpu *fpu) {WARN_ON_FPU (fpu == ¤t->thread.fpu); -if (!fpu->fpstate_active) { +if (!fpu->initialized) {fpstate_init (&fpu->state);trace_x86_fpu_init_state (fpu);trace_x86_fpu_activate_state (fpu);/* Safe to do for current and for stopped child tasks: */ - fpu->fpstate_active =1 ; + fpu->initialized =1 ; } }
@@ -292,7 +292,7 @@ void fpu__activate_fpstate_write(struct fpu *fpu)*/ WARN_ON_FPU (fpu == ¤t->thread.fpu); -if (fpu->fpstate_active) { +if (fpu->initialized) {/* Invalidate any lazy state: */ __fpu_invalidate_fpregs_state (fpu); }else {
@@ -301,7 +301,7 @@ void fpu__activate_fpstate_write(struct fpu *fpu)trace_x86_fpu_activate_state (fpu);/* Safe to do for stopped child tasks: */ - fpu->fpstate_active =1 ; + fpu->initialized =1 ; } }
@@ -343,7 +343,7 @@ void fpu__drop(struct fpu *fpu)preempt_disable ();if (fpu == ¤t->thread.fpu) { -if (fpu->fpstate_active) { +if (fpu->initialized) {/* Ignore delayed exceptions from user space */ asmvolatile ("1: fwait\n" "2:\n"
@@ -352,7 +352,7 @@ void fpu__drop(struct fpu *fpu) } } - fpu->fpstate_active =0 ; + fpu->initialized =0 ;trace_x86_fpu_dropped (fpu);
arch/x86/kernel/fpu/init.c +1 -1
@@ -240,7 +240,7 @@ static void __init fpu__init_system_ctx_switch(void)WARN_ON_FPU (!on_boot_cpu); on_boot_cpu =0 ; -WARN_ON_FPU (current->thread.fpu.fpstate_active); +WARN_ON_FPU (current->thread.fpu.initialized); }/*
arch/x86/kernel/fpu/regset.c +3 -3
@@ -16,14 +16,14 @@ int regset_fpregs_active(struct task_struct *target, const struct user_regset *r {struct fpu *target_fpu = &target->thread.fpu; -return target_fpu->fpstate_active ? regset->n :0 ; +return target_fpu->initialized ? regset->n :0 ; }int regset_xregset_fpregs_active (struct task_struct *target,const struct user_regset *regset) {struct fpu *target_fpu = &target->thread.fpu; -if (boot_cpu_has (X86_FEATURE_FXSR ) && target_fpu->fpstate_active) +if (boot_cpu_has (X86_FEATURE_FXSR ) && target_fpu->initialized)return regset->n;else return 0 ;
@@ -373,7 +373,7 @@ int dump_fpu(struct pt_regs *regs, struct user_i387_struct *ufpu)struct fpu *fpu = &tsk->thread.fpu;int fpvalid; - fpvalid = fpu->fpstate_active; + fpvalid = fpu->initialized;if (fpvalid) fpvalid = !fpregs_get(tsk, NULL, 0, sizeof(struct user_i387_ia32_struct),
arch/x86/kernel/fpu/signal.c +4 -4
@@ -171,7 +171,7 @@ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)sizeof (struct user_i387_ia32_struct ),NULL , (struct _fpstate_32 __user *) buf) ? -1 : 1; -if (fpu->fpstate_active ||using_compacted_format ()) { +if (fpu->initialized ||using_compacted_format ()) {/* Save the live register state to the user directly. */ if (copy_fpregs_to_sigframe (buf_fx))return -1 ;
@@ -318,12 +318,12 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)int err =0 ;/* -* Drop the current fpu which clears fpu->fpstate_active. This ensures +* Drop the current fpu which clears fpu->initialized. This ensures * that any context-switch during the copy of the new state, * avoids the intermediate state from getting restored/saved. * Thus avoiding the new restored state from getting corrupted. * We will be ready to restore/save the state only after -* fpu->fpstate_active is again set. +* fpu->initialized is again set. */ fpu__drop (fpu);
@@ -343,7 +343,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)sanitize_restored_xstate (tsk, &env, xfeatures, fx_only); } - fpu->fpstate_active =1 ; + fpu->initialized =1 ;preempt_disable ();fpu__restore (fpu);preempt_enable ();
arch/x86/kernel/fpu/xstate.c +1 -1
@@ -867,7 +867,7 @@ const void *get_xsave_field_ptr(int xsave_state) {struct fpu *fpu = ¤t->thread.fpu; -if (!fpu->fpstate_active) +if (!fpu->initialized)return NULL ;/* * fpu__save() takes the CPU's xstate registers
arch/x86/kernel/signal.c +3 -3
@@ -263,7 +263,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, sp = (unsigned long ) ka->sa.sa_restorer; } -if (fpu->fpstate_active) { +if (fpu->initialized) { sp =fpu__alloc_mathframe (sp,IS_ENABLED (CONFIG_X86_32 ), &buf_fx, &math_size); *fpstate = (void __user *)sp;
@@ -279,7 +279,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,return (void __user *)-1L ;/* save i387 and extended state */ -if (fpu->fpstate_active && +if (fpu->initialized &©_fpstate_to_sigframe (*fpstate, (void __user *)buf_fx, math_size) <0 )return (void __user *)-1L ;
@@ -755,7 +755,7 @@ handle_signal(struct ksignal *ksig, struct pt_regs *regs)/* * Ensure the signal handler starts with the new fpu state. */ -if (fpu->fpstate_active) +if (fpu->initialized)fpu__clear (fpu); }signal_setup_done (failed, ksig, stepping);
arch/x86/mm/pkeys.c +1 -1
@@ -44,7 +44,7 @@ int __execute_only_pkey(struct mm_struct *mm)*/ preempt_disable ();if (!need_to_set_mm_pkey && - current->thread.fpu.fpstate_active && + current->thread.fpu.initialized && !__pkru_allows_read (read_pkru (), execute_only_pkey)) {preempt_enable ();return execute_only_pkey;
Signature · 1 line
2.11.0
tip-bot for Ingo Molnar
merge bot[tip:x86/fpu] x86/fpu: Rename fpu::fpstate_active to fpu::initialized
x86/fpu: Rename fpu::fpstate_active to fpu::initialized
Commit-ID: e4a81bfcaae1ebbdc6efe74e8ea563144d90e9a9 Gitweb: http://git.kernel.org/tip/e4a81bfcaae1ebbdc6efe74e8ea563144d90e9a9 Author: Ingo Molnar <[email protected]> AuthorDate: Tue, 26 Sep 2017 09:43:36 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 26 Sep 2017 09:43:36 +0200
x86/fpu: Rename fpu::fpstate_active to fpu::initialized
The x86 FPU code used to have a complex state machine where both the FPU registers and the FPU state context could be 'active' (or inactive) independently of each other - which enabled features like lazy FPU restore.
Much of this complexity is gone in the current code: now we basically can have FPU-less tasks (kernel threads) that don't use (and save/restore) FPU state at all, plus full FPU users that save/restore directly with no laziness whatsoever.
But the fpu::fpstate_active still carries bits of the old complexity - meanwhile this flag has become a simple flag that shows whether the FPU context saving area in the thread struct is initialized and used, or not.
Rename it to fpu::initialized to express this simplicity in the name as well.
--- arch/x86/ia32/ia32_signal.c | 2 +- arch/x86/include/asm/fpu/internal.h | 4 ++-- arch/x86/include/asm/fpu/types.h | 6 +++--- arch/x86/include/asm/trace/fpu.h | 8 ++++---- arch/x86/kernel/fpu/core.c | 24 ++++++++++++------------ arch/x86/kernel/fpu/init.c | 2 +- arch/x86/kernel/fpu/regset.c | 6 +++--- arch/x86/kernel/fpu/signal.c | 8 ++++---- arch/x86/kernel/fpu/xstate.c | 2 +- arch/x86/kernel/signal.c | 6 +++--- arch/x86/mm/pkeys.c | 2 +- 11 files changed, 35 insertions(+), 35 deletions(-)
arch/x86/ia32/ia32_signal.c +1 -1
@@ -231,7 +231,7 @@ static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, ksig->ka.sa.sa_restorer) sp = (unsigned long ) ksig->ka.sa.sa_restorer; -if (fpu->fpstate_active) { +if (fpu->initialized) {unsigned long fx_aligned, math_size; sp =fpu__alloc_mathframe (sp,1 , &fx_aligned, &math_size);
arch/x86/include/asm/fpu/internal.h +2 -2
@@ -527,7 +527,7 @@ static inline void fpregs_activate(struct fpu *fpu)static inline void switch_fpu_prepare (struct fpu *old_fpu,int cpu) { -if (old_fpu->fpstate_active) { +if (old_fpu->initialized) {if (!copy_fpregs_to_fpstate (old_fpu)) old_fpu->last_cpu =-1 ;else
@@ -550,7 +550,7 @@ switch_fpu_prepare(struct fpu *old_fpu, int cpu)static inline void switch_fpu_finish (struct fpu *new_fpu,int cpu) {bool preload =static_cpu_has (X86_FEATURE_FPU ) && - new_fpu->fpstate_active; + new_fpu->initialized;if (preload) {if (!fpregs_state_valid (new_fpu, cpu))
arch/x86/include/asm/fpu/types.h +3 -3
@@ -293,13 +293,13 @@ struct fpu {unsigned int last_cpu;/* -* @fpstate_active: +* @initialized: * -* This flag indicates whether this context is active: if the task +* This flag indicates whether this context is initialized: if the task * is not running then we can restore from this context, if the task * is running then we should save into this context. */ -unsigned char fpstate_active; +unsigned char initialized;/* * @state:
arch/x86/include/asm/trace/fpu.h +4 -4
@@ -12,22 +12,22 @@ DECLARE_EVENT_CLASS(x86_fpu,TP_STRUCT__entry (__field (struct fpu *,fpu ) -__field (bool, fpstate_active) +__field (bool, initialized)__field (u64, xfeatures)__field (u64, xcomp_bv) ),TP_fast_assign ( __entry->fpu = fpu; - __entry->fpstate_active = fpu->fpstate_active; + __entry->initialized = fpu->initialized;if (boot_cpu_has (X86_FEATURE_OSXSAVE )) { __entry->xfeatures = fpu->state.xsave.header.xfeatures; __entry->xcomp_bv = fpu->state.xsave.header.xcomp_bv; } ), -TP_printk ("x86/fpu: %p fpstate_active: %d xfeatures: %llx xcomp_bv: %llx" , +TP_printk ("x86/fpu: %p initialized: %d xfeatures: %llx xcomp_bv: %llx" , __entry->fpu, - __entry->fpstate_active, + __entry->initialized, __entry->xfeatures, __entry->xcomp_bv )
arch/x86/kernel/fpu/core.c +12 -12
@@ -100,7 +100,7 @@ void __kernel_fpu_begin(void)kernel_fpu_disable (); -if (fpu->fpstate_active) { +if (fpu->initialized) {/* * Ignore return value -- we don't care if reg state * is clobbered.
@@ -116,7 +116,7 @@ void __kernel_fpu_end(void) {struct fpu *fpu = ¤t->thread.fpu; -if (fpu->fpstate_active) +if (fpu->initialized)copy_kernel_to_fpregs (&fpu->state);kernel_fpu_enable ();
@@ -148,7 +148,7 @@ void fpu__save(struct fpu *fpu)preempt_disable ();trace_x86_fpu_before_save (fpu); -if (fpu->fpstate_active) { +if (fpu->initialized) {if (!copy_fpregs_to_fpstate (fpu)) {copy_kernel_to_fpregs (&fpu->state); }
@@ -191,7 +191,7 @@ int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu) { dst_fpu->last_cpu =-1 ; -if (!src_fpu->fpstate_active || !static_cpu_has (X86_FEATURE_FPU )) +if (!src_fpu->initialized || !static_cpu_has (X86_FEATURE_FPU ))return 0 ;WARN_ON_FPU (src_fpu != ¤t->thread.fpu);
@@ -240,13 +240,13 @@ void fpu__activate_curr(struct fpu *fpu) {WARN_ON_FPU (fpu != ¤t->thread.fpu); -if (!fpu->fpstate_active) { +if (!fpu->initialized) {fpstate_init (&fpu->state);trace_x86_fpu_init_state (fpu);trace_x86_fpu_activate_state (fpu);/* Safe to do for the current task: */ - fpu->fpstate_active =1 ; + fpu->initialized =1 ; } }EXPORT_SYMBOL_GPL (fpu__activate_curr);
@@ -271,13 +271,13 @@ void fpu__activate_fpstate_read(struct fpu *fpu)if (fpu == ¤t->thread.fpu) {fpu__save (fpu); }else { -if (!fpu->fpstate_active) { +if (!fpu->initialized) {fpstate_init (&fpu->state);trace_x86_fpu_init_state (fpu);trace_x86_fpu_activate_state (fpu);/* Safe to do for current and for stopped child tasks: */ - fpu->fpstate_active =1 ; + fpu->initialized =1 ; } } }
@@ -303,7 +303,7 @@ void fpu__activate_fpstate_write(struct fpu *fpu)*/ WARN_ON_FPU (fpu == ¤t->thread.fpu); -if (fpu->fpstate_active) { +if (fpu->initialized) {/* Invalidate any lazy state: */ __fpu_invalidate_fpregs_state (fpu); }else {
@@ -312,7 +312,7 @@ void fpu__activate_fpstate_write(struct fpu *fpu)trace_x86_fpu_activate_state (fpu);/* Safe to do for stopped child tasks: */ - fpu->fpstate_active =1 ; + fpu->initialized =1 ; } }
@@ -354,7 +354,7 @@ void fpu__drop(struct fpu *fpu)preempt_disable ();if (fpu == ¤t->thread.fpu) { -if (fpu->fpstate_active) { +if (fpu->initialized) {/* Ignore delayed exceptions from user space */ asmvolatile ("1: fwait\n" "2:\n"
@@ -363,7 +363,7 @@ void fpu__drop(struct fpu *fpu) } } - fpu->fpstate_active =0 ; + fpu->initialized =0 ;trace_x86_fpu_dropped (fpu);
arch/x86/kernel/fpu/init.c +1 -1
@@ -240,7 +240,7 @@ static void __init fpu__init_system_ctx_switch(void)WARN_ON_FPU (!on_boot_cpu); on_boot_cpu =0 ; -WARN_ON_FPU (current->thread.fpu.fpstate_active); +WARN_ON_FPU (current->thread.fpu.initialized); }/*
arch/x86/kernel/fpu/regset.c +3 -3
@@ -16,14 +16,14 @@ int regset_fpregs_active(struct task_struct *target, const struct user_regset *r {struct fpu *target_fpu = &target->thread.fpu; -return target_fpu->fpstate_active ? regset->n :0 ; +return target_fpu->initialized ? regset->n :0 ; }int regset_xregset_fpregs_active (struct task_struct *target,const struct user_regset *regset) {struct fpu *target_fpu = &target->thread.fpu; -if (boot_cpu_has (X86_FEATURE_FXSR ) && target_fpu->fpstate_active) +if (boot_cpu_has (X86_FEATURE_FXSR ) && target_fpu->initialized)return regset->n;else return 0 ;
@@ -380,7 +380,7 @@ int dump_fpu(struct pt_regs *regs, struct user_i387_struct *ufpu)struct fpu *fpu = &tsk->thread.fpu;int fpvalid; - fpvalid = fpu->fpstate_active; + fpvalid = fpu->initialized;if (fpvalid) fpvalid = !fpregs_get(tsk, NULL, 0, sizeof(struct user_i387_ia32_struct),
arch/x86/kernel/fpu/signal.c +4 -4
@@ -171,7 +171,7 @@ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)sizeof (struct user_i387_ia32_struct ),NULL , (struct _fpstate_32 __user *) buf) ? -1 : 1; -if (fpu->fpstate_active ||using_compacted_format ()) { +if (fpu->initialized ||using_compacted_format ()) {/* Save the live register state to the user directly. */ if (copy_fpregs_to_sigframe (buf_fx))return -1 ;
@@ -315,12 +315,12 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)int err =0 ;/* -* Drop the current fpu which clears fpu->fpstate_active. This ensures +* Drop the current fpu which clears fpu->initialized. This ensures * that any context-switch during the copy of the new state, * avoids the intermediate state from getting restored/saved. * Thus avoiding the new restored state from getting corrupted. * We will be ready to restore/save the state only after -* fpu->fpstate_active is again set. +* fpu->initialized is again set. */ fpu__drop (fpu);
@@ -342,7 +342,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)sanitize_restored_xstate (tsk, &env, xfeatures, fx_only); } - fpu->fpstate_active =1 ; + fpu->initialized =1 ;preempt_disable ();fpu__restore (fpu);preempt_enable ();
arch/x86/kernel/fpu/xstate.c +1 -1
@@ -867,7 +867,7 @@ const void *get_xsave_field_ptr(int xsave_state) {struct fpu *fpu = ¤t->thread.fpu; -if (!fpu->fpstate_active) +if (!fpu->initialized)return NULL ;/* * fpu__save() takes the CPU's xstate registers
arch/x86/kernel/signal.c +3 -3
@@ -263,7 +263,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, sp = (unsigned long ) ka->sa.sa_restorer; } -if (fpu->fpstate_active) { +if (fpu->initialized) { sp =fpu__alloc_mathframe (sp,IS_ENABLED (CONFIG_X86_32 ), &buf_fx, &math_size); *fpstate = (void __user *)sp;
@@ -279,7 +279,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,return (void __user *)-1L ;/* save i387 and extended state */ -if (fpu->fpstate_active && +if (fpu->initialized &©_fpstate_to_sigframe (*fpstate, (void __user *)buf_fx, math_size) <0 )return (void __user *)-1L ;
@@ -755,7 +755,7 @@ handle_signal(struct ksignal *ksig, struct pt_regs *regs)/* * Ensure the signal handler starts with the new fpu state. */ -if (fpu->fpstate_active) +if (fpu->initialized)fpu__clear (fpu); }signal_setup_done (failed, ksig, stepping);
arch/x86/mm/pkeys.c +1 -1
@@ -44,7 +44,7 @@ int __execute_only_pkey(struct mm_struct *mm)*/ preempt_disable ();if (!need_to_set_mm_pkey && - current->thread.fpu.fpstate_active && + current->thread.fpu.initialized && !__pkru_allows_read (read_pkru (), execute_only_pkey)) {preempt_enable ();return execute_only_pkey;
PATCH 30/33 x86/fpu: Fix stale comments about lazy FPU logic
In reply to Ingo MolnarWe don't do any lazy restore anymore, what we have are two pieces of optimization:
- no-FPU tasks that don't save/restore the FPU context (kernel threads are such)
- cached FPU registers maintained via the fpu->last_cpu field. This means that if an FPU task context switches to a non-FPU task then we can maintain the FPU registers as an in-FPU copies (cache), and skip the restoration of them once we switch back to the original FPU-using task.
Update all the comments that still referred to old 'lazy' and 'unlazy' concepts.
--- arch/x86/kernel/fpu/core.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-)
arch/x86/kernel/fpu/core.c +3 -6
@@ -205,9 +205,6 @@ int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu)/* * Save current FPU registers directly into the child * FPU context, without any memory-to-memory copying. -* In lazy mode, if the FPU context isn't loaded into -* fpregs, CR0.TS will be set and do_device_not_available -* will load the FPU context. * * We have to do all this with preemption disabled, * mostly because of the FNSAVE case, because in that
@@ -274,13 +271,13 @@ void fpu__activate_fpstate_read(struct fpu *fpu)/* * This function must be called before we write a task's fpstate. * -* If the task has used the FPU before then unlazy it. +* If the task has used the FPU before then invalidate any cached FPU registers. * If the task has not used the FPU before then initialize its fpstate. * * After this function call, after registers in the fpstate are * modified and the child task has woken up, the child task will * restore the modified FPU state from the modified context. If we -* didn't clear its lazy status here then the lazy in-registers +* didn't clear its cached status here then the cached in-registers * state pending on its former CPU could be restored, corrupting * the modifications. */
@@ -293,7 +290,7 @@ void fpu__activate_fpstate_write(struct fpu *fpu)WARN_ON_FPU (fpu == ¤t->thread.fpu);if (fpu->initialized) { -/* Invalidate any lazy state: */ +/* Invalidate any cached state: */ __fpu_invalidate_fpregs_state (fpu); }else {fpstate_init (&fpu->state);
Signature · 1 line
2.11.0
tip-bot for Ingo Molnar
merge bot[tip:x86/fpu] x86/fpu: Fix stale comments about lazy FPU logic
x86/fpu: Fix stale comments about lazy FPU logic
Commit-ID: 7f1487c59b7c6dcb20155f4302985da2659a2997 Gitweb: http://git.kernel.org/tip/7f1487c59b7c6dcb20155f4302985da2659a2997 Author: Ingo Molnar <[email protected]> AuthorDate: Sat, 23 Sep 2017 15:00:13 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 26 Sep 2017 09:43:43 +0200
x86/fpu: Fix stale comments about lazy FPU logic
We don't do any lazy restore anymore, what we have are two pieces of optimization:
- no-FPU tasks that don't save/restore the FPU context (kernel threads are such)
- cached FPU registers maintained via the fpu->last_cpu field. This means that if an FPU task context switches to a non-FPU task then we can maintain the FPU registers as an in-FPU copies (cache), and skip the restoration of them once we switch back to the original FPU-using task.
Update all the comments that still referred to old 'lazy' and 'unlazy' concepts.
--- arch/x86/kernel/fpu/core.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-)
arch/x86/kernel/fpu/core.c +3 -6
@@ -205,9 +205,6 @@ int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu)/* * Save current FPU registers directly into the child * FPU context, without any memory-to-memory copying. -* In lazy mode, if the FPU context isn't loaded into -* fpregs, CR0.TS will be set and do_device_not_available -* will load the FPU context. * * We have to do all this with preemption disabled, * mostly because of the FNSAVE case, because in that
@@ -285,13 +282,13 @@ void fpu__activate_fpstate_read(struct fpu *fpu)/* * This function must be called before we write a task's fpstate. * -* If the task has used the FPU before then unlazy it. +* If the task has used the FPU before then invalidate any cached FPU registers. * If the task has not used the FPU before then initialize its fpstate. * * After this function call, after registers in the fpstate are * modified and the child task has woken up, the child task will * restore the modified FPU state from the modified context. If we -* didn't clear its lazy status here then the lazy in-registers +* didn't clear its cached status here then the cached in-registers * state pending on its former CPU could be restored, corrupting * the modifications. */
@@ -304,7 +301,7 @@ void fpu__activate_fpstate_write(struct fpu *fpu)WARN_ON_FPU (fpu == ¤t->thread.fpu);if (fpu->initialized) { -/* Invalidate any lazy state: */ +/* Invalidate any cached state: */ __fpu_invalidate_fpregs_state (fpu); }else {fpstate_init (&fpu->state);
PATCH 31/33 x86/fpu: Simplify and speed up fpu__copy()
In reply to Ingo Molnarfpu__copy() has a preempt_disable()/enable() pair, which it had to do to be able to atomically unlazy the current task when doing an FNSAVE.
But we don't unlazy tasks anymore, we always do direct saves/restores of FPU context.
So remove both the unnecessary critical section, and update the comments.
--- arch/x86/kernel/fpu/core.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-)
arch/x86/kernel/fpu/core.c +3 -12
@@ -206,22 +206,13 @@ int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu)* Save current FPU registers directly into the child * FPU context, without any memory-to-memory copying. * -* We have to do all this with preemption disabled, -* mostly because of the FNSAVE case, because in that -* case we must not allow preemption in the window -* between the FNSAVE and us marking the context lazy. -* -* It shouldn't be an issue as even FNSAVE is plenty -* fast in terms of critical section length. +* ( The function 'fails' in the FNSAVE case, which destroys +* register contents so we have to copy them back. ) */ -preempt_disable ();if (!copy_fpregs_to_fpstate (dst_fpu)) { -memcpy (&src_fpu->state, &dst_fpu->state, - fpu_kernel_xstate_size); - +memcpy (&src_fpu->state, &dst_fpu->state, fpu_kernel_xstate_size);copy_kernel_to_fpregs (&src_fpu->state); } -preempt_enable ();trace_x86_fpu_copy_src (src_fpu);trace_x86_fpu_copy_dst (dst_fpu);
Signature · 1 line
2.11.0
tip-bot for Ingo Molnar
merge bot[tip:x86/fpu] x86/fpu: Simplify and speed up fpu__copy()
x86/fpu: Simplify and speed up fpu__copy()
Commit-ID: e10078eba69859359ce8644dd423b4132a6a8913 Gitweb: http://git.kernel.org/tip/e10078eba69859359ce8644dd423b4132a6a8913 Author: Ingo Molnar <[email protected]> AuthorDate: Sat, 23 Sep 2017 15:00:14 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 26 Sep 2017 09:43:44 +0200
x86/fpu: Simplify and speed up fpu__copy()
fpu__copy() has a preempt_disable()/enable() pair, which it had to do to be able to atomically unlazy the current task when doing an FNSAVE.
But we don't unlazy tasks anymore, we always do direct saves/restores of FPU context.
So remove both the unnecessary critical section, and update the comments.
--- arch/x86/kernel/fpu/core.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-)
arch/x86/kernel/fpu/core.c +3 -12
@@ -206,22 +206,13 @@ int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu)* Save current FPU registers directly into the child * FPU context, without any memory-to-memory copying. * -* We have to do all this with preemption disabled, -* mostly because of the FNSAVE case, because in that -* case we must not allow preemption in the window -* between the FNSAVE and us marking the context lazy. -* -* It shouldn't be an issue as even FNSAVE is plenty -* fast in terms of critical section length. +* ( The function 'fails' in the FNSAVE case, which destroys +* register contents so we have to copy them back. ) */ -preempt_disable ();if (!copy_fpregs_to_fpstate (dst_fpu)) { -memcpy (&src_fpu->state, &dst_fpu->state, - fpu_kernel_xstate_size); - +memcpy (&src_fpu->state, &dst_fpu->state, fpu_kernel_xstate_size);copy_kernel_to_fpregs (&src_fpu->state); } -preempt_enable ();trace_x86_fpu_copy_src (src_fpu);trace_x86_fpu_copy_dst (dst_fpu);
PATCH 32/33 x86/fpu: Rename fpu__activate_curr() to fpu__initialize()
In reply to Ingo MolnarRename this function to better express that it's all about initializing the FPU state of a task which goes hand in hand with the fpu::initialized field.
--- arch/x86/include/asm/fpu/internal.h | 2 +- arch/x86/kernel/fpu/core.c | 8 ++++---- arch/x86/kernel/fpu/signal.c | 2 +- arch/x86/kvm/x86.c | 2 +- arch/x86/math-emu/fpu_entry.c | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-)
arch/x86/include/asm/fpu/internal.h +1 -1
@@ -23,7 +23,7 @@/* * High level FPU state handling functions: */ -extern void fpu__activate_curr (struct fpu *fpu); +extern void fpu__initialize (struct fpu *fpu);extern void fpu__activate_fpstate_read (struct fpu *fpu);extern void fpu__activate_fpstate_write (struct fpu *fpu);extern void fpu__save (struct fpu *fpu);
arch/x86/kernel/fpu/core.c +4 -4
@@ -224,7 +224,7 @@ int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu)* Activate the current task's in-memory FPU context, * if it has not been used before: */ -void fpu__activate_curr (struct fpu *fpu) +void fpu__initialize (struct fpu *fpu) {WARN_ON_FPU (fpu != ¤t->thread.fpu);
@@ -237,7 +237,7 @@ void fpu__activate_curr(struct fpu *fpu) fpu->initialized =1 ; } } -EXPORT_SYMBOL_GPL (fpu__activate_curr); +EXPORT_SYMBOL_GPL (fpu__initialize);/* * This function must be called before we read a task's fpstate.
@@ -305,7 +305,7 @@ void fpu__activate_fpstate_write(struct fpu *fpu)*/ void fpu__restore (struct fpu *fpu) { -fpu__activate_curr (fpu); +fpu__initialize (fpu);/* Avoid __kernel_fpu_begin() right after fpregs_activate() */ kernel_fpu_disable ();
@@ -381,7 +381,7 @@ void fpu__clear(struct fpu *fpu)*/ if (static_cpu_has (X86_FEATURE_FPU )) {preempt_disable (); -fpu__activate_curr (fpu); +fpu__initialize (fpu);user_fpu_begin ();copy_init_fpstate_to_fpregs ();preempt_enable ();
arch/x86/kernel/fpu/signal.c +1 -1
@@ -283,7 +283,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)if (!access_ok (VERIFY_READ , buf, size))return -EACCES ; -fpu__activate_curr (fpu); +fpu__initialize (fpu);if (!static_cpu_has (X86_FEATURE_FPU )) return fpregs_soft_set(current, NULL,
arch/x86/kvm/x86.c +1 -1
@@ -7225,7 +7225,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)int r;sigset_t sigsaved; -fpu__activate_curr (fpu); +fpu__initialize (fpu);if (vcpu->sigset_active)sigprocmask (SIG_SETMASK , &vcpu->sigset, &sigsaved);
arch/x86/math-emu/fpu_entry.c +1 -1
@@ -114,7 +114,7 @@ void math_emulate(struct math_emu_info *info)struct desc_struct code_descriptor;struct fpu *fpu = ¤t->thread.fpu; -fpu__activate_curr (fpu); +fpu__initialize (fpu);#ifdef RE_ENTRANT_CHECKING if (emulating) {
Signature · 1 line
2.11.0
tip-bot for Ingo Molnar
merge bot[tip:x86/fpu] x86/fpu: Rename fpu__activate_curr() to fpu__initialize()
x86/fpu: Rename fpu__activate_curr() to fpu__initialize()
Commit-ID: 2ce03d850b9a2f17d55596ecfa86e72b5687a627 Gitweb: http://git.kernel.org/tip/2ce03d850b9a2f17d55596ecfa86e72b5687a627 Author: Ingo Molnar <[email protected]> AuthorDate: Sat, 23 Sep 2017 15:00:15 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 26 Sep 2017 09:43:44 +0200
x86/fpu: Rename fpu__activate_curr() to fpu__initialize()
Rename this function to better express that it's all about initializing the FPU state of a task which goes hand in hand with the fpu::initialized field.
--- arch/x86/include/asm/fpu/internal.h | 2 +- arch/x86/kernel/fpu/core.c | 8 ++++---- arch/x86/kernel/fpu/signal.c | 2 +- arch/x86/kvm/x86.c | 2 +- arch/x86/math-emu/fpu_entry.c | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-)
arch/x86/include/asm/fpu/internal.h +1 -1
@@ -23,7 +23,7 @@/* * High level FPU state handling functions: */ -extern void fpu__activate_curr (struct fpu *fpu); +extern void fpu__initialize (struct fpu *fpu);extern void fpu__activate_fpstate_read (struct fpu *fpu);extern void fpu__activate_fpstate_write (struct fpu *fpu);extern void fpu__save (struct fpu *fpu);
arch/x86/kernel/fpu/core.c +4 -4
@@ -224,7 +224,7 @@ int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu)* Activate the current task's in-memory FPU context, * if it has not been used before: */ -void fpu__activate_curr (struct fpu *fpu) +void fpu__initialize (struct fpu *fpu) {WARN_ON_FPU (fpu != ¤t->thread.fpu);
@@ -237,7 +237,7 @@ void fpu__activate_curr(struct fpu *fpu) fpu->initialized =1 ; } } -EXPORT_SYMBOL_GPL (fpu__activate_curr); +EXPORT_SYMBOL_GPL (fpu__initialize);/* * This function must be called before we read a task's fpstate.
@@ -316,7 +316,7 @@ void fpu__activate_fpstate_write(struct fpu *fpu)*/ void fpu__restore (struct fpu *fpu) { -fpu__activate_curr (fpu); +fpu__initialize (fpu);/* Avoid __kernel_fpu_begin() right after fpregs_activate() */ kernel_fpu_disable ();
@@ -392,7 +392,7 @@ void fpu__clear(struct fpu *fpu)*/ if (static_cpu_has (X86_FEATURE_FPU )) {preempt_disable (); -fpu__activate_curr (fpu); +fpu__initialize (fpu);user_fpu_begin ();copy_init_fpstate_to_fpregs ();preempt_enable ();
arch/x86/kernel/fpu/signal.c +1 -1
@@ -280,7 +280,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)if (!access_ok (VERIFY_READ , buf, size))return -EACCES ; -fpu__activate_curr (fpu); +fpu__initialize (fpu);if (!static_cpu_has (X86_FEATURE_FPU )) return fpregs_soft_set(current, NULL,
arch/x86/kvm/x86.c +1 -1
@@ -7225,7 +7225,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)int r;sigset_t sigsaved; -fpu__activate_curr (fpu); +fpu__initialize (fpu);if (vcpu->sigset_active)sigprocmask (SIG_SETMASK , &vcpu->sigset, &sigsaved);
arch/x86/math-emu/fpu_entry.c +1 -1
@@ -114,7 +114,7 @@ void math_emulate(struct math_emu_info *info)struct desc_struct code_descriptor;struct fpu *fpu = ¤t->thread.fpu; -fpu__activate_curr (fpu); +fpu__initialize (fpu);#ifdef RE_ENTRANT_CHECKING if (emulating) {
PATCH 33/33 x86/fpu: Rename fpu__activate_fpstate_read/write() to fpu__read/write()
In reply to Ingo MolnarAs per the new nomenclature we don't 'activate' the FPU state anymore, we initialize it. So drop the _activate_fpstate name from these functions, which were a bit of a mouthful anyway.
--- arch/x86/include/asm/fpu/internal.h | 4 ++-- arch/x86/kernel/fpu/core.c | 4 ++-- arch/x86/kernel/fpu/regset.c | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-)
arch/x86/include/asm/fpu/internal.h +2 -2
@@ -24,8 +24,8 @@* High level FPU state handling functions: */ extern void fpu__initialize (struct fpu *fpu); -extern void fpu__activate_fpstate_read (struct fpu *fpu); -extern void fpu__activate_fpstate_write (struct fpu *fpu); +extern void fpu__read (struct fpu *fpu); +extern void fpu__write (struct fpu *fpu);extern void fpu__save (struct fpu *fpu);extern void fpu__restore (struct fpu *fpu);extern int fpu__restore_sig (void __user *buf,int ia32_frame);
arch/x86/kernel/fpu/core.c +2 -2
@@ -245,7 +245,7 @@ EXPORT_SYMBOL_GPL(fpu__initialize);* If the task has not used the FPU before then initialize its * fpstate. */ -void fpu__activate_fpstate_read (struct fpu *fpu) +void fpu__read (struct fpu *fpu) {WARN_ON_FPU (fpu == ¤t->thread.fpu);
@@ -272,7 +272,7 @@ void fpu__activate_fpstate_read(struct fpu *fpu)* state pending on its former CPU could be restored, corrupting * the modifications. */ -void fpu__activate_fpstate_write (struct fpu *fpu) +void fpu__write (struct fpu *fpu) {/* * Only stopped child tasks can be used to modify the FPU
arch/x86/kernel/fpu/regset.c +6 -6
@@ -38,7 +38,7 @@ int xfpregs_get(struct task_struct *target, const struct user_regset *regset,if (!boot_cpu_has (X86_FEATURE_FXSR ))return -ENODEV ; -fpu__activate_fpstate_read (fpu); +fpu__read (fpu);fpstate_sanitize_xstate (fpu); return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
@@ -55,7 +55,7 @@ int xfpregs_set(struct task_struct *target, const struct user_regset *regset,if (!boot_cpu_has (X86_FEATURE_FXSR ))return -ENODEV ; -fpu__activate_fpstate_write (fpu); +fpu__write (fpu);fpstate_sanitize_xstate (fpu); ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
@@ -89,7 +89,7 @@ int xstateregs_get(struct task_struct *target, const struct user_regset *regset, xsave = &fpu->state.xsave; -fpu__activate_fpstate_read (fpu); +fpu__read (fpu);if (using_compacted_format ()) {if (kbuf)
@@ -132,7 +132,7 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset, xsave = &fpu->state.xsave; -fpu__activate_fpstate_write (fpu); +fpu__write (fpu);if (using_compacted_format ()) {if (kbuf)
@@ -303,7 +303,7 @@ int fpregs_get(struct task_struct *target, const struct user_regset *regset,struct fpu *fpu = &target->thread.fpu;struct user_i387_ia32_struct env; -fpu__activate_fpstate_read (fpu); +fpu__read (fpu);if (!boot_cpu_has (X86_FEATURE_FPU ))return fpregs_soft_get (target, regset, pos, count, kbuf, ubuf);
@@ -333,7 +333,7 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset,struct user_i387_ia32_struct env;int ret; -fpu__activate_fpstate_write (fpu); +fpu__write (fpu);fpstate_sanitize_xstate (fpu);if (!boot_cpu_has (X86_FEATURE_FPU ))
Signature · 1 line
2.11.0