LCOV - code coverage report
Current view: top level - arch/arm/include/asm - futex.h (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_real_modules_combined.info Lines: 7 15 46.7 %
Date: 2020-09-30 20:25:40 Functions: 1 2 50.0 %
Branches: 1 8 12.5 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: GPL-2.0 */
       2                 :            : #ifndef _ASM_ARM_FUTEX_H
       3                 :            : #define _ASM_ARM_FUTEX_H
       4                 :            : 
       5                 :            : #ifdef __KERNEL__
       6                 :            : 
       7                 :            : #include <linux/futex.h>
       8                 :            : #include <linux/uaccess.h>
       9                 :            : #include <asm/errno.h>
      10                 :            : 
      11                 :            : #define __futex_atomic_ex_table(err_reg)                        \
      12                 :            :         "3:\n"                                                        \
      13                 :            :         "  .pushsection __ex_table,\"a\"\n"         \
      14                 :            :         "  .align  3\n"                                       \
      15                 :            :         "  .long   1b, 4f, 2b, 4f\n"                  \
      16                 :            :         "  .popsection\n"                                     \
      17                 :            :         "  .pushsection .text.fixup,\"ax\"\n"               \
      18                 :            :         "  .align  2\n"                                       \
      19                 :            :         "4:        mov     %0, " err_reg "\n"                       \
      20                 :            :         "  b       3b\n"                                      \
      21                 :            :         "  .popsection"
      22                 :            : 
      23                 :            : #ifdef CONFIG_SMP
      24                 :            : 
      25                 :            : #define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \
      26                 :            : ({                                                              \
      27                 :            :         unsigned int __ua_flags;                                \
      28                 :            :         smp_mb();                                               \
      29                 :            :         prefetchw(uaddr);                                       \
      30                 :            :         __ua_flags = uaccess_save_and_enable();                 \
      31                 :            :         __asm__ __volatile__(                                   \
      32                 :            :         "1:        ldrex   %1, [%3]\n"                                \
      33                 :            :         "  " insn "\n"                                      \
      34                 :            :         "2:        strex   %2, %0, [%3]\n"                            \
      35                 :            :         "  teq     %2, #0\n"                          \
      36                 :            :         "  bne     1b\n"                                      \
      37                 :            :         "  mov     %0, #0\n"                          \
      38                 :            :         __futex_atomic_ex_table("%5")                         \
      39                 :            :         : "=&r" (ret), "=&r" (oldval), "=&r" (tmp)            \
      40                 :            :         : "r" (uaddr), "r" (oparg), "Ir" (-EFAULT)                \
      41                 :            :         : "cc", "memory");                                  \
      42                 :            :         uaccess_restore(__ua_flags);                            \
      43                 :            : })
      44                 :            : 
      45                 :            : static inline int
      46                 :        207 : futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
      47                 :            :                               u32 oldval, u32 newval)
      48                 :            : {
      49                 :            :         unsigned int __ua_flags;
      50                 :            :         int ret;
      51                 :            :         u32 val;
      52                 :            : 
      53         [ +  - ]:        207 :         if (!access_ok(uaddr, sizeof(u32)))
      54                 :            :                 return -EFAULT;
      55                 :            : 
      56                 :        207 :         smp_mb();
      57                 :            :         /* Prefetching cannot fault */
      58                 :            :         prefetchw(uaddr);
      59                 :            :         __ua_flags = uaccess_save_and_enable();
      60                 :        207 :         __asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n"
      61                 :            :         "1:        ldrex   %1, [%4]\n"
      62                 :            :         "  teq     %1, %2\n"
      63                 :            :         "  ite     eq      @ explicit IT needed for the 2b label\n"
      64                 :            :         "2:        strexeq %0, %3, [%4]\n"
      65                 :            :         "  movne   %0, #0\n"
      66                 :            :         "  teq     %0, #0\n"
      67                 :            :         "  bne     1b\n"
      68                 :            :         __futex_atomic_ex_table("%5")
      69                 :            :         : "=&r" (ret), "=&r" (val)
      70                 :            :         : "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT)
      71                 :            :         : "cc", "memory");
      72                 :            :         uaccess_restore(__ua_flags);
      73                 :        207 :         smp_mb();
      74                 :            : 
      75                 :        207 :         *uval = val;
      76                 :        207 :         return ret;
      77                 :            : }
      78                 :            : 
      79                 :            : #else /* !SMP, we can work around lack of atomic ops by disabling preemption */
      80                 :            : 
      81                 :            : #include <linux/preempt.h>
      82                 :            : #include <asm/domain.h>
      83                 :            : 
      84                 :            : #define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \
      85                 :            : ({                                                              \
      86                 :            :         unsigned int __ua_flags = uaccess_save_and_enable();    \
      87                 :            :         __asm__ __volatile__(                                   \
      88                 :            :         "1:        " TUSER(ldr) "        %1, [%3]\n"                        \
      89                 :            :         "  " insn "\n"                                      \
      90                 :            :         "2:        " TUSER(str) "        %0, [%3]\n"                        \
      91                 :            :         "  mov     %0, #0\n"                          \
      92                 :            :         __futex_atomic_ex_table("%5")                         \
      93                 :            :         : "=&r" (ret), "=&r" (oldval), "=&r" (tmp)            \
      94                 :            :         : "r" (uaddr), "r" (oparg), "Ir" (-EFAULT)                \
      95                 :            :         : "cc", "memory");                                  \
      96                 :            :         uaccess_restore(__ua_flags);                            \
      97                 :            : })
      98                 :            : 
      99                 :            : static inline int
     100                 :            : futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
     101                 :            :                               u32 oldval, u32 newval)
     102                 :            : {
     103                 :            :         unsigned int __ua_flags;
     104                 :            :         int ret = 0;
     105                 :            :         u32 val;
     106                 :            : 
     107                 :            :         if (!access_ok(uaddr, sizeof(u32)))
     108                 :            :                 return -EFAULT;
     109                 :            : 
     110                 :            :         preempt_disable();
     111                 :            :         __ua_flags = uaccess_save_and_enable();
     112                 :            :         __asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n"
     113                 :            :         "  .syntax unified\n"
     114                 :            :         "1:        " TUSER(ldr) "        %1, [%4]\n"
     115                 :            :         "  teq     %1, %2\n"
     116                 :            :         "  it      eq      @ explicit IT needed for the 2b label\n"
     117                 :            :         "2:        " TUSERCOND(str, eq) "        %3, [%4]\n"
     118                 :            :         __futex_atomic_ex_table("%5")
     119                 :            :         : "+r" (ret), "=&r" (val)
     120                 :            :         : "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT)
     121                 :            :         : "cc", "memory");
     122                 :            :         uaccess_restore(__ua_flags);
     123                 :            : 
     124                 :            :         *uval = val;
     125                 :            :         preempt_enable();
     126                 :            : 
     127                 :            :         return ret;
     128                 :            : }
     129                 :            : 
     130                 :            : #endif /* !SMP */
     131                 :            : 
     132                 :            : static inline int
     133                 :          0 : arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
     134                 :            : {
     135                 :            :         int oldval = 0, ret, tmp;
     136                 :            : 
     137                 :            : #ifndef CONFIG_SMP
     138                 :            :         preempt_disable();
     139                 :            : #endif
     140                 :            :         pagefault_disable();
     141                 :            : 
     142   [ #  #  #  #  :          0 :         switch (op) {
                   #  # ]
     143                 :            :         case FUTEX_OP_SET:
     144                 :          0 :                 __futex_atomic_op("mov     %0, %4", ret, oldval, tmp, uaddr, oparg);
     145                 :            :                 break;
     146                 :            :         case FUTEX_OP_ADD:
     147                 :          0 :                 __futex_atomic_op("add     %0, %1, %4", ret, oldval, tmp, uaddr, oparg);
     148                 :            :                 break;
     149                 :            :         case FUTEX_OP_OR:
     150                 :          0 :                 __futex_atomic_op("orr     %0, %1, %4", ret, oldval, tmp, uaddr, oparg);
     151                 :            :                 break;
     152                 :            :         case FUTEX_OP_ANDN:
     153                 :          0 :                 __futex_atomic_op("and     %0, %1, %4", ret, oldval, tmp, uaddr, ~oparg);
     154                 :            :                 break;
     155                 :            :         case FUTEX_OP_XOR:
     156                 :          0 :                 __futex_atomic_op("eor     %0, %1, %4", ret, oldval, tmp, uaddr, oparg);
     157                 :            :                 break;
     158                 :            :         default:
     159                 :            :                 ret = -ENOSYS;
     160                 :            :         }
     161                 :            : 
     162                 :            :         pagefault_enable();
     163                 :            : #ifndef CONFIG_SMP
     164                 :            :         preempt_enable();
     165                 :            : #endif
     166                 :            : 
     167                 :            :         /*
     168                 :            :          * Store unconditionally. If ret != 0 the extra store is the least
     169                 :            :          * of the worries but GCC cannot figure out that __futex_atomic_op()
     170                 :            :          * is either setting ret to -EFAULT or storing the old value in
     171                 :            :          * oldval which results in a uninitialized warning at the call site.
     172                 :            :          */
     173                 :            :         *oval = oldval;
     174                 :            : 
     175                 :          0 :         return ret;
     176                 :            : }
     177                 :            : 
     178                 :            : #endif /* __KERNEL__ */
     179                 :            : #endif /* _ASM_ARM_FUTEX_H */

Generated by: LCOV version 1.14