Unverified Commit 931de11f authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Palmer Dabbelt
Browse files

asm-generic: improve the nommu {get,put}_user handling



Instead of reusing raw_{copy,to}_from_user implement separate handlers
using {get,put}_unaligned.  This ensures unaligned access is handled
correctly, and avoid the need for the small constant size optimization
in raw_{copy,to}_from_user.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Acked-by: default avatarArnd Bergmann <arnd@arndb.de>
Signed-off-by: default avatarPalmer Dabbelt <palmerdabbelt@google.com>
parent 24ce66c0
Loading
Loading
Loading
Loading
+51 −40
Original line number Diff line number Diff line
@@ -10,56 +10,67 @@
#include <linux/string.h>

#ifdef CONFIG_UACCESS_MEMCPY
static inline __must_check unsigned long
raw_copy_from_user(void *to, const void __user * from, unsigned long n)
#include <asm/unaligned.h>

static inline int __get_user_fn(size_t size, const void __user *from, void *to)
{
	if (__builtin_constant_p(n)) {
		switch(n) {
	BUILD_BUG_ON(!__builtin_constant_p(size));

	switch (size) {
	case 1:
			*(u8 *)to = *(u8 __force *)from;
		*(u8 *)to = get_unaligned((u8 __force *)from);
		return 0;
	case 2:
			*(u16 *)to = *(u16 __force *)from;
		*(u16 *)to = get_unaligned((u16 __force *)from);
		return 0;
	case 4:
			*(u32 *)to = *(u32 __force *)from;
		*(u32 *)to = get_unaligned((u32 __force *)from);
		return 0;
#ifdef CONFIG_64BIT
	case 8:
			*(u64 *)to = *(u64 __force *)from;
		*(u64 *)to = get_unaligned((u64 __force *)from);
		return 0;
	default:
		BUILD_BUG();
		return 0;
#endif
		}
	}

	memcpy(to, (const void __force *)from, n);
	return 0;
}
#define __get_user_fn(sz, u, k)	__get_user_fn(sz, u, k)

static inline __must_check unsigned long
raw_copy_to_user(void __user *to, const void *from, unsigned long n)
static inline int __put_user_fn(size_t size, void __user *to, void *from)
{
	if (__builtin_constant_p(n)) {
		switch(n) {
	BUILD_BUG_ON(!__builtin_constant_p(size));

	switch (size) {
	case 1:
			*(u8 __force *)to = *(u8 *)from;
		put_unaligned(*(u8 *)from, (u8 __force *)to);
		return 0;
	case 2:
			*(u16 __force *)to = *(u16 *)from;
		put_unaligned(*(u16 *)from, (u16 __force *)to);
		return 0;
	case 4:
			*(u32 __force *)to = *(u32 *)from;
		put_unaligned(*(u32 *)from, (u32 __force *)to);
		return 0;
#ifdef CONFIG_64BIT
	case 8:
			*(u64 __force *)to = *(u64 *)from;
		put_unaligned(*(u64 *)from, (u64 __force *)to);
		return 0;
#endif
	default:
			break;
		BUILD_BUG();
		return 0;
	}
}
#define __put_user_fn(sz, u, k)	__put_user_fn(sz, u, k)

static inline __must_check unsigned long
raw_copy_from_user(void *to, const void __user * from, unsigned long n)
{
	memcpy(to, (const void __force *)from, n);
	return 0;
}

static inline __must_check unsigned long
raw_copy_to_user(void __user *to, const void *from, unsigned long n)
{
	memcpy((void __force *)to, from, n);
	return 0;
}