Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 #ifndef _ASM_GENERIC_FUTEX_H
0003 #define _ASM_GENERIC_FUTEX_H
0004 
0005 #include <linux/futex.h>
0006 #include <linux/uaccess.h>
0007 #include <asm/errno.h>
0008 
0009 #ifndef futex_atomic_cmpxchg_inatomic
0010 #ifndef CONFIG_SMP
0011 /*
0012  * The following implementation only for uniprocessor machines.
0013  * It relies on preempt_disable() ensuring mutual exclusion.
0014  *
0015  */
0016 #define futex_atomic_cmpxchg_inatomic(uval, uaddr, oldval, newval) \
0017     futex_atomic_cmpxchg_inatomic_local(uval, uaddr, oldval, newval)
0018 #define arch_futex_atomic_op_inuser(op, oparg, oval, uaddr) \
0019     futex_atomic_op_inuser_local(op, oparg, oval, uaddr)
0020 #endif /* CONFIG_SMP */
0021 #endif
0022 
0023 /**
0024  * futex_atomic_op_inuser_local() - Atomic arithmetic operation with constant
0025  *            argument and comparison of the previous
0026  *            futex value with another constant.
0027  *
0028  * @encoded_op: encoded operation to execute
0029  * @uaddr:  pointer to user space address
0030  *
0031  * Return:
0032  * 0 - On success
0033  * -EFAULT - User access resulted in a page fault
0034  * -EAGAIN - Atomic operation was unable to complete due to contention
0035  * -ENOSYS - Operation not supported
0036  */
0037 static inline int
0038 futex_atomic_op_inuser_local(int op, u32 oparg, int *oval, u32 __user *uaddr)
0039 {
0040     int oldval, ret;
0041     u32 tmp;
0042 
0043     preempt_disable();
0044 
0045     ret = -EFAULT;
0046     if (unlikely(get_user(oldval, uaddr) != 0))
0047         goto out_pagefault_enable;
0048 
0049     ret = 0;
0050     tmp = oldval;
0051 
0052     switch (op) {
0053     case FUTEX_OP_SET:
0054         tmp = oparg;
0055         break;
0056     case FUTEX_OP_ADD:
0057         tmp += oparg;
0058         break;
0059     case FUTEX_OP_OR:
0060         tmp |= oparg;
0061         break;
0062     case FUTEX_OP_ANDN:
0063         tmp &= ~oparg;
0064         break;
0065     case FUTEX_OP_XOR:
0066         tmp ^= oparg;
0067         break;
0068     default:
0069         ret = -ENOSYS;
0070     }
0071 
0072     if (ret == 0 && unlikely(put_user(tmp, uaddr) != 0))
0073         ret = -EFAULT;
0074 
0075 out_pagefault_enable:
0076     preempt_enable();
0077 
0078     if (ret == 0)
0079         *oval = oldval;
0080 
0081     return ret;
0082 }
0083 
0084 /**
0085  * futex_atomic_cmpxchg_inatomic_local() - Compare and exchange the content of the
0086  *              uaddr with newval if the current value is
0087  *              oldval.
0088  * @uval:   pointer to store content of @uaddr
0089  * @uaddr:  pointer to user space address
0090  * @oldval: old value
0091  * @newval: new value to store to @uaddr
0092  *
0093  * Return:
0094  * 0 - On success
0095  * -EFAULT - User access resulted in a page fault
0096  * -EAGAIN - Atomic operation was unable to complete due to contention
0097  */
0098 static inline int
0099 futex_atomic_cmpxchg_inatomic_local(u32 *uval, u32 __user *uaddr,
0100                   u32 oldval, u32 newval)
0101 {
0102     u32 val;
0103 
0104     preempt_disable();
0105     if (unlikely(get_user(val, uaddr) != 0)) {
0106         preempt_enable();
0107         return -EFAULT;
0108     }
0109 
0110     if (val == oldval && unlikely(put_user(newval, uaddr) != 0)) {
0111         preempt_enable();
0112         return -EFAULT;
0113     }
0114 
0115     *uval = val;
0116     preempt_enable();
0117 
0118     return 0;
0119 }
0120 
0121 #endif