diff mbox

x86/fpu: move FPU state into separate cache

Message ID 20170329203908.GA39222@beast (mailing list archive)
State New, archived
Headers show

Commit Message

Kees Cook March 29, 2017, 8:39 p.m. UTC
This removes ARCH_WANTS_DYNAMIC_TASK_STRUCT from x86, leaving only s390
still defining this config.

In order to support future structure layout randomization of the
task_struct, none of the structure fields are allowed to have a specific
position or dynamic size. To enable randomization of task_struct on
x86, the FPU state must be moved to its own dynamically sized cache,
and dereferenced from the task_struct.

This change is nearly identical to what was done in grsecurity to support
structure layout randomization. Hopefully I found all the needed changes.
This passes allyesconfig, and boot tests.

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 arch/x86/Kconfig                    |  1 -
 arch/x86/include/asm/fpu/internal.h | 16 ++++++------
 arch/x86/include/asm/fpu/types.h    |  6 +----
 arch/x86/include/asm/processor.h    | 10 +++-----
 arch/x86/include/asm/trace/fpu.h    |  4 +--
 arch/x86/kernel/fpu/core.c          | 31 +++++++++++------------
 arch/x86/kernel/fpu/init.c          | 50 ++-----------------------------------
 arch/x86/kernel/fpu/regset.c        | 24 +++++++++---------
 arch/x86/kernel/fpu/signal.c        | 12 ++++-----
 arch/x86/kernel/fpu/xstate.c        |  6 ++---
 arch/x86/kernel/process.c           | 24 ++++++++++++++++--
 arch/x86/kvm/x86.c                  | 36 ++++++++++++++++----------
 include/linux/sched.h               |  5 ++--
 13 files changed, 100 insertions(+), 125 deletions(-)

Comments

H. Peter Anvin March 29, 2017, 8:45 p.m. UTC | #1
On 03/29/17 13:39, Kees Cook wrote:
> This removes ARCH_WANTS_DYNAMIC_TASK_STRUCT from x86, leaving only s390
> still defining this config.
> 
> In order to support future structure layout randomization of the
> task_struct, none of the structure fields are allowed to have a specific
> position or dynamic size. To enable randomization of task_struct on
> x86, the FPU state must be moved to its own dynamically sized cache,
> and dereferenced from the task_struct.
> 
> This change is nearly identical to what was done in grsecurity to support
> structure layout randomization. Hopefully I found all the needed changes.
> This passes allyesconfig, and boot tests.

Is this really what we want to happen?  It seems much more sane to
simply make them adjacent; they don't need to be part of the same
structure (in practice, there are three objects: thread_info,
task_struct, and the FPU state.)

	-hpa
Kees Cook March 29, 2017, 9:09 p.m. UTC | #2
On Wed, Mar 29, 2017 at 1:45 PM, H. Peter Anvin <hpa@zytor.com> wrote:
> On 03/29/17 13:39, Kees Cook wrote:
>> This removes ARCH_WANTS_DYNAMIC_TASK_STRUCT from x86, leaving only s390
>> still defining this config.
>>
>> In order to support future structure layout randomization of the
>> task_struct, none of the structure fields are allowed to have a specific
>> position or dynamic size. To enable randomization of task_struct on
>> x86, the FPU state must be moved to its own dynamically sized cache,
>> and dereferenced from the task_struct.
>>
>> This change is nearly identical to what was done in grsecurity to support
>> structure layout randomization. Hopefully I found all the needed changes.
>> This passes allyesconfig, and boot tests.
>
> Is this really what we want to happen?  It seems much more sane to
> simply make them adjacent; they don't need to be part of the same
> structure (in practice, there are three objects: thread_info,
> task_struct, and the FPU state.)

They're adjacent already, which poses a problem for the struct layout
randomization plugin, since adjacency may no longer be true (after
layout randomization). This adjacency (or not) isn't really the
problem: it's that FPU state size is only known at runtime. Another
solution would be to have FPU state be a fixed size...

-Kees
Dave Hansen March 29, 2017, 9:19 p.m. UTC | #3
On 03/29/2017 02:09 PM, Kees Cook wrote:
> They're adjacent already, which poses a problem for the struct layout
> randomization plugin, since adjacency may no longer be true (after
> layout randomization). This adjacency (or not) isn't really the
> problem: it's that FPU state size is only known at runtime. Another
> solution would be to have FPU state be a fixed size...

We don't want that.  It varies from a couple hundred bytes to ~3k on
newer CPUs.  We don't want to eat an extra 2.5k per task on the older
processors.
Linus Torvalds March 29, 2017, 9:30 p.m. UTC | #4
On Wed, Mar 29, 2017 at 2:09 PM, Kees Cook <keescook@chromium.org> wrote:
>
> They're adjacent already, which poses a problem for the struct layout
> randomization plugin, since adjacency may no longer be true (after
> layout randomization). T

What?

The layout randomization can't change anything, if you just make the
adjacency be done explicitly instead of by having the thing be a fixed
member.

The trivial model might be to just declare the fpu part as an unsized
array at the end:

        /* Floating point and extended processor state */
        struct fpu              fpu[];

because there is no way in hell that any randomization code can move
those kinds of unsized arrays around. If it does, the gcc plugin is
such unbelievable garbage that it would be insane to depend on such
shit in the first place.

                    Linus
Andy Lutomirski March 29, 2017, 9:35 p.m. UTC | #5
On Wed, Mar 29, 2017 at 2:30 PM, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
> On Wed, Mar 29, 2017 at 2:09 PM, Kees Cook <keescook@chromium.org> wrote:
>>
>> They're adjacent already, which poses a problem for the struct layout
>> randomization plugin, since adjacency may no longer be true (after
>> layout randomization). T
>
> What?
>
> The layout randomization can't change anything, if you just make the
> adjacency be done explicitly instead of by having the thing be a fixed
> member.
>
> The trivial model might be to just declare the fpu part as an unsized
> array at the end:
>
>         /* Floating point and extended processor state */
>         struct fpu              fpu[];
>
> because there is no way in hell that any randomization code can move
> those kinds of unsized arrays around. If it does, the gcc plugin is
> such unbelievable garbage that it would be insane to depend on such
> shit in the first place.
>

Randomization also needs to leave thread_info at the beginning.  Can it do that?
Linus Torvalds March 29, 2017, 9:35 p.m. UTC | #6
On Wed, Mar 29, 2017 at 2:30 PM, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>
> The trivial model might be to just declare the fpu part as an unsized
> array at the end:
>
>         /* Floating point and extended processor state */
>         struct fpu              fpu[];
>
> because there is no way in hell that any randomization code can move
> those kinds of unsized arrays around.

Side note: that approach would seem to have the added advantage that
because "fpu" now is an array, it syntactically acts like a pointer in
C, so now syntactically it's going to be equivalent to having a
"struct fpu *" pointer element, but from an allocation and code
generation standpoint it all is like allocating the fpu structure
together with the task struct.

                 Linus
Linus Torvalds March 29, 2017, 9:41 p.m. UTC | #7
On Wed, Mar 29, 2017 at 2:35 PM, Andy Lutomirski <luto@amacapital.net> wrote:
>
> Randomization also needs to leave thread_info at the beginning.  Can it do that?

Good point, and good question. No idea if the gcc extension can do,
but yes, it clearly needs a "you can't move this entry".

I assume it has some such capability already, because it's fairly
common to have that kind of "beginning of structure if fixed" due to
unions of structures anyway.

                 Linus
H. Peter Anvin March 29, 2017, 10:28 p.m. UTC | #8
On March 29, 2017 2:41:00 PM PDT, Linus Torvalds <torvalds@linux-foundation.org> wrote:
>On Wed, Mar 29, 2017 at 2:35 PM, Andy Lutomirski <luto@amacapital.net>
>wrote:
>>
>> Randomization also needs to leave thread_info at the beginning.  Can
>it do that?
>
>Good point, and good question. No idea if the gcc extension can do,
>but yes, it clearly needs a "you can't move this entry".
>
>I assume it has some such capability already, because it's fairly
>common to have that kind of "beginning of structure if fixed" due to
>unions of structures anyway.
>
>                 Linus

An alternative is to wrap the randomized structure inside a nonrandomized wrapper structure.
Linus Torvalds March 29, 2017, 11:56 p.m. UTC | #9
On Wed, Mar 29, 2017 at 3:28 PM,  <hpa@zytor.com> wrote:
> On March 29, 2017 2:41:00 PM PDT, Linus Torvalds <torvalds@linux-foundation.org> wrote:
>
> An alternative is to wrap the randomized structure inside a nonrandomized wrapper structure.

That's probably a reasonable alternative. Making "struct task_struct"
be something that contains a fixed beginning and end, and just have an
unnamed randomized part in the middle might be the way to go.

Something like

    struct task_struct {
        struct thread_info thread_info;

        /* Critical scheduling state goes here */
        /* .. keep it all in one cacheline */

       struct randomized_task_struct {
            this is where the "I don't care" stuff goes..
       };

        /* CPU-specific state of this task: */
        struct thread_struct            thread;

        /*
         * WARNING: on x86, 'thread_struct' contains a variable-sized
         * structure.  It *MUST* be at the end of 'task_struct'.
         *
         * Do not put anything below here!
         */
    };

would randomize the bulk of it but leave some core stuff at fixed places.

Note that the whole concept of randomized structure member ordering is
largely security theater. It makes different distributions have
different offsets, but practically speaking

 (a) you'll be able to match up offsets with "uname -r", so it's a
slight inconvenience and mostly useless for big distros that would be
common targets (or common IoT targets or whatever)

 (b) any distro that supports some binary modules (which includes a
lot of Android stuff, for example) will have serious problems and
likely turn it off

so it's imnsho a pretty questionable security thing. It's likely most
useful for one-off "special secure installations" than mass
productions.

So I seriously believe that it's useful mainly *only* if it's really
simple and convenient (for both distributions and developers), and
once we have to play games to work around it, I think that's a strong
signal that we shouldn't bother.

                      Linus
Kees Cook March 30, 2017, 1:50 a.m. UTC | #10
On Wed, Mar 29, 2017 at 4:56 PM, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
> On Wed, Mar 29, 2017 at 3:28 PM,  <hpa@zytor.com> wrote:
>> On March 29, 2017 2:41:00 PM PDT, Linus Torvalds <torvalds@linux-foundation.org> wrote:
>>
>> An alternative is to wrap the randomized structure inside a nonrandomized wrapper structure.
>
> That's probably a reasonable alternative. Making "struct task_struct"
> be something that contains a fixed beginning and end, and just have an
> unnamed randomized part in the middle might be the way to go.

That could work. I'll play around with it.

(And to answer from earlier in the thread: yes the plugin handles
trailing "char foo[]" stuff, etc.)

> Something like
>
>     struct task_struct {
>         struct thread_info thread_info;
>
>         /* Critical scheduling state goes here */
>         /* .. keep it all in one cacheline */
>
>        struct randomized_task_struct {
>             this is where the "I don't care" stuff goes..
>        };
>
>         /* CPU-specific state of this task: */
>         struct thread_struct            thread;
>
>         /*
>          * WARNING: on x86, 'thread_struct' contains a variable-sized
>          * structure.  It *MUST* be at the end of 'task_struct'.
>          *
>          * Do not put anything below here!
>          */
>     };
>
> would randomize the bulk of it but leave some core stuff at fixed places.
>
> Note that the whole concept of randomized structure member ordering is
> largely security theater. It makes different distributions have
> different offsets, but practically speaking

Distros, yes, it's just another factor the attack has to look up. For
internally/locally built kernels, though, it becomes an interesting
problem for an attack.

>  (a) you'll be able to match up offsets with "uname -r", so it's a
> slight inconvenience and mostly useless for big distros that would be
> common targets (or common IoT targets or whatever)
>
>  (b) any distro that supports some binary modules (which includes a
> lot of Android stuff, for example) will have serious problems and
> likely turn it off

Ironically, solving "b" for the distro makes solving "a" for the
attacker easier: the random seed is already part of the build output,
so third-party modules can be built against it with the plugin too.
(FWIW, very few Android devices use modular kernels.)

> so it's imnsho a pretty questionable security thing. It's likely most
> useful for one-off "special secure installations" than mass
> productions.

Well, Facebook and Google don't publish their kernel builds. :)

> So I seriously believe that it's useful mainly *only* if it's really
> simple and convenient (for both distributions and developers), and
> once we have to play games to work around it, I think that's a strong
> signal that we shouldn't bother.

Agreed: that's why I'm trying to see what's actually reasonable to do
here. I think randomizing task_struct is still possible. (There are a
few tricky structs, but for most stuff It Just Works.)

-Kees
kernel test robot March 31, 2017, 4:59 a.m. UTC | #11
Hi Kees,

[auto build test ERROR on kvm/linux-next]
[also build test ERROR on v4.11-rc4 next-20170330]
[cannot apply to tip/x86/core]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Kees-Cook/x86-fpu-move-FPU-state-into-separate-cache/20170331-110507
base:   https://git.kernel.org/pub/scm/virt/kvm/kvm.git linux-next
config: i386-randconfig-r0-201713 (attached as .config)
compiler: gcc-5 (Debian 5.4.1-2) 5.4.1 20160904
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All error/warnings (new ones prefixed by >>):

   arch/x86/math-emu/fpu_entry.c: In function 'valid_prefix':
   arch/x86/math-emu/fpu_system.h:50:24: error: request for member 'soft' in something not a structure or union
    #define FPU_info  (I387->soft.info)
                           ^
   include/linux/compiler.h:178:40: note: in definition of macro 'likely'
    # define likely(x) __builtin_expect(!!(x), 1)
                                           ^
   arch/x86/include/asm/uaccess.h:100:10: note: in expansion of macro '__range_not_ok'
     likely(!__range_not_ok(addr, size, user_addr_max()));  \
             ^
   arch/x86/math-emu/fpu_system.h:80:36: note: in expansion of macro 'access_ok'
    #define FPU_access_ok(x,y,z) if ( !access_ok(x,y,z) ) \
                                       ^
   arch/x86/math-emu/fpu_system.h:95:31: note: in expansion of macro 'FPU_access_ok'
    #define FPU_code_access_ok(z) FPU_access_ok(VERIFY_READ,(void __user *)FPU_EIP,z)
                                  ^
   arch/x86/math-emu/fpu_system.h:57:20: note: in expansion of macro 'FPU_info'
    #define FPU_EIP   (FPU_info->regs->ip)
                       ^
   arch/x86/math-emu/fpu_system.h:95:72: note: in expansion of macro 'FPU_EIP'
    #define FPU_code_access_ok(z) FPU_access_ok(VERIFY_READ,(void __user *)FPU_EIP,z)
                                                                           ^
   arch/x86/math-emu/fpu_entry.c:558:2: note: in expansion of macro 'FPU_code_access_ok'
     FPU_code_access_ok(1);
     ^
   In file included from arch/x86/math-emu/fpu_entry.c:35:0:
   arch/x86/math-emu/fpu_system.h:50:24: error: request for member 'soft' in something not a structure or union
    #define FPU_info  (I387->soft.info)
                           ^
   arch/x86/math-emu/fpu_system.h:81:16: note: in expansion of macro 'FPU_info'
        math_abort(FPU_info,SIGSEGV)
                   ^
   arch/x86/math-emu/fpu_system.h:95:31: note: in expansion of macro 'FPU_access_ok'
    #define FPU_code_access_ok(z) FPU_access_ok(VERIFY_READ,(void __user *)FPU_EIP,z)
                                  ^
   arch/x86/math-emu/fpu_entry.c:558:2: note: in expansion of macro 'FPU_code_access_ok'
     FPU_code_access_ok(1);
     ^
   In file included from include/asm-generic/bug.h:4:0,
                    from arch/x86/include/asm/bug.h:35,
                    from include/linux/bug.h:4,
                    from include/linux/signal.h:4,
                    from arch/x86/math-emu/fpu_entry.c:27:
   arch/x86/math-emu/fpu_system.h:50:24: error: request for member 'soft' in something not a structure or union
    #define FPU_info  (I387->soft.info)
                           ^
   include/linux/compiler.h:178:40: note: in definition of macro 'likely'
    # define likely(x) __builtin_expect(!!(x), 1)
                                           ^
   arch/x86/include/asm/uaccess.h:100:10: note: in expansion of macro '__range_not_ok'
     likely(!__range_not_ok(addr, size, user_addr_max()));  \
             ^
   arch/x86/math-emu/fpu_system.h:80:36: note: in expansion of macro 'access_ok'
    #define FPU_access_ok(x,y,z) if ( !access_ok(x,y,z) ) \
                                       ^
   arch/x86/math-emu/fpu_system.h:95:31: note: in expansion of macro 'FPU_access_ok'
    #define FPU_code_access_ok(z) FPU_access_ok(VERIFY_READ,(void __user *)FPU_EIP,z)
                                  ^
   arch/x86/math-emu/fpu_system.h:57:20: note: in expansion of macro 'FPU_info'
    #define FPU_EIP   (FPU_info->regs->ip)
                       ^
   arch/x86/math-emu/fpu_system.h:95:72: note: in expansion of macro 'FPU_EIP'
    #define FPU_code_access_ok(z) FPU_access_ok(VERIFY_READ,(void __user *)FPU_EIP,z)
                                                                           ^
   arch/x86/math-emu/fpu_entry.c:602:4: note: in expansion of macro 'FPU_code_access_ok'
       FPU_code_access_ok(1);
       ^
   In file included from arch/x86/math-emu/fpu_entry.c:35:0:
   arch/x86/math-emu/fpu_system.h:50:24: error: request for member 'soft' in something not a structure or union
    #define FPU_info  (I387->soft.info)
                           ^
   arch/x86/math-emu/fpu_system.h:81:16: note: in expansion of macro 'FPU_info'
        math_abort(FPU_info,SIGSEGV)
                   ^
   arch/x86/math-emu/fpu_system.h:95:31: note: in expansion of macro 'FPU_access_ok'
    #define FPU_code_access_ok(z) FPU_access_ok(VERIFY_READ,(void __user *)FPU_EIP,z)
                                  ^
   arch/x86/math-emu/fpu_entry.c:602:4: note: in expansion of macro 'FPU_code_access_ok'
       FPU_code_access_ok(1);
       ^
   arch/x86/math-emu/fpu_entry.c: In function 'math_abort':
   arch/x86/math-emu/fpu_system.h:50:24: error: request for member 'soft' in something not a structure or union
    #define FPU_info  (I387->soft.info)
                           ^
   arch/x86/math-emu/fpu_system.h:57:20: note: in expansion of macro 'FPU_info'
    #define FPU_EIP   (FPU_info->regs->ip)
                       ^
   arch/x86/math-emu/fpu_entry.c:626:2: note: in expansion of macro 'FPU_EIP'
     FPU_EIP = FPU_ORIG_EIP;
     ^
   arch/x86/math-emu/fpu_system.h:50:24: error: request for member 'soft' in something not a structure or union
    #define FPU_info  (I387->soft.info)
                           ^
   arch/x86/math-emu/fpu_system.h:58:24: note: in expansion of macro 'FPU_info'
    #define FPU_ORIG_EIP  (FPU_info->___orig_eip)
                           ^
   arch/x86/math-emu/fpu_entry.c:626:12: note: in expansion of macro 'FPU_ORIG_EIP'
     FPU_EIP = FPU_ORIG_EIP;
               ^
   arch/x86/math-emu/fpu_entry.c: In function 'fpregs_soft_set':
>> arch/x86/math-emu/fpu_entry.c:646:55: error: request for member 'soft' in something not a structure or union
     struct swregs_state *s387 = &target->thread.fpu.state.soft;
                                                          ^
   arch/x86/math-emu/fpu_entry.c: In function 'fpregs_soft_get':
   arch/x86/math-emu/fpu_entry.c:698:55: error: request for member 'soft' in something not a structure or union
     struct swregs_state *s387 = &target->thread.fpu.state.soft;
                                                          ^
--
      ^
   arch/x86/math-emu/errors.c: In function 'set_precision_flag_down':
   arch/x86/math-emu/fpu_system.h:72:28: error: request for member 'soft' in something not a structure or union
    #define control_word  (I387->soft.cwd)
                               ^
   arch/x86/math-emu/errors.c:553:6: note: in expansion of macro 'control_word'
     if (control_word & CW_Precision) { /* The masked response */
         ^
   arch/x86/math-emu/fpu_system.h:71:30: error: request for member 'soft' in something not a structure or union
    #define partial_status  (I387->soft.swd)
                                 ^
   arch/x86/math-emu/errors.c:554:3: note: in expansion of macro 'partial_status'
      partial_status &= ~SW_C1;
      ^
   arch/x86/math-emu/fpu_system.h:71:30: error: request for member 'soft' in something not a structure or union
    #define partial_status  (I387->soft.swd)
                                 ^
   arch/x86/math-emu/errors.c:555:3: note: in expansion of macro 'partial_status'
      partial_status |= SW_Precision;
      ^
   arch/x86/math-emu/errors.c: In function 'denormal_operand':
   arch/x86/math-emu/fpu_system.h:72:28: error: request for member 'soft' in something not a structure or union
    #define control_word  (I387->soft.cwd)
                               ^
   arch/x86/math-emu/errors.c:562:6: note: in expansion of macro 'control_word'
     if (control_word & CW_Denormal) { /* The masked response */
         ^
   arch/x86/math-emu/fpu_system.h:71:30: error: request for member 'soft' in something not a structure or union
    #define partial_status  (I387->soft.swd)
                                 ^
   arch/x86/math-emu/errors.c:563:3: note: in expansion of macro 'partial_status'
      partial_status |= SW_Denorm_Op;
      ^
   arch/x86/math-emu/errors.c: In function 'arith_overflow':
   arch/x86/math-emu/fpu_system.h:72:28: error: request for member 'soft' in something not a structure or union
    #define control_word  (I387->soft.cwd)
                               ^
   arch/x86/math-emu/errors.c:575:6: note: in expansion of macro 'control_word'
     if (control_word & CW_Overflow) {
         ^
   arch/x86/math-emu/fpu_system.h:72:28: error: request for member 'soft' in something not a structure or union
    #define control_word  (I387->soft.cwd)
                               ^
   arch/x86/math-emu/errors.c:586:6: note: in expansion of macro 'control_word'
     if (control_word & CW_Overflow) {
         ^
   arch/x86/math-emu/errors.c: In function 'arith_underflow':
   arch/x86/math-emu/fpu_system.h:72:28: error: request for member 'soft' in something not a structure or union
    #define control_word  (I387->soft.cwd)
                               ^
   arch/x86/math-emu/errors.c:603:6: note: in expansion of macro 'control_word'
     if (control_word & CW_Underflow) {
         ^
   arch/x86/math-emu/fpu_system.h:71:30: error: request for member 'soft' in something not a structure or union
    #define partial_status  (I387->soft.swd)
                                 ^
   arch/x86/math-emu/errors.c:607:4: note: in expansion of macro 'partial_status'
       partial_status &= ~SW_C1; /* Round down. */
       ^
   arch/x86/math-emu/fpu_system.h:72:28: error: request for member 'soft' in something not a structure or union
    #define control_word  (I387->soft.cwd)
                               ^
   arch/x86/math-emu/errors.c:618:6: note: in expansion of macro 'control_word'
     if (control_word & CW_Underflow) {
         ^
   arch/x86/math-emu/errors.c: In function 'FPU_stack_overflow':
   arch/x86/math-emu/fpu_system.h:72:28: error: request for member 'soft' in something not a structure or union
    #define control_word  (I387->soft.cwd)
                               ^
   arch/x86/math-emu/errors.c:631:6: note: in expansion of macro 'control_word'
     if (control_word & CW_Invalid) {
         ^
   arch/x86/math-emu/fpu_system.h:75:20: error: request for member 'soft' in something not a structure or union
    #define top   (I387->soft.ftop)
                       ^
   arch/x86/math-emu/errors.c:633:3: note: in expansion of macro 'top'
      top--;
      ^
   arch/x86/math-emu/errors.c: In function 'FPU_stack_underflow':
   arch/x86/math-emu/fpu_system.h:72:28: error: request for member 'soft' in something not a structure or union
    #define control_word  (I387->soft.cwd)
                               ^
   arch/x86/math-emu/errors.c:646:6: note: in expansion of macro 'control_word'
     if (control_word & CW_Invalid) {
         ^
   arch/x86/math-emu/errors.c: In function 'FPU_stack_underflow_i':
   arch/x86/math-emu/fpu_system.h:72:28: error: request for member 'soft' in something not a structure or union
    #define control_word  (I387->soft.cwd)
                               ^
   arch/x86/math-emu/errors.c:660:6: note: in expansion of macro 'control_word'
     if (control_word & CW_Invalid) {
         ^
   arch/x86/math-emu/errors.c: In function 'FPU_stack_underflow_pop':
   arch/x86/math-emu/fpu_system.h:72:28: error: request for member 'soft' in something not a structure or union
    #define control_word  (I387->soft.cwd)
                               ^
   arch/x86/math-emu/errors.c:674:6: note: in expansion of macro 'control_word'
     if (control_word & CW_Invalid) {
         ^
   arch/x86/math-emu/errors.c: In function 'real_1op_NaN':
>> arch/x86/math-emu/errors.c:407:1: warning: control reaches end of non-void function [-Wreturn-type]
    }
    ^
   arch/x86/math-emu/errors.c: In function 'real_2op_NaN':
   arch/x86/math-emu/errors.c:491:1: warning: control reaches end of non-void function [-Wreturn-type]
    }
    ^
   arch/x86/math-emu/errors.c: In function 'arith_invalid':
   arch/x86/math-emu/errors.c:507:1: warning: control reaches end of non-void function [-Wreturn-type]
    }
    ^
   arch/x86/math-emu/errors.c: In function 'FPU_divide_by_zero':
   arch/x86/math-emu/errors.c:526:1: warning: control reaches end of non-void function [-Wreturn-type]
    }
    ^
   arch/x86/math-emu/errors.c: In function 'set_precision_flag':
   arch/x86/math-emu/errors.c:539:1: warning: control reaches end of non-void function [-Wreturn-type]
    }
    ^
   arch/x86/math-emu/errors.c: In function 'denormal_operand':
   arch/x86/math-emu/errors.c:569:1: warning: control reaches end of non-void function [-Wreturn-type]
    }
    ^
--
   In file included from arch/x86/math-emu/fpu_aux.c:13:0:
   arch/x86/math-emu/status_w.h: In function 'setcc':
   arch/x86/math-emu/fpu_system.h:71:30: error: request for member 'soft' in something not a structure or union
    #define partial_status  (I387->soft.swd)
                                 ^
   arch/x86/math-emu/status_w.h:53:2: note: in expansion of macro 'partial_status'
     partial_status &= ~(SW_C0 | SW_C1 | SW_C2 | SW_C3);
     ^
   arch/x86/math-emu/fpu_system.h:71:30: error: request for member 'soft' in something not a structure or union
    #define partial_status  (I387->soft.swd)
                                 ^
   arch/x86/math-emu/status_w.h:54:2: note: in expansion of macro 'partial_status'
     partial_status |= (cc) & (SW_C0 | SW_C1 | SW_C2 | SW_C3);
     ^
   arch/x86/math-emu/fpu_aux.c: In function 'fclex':
   arch/x86/math-emu/fpu_system.h:71:30: error: request for member 'soft' in something not a structure or union
    #define partial_status  (I387->soft.swd)
                                 ^
   arch/x86/math-emu/fpu_aux.c:25:2: note: in expansion of macro 'partial_status'
     partial_status &=
     ^
   arch/x86/math-emu/fpu_system.h:64:41: error: request for member 'soft' in something not a structure or union
    #define no_ip_update  (*(u_char *)&(I387->soft.no_update))
                                            ^
   arch/x86/math-emu/fpu_aux.c:29:2: note: in expansion of macro 'no_ip_update'
     no_ip_update = 1;
     ^
   arch/x86/math-emu/fpu_aux.c: In function 'finit':
>> arch/x86/math-emu/fpu_aux.c:55:46: error: request for member 'soft' in something not a structure or union
     fpstate_init_soft(&current->thread.fpu.state.soft);
                                                 ^
   In file included from arch/x86/math-emu/fpu_aux.c:13:0:
   arch/x86/math-emu/fpu_aux.c: In function 'finit_':
   arch/x86/math-emu/fpu_system.h:65:36: error: request for member 'soft' in something not a structure or union
    #define FPU_rm   (*(u_char *)&(I387->soft.rm))
                                       ^
   arch/x86/math-emu/fpu_aux.c:72:15: note: in expansion of macro 'FPU_rm'
     (finit_table[FPU_rm]) ();
                  ^
   arch/x86/math-emu/fpu_aux.c: In function 'fstsw_ax':
   arch/x86/math-emu/fpu_system.h:50:24: error: request for member 'soft' in something not a structure or union
    #define FPU_info  (I387->soft.info)
                           ^
   arch/x86/math-emu/fpu_system.h:55:20: note: in expansion of macro 'FPU_info'
    #define FPU_EAX   (FPU_info->regs->ax)
                       ^
   arch/x86/math-emu/fpu_aux.c:77:13: note: in expansion of macro 'FPU_EAX'
     *(short *)&FPU_EAX = status_word();
                ^
   arch/x86/math-emu/fpu_system.h:71:30: error: request for member 'soft' in something not a structure or union
    #define partial_status  (I387->soft.swd)
                                 ^
   arch/x86/math-emu/status_w.h:50:5: note: in expansion of macro 'partial_status'
      ((partial_status & ~SW_Top & 0xffff) | ((top << SW_Top_Shift) & SW_Top))
        ^
   arch/x86/math-emu/fpu_aux.c:77:23: note: in expansion of macro 'status_word'
     *(short *)&FPU_EAX = status_word();
                          ^
   arch/x86/math-emu/fpu_system.h:75:20: error: request for member 'soft' in something not a structure or union
    #define top   (I387->soft.ftop)
                       ^
   arch/x86/math-emu/status_w.h:50:44: note: in expansion of macro 'top'
      ((partial_status & ~SW_Top & 0xffff) | ((top << SW_Top_Shift) & SW_Top))
                                               ^
   arch/x86/math-emu/fpu_aux.c:77:23: note: in expansion of macro 'status_word'
     *(short *)&FPU_EAX = status_word();
                          ^
   arch/x86/math-emu/fpu_system.h:64:41: error: request for member 'soft' in something not a structure or union
    #define no_ip_update  (*(u_char *)&(I387->soft.no_update))
                                            ^
   arch/x86/math-emu/fpu_aux.c:78:2: note: in expansion of macro 'no_ip_update'
     no_ip_update = 1;
     ^
   arch/x86/math-emu/fpu_aux.c: In function 'fstsw_':
   arch/x86/math-emu/fpu_system.h:65:36: error: request for member 'soft' in something not a structure or union
    #define FPU_rm   (*(u_char *)&(I387->soft.rm))
                                       ^
   arch/x86/math-emu/fpu_aux.c:88:15: note: in expansion of macro 'FPU_rm'
     (fstsw_table[FPU_rm]) ();
                  ^
   arch/x86/math-emu/fpu_aux.c: In function 'fp_nop':
   arch/x86/math-emu/fpu_system.h:65:36: error: request for member 'soft' in something not a structure or union
    #define FPU_rm   (*(u_char *)&(I387->soft.rm))
                                       ^
   arch/x86/math-emu/fpu_aux.c:98:16: note: in expansion of macro 'FPU_rm'
     (fp_nop_table[FPU_rm]) ();
                   ^
   arch/x86/math-emu/fpu_aux.c: In function 'fld_i_':
   arch/x86/math-emu/fpu_system.h:65:36: error: request for member 'soft' in something not a structure or union
    #define FPU_rm   (*(u_char *)&(I387->soft.rm))
                                       ^
   arch/x86/math-emu/fpu_aux.c:113:6: note: in expansion of macro 'FPU_rm'
     i = FPU_rm;
         ^
   arch/x86/math-emu/fpu_system.h:74:25: error: request for member 'soft' in something not a structure or union
    #define registers  (I387->soft.st_space)
                            ^
   arch/x86/math-emu/fpu_emu.h:144:35: note: in expansion of macro 'registers'
    #define register_base ((u_char *) registers )
                                      ^
   arch/x86/math-emu/fpu_emu.h:146:38: note: in expansion of macro 'register_base'
    #define st(x)      ( * ((FPU_REG *)( register_base + 10 * ((top+x) & 7) )) )
                                         ^
   arch/x86/math-emu/fpu_aux.c:115:13: note: in expansion of macro 'st'
      reg_copy(&st(i), st_new_ptr);
                ^
   arch/x86/math-emu/fpu_system.h:75:20: error: request for member 'soft' in something not a structure or union
    #define top   (I387->soft.ftop)
                       ^
   arch/x86/math-emu/fpu_emu.h:146:61: note: in expansion of macro 'top'
    #define st(x)      ( * ((FPU_REG *)( register_base + 10 * ((top+x) & 7) )) )
                                                                ^
   arch/x86/math-emu/fpu_aux.c:115:13: note: in expansion of macro 'st'
      reg_copy(&st(i), st_new_ptr);
                ^
   arch/x86/math-emu/fpu_system.h:75:20: error: request for member 'soft' in something not a structure or union
    #define top   (I387->soft.ftop)
                       ^
   arch/x86/math-emu/fpu_emu.h:156:18: note: in expansion of macro 'top'
    #define push() { top--; }
                     ^
   arch/x86/math-emu/fpu_aux.c:117:3: note: in expansion of macro 'push'
      push();
      ^
   arch/x86/math-emu/fpu_system.h:72:28: error: request for member 'soft' in something not a structure or union
    #define control_word  (I387->soft.cwd)
                               ^
   arch/x86/math-emu/fpu_aux.c:120:7: note: in expansion of macro 'control_word'
      if (control_word & CW_Invalid) {
..

vim +/soft +646 arch/x86/math-emu/fpu_entry.c

^1da177e arch/i386/math-emu/fpu_entry.c Linus Torvalds    2005-04-16  620  		}
^1da177e arch/i386/math-emu/fpu_entry.c Linus Torvalds    2005-04-16  621  	}
^1da177e arch/i386/math-emu/fpu_entry.c Linus Torvalds    2005-04-16  622  }
^1da177e arch/i386/math-emu/fpu_entry.c Linus Torvalds    2005-04-16  623  
ae6af41f arch/x86/math-emu/fpu_entry.c  Tejun Heo         2009-02-09  624  void math_abort(struct math_emu_info *info, unsigned int signal)
^1da177e arch/i386/math-emu/fpu_entry.c Linus Torvalds    2005-04-16  625  {
^1da177e arch/i386/math-emu/fpu_entry.c Linus Torvalds    2005-04-16 @626  	FPU_EIP = FPU_ORIG_EIP;
51e7dc70 arch/x86/math-emu/fpu_entry.c  Srikar Dronamraju 2012-03-12  627  	current->thread.trap_nr = X86_TRAP_MF;
^1da177e arch/i386/math-emu/fpu_entry.c Linus Torvalds    2005-04-16  628  	current->thread.error_code = 0;
^1da177e arch/i386/math-emu/fpu_entry.c Linus Torvalds    2005-04-16  629  	send_sig(signal, current, 1);
^1da177e arch/i386/math-emu/fpu_entry.c Linus Torvalds    2005-04-16  630  	RE_ENTRANT_CHECK_OFF;
^1da177e arch/i386/math-emu/fpu_entry.c Linus Torvalds    2005-04-16  631        __asm__("movl %0,%%esp ; ret": :"g"(((long)info) - 4));
^1da177e arch/i386/math-emu/fpu_entry.c Linus Torvalds    2005-04-16  632  #ifdef PARANOID
^1da177e arch/i386/math-emu/fpu_entry.c Linus Torvalds    2005-04-16  633  	printk("ERROR: wm-FPU-emu math_abort failed!\n");
^1da177e arch/i386/math-emu/fpu_entry.c Linus Torvalds    2005-04-16  634  #endif /* PARANOID */
^1da177e arch/i386/math-emu/fpu_entry.c Linus Torvalds    2005-04-16  635  }
^1da177e arch/i386/math-emu/fpu_entry.c Linus Torvalds    2005-04-16  636  
c47ada30 arch/x86/math-emu/fpu_entry.c  Ingo Molnar       2015-04-30  637  #define S387 ((struct swregs_state *)s387)
^1da177e arch/i386/math-emu/fpu_entry.c Linus Torvalds    2005-04-16  638  #define sstatus_word() \
^1da177e arch/i386/math-emu/fpu_entry.c Linus Torvalds    2005-04-16  639    ((S387->swd & ~SW_Top & 0xffff) | ((S387->ftop << SW_Top_Shift) & SW_Top))
^1da177e arch/i386/math-emu/fpu_entry.c Linus Torvalds    2005-04-16  640  
ff0ebb23 arch/x86/math-emu/fpu_entry.c  Roland McGrath    2008-01-30  641  int fpregs_soft_set(struct task_struct *target,
ff0ebb23 arch/x86/math-emu/fpu_entry.c  Roland McGrath    2008-01-30  642  		    const struct user_regset *regset,
ff0ebb23 arch/x86/math-emu/fpu_entry.c  Roland McGrath    2008-01-30  643  		    unsigned int pos, unsigned int count,
ff0ebb23 arch/x86/math-emu/fpu_entry.c  Roland McGrath    2008-01-30  644  		    const void *kbuf, const void __user *ubuf)
^1da177e arch/i386/math-emu/fpu_entry.c Linus Torvalds    2005-04-16  645  {
c47ada30 arch/x86/math-emu/fpu_entry.c  Ingo Molnar       2015-04-30 @646  	struct swregs_state *s387 = &target->thread.fpu.state.soft;
ff0ebb23 arch/x86/math-emu/fpu_entry.c  Roland McGrath    2008-01-30  647  	void *space = s387->st_space;
ff0ebb23 arch/x86/math-emu/fpu_entry.c  Roland McGrath    2008-01-30  648  	int ret;
^1da177e arch/i386/math-emu/fpu_entry.c Linus Torvalds    2005-04-16  649  	int offset, other, i, tags, regnr, tag, newtop;

:::::: The code at line 646 was first introduced by commit
:::::: c47ada305de3803517ae64aa50686f644c5456fa x86/fpu: Harmonize FPU register state types

:::::: TO: Ingo Molnar <mingo@kernel.org>
:::::: CC: Ingo Molnar <mingo@kernel.org>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
kernel test robot March 31, 2017, 5:57 a.m. UTC | #12
Hi Kees,

[auto build test ERROR on kvm/linux-next]
[also build test ERROR on v4.11-rc4 next-20170330]
[cannot apply to tip/x86/core]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Kees-Cook/x86-fpu-move-FPU-state-into-separate-cache/20170331-110507
base:   https://git.kernel.org/pub/scm/virt/kvm/kvm.git linux-next
config: i386-randconfig-s0-201713 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All error/warnings (new ones prefixed by >>):

   In file included from arch/x86/include/asm/cpufeature.h:4:0,
                    from arch/x86/include/asm/thread_info.h:52,
                    from include/linux/thread_info.h:25,
                    from arch/x86/include/asm/preempt.h:6,
                    from include/linux/preempt.h:80,
                    from include/linux/spinlock.h:50,
                    from include/linux/rcupdate.h:38,
                    from include/linux/init_task.h:4,
                    from init/init_task.c:1:
>> arch/x86/include/asm/processor.h:805:17: error: 'init_fpregs_state' undeclared here (not in a function)
     .fpu.state  = &init_fpregs_state,     \
                    ^
>> include/linux/init_task.h:255:13: note: in expansion of macro 'INIT_THREAD'
     .thread  = INIT_THREAD,     \
                ^~~~~~~~~~~
>> init/init_task.c:19:32: note: in expansion of macro 'INIT_TASK'
    struct task_struct init_task = INIT_TASK(init_task);
                                   ^~~~~~~~~
--
   In file included from arch/x86/math-emu/fpu_entry.c:35:0:
   arch/x86/math-emu/status_w.h: In function 'setcc':
>> arch/x86/math-emu/fpu_system.h:71:30: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define partial_status  (I387->soft.swd)
                                 ^
     ->
>> arch/x86/math-emu/status_w.h:53:2: note: in expansion of macro 'partial_status'
     partial_status &= ~(SW_C0 | SW_C1 | SW_C2 | SW_C3);
     ^~~~~~~~~~~~~~
>> arch/x86/math-emu/fpu_system.h:71:30: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define partial_status  (I387->soft.swd)
                                 ^
     ->
   arch/x86/math-emu/status_w.h:54:2: note: in expansion of macro 'partial_status'
     partial_status |= (cc) & (SW_C0 | SW_C1 | SW_C2 | SW_C3);
     ^~~~~~~~~~~~~~
   arch/x86/math-emu/fpu_entry.c: In function 'math_emulate':
   arch/x86/math-emu/fpu_system.h:50:24: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define FPU_info  (I387->soft.info)
                           ^
     ->
>> arch/x86/math-emu/fpu_entry.c:126:2: note: in expansion of macro 'FPU_info'
     FPU_info = info;
     ^~~~~~~~
   arch/x86/math-emu/fpu_system.h:50:24: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define FPU_info  (I387->soft.info)
                           ^
     ->
>> arch/x86/math-emu/fpu_system.h:58:24: note: in expansion of macro 'FPU_info'
    #define FPU_ORIG_EIP  (FPU_info->___orig_eip)
                           ^~~~~~~~
>> arch/x86/math-emu/fpu_entry.c:128:2: note: in expansion of macro 'FPU_ORIG_EIP'
     FPU_ORIG_EIP = FPU_EIP;
     ^~~~~~~~~~~~
   arch/x86/math-emu/fpu_system.h:50:24: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define FPU_info  (I387->soft.info)
                           ^
                    ->
   arch/x86/math-emu/fpu_system.h:57:20: note: in expansion of macro 'FPU_info'
    #define FPU_EIP   (FPU_info->regs->ip)
                       ^~~~~~~~
>> arch/x86/math-emu/fpu_entry.c:128:17: note: in expansion of macro 'FPU_EIP'
     FPU_ORIG_EIP = FPU_EIP;
                    ^~~~~~~
   arch/x86/math-emu/fpu_system.h:50:24: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define FPU_info  (I387->soft.info)
                           ^
          ->
   arch/x86/math-emu/fpu_system.h:56:22: note: in expansion of macro 'FPU_info'
    #define FPU_EFLAGS  (FPU_info->regs->flags)
                         ^~~~~~~~
>> arch/x86/math-emu/fpu_entry.c:130:7: note: in expansion of macro 'FPU_EFLAGS'
     if ((FPU_EFLAGS & 0x00020000) != 0) {
          ^~~~~~~~~~
   arch/x86/math-emu/fpu_system.h:50:24: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define FPU_info  (I387->soft.info)
                           ^
      ->
   arch/x86/math-emu/fpu_system.h:57:20: note: in expansion of macro 'FPU_info'
    #define FPU_EIP   (FPU_info->regs->ip)
                       ^~~~~~~~
   arch/x86/math-emu/fpu_entry.c:133:3: note: in expansion of macro 'FPU_EIP'
      FPU_EIP += code_base = FPU_CS << 4;
      ^~~~~~~
   arch/x86/math-emu/fpu_system.h:50:24: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define FPU_info  (I387->soft.info)
                           ^
                             ->
   arch/x86/math-emu/fpu_system.h:52:41: note: in expansion of macro 'FPU_info'
    #define FPU_CS   (*(unsigned short *) &(FPU_info->regs->cs))
                                            ^~~~~~~~
>> arch/x86/math-emu/fpu_entry.c:133:26: note: in expansion of macro 'FPU_CS'
      FPU_EIP += code_base = FPU_CS << 4;
                             ^~~~~~
   arch/x86/math-emu/fpu_system.h:50:24: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define FPU_info  (I387->soft.info)
                           ^
                ->
   arch/x86/math-emu/fpu_system.h:52:41: note: in expansion of macro 'FPU_info'
    #define FPU_CS   (*(unsigned short *) &(FPU_info->regs->cs))
                                            ^~~~~~~~
   arch/x86/math-emu/fpu_entry.c:135:13: note: in expansion of macro 'FPU_CS'
     } else if (FPU_CS == __USER_CS && FPU_DS == __USER_DS) {
                ^~~~~~
   arch/x86/math-emu/fpu_system.h:50:24: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define FPU_info  (I387->soft.info)
                           ^
                                       ->
   arch/x86/math-emu/fpu_system.h:54:41: note: in expansion of macro 'FPU_info'
    #define FPU_DS   (*(unsigned short *) &(FPU_info->regs->ds))
                                            ^~~~~~~~
>> arch/x86/math-emu/fpu_entry.c:135:36: note: in expansion of macro 'FPU_DS'
     } else if (FPU_CS == __USER_CS && FPU_DS == __USER_DS) {
                                       ^~~~~~
   arch/x86/math-emu/fpu_system.h:50:24: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define FPU_info  (I387->soft.info)
                           ^
                ->
   arch/x86/math-emu/fpu_system.h:52:41: note: in expansion of macro 'FPU_info'
    #define FPU_CS   (*(unsigned short *) &(FPU_info->regs->cs))
                                            ^~~~~~~~
   arch/x86/math-emu/fpu_entry.c:137:13: note: in expansion of macro 'FPU_CS'
     } else if (FPU_CS == __KERNEL_CS) {
                ^~~~~~
   arch/x86/math-emu/fpu_system.h:50:24: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define FPU_info  (I387->soft.info)
                           ^
                                           ->
   arch/x86/math-emu/fpu_system.h:52:41: note: in expansion of macro 'FPU_info'
    #define FPU_CS   (*(unsigned short *) &(FPU_info->regs->cs))
                                            ^~~~~~~~
   arch/x86/math-emu/fpu_entry.c:138:40: note: in expansion of macro 'FPU_CS'
      printk("math_emulate: %04x:%08lx\n", FPU_CS, FPU_EIP);
                                           ^~~~~~
   arch/x86/math-emu/fpu_system.h:50:24: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define FPU_info  (I387->soft.info)
                           ^
                                                   ->
   arch/x86/math-emu/fpu_system.h:57:20: note: in expansion of macro 'FPU_info'
    #define FPU_EIP   (FPU_info->regs->ip)
                       ^~~~~~~~
   arch/x86/math-emu/fpu_entry.c:138:48: note: in expansion of macro 'FPU_EIP'
      printk("math_emulate: %04x:%08lx\n", FPU_CS, FPU_EIP);
                                                   ^~~~~~~
   arch/x86/math-emu/fpu_system.h:50:24: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define FPU_info  (I387->soft.info)
                           ^
           ->
   arch/x86/math-emu/fpu_system.h:52:41: note: in expansion of macro 'FPU_info'
    #define FPU_CS   (*(unsigned short *) &(FPU_info->regs->cs))
                                            ^~~~~~~~
   arch/x86/math-emu/fpu_entry.c:142:8: note: in expansion of macro 'FPU_CS'
      if ((FPU_CS & 4) != 4) { /* Must be in the LDT */
           ^~~~~~
   arch/x86/math-emu/fpu_system.h:50:24: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define FPU_info  (I387->soft.info)
                           ^
                  ->
   arch/x86/math-emu/fpu_entry.c:146:15: note: in expansion of macro 'FPU_info'
       math_abort(FPU_info, SIGILL);
                  ^~~~~~~~
   arch/x86/math-emu/fpu_system.h:50:24: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define FPU_info  (I387->soft.info)
                           ^
                                               ->
   arch/x86/math-emu/fpu_system.h:52:41: note: in expansion of macro 'FPU_info'
    #define FPU_CS   (*(unsigned short *) &(FPU_info->regs->cs))
                                            ^~~~~~~~
   arch/x86/math-emu/fpu_entry.c:149:44: note: in expansion of macro 'FPU_CS'
      code_descriptor = FPU_get_ldt_descriptor(FPU_CS);
                                               ^~~~~~
   arch/x86/math-emu/fpu_system.h:50:24: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define FPU_info  (I387->soft.info)
                           ^
      ->
   arch/x86/math-emu/fpu_system.h:57:20: note: in expansion of macro 'FPU_info'
    #define FPU_EIP   (FPU_info->regs->ip)
                       ^~~~~~~~
   arch/x86/math-emu/fpu_entry.c:158:3: note: in expansion of macro 'FPU_EIP'
      FPU_EIP += code_base = SEG_BASE_ADDR(code_descriptor);
      ^~~~~~~
   arch/x86/math-emu/fpu_system.h:60:38: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define FPU_lookahead           (I387->soft.lookahead)
                                         ^
     ->
>> arch/x86/math-emu/fpu_entry.c:167:2: note: in expansion of macro 'FPU_lookahead'
     FPU_lookahead = !(FPU_EFLAGS & X86_EFLAGS_TF);
     ^~~~~~~~~~~~~
   arch/x86/math-emu/fpu_system.h:50:24: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define FPU_info  (I387->soft.info)
                           ^
                       ->
   arch/x86/math-emu/fpu_system.h:56:22: note: in expansion of macro 'FPU_info'
    #define FPU_EFLAGS  (FPU_info->regs->flags)
                         ^~~~~~~~
   arch/x86/math-emu/fpu_entry.c:167:20: note: in expansion of macro 'FPU_EFLAGS'
     FPU_lookahead = !(FPU_EFLAGS & X86_EFLAGS_TF);
                       ^~~~~~~~~~
   arch/x86/math-emu/fpu_system.h:50:24: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define FPU_info  (I387->soft.info)
                           ^
                                                    ->
   arch/x86/math-emu/fpu_system.h:57:20: note: in expansion of macro 'FPU_info'
    #define FPU_EIP   (FPU_info->regs->ip)
                       ^~~~~~~~
   arch/x86/math-emu/fpu_entry.c:169:49: note: in expansion of macro 'FPU_EIP'
     if (!valid_prefix(&byte1, (u_char __user **) & FPU_EIP,
                                                    ^~~~~~~
   arch/x86/math-emu/fpu_system.h:50:24: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define FPU_info  (I387->soft.info)
                           ^
                 ->
   arch/x86/math-emu/fpu_entry.c:178:14: note: in expansion of macro 'FPU_info'
      math_abort(FPU_info, SIGILL);
                 ^~~~~~~~
   arch/x86/math-emu/fpu_system.h:64:41: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define no_ip_update  (*(u_char *)&(I387->soft.no_update))
                                            ^
     ->
>> arch/x86/math-emu/fpu_entry.c:183:2: note: in expansion of macro 'no_ip_update'
     no_ip_update = 0;
     ^~~~~~~~~~~~
   arch/x86/math-emu/fpu_system.h:50:24: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define FPU_info  (I387->soft.info)
                           ^
     ->
   arch/x86/math-emu/fpu_system.h:57:20: note: in expansion of macro 'FPU_info'
    #define FPU_EIP   (FPU_info->regs->ip)
                       ^~~~~~~~
   arch/x86/math-emu/fpu_entry.c:185:2: note: in expansion of macro 'FPU_EIP'
     FPU_EIP++;  /* We have fetched the prefix and first code bytes. */
     ^~~~~~~
   arch/x86/math-emu/fpu_system.h:50:24: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define FPU_info  (I387->soft.info)
                           ^
          ->
   arch/x86/math-emu/fpu_system.h:57:20: note: in expansion of macro 'FPU_info'
    #define FPU_EIP   (FPU_info->regs->ip)
                       ^~~~~~~~
   arch/x86/math-emu/fpu_entry.c:190:7: note: in expansion of macro 'FPU_EIP'
      if (FPU_EIP > code_limit)
          ^~~~~~~
   arch/x86/math-emu/fpu_system.h:50:24: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define FPU_info  (I387->soft.info)
                           ^
                  ->
   arch/x86/math-emu/fpu_entry.c:191:15: note: in expansion of macro 'FPU_info'
       math_abort(FPU_info, SIGSEGV);
                  ^~~~~~~~
>> arch/x86/math-emu/fpu_system.h:71:30: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define partial_status  (I387->soft.swd)
                                 ^
           ->
>> arch/x86/math-emu/fpu_entry.c:196:8: note: in expansion of macro 'partial_status'
       if (partial_status & SW_Summary)
           ^~~~~~~~~~~~~~
   arch/x86/math-emu/fpu_system.h:50:24: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define FPU_info  (I387->soft.info)
                           ^
                 ->
   arch/x86/math-emu/fpu_entry.c:203:14: note: in expansion of macro 'FPU_info'
      math_abort(FPU_info, SIGILL);
                 ^~~~~~~~
   In file included from include/asm-generic/bug.h:4:0,
                    from arch/x86/include/asm/bug.h:35,
                    from include/linux/bug.h:4,
                    from include/linux/signal.h:4,
                    from arch/x86/math-emu/fpu_entry.c:27:
   arch/x86/math-emu/fpu_system.h:50:24: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define FPU_info  (I387->soft.info)
                           ^
     ->
   include/linux/compiler.h:178:40: note: in definition of macro 'likely'
    # define likely(x) __builtin_expect(!!(x), 1)
                                           ^
>> arch/x86/include/asm/uaccess.h:100:10: note: in expansion of macro '__range_not_ok'
     likely(!__range_not_ok(addr, size, user_addr_max()));  \
             ^~~~~~~~~~~~~~
>> arch/x86/math-emu/fpu_system.h:80:36: note: in expansion of macro 'access_ok'
    #define FPU_access_ok(x,y,z) if ( !access_ok(x,y,z) ) \
                                       ^~~~~~~~~
>> arch/x86/math-emu/fpu_system.h:95:31: note: in expansion of macro 'FPU_access_ok'
    #define FPU_code_access_ok(z) FPU_access_ok(VERIFY_READ,(void __user *)FPU_EIP,z)
                                  ^~~~~~~~~~~~~
   arch/x86/math-emu/fpu_system.h:57:20: note: in expansion of macro 'FPU_info'
    #define FPU_EIP   (FPU_info->regs->ip)
                       ^~~~~~~~
>> arch/x86/math-emu/fpu_system.h:95:72: note: in expansion of macro 'FPU_EIP'
    #define FPU_code_access_ok(z) FPU_access_ok(VERIFY_READ,(void __user *)FPU_EIP,z)
                                                                           ^~~~~~~
>> arch/x86/math-emu/fpu_entry.c:208:2: note: in expansion of macro 'FPU_code_access_ok'
     FPU_code_access_ok(1);
     ^~~~~~~~~~~~~~~~~~
   In file included from arch/x86/math-emu/fpu_entry.c:35:0:
   arch/x86/math-emu/fpu_system.h:50:24: error: 'get_current()->thread.fpu.state' is a pointer; did you mean to use '->'?
    #define FPU_info  (I387->soft.info)
                           ^
     ->
   arch/x86/math-emu/fpu_system.h:81:16: note: in expansion of macro 'FPU_info'
        math_abort(FPU_info,SIGSEGV)
                   ^~~~~~~~
>> arch/x86/math-emu/fpu_system.h:95:31: note: in expansion of macro 'FPU_access_ok'
    #define FPU_code_access_ok(z) FPU_access_ok(VERIFY_READ,(void __user *)FPU_EIP,z)
                                  ^~~~~~~~~~~~~
..

vim +/init_fpregs_state +805 arch/x86/include/asm/processor.h

   799	
   800	#define INIT_THREAD  {							  \
   801		.sp0			= TOP_OF_INIT_STACK,			  \
   802		.sysenter_cs		= __KERNEL_CS,				  \
   803		.io_bitmap_ptr		= NULL,					  \
   804		.addr_limit		= KERNEL_DS,				  \
 > 805		.fpu.state		= &init_fpregs_state,			  \
   806	}
   807	
   808	/*

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
diff mbox

Patch

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 9a5af1e1cd61..13b54a5ddfde 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -71,7 +71,6 @@  config X86
 	select ARCH_USE_QUEUED_SPINLOCKS
 	select ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH if SMP
 	select ARCH_WANT_FRAME_POINTERS
-	select ARCH_WANTS_DYNAMIC_TASK_STRUCT
 	select BUILDTIME_EXTABLE_SORT
 	select CLKEVT_I8253
 	select CLOCKSOURCE_VALIDATE_LAST_CYCLE
diff --git a/arch/x86/include/asm/fpu/internal.h b/arch/x86/include/asm/fpu/internal.h
index 255645f60ca2..f564c29d5194 100644
--- a/arch/x86/include/asm/fpu/internal.h
+++ b/arch/x86/include/asm/fpu/internal.h
@@ -196,9 +196,9 @@  static inline int copy_user_to_fregs(struct fregs_state __user *fx)
 static inline void copy_fxregs_to_kernel(struct fpu *fpu)
 {
 	if (IS_ENABLED(CONFIG_X86_32))
-		asm volatile( "fxsave %[fx]" : [fx] "=m" (fpu->state.fxsave));
+		asm volatile( "fxsave %[fx]" : [fx] "=m" (fpu->state->fxsave));
 	else if (IS_ENABLED(CONFIG_AS_FXSAVEQ))
-		asm volatile("fxsaveq %[fx]" : [fx] "=m" (fpu->state.fxsave));
+		asm volatile("fxsaveq %[fx]" : [fx] "=m" (fpu->state->fxsave));
 	else {
 		/* Using "rex64; fxsave %0" is broken because, if the memory
 		 * operand uses any extended registers for addressing, a second
@@ -215,15 +215,15 @@  static inline void copy_fxregs_to_kernel(struct fpu *fpu)
 		 * an extended register is needed for addressing (fix submitted
 		 * to mainline 2005-11-21).
 		 *
-		 *  asm volatile("rex64/fxsave %0" : "=m" (fpu->state.fxsave));
+		 *  asm volatile("rex64/fxsave %0" : "=m" (fpu->state->fxsave));
 		 *
 		 * This, however, we can work around by forcing the compiler to
 		 * select an addressing mode that doesn't require extended
 		 * registers.
 		 */
 		asm volatile( "rex64/fxsave (%[fx])"
-			     : "=m" (fpu->state.fxsave)
-			     : [fx] "R" (&fpu->state.fxsave));
+			     : "=m" (fpu->state->fxsave)
+			     : [fx] "R" (&fpu->state->fxsave));
 	}
 }
 
@@ -432,7 +432,7 @@  static inline int copy_user_to_xregs(struct xregs_state __user *buf, u64 mask)
 static inline int copy_fpregs_to_fpstate(struct fpu *fpu)
 {
 	if (likely(use_xsave())) {
-		copy_xregs_to_kernel(&fpu->state.xsave);
+		copy_xregs_to_kernel(&fpu->state->xsave);
 		return 1;
 	}
 
@@ -445,7 +445,7 @@  static inline int copy_fpregs_to_fpstate(struct fpu *fpu)
 	 * Legacy FPU register saving, FNSAVE always clears FPU registers,
 	 * so we have to mark them inactive:
 	 */
-	asm volatile("fnsave %[fp]; fwait" : [fp] "=m" (fpu->state.fsave));
+	asm volatile("fnsave %[fp]; fwait" : [fp] "=m" (fpu->state->fsave));
 
 	return 0;
 }
@@ -599,7 +599,7 @@  static inline void switch_fpu_finish(struct fpu *new_fpu, int cpu)
 
 	if (preload) {
 		if (!fpregs_state_valid(new_fpu, cpu))
-			copy_kernel_to_fpregs(&new_fpu->state);
+			copy_kernel_to_fpregs(new_fpu->state);
 		fpregs_activate(new_fpu);
 	}
 }
diff --git a/arch/x86/include/asm/fpu/types.h b/arch/x86/include/asm/fpu/types.h
index 3c80f5b9c09d..c828fefc2133 100644
--- a/arch/x86/include/asm/fpu/types.h
+++ b/arch/x86/include/asm/fpu/types.h
@@ -330,11 +330,7 @@  struct fpu {
 	 * copy. If the task context-switches away then they get
 	 * saved here and represent the FPU state.
 	 */
-	union fpregs_state		state;
-	/*
-	 * WARNING: 'state' is dynamically-sized.  Do not put
-	 * anything after it here.
-	 */
+	union fpregs_state		*state;
 };
 
 #endif /* _ASM_X86_FPU_H */
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index e2335edb9fc5..fcf76cb0ae1c 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -440,6 +440,8 @@  struct thread_struct {
 	unsigned long gs;
 #endif
 
+	/* Floating point and extended processor state */
+	struct fpu		fpu;
 	/* Save middle states of ptrace breakpoints */
 	struct perf_event	*ptrace_bps[HBP_NUM];
 	/* Debug status used for traps, single steps, etc... */
@@ -464,13 +466,6 @@  struct thread_struct {
 
 	unsigned int		sig_on_uaccess_err:1;
 	unsigned int		uaccess_err:1;	/* uaccess failed */
-
-	/* Floating point and extended processor state */
-	struct fpu		fpu;
-	/*
-	 * WARNING: 'fpu' is dynamically-sized.  It *MUST* be at
-	 * the end.
-	 */
 };
 
 /*
@@ -803,6 +798,7 @@  static inline void spin_lock_prefetch(const void *x)
 	.sysenter_cs		= __KERNEL_CS,				  \
 	.io_bitmap_ptr		= NULL,					  \
 	.addr_limit		= KERNEL_DS,				  \
+	.fpu.state		= &init_fpregs_state,			  \
 }
 
 /*
diff --git a/arch/x86/include/asm/trace/fpu.h b/arch/x86/include/asm/trace/fpu.h
index 342e59789fcd..4c07f7b49773 100644
--- a/arch/x86/include/asm/trace/fpu.h
+++ b/arch/x86/include/asm/trace/fpu.h
@@ -23,8 +23,8 @@  DECLARE_EVENT_CLASS(x86_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;
+			__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",
diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c
index e1114f070c2d..f935effa0b69 100644
--- a/arch/x86/kernel/fpu/core.c
+++ b/arch/x86/kernel/fpu/core.c
@@ -117,7 +117,7 @@  void __kernel_fpu_end(void)
 	struct fpu *fpu = &current->thread.fpu;
 
 	if (fpu->fpregs_active)
-		copy_kernel_to_fpregs(&fpu->state);
+		copy_kernel_to_fpregs(fpu->state);
 
 	kernel_fpu_enable();
 }
@@ -150,7 +150,7 @@  void fpu__save(struct fpu *fpu)
 	trace_x86_fpu_before_save(fpu);
 	if (fpu->fpregs_active) {
 		if (!copy_fpregs_to_fpstate(fpu)) {
-			copy_kernel_to_fpregs(&fpu->state);
+			copy_kernel_to_fpregs(fpu->state);
 		}
 	}
 	trace_x86_fpu_after_save(fpu);
@@ -201,7 +201,7 @@  int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu)
 	 * Don't let 'init optimized' areas of the XSAVE area
 	 * leak into the child task:
 	 */
-	memset(&dst_fpu->state.xsave, 0, fpu_kernel_xstate_size);
+	memset(&dst_fpu->state->xsave, 0, fpu_kernel_xstate_size);
 
 	/*
 	 * Save current FPU registers directly into the child
@@ -220,10 +220,9 @@  int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu)
 	 */
 	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);
+		copy_kernel_to_fpregs(src_fpu->state);
 	}
 	preempt_enable();
 
@@ -242,7 +241,7 @@  void fpu__activate_curr(struct fpu *fpu)
 	WARN_ON_FPU(fpu != &current->thread.fpu);
 
 	if (!fpu->fpstate_active) {
-		fpstate_init(&fpu->state);
+		fpstate_init(fpu->state);
 		trace_x86_fpu_init_state(fpu);
 
 		trace_x86_fpu_activate_state(fpu);
@@ -270,7 +269,7 @@  void fpu__activate_fpstate_read(struct fpu *fpu)
 		fpu__save(fpu);
 	} else {
 		if (!fpu->fpstate_active) {
-			fpstate_init(&fpu->state);
+			fpstate_init(fpu->state);
 			trace_x86_fpu_init_state(fpu);
 
 			trace_x86_fpu_activate_state(fpu);
@@ -305,7 +304,7 @@  void fpu__activate_fpstate_write(struct fpu *fpu)
 		/* Invalidate any lazy state: */
 		__fpu_invalidate_fpregs_state(fpu);
 	} else {
-		fpstate_init(&fpu->state);
+		fpstate_init(fpu->state);
 		trace_x86_fpu_init_state(fpu);
 
 		trace_x86_fpu_activate_state(fpu);
@@ -368,7 +367,7 @@  void fpu__current_fpstate_write_end(void)
 	 * an XRSTOR if they are active.
 	 */
 	if (fpregs_active())
-		copy_kernel_to_fpregs(&fpu->state);
+		copy_kernel_to_fpregs(fpu->state);
 
 	/*
 	 * Our update is done and the fpregs/fpstate are in sync
@@ -395,7 +394,7 @@  void fpu__restore(struct fpu *fpu)
 	kernel_fpu_disable();
 	trace_x86_fpu_before_restore(fpu);
 	fpregs_activate(fpu);
-	copy_kernel_to_fpregs(&fpu->state);
+	copy_kernel_to_fpregs(fpu->state);
 	trace_x86_fpu_after_restore(fpu);
 	kernel_fpu_enable();
 }
@@ -489,11 +488,11 @@  int fpu__exception_code(struct fpu *fpu, int trap_nr)
 		 * fully reproduce the context of the exception.
 		 */
 		if (boot_cpu_has(X86_FEATURE_FXSR)) {
-			cwd = fpu->state.fxsave.cwd;
-			swd = fpu->state.fxsave.swd;
+			cwd = fpu->state->fxsave.cwd;
+			swd = fpu->state->fxsave.swd;
 		} else {
-			cwd = (unsigned short)fpu->state.fsave.cwd;
-			swd = (unsigned short)fpu->state.fsave.swd;
+			cwd = (unsigned short)fpu->state->fsave.cwd;
+			swd = (unsigned short)fpu->state->fsave.swd;
 		}
 
 		err = swd & ~cwd;
@@ -507,7 +506,7 @@  int fpu__exception_code(struct fpu *fpu, int trap_nr)
 		unsigned short mxcsr = MXCSR_DEFAULT;
 
 		if (boot_cpu_has(X86_FEATURE_XMM))
-			mxcsr = fpu->state.fxsave.mxcsr;
+			mxcsr = fpu->state->fxsave.mxcsr;
 
 		err = ~(mxcsr >> 7) & mxcsr;
 	}
diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c
index c2f8dde3255c..74a0fb816351 100644
--- a/arch/x86/kernel/fpu/init.c
+++ b/arch/x86/kernel/fpu/init.c
@@ -34,7 +34,7 @@  static void fpu__init_cpu_generic(void)
 	/* Flush out any pending x87 state: */
 #ifdef CONFIG_MATH_EMULATION
 	if (!boot_cpu_has(X86_FEATURE_FPU))
-		fpstate_init_soft(&current->thread.fpu.state.soft);
+		fpstate_init_soft(&current->thread.fpu.state->soft);
 	else
 #endif
 		asm volatile ("fninit");
@@ -137,51 +137,7 @@  static void __init fpu__init_system_generic(void)
 unsigned int fpu_kernel_xstate_size;
 EXPORT_SYMBOL_GPL(fpu_kernel_xstate_size);
 
-/* Get alignment of the TYPE. */
-#define TYPE_ALIGN(TYPE) offsetof(struct { char x; TYPE test; }, test)
-
-/*
- * Enforce that 'MEMBER' is the last field of 'TYPE'.
- *
- * Align the computed size with alignment of the TYPE,
- * because that's how C aligns structs.
- */
-#define CHECK_MEMBER_AT_END_OF(TYPE, MEMBER) \
-	BUILD_BUG_ON(sizeof(TYPE) != ALIGN(offsetofend(TYPE, MEMBER), \
-					   TYPE_ALIGN(TYPE)))
-
-/*
- * We append the 'struct fpu' to the task_struct:
- */
-static void __init fpu__init_task_struct_size(void)
-{
-	int task_size = sizeof(struct task_struct);
-
-	/*
-	 * Subtract off the static size of the register state.
-	 * It potentially has a bunch of padding.
-	 */
-	task_size -= sizeof(((struct task_struct *)0)->thread.fpu.state);
-
-	/*
-	 * Add back the dynamically-calculated register state
-	 * size.
-	 */
-	task_size += fpu_kernel_xstate_size;
-
-	/*
-	 * We dynamically size 'struct fpu', so we require that
-	 * it be at the end of 'thread_struct' and that
-	 * 'thread_struct' be at the end of 'task_struct'.  If
-	 * you hit a compile error here, check the structure to
-	 * see if something got added to the end.
-	 */
-	CHECK_MEMBER_AT_END_OF(struct fpu, state);
-	CHECK_MEMBER_AT_END_OF(struct thread_struct, fpu);
-	CHECK_MEMBER_AT_END_OF(struct task_struct, thread);
-
-	arch_task_struct_size = task_size;
-}
+union fpregs_state init_fpregs_state;
 
 /*
  * Set up the user and kernel xstate sizes based on the legacy FPU context size.
@@ -285,7 +241,5 @@  void __init fpu__init_system(struct cpuinfo_x86 *c)
 	fpu__init_system_generic();
 	fpu__init_system_xstate_size_legacy();
 	fpu__init_system_xstate();
-	fpu__init_task_struct_size();
-
 	fpu__init_system_ctx_switch();
 }
diff --git a/arch/x86/kernel/fpu/regset.c b/arch/x86/kernel/fpu/regset.c
index b188b16841e3..c75bed318070 100644
--- a/arch/x86/kernel/fpu/regset.c
+++ b/arch/x86/kernel/fpu/regset.c
@@ -42,7 +42,7 @@  int xfpregs_get(struct task_struct *target, const struct user_regset *regset,
 	fpstate_sanitize_xstate(fpu);
 
 	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
-				   &fpu->state.fxsave, 0, -1);
+				   &fpu->state->fxsave, 0, -1);
 }
 
 int xfpregs_set(struct task_struct *target, const struct user_regset *regset,
@@ -59,19 +59,19 @@  int xfpregs_set(struct task_struct *target, const struct user_regset *regset,
 	fpstate_sanitize_xstate(fpu);
 
 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-				 &fpu->state.fxsave, 0, -1);
+				 &fpu->state->fxsave, 0, -1);
 
 	/*
 	 * mxcsr reserved bits must be masked to zero for security reasons.
 	 */
-	fpu->state.fxsave.mxcsr &= mxcsr_feature_mask;
+	fpu->state->fxsave.mxcsr &= mxcsr_feature_mask;
 
 	/*
 	 * update the header bits in the xsave header, indicating the
 	 * presence of FP and SSE state.
 	 */
 	if (boot_cpu_has(X86_FEATURE_XSAVE))
-		fpu->state.xsave.header.xfeatures |= XFEATURE_MASK_FPSSE;
+		fpu->state->xsave.header.xfeatures |= XFEATURE_MASK_FPSSE;
 
 	return ret;
 }
@@ -87,7 +87,7 @@  int xstateregs_get(struct task_struct *target, const struct user_regset *regset,
 	if (!boot_cpu_has(X86_FEATURE_XSAVE))
 		return -ENODEV;
 
-	xsave = &fpu->state.xsave;
+	xsave = &fpu->state->xsave;
 
 	fpu__activate_fpstate_read(fpu);
 
@@ -127,7 +127,7 @@  int xstateregs_set(struct task_struct *target, const struct user_regset *regset,
 	if ((pos != 0) || (count < fpu_user_xstate_size))
 		return -EFAULT;
 
-	xsave = &fpu->state.xsave;
+	xsave = &fpu->state->xsave;
 
 	fpu__activate_fpstate_write(fpu);
 
@@ -140,7 +140,7 @@  int xstateregs_set(struct task_struct *target, const struct user_regset *regset,
 	 * In case of failure, mark all states as init:
 	 */
 	if (ret)
-		fpstate_init(&fpu->state);
+		fpstate_init(fpu->state);
 
 	/*
 	 * mxcsr reserved bits must be masked to zero for security reasons.
@@ -230,7 +230,7 @@  static inline u32 twd_fxsr_to_i387(struct fxregs_state *fxsave)
 void
 convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk)
 {
-	struct fxregs_state *fxsave = &tsk->thread.fpu.state.fxsave;
+	struct fxregs_state *fxsave = &tsk->thread.fpu.state->fxsave;
 	struct _fpreg *to = (struct _fpreg *) &env->st_space[0];
 	struct _fpxreg *from = (struct _fpxreg *) &fxsave->st_space[0];
 	int i;
@@ -268,7 +268,7 @@  void convert_to_fxsr(struct task_struct *tsk,
 		     const struct user_i387_ia32_struct *env)
 
 {
-	struct fxregs_state *fxsave = &tsk->thread.fpu.state.fxsave;
+	struct fxregs_state *fxsave = &tsk->thread.fpu.state->fxsave;
 	struct _fpreg *from = (struct _fpreg *) &env->st_space[0];
 	struct _fpxreg *to = (struct _fpxreg *) &fxsave->st_space[0];
 	int i;
@@ -306,7 +306,7 @@  int fpregs_get(struct task_struct *target, const struct user_regset *regset,
 
 	if (!boot_cpu_has(X86_FEATURE_FXSR))
 		return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
-					   &fpu->state.fsave, 0,
+					   &fpu->state->fsave, 0,
 					   -1);
 
 	fpstate_sanitize_xstate(fpu);
@@ -337,7 +337,7 @@  int fpregs_set(struct task_struct *target, const struct user_regset *regset,
 
 	if (!boot_cpu_has(X86_FEATURE_FXSR))
 		return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-					  &fpu->state.fsave, 0,
+					  &fpu->state->fsave, 0,
 					  -1);
 
 	if (pos > 0 || count < sizeof(env))
@@ -352,7 +352,7 @@  int fpregs_set(struct task_struct *target, const struct user_regset *regset,
 	 * presence of FP.
 	 */
 	if (boot_cpu_has(X86_FEATURE_XSAVE))
-		fpu->state.xsave.header.xfeatures |= XFEATURE_MASK_FP;
+		fpu->state->xsave.header.xfeatures |= XFEATURE_MASK_FP;
 	return ret;
 }
 
diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c
index 83c23c230b4c..d943bfa48e83 100644
--- a/arch/x86/kernel/fpu/signal.c
+++ b/arch/x86/kernel/fpu/signal.c
@@ -56,7 +56,7 @@  static inline int check_for_xstate(struct fxregs_state __user *buf,
 static inline int save_fsave_header(struct task_struct *tsk, void __user *buf)
 {
 	if (use_fxsr()) {
-		struct xregs_state *xsave = &tsk->thread.fpu.state.xsave;
+		struct xregs_state *xsave = &tsk->thread.fpu.state->xsave;
 		struct user_i387_ia32_struct env;
 		struct _fpstate_32 __user *fp = buf;
 
@@ -155,7 +155,7 @@  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 = &current->thread.fpu.state.xsave;
+	struct xregs_state *xsave = &current->thread.fpu.state->xsave;
 	struct task_struct *tsk = current;
 	int ia32_fxstate = (buf != buf_fx);
 
@@ -209,7 +209,7 @@  sanitize_restored_xstate(struct task_struct *tsk,
 			 struct user_i387_ia32_struct *ia32_env,
 			 u64 xfeatures, int fx_only)
 {
-	struct xregs_state *xsave = &tsk->thread.fpu.state.xsave;
+	struct xregs_state *xsave = &tsk->thread.fpu.state->xsave;
 	struct xstate_header *header = &xsave->header;
 
 	if (use_xsave()) {
@@ -325,14 +325,14 @@  static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
 
 		if (using_compacted_format()) {
 			err = copyin_to_xsaves(NULL, buf_fx,
-					       &fpu->state.xsave);
+					       &fpu->state->xsave);
 		} else {
-			err = __copy_from_user(&fpu->state.xsave,
+			err = __copy_from_user(&fpu->state->xsave,
 					       buf_fx, state_size);
 		}
 
 		if (err || __copy_from_user(&env, buf, sizeof(env))) {
-			fpstate_init(&fpu->state);
+			fpstate_init(fpu->state);
 			trace_x86_fpu_init_state(fpu);
 			err = -1;
 		} else {
diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c
index c24ac1efb12d..2ba5e6f18775 100644
--- a/arch/x86/kernel/fpu/xstate.c
+++ b/arch/x86/kernel/fpu/xstate.c
@@ -157,14 +157,14 @@  static int xfeature_is_user(int xfeature_nr)
  */
 void fpstate_sanitize_xstate(struct fpu *fpu)
 {
-	struct fxregs_state *fx = &fpu->state.fxsave;
+	struct fxregs_state *fx = &fpu->state->fxsave;
 	int feature_bit;
 	u64 xfeatures;
 
 	if (!use_xsaveopt())
 		return;
 
-	xfeatures = fpu->state.xsave.header.xfeatures;
+	xfeatures = fpu->state->xsave.header.xfeatures;
 
 	/*
 	 * None of the feature bits are in init state. So nothing else
@@ -875,7 +875,7 @@  const void *get_xsave_field_ptr(int xsave_state)
 	 */
 	fpu__save(fpu);
 
-	return get_xsave_addr(&fpu->state.xsave, xsave_state);
+	return get_xsave_addr(&fpu->state->xsave, xsave_state);
 }
 
 #ifdef CONFIG_ARCH_HAS_PKEYS
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 0bb88428cbf2..60129943a064 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -20,8 +20,8 @@ 
 #include <linux/dmi.h>
 #include <linux/utsname.h>
 #include <linux/stackprotector.h>
-#include <linux/tick.h>
 #include <linux/cpuidle.h>
+#include <linux/kthread.h>
 #include <trace/events/power.h>
 #include <linux/hw_breakpoint.h>
 #include <asm/cpu.h>
@@ -73,20 +73,40 @@  EXPORT_PER_CPU_SYMBOL(cpu_tss);
 DEFINE_PER_CPU(bool, __tss_limit_invalid);
 EXPORT_PER_CPU_SYMBOL_GPL(__tss_limit_invalid);
 
+struct kmem_cache *fpregs_state_cachep;
+EXPORT_SYMBOL(fpregs_state_cachep);
+
+void __init arch_task_cache_init(void)
+{
+	/* create a slab on which fpregs_states can be allocated */
+	fpregs_state_cachep = kmem_cache_create("fpregs_state",
+				fpu_kernel_xstate_size,
+				ARCH_MIN_TASKALIGN, SLAB_PANIC | SLAB_NOTRACK,
+				NULL);
+}
+
 /*
  * this gets called so that we can store lazy state into memory and copy the
  * current task into the new thread.
  */
 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
-	memcpy(dst, src, arch_task_struct_size);
+	*dst = *src;
 #ifdef CONFIG_VM86
 	dst->thread.vm86 = NULL;
 #endif
+	dst->thread.fpu.state = kmem_cache_alloc_node(fpregs_state_cachep,
+					GFP_KERNEL, tsk_fork_get_node(src));
 
 	return fpu__copy(&dst->thread.fpu, &src->thread.fpu);
 }
 
+void arch_release_task_struct(struct task_struct *tsk)
+{
+	kmem_cache_free(fpregs_state_cachep, tsk->thread.fpu.state);
+	tsk->thread.fpu.state = NULL;
+}
+
 /*
  * Free current thread data structures etc..
  */
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index ee22226e3807..17d2cbc838d6 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3213,7 +3213,7 @@  static int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu,
 
 static void fill_xsave(u8 *dest, struct kvm_vcpu *vcpu)
 {
-	struct xregs_state *xsave = &vcpu->arch.guest_fpu.state.xsave;
+	struct xregs_state *xsave = &vcpu->arch.guest_fpu.state->xsave;
 	u64 xstate_bv = xsave->header.xfeatures;
 	u64 valid;
 
@@ -3250,7 +3250,7 @@  static void fill_xsave(u8 *dest, struct kvm_vcpu *vcpu)
 
 static void load_xsave(struct kvm_vcpu *vcpu, u8 *src)
 {
-	struct xregs_state *xsave = &vcpu->arch.guest_fpu.state.xsave;
+	struct xregs_state *xsave = &vcpu->arch.guest_fpu.state->xsave;
 	u64 xstate_bv = *(u64 *)(src + XSAVE_HDR_OFFSET);
 	u64 valid;
 
@@ -3294,7 +3294,7 @@  static void kvm_vcpu_ioctl_x86_get_xsave(struct kvm_vcpu *vcpu,
 		fill_xsave((u8 *) guest_xsave->region, vcpu);
 	} else {
 		memcpy(guest_xsave->region,
-			&vcpu->arch.guest_fpu.state.fxsave,
+			&vcpu->arch.guest_fpu.state->fxsave,
 			sizeof(struct fxregs_state));
 		*(u64 *)&guest_xsave->region[XSAVE_HDR_OFFSET / sizeof(u32)] =
 			XFEATURE_MASK_FPSSE;
@@ -3319,7 +3319,7 @@  static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu,
 	} else {
 		if (xstate_bv & ~XFEATURE_MASK_FPSSE)
 			return -EINVAL;
-		memcpy(&vcpu->arch.guest_fpu.state.fxsave,
+		memcpy(&vcpu->arch.guest_fpu.state->fxsave,
 			guest_xsave->region, sizeof(struct fxregs_state));
 	}
 	return 0;
@@ -7545,7 +7545,7 @@  int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
 int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
 {
 	struct fxregs_state *fxsave =
-			&vcpu->arch.guest_fpu.state.fxsave;
+			&vcpu->arch.guest_fpu.state->fxsave;
 
 	memcpy(fpu->fpr, fxsave->st_space, 128);
 	fpu->fcw = fxsave->cwd;
@@ -7562,7 +7562,7 @@  int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
 int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
 {
 	struct fxregs_state *fxsave =
-			&vcpu->arch.guest_fpu.state.fxsave;
+			&vcpu->arch.guest_fpu.state->fxsave;
 
 	memcpy(fxsave->st_space, fpu->fpr, 128);
 	fxsave->cwd = fpu->fcw;
@@ -7578,9 +7578,9 @@  int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
 
 static void fx_init(struct kvm_vcpu *vcpu)
 {
-	fpstate_init(&vcpu->arch.guest_fpu.state);
+	fpstate_init(vcpu->arch.guest_fpu.state);
 	if (boot_cpu_has(X86_FEATURE_XSAVES))
-		vcpu->arch.guest_fpu.state.xsave.header.xcomp_bv =
+		vcpu->arch.guest_fpu.state->xsave.header.xcomp_bv =
 			host_xcr0 | XSTATE_COMPACTION_ENABLED;
 
 	/*
@@ -7603,7 +7603,7 @@  void kvm_load_guest_fpu(struct kvm_vcpu *vcpu)
 	 */
 	vcpu->guest_fpu_loaded = 1;
 	__kernel_fpu_begin();
-	__copy_kernel_to_fpregs(&vcpu->arch.guest_fpu.state);
+	__copy_kernel_to_fpregs(vcpu->arch.guest_fpu.state);
 	trace_kvm_fpu(1);
 }
 
@@ -7891,6 +7891,8 @@  bool kvm_vcpu_is_bsp(struct kvm_vcpu *vcpu)
 struct static_key kvm_no_apic_vcpu __read_mostly;
 EXPORT_SYMBOL_GPL(kvm_no_apic_vcpu);
 
+extern struct kmem_cache *fpregs_state_cachep;
+
 int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 {
 	struct page *page;
@@ -7908,11 +7910,15 @@  int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 	else
 		vcpu->arch.mp_state = KVM_MP_STATE_UNINITIALIZED;
 
-	page = alloc_page(GFP_KERNEL | __GFP_ZERO);
-	if (!page) {
-		r = -ENOMEM;
+	r = -ENOMEM;
+	vcpu->arch.guest_fpu.state = kmem_cache_alloc(fpregs_state_cachep,
+						      GFP_KERNEL);
+	if (!vcpu->arch.guest_fpu.state)
 		goto fail;
-	}
+
+	page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+	if (!page)
+		goto fail_free_fpregs;
 	vcpu->arch.pio_data = page_address(page);
 
 	kvm_set_tsc_khz(vcpu, max_tsc_khz);
@@ -7970,6 +7976,8 @@  int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 	kvm_mmu_destroy(vcpu);
 fail_free_pio_data:
 	free_page((unsigned long)vcpu->arch.pio_data);
+fail_free_fpregs:
+	kmem_cache_free(fpregs_state_cachep, vcpu->arch.guest_fpu.state);
 fail:
 	return r;
 }
@@ -7988,6 +7996,8 @@  void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
 	free_page((unsigned long)vcpu->arch.pio_data);
 	if (!lapic_in_kernel(vcpu))
 		static_key_slow_dec(&kvm_no_apic_vcpu);
+	kmem_cache_free(fpregs_state_cachep, vcpu->arch.guest_fpu.state);
+	vcpu->arch.guest_fpu.state = NULL;
 }
 
 void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index d31a8095237b..a7b239a87160 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1053,8 +1053,9 @@  struct task_struct {
 	struct thread_struct		thread;
 
 	/*
-	 * WARNING: on x86, 'thread_struct' contains a variable-sized
-	 * structure.  It *MUST* be at the end of 'task_struct'.
+	 * WARNING: Under CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT,
+	 * 'thread_struct' contains a variable-sized structure.
+	 * It *MUST* be at the end of 'task_struct'.
 	 *
 	 * Do not put anything below here!
 	 */