LCOV - code coverage report
Current view: top level - arch/x86/kernel/fpu - regset.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 148 0.0 %
Date: 2022-04-01 13:59:58 Functions: 0 12 0.0 %
Branches: 0 61 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : /*
       3                 :            :  * FPU register's regset abstraction, for ptrace, core dumps, etc.
       4                 :            :  */
       5                 :            : #include <asm/fpu/internal.h>
       6                 :            : #include <asm/fpu/signal.h>
       7                 :            : #include <asm/fpu/regset.h>
       8                 :            : #include <asm/fpu/xstate.h>
       9                 :            : #include <linux/sched/task_stack.h>
      10                 :            : 
      11                 :            : /*
      12                 :            :  * The xstateregs_active() routine is the same as the regset_fpregs_active() routine,
      13                 :            :  * as the "regset->n" for the xstate regset will be updated based on the feature
      14                 :            :  * capabilities supported by the xsave.
      15                 :            :  */
      16                 :          0 : int regset_fpregs_active(struct task_struct *target, const struct user_regset *regset)
      17                 :            : {
      18                 :          0 :         return regset->n;
      19                 :            : }
      20                 :            : 
      21                 :          0 : int regset_xregset_fpregs_active(struct task_struct *target, const struct user_regset *regset)
      22                 :            : {
      23                 :          0 :         if (boot_cpu_has(X86_FEATURE_FXSR))
      24                 :          0 :                 return regset->n;
      25                 :            :         else
      26                 :            :                 return 0;
      27                 :            : }
      28                 :            : 
      29                 :          0 : int xfpregs_get(struct task_struct *target, const struct user_regset *regset,
      30                 :            :                 unsigned int pos, unsigned int count,
      31                 :            :                 void *kbuf, void __user *ubuf)
      32                 :            : {
      33                 :          0 :         struct fpu *fpu = &target->thread.fpu;
      34                 :            : 
      35                 :          0 :         if (!boot_cpu_has(X86_FEATURE_FXSR))
      36                 :            :                 return -ENODEV;
      37                 :            : 
      38                 :          0 :         fpu__prepare_read(fpu);
      39                 :          0 :         fpstate_sanitize_xstate(fpu);
      40                 :            : 
      41                 :          0 :         return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
      42                 :          0 :                                    &fpu->state.fxsave, 0, -1);
      43                 :            : }
      44                 :            : 
      45                 :          0 : int xfpregs_set(struct task_struct *target, const struct user_regset *regset,
      46                 :            :                 unsigned int pos, unsigned int count,
      47                 :            :                 const void *kbuf, const void __user *ubuf)
      48                 :            : {
      49                 :          0 :         struct fpu *fpu = &target->thread.fpu;
      50                 :          0 :         int ret;
      51                 :            : 
      52                 :          0 :         if (!boot_cpu_has(X86_FEATURE_FXSR))
      53                 :            :                 return -ENODEV;
      54                 :            : 
      55                 :          0 :         fpu__prepare_write(fpu);
      56                 :          0 :         fpstate_sanitize_xstate(fpu);
      57                 :            : 
      58                 :          0 :         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
      59                 :          0 :                                  &fpu->state.fxsave, 0, -1);
      60                 :            : 
      61                 :            :         /*
      62                 :            :          * mxcsr reserved bits must be masked to zero for security reasons.
      63                 :            :          */
      64                 :          0 :         fpu->state.fxsave.mxcsr &= mxcsr_feature_mask;
      65                 :            : 
      66                 :            :         /*
      67                 :            :          * update the header bits in the xsave header, indicating the
      68                 :            :          * presence of FP and SSE state.
      69                 :            :          */
      70         [ #  # ]:          0 :         if (boot_cpu_has(X86_FEATURE_XSAVE))
      71                 :          0 :                 fpu->state.xsave.header.xfeatures |= XFEATURE_MASK_FPSSE;
      72                 :            : 
      73                 :          0 :         return ret;
      74                 :            : }
      75                 :            : 
      76                 :          0 : int xstateregs_get(struct task_struct *target, const struct user_regset *regset,
      77                 :            :                 unsigned int pos, unsigned int count,
      78                 :            :                 void *kbuf, void __user *ubuf)
      79                 :            : {
      80                 :          0 :         struct fpu *fpu = &target->thread.fpu;
      81                 :          0 :         struct xregs_state *xsave;
      82                 :          0 :         int ret;
      83                 :            : 
      84         [ #  # ]:          0 :         if (!boot_cpu_has(X86_FEATURE_XSAVE))
      85                 :            :                 return -ENODEV;
      86                 :            : 
      87                 :          0 :         xsave = &fpu->state.xsave;
      88                 :            : 
      89                 :          0 :         fpu__prepare_read(fpu);
      90                 :            : 
      91         [ #  # ]:          0 :         if (using_compacted_format()) {
      92         [ #  # ]:          0 :                 if (kbuf)
      93                 :          0 :                         ret = copy_xstate_to_kernel(kbuf, xsave, pos, count);
      94                 :            :                 else
      95                 :          0 :                         ret = copy_xstate_to_user(ubuf, xsave, pos, count);
      96                 :            :         } else {
      97                 :          0 :                 fpstate_sanitize_xstate(fpu);
      98                 :            :                 /*
      99                 :            :                  * Copy the 48 bytes defined by the software into the xsave
     100                 :            :                  * area in the thread struct, so that we can copy the whole
     101                 :            :                  * area to user using one user_regset_copyout().
     102                 :            :                  */
     103                 :          0 :                 memcpy(&xsave->i387.sw_reserved, xstate_fx_sw_bytes, sizeof(xstate_fx_sw_bytes));
     104                 :            : 
     105                 :            :                 /*
     106                 :            :                  * Copy the xstate memory layout.
     107                 :            :                  */
     108                 :          0 :                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, xsave, 0, -1);
     109                 :            :         }
     110                 :            :         return ret;
     111                 :            : }
     112                 :            : 
     113                 :          0 : int xstateregs_set(struct task_struct *target, const struct user_regset *regset,
     114                 :            :                   unsigned int pos, unsigned int count,
     115                 :            :                   const void *kbuf, const void __user *ubuf)
     116                 :            : {
     117                 :          0 :         struct fpu *fpu = &target->thread.fpu;
     118                 :          0 :         struct xregs_state *xsave;
     119                 :          0 :         int ret;
     120                 :            : 
     121         [ #  # ]:          0 :         if (!boot_cpu_has(X86_FEATURE_XSAVE))
     122                 :            :                 return -ENODEV;
     123                 :            : 
     124                 :            :         /*
     125                 :            :          * A whole standard-format XSAVE buffer is needed:
     126                 :            :          */
     127   [ #  #  #  # ]:          0 :         if ((pos != 0) || (count < fpu_user_xstate_size))
     128                 :            :                 return -EFAULT;
     129                 :            : 
     130                 :          0 :         xsave = &fpu->state.xsave;
     131                 :            : 
     132                 :          0 :         fpu__prepare_write(fpu);
     133                 :            : 
     134         [ #  # ]:          0 :         if (using_compacted_format()) {
     135         [ #  # ]:          0 :                 if (kbuf)
     136                 :          0 :                         ret = copy_kernel_to_xstate(xsave, kbuf);
     137                 :            :                 else
     138                 :          0 :                         ret = copy_user_to_xstate(xsave, ubuf);
     139                 :            :         } else {
     140                 :          0 :                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, xsave, 0, -1);
     141         [ #  # ]:          0 :                 if (!ret)
     142                 :          0 :                         ret = validate_xstate_header(&xsave->header);
     143                 :            :         }
     144                 :            : 
     145                 :            :         /*
     146                 :            :          * mxcsr reserved bits must be masked to zero for security reasons.
     147                 :            :          */
     148                 :          0 :         xsave->i387.mxcsr &= mxcsr_feature_mask;
     149                 :            : 
     150                 :            :         /*
     151                 :            :          * In case of failure, mark all states as init:
     152                 :            :          */
     153         [ #  # ]:          0 :         if (ret)
     154                 :          0 :                 fpstate_init(&fpu->state);
     155                 :            : 
     156                 :            :         return ret;
     157                 :            : }
     158                 :            : 
     159                 :            : #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
     160                 :            : 
     161                 :            : /*
     162                 :            :  * FPU tag word conversions.
     163                 :            :  */
     164                 :            : 
     165                 :          0 : static inline unsigned short twd_i387_to_fxsr(unsigned short twd)
     166                 :            : {
     167                 :          0 :         unsigned int tmp; /* to avoid 16 bit prefixes in the code */
     168                 :            : 
     169                 :            :         /* Transform each pair of bits into 01 (valid) or 00 (empty) */
     170                 :          0 :         tmp = ~twd;
     171                 :          0 :         tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
     172                 :            :         /* and move the valid bits to the lower byte. */
     173                 :          0 :         tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */
     174                 :          0 :         tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
     175                 :          0 :         tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */
     176                 :            : 
     177                 :          0 :         return tmp;
     178                 :            : }
     179                 :            : 
     180                 :            : #define FPREG_ADDR(f, n)        ((void *)&(f)->st_space + (n) * 16)
     181                 :            : #define FP_EXP_TAG_VALID        0
     182                 :            : #define FP_EXP_TAG_ZERO         1
     183                 :            : #define FP_EXP_TAG_SPECIAL      2
     184                 :            : #define FP_EXP_TAG_EMPTY        3
     185                 :            : 
     186                 :          0 : static inline u32 twd_fxsr_to_i387(struct fxregs_state *fxsave)
     187                 :            : {
     188                 :          0 :         struct _fpxreg *st;
     189                 :          0 :         u32 tos = (fxsave->swd >> 11) & 7;
     190                 :          0 :         u32 twd = (unsigned long) fxsave->twd;
     191                 :          0 :         u32 tag;
     192                 :          0 :         u32 ret = 0xffff0000u;
     193                 :          0 :         int i;
     194                 :            : 
     195         [ #  # ]:          0 :         for (i = 0; i < 8; i++, twd >>= 1) {
     196         [ #  # ]:          0 :                 if (twd & 0x1) {
     197                 :          0 :                         st = FPREG_ADDR(fxsave, (i - tos) & 7);
     198                 :            : 
     199      [ #  #  # ]:          0 :                         switch (st->exponent & 0x7fff) {
     200                 :            :                         case 0x7fff:
     201                 :            :                                 tag = FP_EXP_TAG_SPECIAL;
     202                 :            :                                 break;
     203                 :          0 :                         case 0x0000:
     204         [ #  # ]:          0 :                                 if (!st->significand[0] &&
     205         [ #  # ]:          0 :                                     !st->significand[1] &&
     206         [ #  # ]:          0 :                                     !st->significand[2] &&
     207         [ #  # ]:          0 :                                     !st->significand[3])
     208                 :            :                                         tag = FP_EXP_TAG_ZERO;
     209                 :            :                                 else
     210                 :          0 :                                         tag = FP_EXP_TAG_SPECIAL;
     211                 :            :                                 break;
     212                 :          0 :                         default:
     213         [ #  # ]:          0 :                                 if (st->significand[3] & 0x8000)
     214                 :            :                                         tag = FP_EXP_TAG_VALID;
     215                 :            :                                 else
     216                 :          0 :                                         tag = FP_EXP_TAG_SPECIAL;
     217                 :            :                                 break;
     218                 :            :                         }
     219                 :            :                 } else {
     220                 :            :                         tag = FP_EXP_TAG_EMPTY;
     221                 :            :                 }
     222                 :          0 :                 ret |= tag << (2 * i);
     223                 :            :         }
     224                 :          0 :         return ret;
     225                 :            : }
     226                 :            : 
     227                 :            : /*
     228                 :            :  * FXSR floating point environment conversions.
     229                 :            :  */
     230                 :            : 
     231                 :            : void
     232                 :          0 : convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk)
     233                 :            : {
     234                 :          0 :         struct fxregs_state *fxsave = &tsk->thread.fpu.state.fxsave;
     235                 :          0 :         struct _fpreg *to = (struct _fpreg *) &env->st_space[0];
     236                 :          0 :         struct _fpxreg *from = (struct _fpxreg *) &fxsave->st_space[0];
     237                 :          0 :         int i;
     238                 :            : 
     239                 :          0 :         env->cwd = fxsave->cwd | 0xffff0000u;
     240                 :          0 :         env->swd = fxsave->swd | 0xffff0000u;
     241                 :          0 :         env->twd = twd_fxsr_to_i387(fxsave);
     242                 :            : 
     243                 :            : #ifdef CONFIG_X86_64
     244                 :          0 :         env->fip = fxsave->rip;
     245                 :          0 :         env->foo = fxsave->rdp;
     246                 :            :         /*
     247                 :            :          * should be actually ds/cs at fpu exception time, but
     248                 :            :          * that information is not available in 64bit mode.
     249                 :            :          */
     250         [ #  # ]:          0 :         env->fcs = task_pt_regs(tsk)->cs;
     251         [ #  # ]:          0 :         if (tsk == current) {
     252                 :          0 :                 savesegment(ds, env->fos);
     253                 :            :         } else {
     254                 :          0 :                 env->fos = tsk->thread.ds;
     255                 :            :         }
     256                 :          0 :         env->fos |= 0xffff0000;
     257                 :            : #else
     258                 :            :         env->fip = fxsave->fip;
     259                 :            :         env->fcs = (u16) fxsave->fcs | ((u32) fxsave->fop << 16);
     260                 :            :         env->foo = fxsave->foo;
     261                 :            :         env->fos = fxsave->fos;
     262                 :            : #endif
     263                 :            : 
     264         [ #  # ]:          0 :         for (i = 0; i < 8; ++i)
     265                 :          0 :                 memcpy(&to[i], &from[i], sizeof(to[0]));
     266                 :          0 : }
     267                 :            : 
     268                 :          0 : void convert_to_fxsr(struct fxregs_state *fxsave,
     269                 :            :                      const struct user_i387_ia32_struct *env)
     270                 :            : 
     271                 :            : {
     272                 :          0 :         struct _fpreg *from = (struct _fpreg *) &env->st_space[0];
     273                 :          0 :         struct _fpxreg *to = (struct _fpxreg *) &fxsave->st_space[0];
     274                 :          0 :         int i;
     275                 :            : 
     276                 :          0 :         fxsave->cwd = env->cwd;
     277                 :          0 :         fxsave->swd = env->swd;
     278                 :          0 :         fxsave->twd = twd_i387_to_fxsr(env->twd);
     279                 :          0 :         fxsave->fop = (u16) ((u32) env->fcs >> 16);
     280                 :            : #ifdef CONFIG_X86_64
     281                 :          0 :         fxsave->rip = env->fip;
     282                 :          0 :         fxsave->rdp = env->foo;
     283                 :            :         /* cs and ds ignored */
     284                 :            : #else
     285                 :            :         fxsave->fip = env->fip;
     286                 :            :         fxsave->fcs = (env->fcs & 0xffff);
     287                 :            :         fxsave->foo = env->foo;
     288                 :            :         fxsave->fos = env->fos;
     289                 :            : #endif
     290                 :            : 
     291         [ #  # ]:          0 :         for (i = 0; i < 8; ++i)
     292                 :          0 :                 memcpy(&to[i], &from[i], sizeof(from[0]));
     293                 :          0 : }
     294                 :            : 
     295                 :          0 : int fpregs_get(struct task_struct *target, const struct user_regset *regset,
     296                 :            :                unsigned int pos, unsigned int count,
     297                 :            :                void *kbuf, void __user *ubuf)
     298                 :            : {
     299                 :          0 :         struct fpu *fpu = &target->thread.fpu;
     300                 :          0 :         struct user_i387_ia32_struct env;
     301                 :            : 
     302                 :          0 :         fpu__prepare_read(fpu);
     303                 :            : 
     304                 :          0 :         if (!boot_cpu_has(X86_FEATURE_FPU))
     305                 :            :                 return fpregs_soft_get(target, regset, pos, count, kbuf, ubuf);
     306                 :            : 
     307                 :          0 :         if (!boot_cpu_has(X86_FEATURE_FXSR))
     308                 :            :                 return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
     309                 :            :                                            &fpu->state.fsave, 0,
     310                 :            :                                            -1);
     311                 :            : 
     312                 :          0 :         fpstate_sanitize_xstate(fpu);
     313                 :            : 
     314   [ #  #  #  #  :          0 :         if (kbuf && pos == 0 && count == sizeof(env)) {
                   #  # ]
     315                 :          0 :                 convert_from_fxsr(kbuf, target);
     316                 :          0 :                 return 0;
     317                 :            :         }
     318                 :            : 
     319                 :          0 :         convert_from_fxsr(&env, target);
     320                 :            : 
     321                 :          0 :         return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &env, 0, -1);
     322                 :            : }
     323                 :            : 
     324                 :          0 : int fpregs_set(struct task_struct *target, const struct user_regset *regset,
     325                 :            :                unsigned int pos, unsigned int count,
     326                 :            :                const void *kbuf, const void __user *ubuf)
     327                 :            : {
     328                 :          0 :         struct fpu *fpu = &target->thread.fpu;
     329                 :          0 :         struct user_i387_ia32_struct env;
     330                 :          0 :         int ret;
     331                 :            : 
     332                 :          0 :         fpu__prepare_write(fpu);
     333                 :          0 :         fpstate_sanitize_xstate(fpu);
     334                 :            : 
     335                 :          0 :         if (!boot_cpu_has(X86_FEATURE_FPU))
     336                 :            :                 return fpregs_soft_set(target, regset, pos, count, kbuf, ubuf);
     337                 :            : 
     338                 :          0 :         if (!boot_cpu_has(X86_FEATURE_FXSR))
     339                 :            :                 return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
     340                 :            :                                           &fpu->state.fsave, 0,
     341                 :            :                                           -1);
     342                 :            : 
     343   [ #  #  #  # ]:          0 :         if (pos > 0 || count < sizeof(env))
     344                 :          0 :                 convert_from_fxsr(&env, target);
     345                 :            : 
     346                 :          0 :         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &env, 0, -1);
     347         [ #  # ]:          0 :         if (!ret)
     348                 :          0 :                 convert_to_fxsr(&target->thread.fpu.state.fxsave, &env);
     349                 :            : 
     350                 :            :         /*
     351                 :            :          * update the header bit in the xsave header, indicating the
     352                 :            :          * presence of FP.
     353                 :            :          */
     354         [ #  # ]:          0 :         if (boot_cpu_has(X86_FEATURE_XSAVE))
     355                 :          0 :                 fpu->state.xsave.header.xfeatures |= XFEATURE_MASK_FP;
     356                 :          0 :         return ret;
     357                 :            : }
     358                 :            : 
     359                 :            : /*
     360                 :            :  * FPU state for core dumps.
     361                 :            :  * This is only used for a.out dumps now.
     362                 :            :  * It is declared generically using elf_fpregset_t (which is
     363                 :            :  * struct user_i387_struct) but is in fact only used for 32-bit
     364                 :            :  * dumps, so on 64-bit it is really struct user_i387_ia32_struct.
     365                 :            :  */
     366                 :          0 : int dump_fpu(struct pt_regs *regs, struct user_i387_struct *ufpu)
     367                 :            : {
     368                 :          0 :         struct task_struct *tsk = current;
     369                 :            : 
     370                 :          0 :         return !fpregs_get(tsk, NULL, 0, sizeof(struct user_i387_ia32_struct),
     371                 :            :                            ufpu, NULL);
     372                 :            : }
     373                 :            : EXPORT_SYMBOL(dump_fpu);
     374                 :            : 
     375                 :            : #endif  /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */

Generated by: LCOV version 1.14