diff options
Diffstat (limited to 'arch/s390/include/asm/uaccess.h')
| -rw-r--r-- | arch/s390/include/asm/uaccess.h | 209 | 
1 files changed, 100 insertions, 109 deletions
diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h index 9c33ed4e666..cd4c68e0398 100644 --- a/arch/s390/include/asm/uaccess.h +++ b/arch/s390/include/asm/uaccess.h @@ -92,39 +92,88 @@ static inline unsigned long extable_fixup(const struct exception_table_entry *x)  #define ARCH_HAS_SORT_EXTABLE  #define ARCH_HAS_SEARCH_EXTABLE -struct uaccess_ops { -	size_t (*copy_from_user)(size_t, const void __user *, void *); -	size_t (*copy_from_user_small)(size_t, const void __user *, void *); -	size_t (*copy_to_user)(size_t, void __user *, const void *); -	size_t (*copy_to_user_small)(size_t, void __user *, const void *); -	size_t (*copy_in_user)(size_t, void __user *, const void __user *); -	size_t (*clear_user)(size_t, void __user *); -	size_t (*strnlen_user)(size_t, const char __user *); -	size_t (*strncpy_from_user)(size_t, const char __user *, char *); -	int (*futex_atomic_op)(int op, u32 __user *, int oparg, int *old); -	int (*futex_atomic_cmpxchg)(u32 *, u32 __user *, u32 old, u32 new); -}; +/** + * __copy_from_user: - Copy a block of data from user space, with less checking. + * @to:   Destination address, in kernel space. + * @from: Source address, in user space. + * @n:	  Number of bytes to copy. + * + * Context: User context only.	This function may sleep. + * + * Copy data from user space to kernel space.  Caller must check + * the specified block with access_ok() before calling this function. + * + * Returns number of bytes that could not be copied. + * On success, this will be zero. + * + * If some data could not be copied, this function will pad the copied + * data to the requested size using zero bytes. + */ +unsigned long __must_check __copy_from_user(void *to, const void __user *from, +					    unsigned long n); -extern struct uaccess_ops uaccess; -extern struct uaccess_ops uaccess_std; -extern struct uaccess_ops uaccess_mvcos; -extern struct uaccess_ops uaccess_mvcos_switch; -extern struct uaccess_ops uaccess_pt; +/** + * __copy_to_user: - Copy a block of data into user space, with less checking. + * @to:   Destination address, in user space. + * @from: Source address, in kernel space. + * @n:	  Number of bytes to copy. + * + * Context: User context only.	This function may sleep. + * + * Copy data from kernel space to user space.  Caller must check + * the specified block with access_ok() before calling this function. + * + * Returns number of bytes that could not be copied. + * On success, this will be zero. + */ +unsigned long __must_check __copy_to_user(void __user *to, const void *from, +					  unsigned long n); + +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user + +#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES + +#define __put_get_user_asm(to, from, size, spec)		\ +({								\ +	register unsigned long __reg0 asm("0") = spec;		\ +	int __rc;						\ +								\ +	asm volatile(						\ +		"0:	mvcos	%1,%3,%2\n"			\ +		"1:	xr	%0,%0\n"			\ +		"2:\n"						\ +		".pushsection .fixup, \"ax\"\n"			\ +		"3:	lhi	%0,%5\n"			\ +		"	jg	2b\n"				\ +		".popsection\n"					\ +		EX_TABLE(0b,3b) EX_TABLE(1b,3b)			\ +		: "=d" (__rc), "=Q" (*(to))			\ +		: "d" (size), "Q" (*(from)),			\ +		  "d" (__reg0), "K" (-EFAULT)			\ +		: "cc");					\ +	__rc;							\ +}) + +#define __put_user_fn(x, ptr, size) __put_get_user_asm(ptr, x, size, 0x810000UL) +#define __get_user_fn(x, ptr, size) __put_get_user_asm(x, ptr, size, 0x81UL) -extern int __handle_fault(unsigned long, unsigned long, int); +#else /* CONFIG_HAVE_MARCH_Z10_FEATURES */ -static inline int __put_user_fn(size_t size, void __user *ptr, void *x) +static inline int __put_user_fn(void *x, void __user *ptr, unsigned long size)  { -	size = uaccess.copy_to_user_small(size, ptr, x); -	return size ? -EFAULT : size; +	size = __copy_to_user(ptr, x, size); +	return size ? -EFAULT : 0;  } -static inline int __get_user_fn(size_t size, const void __user *ptr, void *x) +static inline int __get_user_fn(void *x, const void __user *ptr, unsigned long size)  { -	size = uaccess.copy_from_user_small(size, ptr, x); -	return size ? -EFAULT : size; +	size = __copy_from_user(x, ptr, size); +	return size ? -EFAULT : 0;  } +#endif /* CONFIG_HAVE_MARCH_Z10_FEATURES */ +  /*   * These are the main single-value transfer routines.  They automatically   * use the right size if we just have the right pointer type. @@ -139,8 +188,8 @@ static inline int __get_user_fn(size_t size, const void __user *ptr, void *x)  	case 2:							\  	case 4:							\  	case 8:							\ -		__pu_err = __put_user_fn(sizeof (*(ptr)),	\ -					 ptr, &__x);		\ +		__pu_err = __put_user_fn(&__x, ptr,		\ +					 sizeof(*(ptr)));	\  		break;						\  	default:						\  		__put_user_bad();				\ @@ -156,7 +205,7 @@ static inline int __get_user_fn(size_t size, const void __user *ptr, void *x)  }) -extern int __put_user_bad(void) __attribute__((noreturn)); +int __put_user_bad(void) __attribute__((noreturn));  #define __get_user(x, ptr)					\  ({								\ @@ -165,29 +214,29 @@ extern int __put_user_bad(void) __attribute__((noreturn));  	switch (sizeof(*(ptr))) {				\  	case 1: {						\  		unsigned char __x;				\ -		__gu_err = __get_user_fn(sizeof (*(ptr)),	\ -					 ptr, &__x);		\ +		__gu_err = __get_user_fn(&__x, ptr,		\ +					 sizeof(*(ptr)));	\  		(x) = *(__force __typeof__(*(ptr)) *) &__x;	\  		break;						\  	};							\  	case 2: {						\  		unsigned short __x;				\ -		__gu_err = __get_user_fn(sizeof (*(ptr)),	\ -					 ptr, &__x);		\ +		__gu_err = __get_user_fn(&__x, ptr,		\ +					 sizeof(*(ptr)));	\  		(x) = *(__force __typeof__(*(ptr)) *) &__x;	\  		break;						\  	};							\  	case 4: {						\  		unsigned int __x;				\ -		__gu_err = __get_user_fn(sizeof (*(ptr)),	\ -					 ptr, &__x);		\ +		__gu_err = __get_user_fn(&__x, ptr,		\ +					 sizeof(*(ptr)));	\  		(x) = *(__force __typeof__(*(ptr)) *) &__x;	\  		break;						\  	};							\  	case 8: {						\  		unsigned long long __x;				\ -		__gu_err = __get_user_fn(sizeof (*(ptr)),	\ -					 ptr, &__x);		\ +		__gu_err = __get_user_fn(&__x, ptr,		\ +					 sizeof(*(ptr)));	\  		(x) = *(__force __typeof__(*(ptr)) *) &__x;	\  		break;						\  	};							\ @@ -204,38 +253,12 @@ extern int __put_user_bad(void) __attribute__((noreturn));  	__get_user(x, ptr);					\  }) -extern int __get_user_bad(void) __attribute__((noreturn)); +int __get_user_bad(void) __attribute__((noreturn));  #define __put_user_unaligned __put_user  #define __get_user_unaligned __get_user  /** - * __copy_to_user: - Copy a block of data into user space, with less checking. - * @to:   Destination address, in user space. - * @from: Source address, in kernel space. - * @n:    Number of bytes to copy. - * - * Context: User context only.  This function may sleep. - * - * Copy data from kernel space to user space.  Caller must check - * the specified block with access_ok() before calling this function. - * - * Returns number of bytes that could not be copied. - * On success, this will be zero. - */ -static inline unsigned long __must_check -__copy_to_user(void __user *to, const void *from, unsigned long n) -{ -	if (__builtin_constant_p(n) && (n <= 256)) -		return uaccess.copy_to_user_small(n, to, from); -	else -		return uaccess.copy_to_user(n, to, from); -} - -#define __copy_to_user_inatomic __copy_to_user -#define __copy_from_user_inatomic __copy_from_user - -/**   * copy_to_user: - Copy a block of data into user space.   * @to:   Destination address, in user space.   * @from: Source address, in kernel space. @@ -255,33 +278,7 @@ copy_to_user(void __user *to, const void *from, unsigned long n)  	return __copy_to_user(to, from, n);  } -/** - * __copy_from_user: - Copy a block of data from user space, with less checking. - * @to:   Destination address, in kernel space. - * @from: Source address, in user space. - * @n:    Number of bytes to copy. - * - * Context: User context only.  This function may sleep. - * - * Copy data from user space to kernel space.  Caller must check - * the specified block with access_ok() before calling this function. - * - * Returns number of bytes that could not be copied. - * On success, this will be zero. - * - * If some data could not be copied, this function will pad the copied - * data to the requested size using zero bytes. - */ -static inline unsigned long __must_check -__copy_from_user(void *to, const void __user *from, unsigned long n) -{ -	if (__builtin_constant_p(n) && (n <= 256)) -		return uaccess.copy_from_user_small(n, from, to); -	else -		return uaccess.copy_from_user(n, from, to); -} - -extern void copy_from_user_overflow(void) +void copy_from_user_overflow(void)  #ifdef CONFIG_DEBUG_STRICT_USER_COPY_CHECKS  __compiletime_warning("copy_from_user() buffer size is not provably correct")  #endif @@ -316,11 +313,8 @@ copy_from_user(void *to, const void __user *from, unsigned long n)  	return __copy_from_user(to, from, n);  } -static inline unsigned long __must_check -__copy_in_user(void __user *to, const void __user *from, unsigned long n) -{ -	return uaccess.copy_in_user(n, to, from); -} +unsigned long __must_check +__copy_in_user(void __user *to, const void __user *from, unsigned long n);  static inline unsigned long __must_check  copy_in_user(void __user *to, const void __user *from, unsigned long n) @@ -332,18 +326,22 @@ copy_in_user(void __user *to, const void __user *from, unsigned long n)  /*   * Copy a null terminated string from userspace.   */ + +long __strncpy_from_user(char *dst, const char __user *src, long count); +  static inline long __must_check  strncpy_from_user(char *dst, const char __user *src, long count)  {  	might_fault(); -	return uaccess.strncpy_from_user(count, src, dst); +	return __strncpy_from_user(dst, src, count);  } -static inline unsigned long -strnlen_user(const char __user * src, unsigned long n) +unsigned long __must_check __strnlen_user(const char __user *src, unsigned long count); + +static inline unsigned long strnlen_user(const char __user *src, unsigned long n)  {  	might_fault(); -	return uaccess.strnlen_user(n, src); +	return __strnlen_user(src, n);  }  /** @@ -365,21 +363,14 @@ strnlen_user(const char __user * src, unsigned long n)  /*   * Zero Userspace   */ +unsigned long __must_check __clear_user(void __user *to, unsigned long size); -static inline unsigned long __must_check -__clear_user(void __user *to, unsigned long n) -{ -	return uaccess.clear_user(n, to); -} - -static inline unsigned long __must_check -clear_user(void __user *to, unsigned long n) +static inline unsigned long __must_check clear_user(void __user *to, unsigned long n)  {  	might_fault(); -	return uaccess.clear_user(n, to); +	return __clear_user(to, n);  } -extern int copy_to_user_real(void __user *dest, void *src, size_t count); -extern int copy_from_user_real(void *dest, void __user *src, size_t count); +int copy_to_user_real(void __user *dest, void *src, unsigned long count);  #endif /* __S390_UACCESS_H */  | 
