|  | @@ -113,3 +113,161 @@ extern int __get_user_4(void *);
 | 
	
		
			
				|  |  |  	   __asm__ __volatile__ (					\
 | 
	
		
			
				|  |  |  		__asmeq("%0", "r0") __asmeq("%1", "r2")			\
 | 
	
		
			
				|  |  |  		__asmeq("%3", "r1")					\
 | 
	
		
			
				|  |  | +		"bl	__get_user_" #__s				\
 | 
	
		
			
				|  |  | +		: "=&r" (__e), "=r" (__r2)				\
 | 
	
		
			
				|  |  | +		: "0" (__p), "r" (__l)					\
 | 
	
		
			
				|  |  | +		: __GUP_CLOBBER_##__s)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#define __get_user_check(x,p)							\
 | 
	
		
			
				|  |  | +	({								\
 | 
	
		
			
				|  |  | +		unsigned long __limit = current_thread_info()->addr_limit - 1; \
 | 
	
		
			
				|  |  | +		register const typeof(*(p)) __user *__p asm("r0") = (p);\
 | 
	
		
			
				|  |  | +		register unsigned long __r2 asm("r2");			\
 | 
	
		
			
				|  |  | +		register unsigned long __l asm("r1") = __limit;		\
 | 
	
		
			
				|  |  | +		register int __e asm("r0");				\
 | 
	
		
			
				|  |  | +		switch (sizeof(*(__p))) {				\
 | 
	
		
			
				|  |  | +		case 1:							\
 | 
	
		
			
				|  |  | +			__get_user_x(__r2, __p, __e, __l, 1);		\
 | 
	
		
			
				|  |  | +			break;						\
 | 
	
		
			
				|  |  | +		case 2:							\
 | 
	
		
			
				|  |  | +			__get_user_x(__r2, __p, __e, __l, 2);		\
 | 
	
		
			
				|  |  | +			break;						\
 | 
	
		
			
				|  |  | +		case 4:							\
 | 
	
		
			
				|  |  | +			__get_user_x(__r2, __p, __e, __l, 4);		\
 | 
	
		
			
				|  |  | +			break;						\
 | 
	
		
			
				|  |  | +		default: __e = __get_user_bad(); break;			\
 | 
	
		
			
				|  |  | +		}							\
 | 
	
		
			
				|  |  | +		x = (typeof(*(p))) __r2;				\
 | 
	
		
			
				|  |  | +		__e;							\
 | 
	
		
			
				|  |  | +	})
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#define get_user(x,p)							\
 | 
	
		
			
				|  |  | +	({								\
 | 
	
		
			
				|  |  | +		might_fault();						\
 | 
	
		
			
				|  |  | +		__get_user_check(x,p);					\
 | 
	
		
			
				|  |  | +	 })
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +extern int __put_user_1(void *, unsigned int);
 | 
	
		
			
				|  |  | +extern int __put_user_2(void *, unsigned int);
 | 
	
		
			
				|  |  | +extern int __put_user_4(void *, unsigned int);
 | 
	
		
			
				|  |  | +extern int __put_user_8(void *, unsigned long long);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#define __put_user_x(__r2,__p,__e,__l,__s)				\
 | 
	
		
			
				|  |  | +	   __asm__ __volatile__ (					\
 | 
	
		
			
				|  |  | +		__asmeq("%0", "r0") __asmeq("%2", "r2")			\
 | 
	
		
			
				|  |  | +		__asmeq("%3", "r1")					\
 | 
	
		
			
				|  |  | +		"bl	__put_user_" #__s				\
 | 
	
		
			
				|  |  | +		: "=&r" (__e)						\
 | 
	
		
			
				|  |  | +		: "0" (__p), "r" (__r2), "r" (__l)			\
 | 
	
		
			
				|  |  | +		: "ip", "lr", "cc")
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#define __put_user_check(x,p)							\
 | 
	
		
			
				|  |  | +	({								\
 | 
	
		
			
				|  |  | +		unsigned long __limit = current_thread_info()->addr_limit - 1; \
 | 
	
		
			
				|  |  | +		register const typeof(*(p)) __r2 asm("r2") = (x);	\
 | 
	
		
			
				|  |  | +		register const typeof(*(p)) __user *__p asm("r0") = (p);\
 | 
	
		
			
				|  |  | +		register unsigned long __l asm("r1") = __limit;		\
 | 
	
		
			
				|  |  | +		register int __e asm("r0");				\
 | 
	
		
			
				|  |  | +		switch (sizeof(*(__p))) {				\
 | 
	
		
			
				|  |  | +		case 1:							\
 | 
	
		
			
				|  |  | +			__put_user_x(__r2, __p, __e, __l, 1);		\
 | 
	
		
			
				|  |  | +			break;						\
 | 
	
		
			
				|  |  | +		case 2:							\
 | 
	
		
			
				|  |  | +			__put_user_x(__r2, __p, __e, __l, 2);		\
 | 
	
		
			
				|  |  | +			break;						\
 | 
	
		
			
				|  |  | +		case 4:							\
 | 
	
		
			
				|  |  | +			__put_user_x(__r2, __p, __e, __l, 4);		\
 | 
	
		
			
				|  |  | +			break;						\
 | 
	
		
			
				|  |  | +		case 8:							\
 | 
	
		
			
				|  |  | +			__put_user_x(__r2, __p, __e, __l, 8);		\
 | 
	
		
			
				|  |  | +			break;						\
 | 
	
		
			
				|  |  | +		default: __e = __put_user_bad(); break;			\
 | 
	
		
			
				|  |  | +		}							\
 | 
	
		
			
				|  |  | +		__e;							\
 | 
	
		
			
				|  |  | +	})
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#define put_user(x,p)							\
 | 
	
		
			
				|  |  | +	({								\
 | 
	
		
			
				|  |  | +		might_fault();						\
 | 
	
		
			
				|  |  | +		__put_user_check(x,p);					\
 | 
	
		
			
				|  |  | +	 })
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#else /* CONFIG_MMU */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/*
 | 
	
		
			
				|  |  | + * uClinux has only one addr space, so has simplified address limits.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +#define USER_DS			KERNEL_DS
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#define segment_eq(a,b)		(1)
 | 
	
		
			
				|  |  | +#define __addr_ok(addr)		((void)(addr),1)
 | 
	
		
			
				|  |  | +#define __range_ok(addr,size)	((void)(addr),0)
 | 
	
		
			
				|  |  | +#define get_fs()		(KERNEL_DS)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static inline void set_fs(mm_segment_t fs)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#define get_user(x,p)	__get_user(x,p)
 | 
	
		
			
				|  |  | +#define put_user(x,p)	__put_user(x,p)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#endif /* CONFIG_MMU */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#define access_ok(type,addr,size)	(__range_ok(addr,size) == 0)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#define user_addr_max() \
 | 
	
		
			
				|  |  | +	(segment_eq(get_fs(), USER_DS) ? TASK_SIZE : ~0UL)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/*
 | 
	
		
			
				|  |  | + * The "__xxx" versions of the user access functions do not verify the
 | 
	
		
			
				|  |  | + * address space - it must have been done previously with a separate
 | 
	
		
			
				|  |  | + * "access_ok()" call.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * The "xxx_error" versions set the third argument to EFAULT if an
 | 
	
		
			
				|  |  | + * error occurs, and leave it unchanged on success.  Note that these
 | 
	
		
			
				|  |  | + * versions are void (ie, don't return a value as such).
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +#define __get_user(x,ptr)						\
 | 
	
		
			
				|  |  | +({									\
 | 
	
		
			
				|  |  | +	long __gu_err = 0;						\
 | 
	
		
			
				|  |  | +	__get_user_err((x),(ptr),__gu_err);				\
 | 
	
		
			
				|  |  | +	__gu_err;							\
 | 
	
		
			
				|  |  | +})
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#define __get_user_error(x,ptr,err)					\
 | 
	
		
			
				|  |  | +({									\
 | 
	
		
			
				|  |  | +	__get_user_err((x),(ptr),err);					\
 | 
	
		
			
				|  |  | +	(void) 0;							\
 | 
	
		
			
				|  |  | +})
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#define __get_user_err(x,ptr,err)					\
 | 
	
		
			
				|  |  | +do {									\
 | 
	
		
			
				|  |  | +	unsigned long __gu_addr = (unsigned long)(ptr);			\
 | 
	
		
			
				|  |  | +	unsigned long __gu_val;						\
 | 
	
		
			
				|  |  | +	__chk_user_ptr(ptr);						\
 | 
	
		
			
				|  |  | +	might_fault();							\
 | 
	
		
			
				|  |  | +	switch (sizeof(*(ptr))) {					\
 | 
	
		
			
				|  |  | +	case 1:	__get_user_asm_byte(__gu_val,__gu_addr,err);	break;	\
 | 
	
		
			
				|  |  | +	case 2:	__get_user_asm_half(__gu_val,__gu_addr,err);	break;	\
 | 
	
		
			
				|  |  | +	case 4:	__get_user_asm_word(__gu_val,__gu_addr,err);	break;	\
 | 
	
		
			
				|  |  | +	default: (__gu_val) = __get_user_bad();				\
 | 
	
		
			
				|  |  | +	}								\
 | 
	
		
			
				|  |  | +	(x) = (__typeof__(*(ptr)))__gu_val;				\
 | 
	
		
			
				|  |  | +} while (0)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#define __get_user_asm_byte(x,addr,err)				\
 | 
	
		
			
				|  |  | +	__asm__ __volatile__(					\
 | 
	
		
			
				|  |  | +	"1:	" TUSER(ldrb) "	%1,[%2],#0\n"			\
 | 
	
		
			
				|  |  | +	"2:\n"							\
 | 
	
		
			
				|  |  | +	"	.pushsection .fixup,\"ax\"\n"			\
 | 
	
		
			
				|  |  | +	"	.align	2\n"					\
 | 
	
		
			
				|  |  | +	"3:	mov	%0, %3\n"				\
 | 
	
		
			
				|  |  | +	"	mov	%1, #0\n"				\
 | 
	
		
			
				|  |  | +	"	b	2b\n"					\
 | 
	
		
			
				|  |  | +	"	.popsection\n"					\
 | 
	
		
			
				|  |  | +	"	.pushsection __ex_table,\"a\"\n"		\
 | 
	
		
			
				|  |  | +	"	.align	3\n"					\
 | 
	
		
			
				|  |  | +	"	.long	1b, 3b\n"				\
 | 
	
		
			
				|  |  | +	"	.popsection"					\
 | 
	
		
			
				|  |  | +	: "+r" (err), "=&r" (x)					\
 | 
	
		
			
				|  |  | +	: "r" (addr), "i" (-EFAULT)				\
 |