Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d9981380 authored by Victor Kamensky's avatar Victor Kamensky Committed by Russell King
Browse files

ARM: 8137/1: fix get_user BE behavior for target variable with size of 8 bytes



e38361d0 'ARM: 8091/2: add get_user() support for 8 byte types' commit
broke V7 BE get_user call when target var size is 64 bit, but '*ptr' size
is 32 bit or smaller. e38361d0 changed type of __r2 from 'register
unsigned long' to 'register typeof(x) __r2 asm("r2")' i.e before the change
even when target variable size was 64 bit, __r2 was still 32 bit.
But after e38361d0 commit, for target var of 64 bit size, __r2 became 64
bit and now it should occupy 2 registers r2, and r3. The issue in BE case
that r3 register is least significant word of __r2 and r2 register is most
significant word of __r2. But __get_user_4 still copies result into r2 (most
significant word of __r2). Subsequent code copies from __r2 into x, but
for situation described it will pick up only garbage from r3 register.

Special __get_user_64t_(124) functions are introduced. They are similar to
corresponding __get_user_(124) function but result stored in r3 register
(lsw in case of 64 bit __r2 in BE image). Those function are used by
get_user macro in case of BE and target var size is 64bit.

Also changed __get_user_lo8 name into __get_user_32t_8 to get consistent
naming accross all cases.

Signed-off-by: default avatarVictor Kamensky <victor.kamensky@linaro.org>
Suggested-by: default avatarDaniel Thompson <daniel.thompson@linaro.org>
Reviewed-by: default avatarDaniel Thompson <daniel.thompson@linaro.org>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent e918a62a
Loading
Loading
Loading
Loading
+39 −9
Original line number Original line Diff line number Diff line
@@ -107,8 +107,11 @@ static inline void set_fs(mm_segment_t fs)
extern int __get_user_1(void *);
extern int __get_user_1(void *);
extern int __get_user_2(void *);
extern int __get_user_2(void *);
extern int __get_user_4(void *);
extern int __get_user_4(void *);
extern int __get_user_lo8(void *);
extern int __get_user_32t_8(void *);
extern int __get_user_8(void *);
extern int __get_user_8(void *);
extern int __get_user_64t_1(void *);
extern int __get_user_64t_2(void *);
extern int __get_user_64t_4(void *);


#define __GUP_CLOBBER_1	"lr", "cc"
#define __GUP_CLOBBER_1	"lr", "cc"
#ifdef CONFIG_CPU_USE_DOMAINS
#ifdef CONFIG_CPU_USE_DOMAINS
@@ -117,7 +120,7 @@ extern int __get_user_8(void *);
#define __GUP_CLOBBER_2 "lr", "cc"
#define __GUP_CLOBBER_2 "lr", "cc"
#endif
#endif
#define __GUP_CLOBBER_4	"lr", "cc"
#define __GUP_CLOBBER_4	"lr", "cc"
#define __GUP_CLOBBER_lo8 "lr", "cc"
#define __GUP_CLOBBER_32t_8 "lr", "cc"
#define __GUP_CLOBBER_8	"lr", "cc"
#define __GUP_CLOBBER_8	"lr", "cc"


#define __get_user_x(__r2,__p,__e,__l,__s)				\
#define __get_user_x(__r2,__p,__e,__l,__s)				\
@@ -131,12 +134,30 @@ extern int __get_user_8(void *);


/* narrowing a double-word get into a single 32bit word register: */
/* narrowing a double-word get into a single 32bit word register: */
#ifdef __ARMEB__
#ifdef __ARMEB__
#define __get_user_xb(__r2, __p, __e, __l, __s)				\
#define __get_user_x_32t(__r2, __p, __e, __l, __s)				\
	__get_user_x(__r2, __p, __e, __l, lo8)
	__get_user_x(__r2, __p, __e, __l, 32t_8)
#else
#else
#define __get_user_xb __get_user_x
#define __get_user_x_32t __get_user_x
#endif
#endif


/*
 * storing result into proper least significant word of 64bit target var,
 * different only for big endian case where 64 bit __r2 lsw is r3:
 */
#ifdef __ARMEB__
#define __get_user_x_64t(__r2, __p, __e, __l, __s)		        \
	   __asm__ __volatile__ (					\
		__asmeq("%0", "r0") __asmeq("%1", "r2")			\
		__asmeq("%3", "r1")					\
		"bl	__get_user_64t_" #__s				\
		: "=&r" (__e), "=r" (__r2)				\
		: "0" (__p), "r" (__l)					\
		: __GUP_CLOBBER_##__s)
#else
#define __get_user_x_64t __get_user_x
#endif


#define __get_user_check(x,p)							\
#define __get_user_check(x,p)							\
	({								\
	({								\
		unsigned long __limit = current_thread_info()->addr_limit - 1; \
		unsigned long __limit = current_thread_info()->addr_limit - 1; \
@@ -146,17 +167,26 @@ extern int __get_user_8(void *);
		register int __e asm("r0");				\
		register int __e asm("r0");				\
		switch (sizeof(*(__p))) {				\
		switch (sizeof(*(__p))) {				\
		case 1:							\
		case 1:							\
			if (sizeof((x)) >= 8)				\
				__get_user_x_64t(__r2, __p, __e, __l, 1); \
			else						\
				__get_user_x(__r2, __p, __e, __l, 1);	\
				__get_user_x(__r2, __p, __e, __l, 1);	\
			break;						\
			break;						\
		case 2:							\
		case 2:							\
			if (sizeof((x)) >= 8)				\
				__get_user_x_64t(__r2, __p, __e, __l, 2); \
			else						\
				__get_user_x(__r2, __p, __e, __l, 2);	\
				__get_user_x(__r2, __p, __e, __l, 2);	\
			break;						\
			break;						\
		case 4:							\
		case 4:							\
			if (sizeof((x)) >= 8)				\
				__get_user_x_64t(__r2, __p, __e, __l, 4); \
			else						\
				__get_user_x(__r2, __p, __e, __l, 4);	\
				__get_user_x(__r2, __p, __e, __l, 4);	\
			break;						\
			break;						\
		case 8:							\
		case 8:							\
			if (sizeof((x)) < 8)				\
			if (sizeof((x)) < 8)				\
				__get_user_xb(__r2, __p, __e, __l, 4);	\
				__get_user_x_32t(__r2, __p, __e, __l, 4); \
			else						\
			else						\
				__get_user_x(__r2, __p, __e, __l, 8);	\
				__get_user_x(__r2, __p, __e, __l, 8);	\
			break;						\
			break;						\
+36 −2
Original line number Original line Diff line number Diff line
@@ -80,7 +80,7 @@ ENTRY(__get_user_8)
ENDPROC(__get_user_8)
ENDPROC(__get_user_8)


#ifdef __ARMEB__
#ifdef __ARMEB__
ENTRY(__get_user_lo8)
ENTRY(__get_user_32t_8)
	check_uaccess r0, 8, r1, r2, __get_user_bad
	check_uaccess r0, 8, r1, r2, __get_user_bad
#ifdef CONFIG_CPU_USE_DOMAINS
#ifdef CONFIG_CPU_USE_DOMAINS
	add	r0, r0, #4
	add	r0, r0, #4
@@ -90,7 +90,37 @@ ENTRY(__get_user_lo8)
#endif
#endif
	mov	r0, #0
	mov	r0, #0
	ret	lr
	ret	lr
ENDPROC(__get_user_lo8)
ENDPROC(__get_user_32t_8)

ENTRY(__get_user_64t_1)
	check_uaccess r0, 1, r1, r2, __get_user_bad8
8: TUSER(ldrb)	r3, [r0]
	mov	r0, #0
	ret	lr
ENDPROC(__get_user_64t_1)

ENTRY(__get_user_64t_2)
	check_uaccess r0, 2, r1, r2, __get_user_bad8
#ifdef CONFIG_CPU_USE_DOMAINS
rb	.req	ip
9:	ldrbt	r3, [r0], #1
10:	ldrbt	rb, [r0], #0
#else
rb	.req	r0
9:	ldrb	r3, [r0]
10:	ldrb	rb, [r0, #1]
#endif
	orr	r3, rb, r3, lsl #8
	mov	r0, #0
	ret	lr
ENDPROC(__get_user_64t_2)

ENTRY(__get_user_64t_4)
	check_uaccess r0, 4, r1, r2, __get_user_bad8
11: TUSER(ldr)	r3, [r0]
	mov	r0, #0
	ret	lr
ENDPROC(__get_user_64t_4)
#endif
#endif


__get_user_bad8:
__get_user_bad8:
@@ -111,5 +141,9 @@ ENDPROC(__get_user_bad8)
	.long	6b, __get_user_bad8
	.long	6b, __get_user_bad8
#ifdef __ARMEB__
#ifdef __ARMEB__
	.long   7b, __get_user_bad
	.long   7b, __get_user_bad
	.long	8b, __get_user_bad8
	.long	9b, __get_user_bad8
	.long	10b, __get_user_bad8
	.long	11b, __get_user_bad8
#endif
#endif
.popsection
.popsection