LCOV - code coverage report
Current view: top level - arch/x86/include/asm - uaccess_64.h (source / functions) Hit Total Coverage
Test: combined.info Lines: 23 90 25.6 %
Date: 2022-03-28 13:20:08 Functions: 0 0 -
Branches: 7 134 5.2 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: GPL-2.0 */
       2                 :            : #ifndef _ASM_X86_UACCESS_64_H
       3                 :            : #define _ASM_X86_UACCESS_64_H
       4                 :            : 
       5                 :            : /*
       6                 :            :  * User space memory access functions
       7                 :            :  */
       8                 :            : #include <linux/compiler.h>
       9                 :            : #include <linux/lockdep.h>
      10                 :            : #include <linux/kasan-checks.h>
      11                 :            : #include <asm/alternative.h>
      12                 :            : #include <asm/cpufeatures.h>
      13                 :            : #include <asm/page.h>
      14                 :            : 
      15                 :            : /*
      16                 :            :  * Copy To/From Userspace
      17                 :            :  */
      18                 :            : 
      19                 :            : /* Handles exceptions in both to and from, but doesn't do access_ok */
      20                 :            : __must_check unsigned long
      21                 :            : copy_user_enhanced_fast_string(void *to, const void *from, unsigned len);
      22                 :            : __must_check unsigned long
      23                 :            : copy_user_generic_string(void *to, const void *from, unsigned len);
      24                 :            : __must_check unsigned long
      25                 :            : copy_user_generic_unrolled(void *to, const void *from, unsigned len);
      26                 :            : 
      27                 :            : static __always_inline __must_check unsigned long
      28                 :    8345445 : copy_user_generic(void *to, const void *from, unsigned len)
      29                 :            : {
      30                 :    8345445 :         unsigned ret;
      31                 :            : 
      32                 :            :         /*
      33                 :            :          * If CPU has ERMS feature, use copy_user_enhanced_fast_string.
      34                 :            :          * Otherwise, if CPU has rep_good feature, use copy_user_generic_string.
      35                 :            :          * Otherwise, use copy_user_generic_unrolled.
      36                 :            :          */
      37                 :    8345445 :         alternative_call_2(copy_user_generic_unrolled,
      38                 :            :                          copy_user_generic_string,
      39                 :            :                          X86_FEATURE_REP_GOOD,
      40                 :            :                          copy_user_enhanced_fast_string,
      41                 :            :                          X86_FEATURE_ERMS,
      42                 :            :                          ASM_OUTPUT2("=a" (ret), "=D" (to), "=S" (from),
      43                 :            :                                      "=d" (len)),
      44                 :            :                          "1" (to), "2" (from), "3" (len)
      45                 :            :                          : "memory", "rcx", "r8", "r9", "r10", "r11");
      46   [ -  -  -  -  :    8345445 :         return ret;
          +  -  -  -  -  
                #  #  # ]
      47                 :            : }
      48                 :            : 
      49                 :            : static __always_inline __must_check unsigned long
      50                 :          0 : copy_to_user_mcsafe(void *to, const void *from, unsigned len)
      51                 :            : {
      52                 :          0 :         unsigned long ret;
      53                 :            : 
      54                 :          0 :         __uaccess_begin();
      55                 :            :         /*
      56                 :            :          * Note, __memcpy_mcsafe() is explicitly used since it can
      57                 :            :          * handle exceptions / faults.  memcpy_mcsafe() may fall back to
      58                 :            :          * memcpy() which lacks this handling.
      59                 :            :          */
      60                 :          0 :         ret = __memcpy_mcsafe(to, from, len);
      61                 :          0 :         __uaccess_end();
      62                 :          0 :         return ret;
      63                 :            : }
      64                 :            : 
      65                 :            : static __always_inline __must_check unsigned long
      66                 :    4686687 : raw_copy_from_user(void *dst, const void __user *src, unsigned long size)
      67                 :            : {
      68                 :    4686687 :         int ret = 0;
      69                 :            : 
      70   [ +  -  +  - ]:    4686687 :         if (!__builtin_constant_p(size))
      71                 :    4615089 :                 return copy_user_generic(dst, (__force void *)src, size);
      72   [ #  #  #  #  :      71598 :         switch (size) {
          #  #  #  #  #  
             #  #  #  #  
                      # ]
      73                 :            :         case 1:
      74                 :          0 :                 __uaccess_begin_nospec();
      75                 :          0 :                 __get_user_asm_nozero(*(u8 *)dst, (u8 __user *)src,
      76                 :            :                               ret, "b", "b", "=q", 1);
      77                 :          0 :                 __uaccess_end();
      78                 :          0 :                 return ret;
      79                 :            :         case 2:
      80                 :          0 :                 __uaccess_begin_nospec();
      81                 :          0 :                 __get_user_asm_nozero(*(u16 *)dst, (u16 __user *)src,
      82                 :            :                               ret, "w", "w", "=r", 2);
      83                 :          0 :                 __uaccess_end();
      84                 :          0 :                 return ret;
      85                 :            :         case 4:
      86                 :          0 :                 __uaccess_begin_nospec();
      87                 :          0 :                 __get_user_asm_nozero(*(u32 *)dst, (u32 __user *)src,
      88                 :            :                               ret, "l", "k", "=r", 4);
      89                 :          0 :                 __uaccess_end();
      90   [ #  #  #  # ]:          0 :                 return ret;
      91                 :            :         case 8:
      92                 :      71598 :                 __uaccess_begin_nospec();
      93                 :      71598 :                 __get_user_asm_nozero(*(u64 *)dst, (u64 __user *)src,
      94                 :            :                               ret, "q", "", "=r", 8);
      95                 :      71598 :                 __uaccess_end();
      96   [ -  +  #  # ]:      71598 :                 return ret;
      97                 :            :         case 10:
      98                 :          0 :                 __uaccess_begin_nospec();
      99                 :          0 :                 __get_user_asm_nozero(*(u64 *)dst, (u64 __user *)src,
     100                 :            :                                ret, "q", "", "=r", 10);
     101   [ #  #  #  # ]:          0 :                 if (likely(!ret))
     102                 :          0 :                         __get_user_asm_nozero(*(u16 *)(8 + (char *)dst),
     103                 :            :                                        (u16 __user *)(8 + (char __user *)src),
     104                 :            :                                        ret, "w", "w", "=r", 2);
     105                 :          0 :                 __uaccess_end();
     106                 :          0 :                 return ret;
     107                 :            :         case 16:
     108                 :          0 :                 __uaccess_begin_nospec();
     109                 :          0 :                 __get_user_asm_nozero(*(u64 *)dst, (u64 __user *)src,
     110                 :            :                                ret, "q", "", "=r", 16);
     111   [ #  #  #  # ]:          0 :                 if (likely(!ret))
     112                 :          0 :                         __get_user_asm_nozero(*(u64 *)(8 + (char *)dst),
     113                 :            :                                        (u64 __user *)(8 + (char __user *)src),
     114                 :            :                                        ret, "q", "", "=r", 8);
     115                 :          0 :                 __uaccess_end();
     116         [ #  # ]:          0 :                 return ret;
     117                 :          0 :         default:
     118                 :          0 :                 return copy_user_generic(dst, (__force void *)src, size);
     119                 :            :         }
     120                 :            : }
     121                 :            : 
     122                 :            : static __always_inline __must_check unsigned long
     123                 :    3801954 : raw_copy_to_user(void __user *dst, const void *src, unsigned long size)
     124                 :            : {
     125                 :    3801954 :         int ret = 0;
     126                 :            : 
     127   [ +  -  #  # ]:    3801954 :         if (!__builtin_constant_p(size))
     128                 :    3657498 :                 return copy_user_generic((__force void *)dst, src, size);
     129   [ #  #  #  #  :     144456 :         switch (size) {
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     130                 :            :         case 1:
     131                 :          0 :                 __uaccess_begin();
     132   [ #  #  #  #  :          0 :                 __put_user_asm(*(u8 *)src, (u8 __user *)dst,
                   #  # ]
     133                 :            :                               ret, "b", "b", "iq", 1);
     134                 :          0 :                 __uaccess_end();
     135         [ #  # ]:          0 :                 return ret;
     136                 :            :         case 2:
     137                 :          0 :                 __uaccess_begin();
     138   [ #  #  #  # ]:          0 :                 __put_user_asm(*(u16 *)src, (u16 __user *)dst,
     139                 :            :                               ret, "w", "w", "ir", 2);
     140                 :          0 :                 __uaccess_end();
     141                 :          0 :                 return ret;
     142                 :            :         case 4:
     143                 :          0 :                 __uaccess_begin();
     144   [ #  #  #  # ]:          0 :                 __put_user_asm(*(u32 *)src, (u32 __user *)dst,
     145                 :            :                               ret, "l", "k", "ir", 4);
     146                 :          0 :                 __uaccess_end();
     147         [ #  # ]:          0 :                 return ret;
     148                 :            :         case 8:
     149                 :      71598 :                 __uaccess_begin();
     150   [ +  -  #  # ]:      71598 :                 __put_user_asm(*(u64 *)src, (u64 __user *)dst,
     151                 :            :                               ret, "q", "", "er", 8);
     152                 :      71598 :                 __uaccess_end();
     153         [ +  - ]:      71598 :                 return ret;
     154                 :            :         case 10:
     155                 :          0 :                 __uaccess_begin();
     156   [ #  #  #  # ]:          0 :                 __put_user_asm(*(u64 *)src, (u64 __user *)dst,
     157                 :            :                                ret, "q", "", "er", 10);
     158   [ #  #  #  # ]:          0 :                 if (likely(!ret)) {
     159                 :          0 :                         asm("":::"memory");
     160   [ #  #  #  # ]:          0 :                         __put_user_asm(4[(u16 *)src], 4 + (u16 __user *)dst,
     161                 :            :                                        ret, "w", "w", "ir", 2);
     162                 :            :                 }
     163                 :          0 :                 __uaccess_end();
     164                 :          0 :                 return ret;
     165                 :            :         case 16:
     166                 :          0 :                 __uaccess_begin();
     167   [ #  #  #  #  :          0 :                 __put_user_asm(*(u64 *)src, (u64 __user *)dst,
             #  #  #  # ]
     168                 :            :                                ret, "q", "", "er", 16);
     169   [ #  #  #  #  :          0 :                 if (likely(!ret)) {
             #  #  #  # ]
     170                 :          0 :                         asm("":::"memory");
     171   [ #  #  #  #  :          0 :                         __put_user_asm(1[(u64 *)src], 1 + (u64 __user *)dst,
             #  #  #  # ]
     172                 :            :                                        ret, "q", "", "er", 8);
     173                 :            :                 }
     174                 :          0 :                 __uaccess_end();
     175   [ #  #  #  # ]:          0 :                 return ret;
     176                 :          0 :         default:
     177                 :      72858 :                 return copy_user_generic((__force void *)dst, src, size);
     178                 :            :         }
     179                 :            : }
     180                 :            : 
     181                 :            : static __always_inline __must_check
     182                 :          0 : unsigned long raw_copy_in_user(void __user *dst, const void __user *src, unsigned long size)
     183                 :            : {
     184                 :          0 :         return copy_user_generic((__force void *)dst,
     185                 :            :                                  (__force void *)src, size);
     186                 :            : }
     187                 :            : 
     188                 :            : extern long __copy_user_nocache(void *dst, const void __user *src,
     189                 :            :                                 unsigned size, int zerorest);
     190                 :            : 
     191                 :            : extern long __copy_user_flushcache(void *dst, const void __user *src, unsigned size);
     192                 :            : extern void memcpy_page_flushcache(char *to, struct page *page, size_t offset,
     193                 :            :                            size_t len);
     194                 :            : 
     195                 :            : static inline int
     196                 :          0 : __copy_from_user_inatomic_nocache(void *dst, const void __user *src,
     197                 :            :                                   unsigned size)
     198                 :            : {
     199                 :          0 :         kasan_check_write(dst, size);
     200   [ #  #  #  # ]:          0 :         return __copy_user_nocache(dst, src, size, 0);
     201                 :            : }
     202                 :            : 
     203                 :            : static inline int
     204                 :          0 : __copy_from_user_flushcache(void *dst, const void __user *src, unsigned size)
     205                 :            : {
     206                 :          0 :         kasan_check_write(dst, size);
     207                 :          0 :         return __copy_user_flushcache(dst, src, size);
     208                 :            : }
     209                 :            : 
     210                 :            : unsigned long
     211                 :            : mcsafe_handle_tail(char *to, char *from, unsigned len);
     212                 :            : 
     213                 :            : #endif /* _ASM_X86_UACCESS_64_H */

Generated by: LCOV version 1.14