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

Commit 20bb78f6 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull parisc fix from Helge Deller:
 "One patch which fixes get_user() for 64-bit values on 32-bit kernels.

  Up to now we lost the upper 32-bits of the returned 64-bit value"

* 'parisc-4.11-5' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux:
  parisc: Fix get_user() for 64-bit value on 32-bit kernel
parents 4f7d029b 3f795cef
Loading
Loading
Loading
Loading
+55 −31
Original line number Diff line number Diff line
@@ -39,10 +39,10 @@
#define get_user __get_user

#if !defined(CONFIG_64BIT)
#define LDD_USER(ptr)		__get_user_asm64(ptr)
#define LDD_USER(val, ptr)	__get_user_asm64(val, ptr)
#define STD_USER(x, ptr)	__put_user_asm64(x, ptr)
#else
#define LDD_USER(ptr)		__get_user_asm("ldd", ptr)
#define LDD_USER(val, ptr)	__get_user_asm(val, "ldd", ptr)
#define STD_USER(x, ptr)	__put_user_asm("std", x, ptr)
#endif

@@ -97,63 +97,87 @@ struct exception_data {
		" mtsp %0,%%sr2\n\t"		\
		: : "r"(get_fs()) : )

#define __get_user(x, ptr)                               \
#define __get_user_internal(val, ptr)			\
({							\
	register long __gu_err __asm__ ("r8") = 0;	\
	register long __gu_val;				 \
							\
	load_sr2();					 \
	switch (sizeof(*(ptr))) {			\
	    case 1: __get_user_asm("ldb", ptr); break;   \
	    case 2: __get_user_asm("ldh", ptr); break;   \
	    case 4: __get_user_asm("ldw", ptr); break;   \
	    case 8: LDD_USER(ptr);  break;		 \
	    default: BUILD_BUG(); break;		 \
	case 1: __get_user_asm(val, "ldb", ptr); break;	\
	case 2: __get_user_asm(val, "ldh", ptr); break; \
	case 4: __get_user_asm(val, "ldw", ptr); break; \
	case 8: LDD_USER(val, ptr); break;		\
	default: BUILD_BUG();				\
	}						\
							\
	(x) = (__force __typeof__(*(ptr))) __gu_val;	 \
	__gu_err;					\
})

#define __get_user_asm(ldx, ptr)                        \
#define __get_user(val, ptr)				\
({							\
	load_sr2();					\
	__get_user_internal(val, ptr);			\
})

#define __get_user_asm(val, ldx, ptr)			\
{							\
	register long __gu_val;				\
							\
	__asm__("1: " ldx " 0(%%sr2,%2),%0\n"		\
		"9:\n"					\
		ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b)	\
		: "=r"(__gu_val), "=r"(__gu_err)        \
		: "r"(ptr), "1"(__gu_err));
		: "r"(ptr), "1"(__gu_err));		\
							\
	(val) = (__force __typeof__(*(ptr))) __gu_val;	\
}

#if !defined(CONFIG_64BIT)

#define __get_user_asm64(ptr) 				\
#define __get_user_asm64(val, ptr)			\
{							\
	union {						\
		unsigned long long	l;		\
		__typeof__(*(ptr))	t;		\
	} __gu_tmp;					\
							\
	__asm__("   copy %%r0,%R0\n"			\
		"1: ldw 0(%%sr2,%2),%0\n"		\
		"2: ldw 4(%%sr2,%2),%R0\n"		\
		"9:\n"					\
		ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b)	\
		ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b)	\
		: "=r"(__gu_val), "=r"(__gu_err)	\
		: "r"(ptr), "1"(__gu_err));
		: "=&r"(__gu_tmp.l), "=r"(__gu_err)	\
		: "r"(ptr), "1"(__gu_err));		\
							\
	(val) = __gu_tmp.t;				\
}

#endif /* !defined(CONFIG_64BIT) */


#define __put_user(x, ptr)                                      \
#define __put_user_internal(x, ptr)				\
({								\
	register long __pu_err __asm__ ("r8") = 0;      	\
        __typeof__(*(ptr)) __x = (__typeof__(*(ptr)))(x);	\
								\
	load_sr2();						\
	switch (sizeof(*(ptr))) {				\
	case 1: __put_user_asm("stb", __x, ptr); break;		\
	case 2: __put_user_asm("sth", __x, ptr); break;		\
	case 4: __put_user_asm("stw", __x, ptr); break;		\
	case 8: STD_USER(__x, ptr); break;			\
	    default: BUILD_BUG(); break;			\
	default: BUILD_BUG();					\
	}							\
								\
	__pu_err;						\
})

#define __put_user(x, ptr)					\
({								\
	load_sr2();						\
	__put_user_internal(x, ptr);				\
})


/*
 * The "__put_user/kernel_asm()" macros tell gcc they read from memory
 * instead of writing. This is because they do not write to any memory