162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * OpenRISC Linux
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Linux architectural port borrowing liberally from similar works of
662306a36Sopenharmony_ci * others.  All original copyrights apply as per the original source
762306a36Sopenharmony_ci * declaration.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * OpenRISC implementation:
1062306a36Sopenharmony_ci * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
1162306a36Sopenharmony_ci * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
1262306a36Sopenharmony_ci * et al.
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#ifndef __ASM_OPENRISC_UACCESS_H
1662306a36Sopenharmony_ci#define __ASM_OPENRISC_UACCESS_H
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/*
1962306a36Sopenharmony_ci * User space memory access functions
2062306a36Sopenharmony_ci */
2162306a36Sopenharmony_ci#include <linux/prefetch.h>
2262306a36Sopenharmony_ci#include <linux/string.h>
2362306a36Sopenharmony_ci#include <asm/page.h>
2462306a36Sopenharmony_ci#include <asm/extable.h>
2562306a36Sopenharmony_ci#include <asm-generic/access_ok.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/*
2862306a36Sopenharmony_ci * These are the main single-value transfer routines.  They automatically
2962306a36Sopenharmony_ci * use the right size if we just have the right pointer type.
3062306a36Sopenharmony_ci *
3162306a36Sopenharmony_ci * This gets kind of ugly. We want to return _two_ values in "get_user()"
3262306a36Sopenharmony_ci * and yet we don't want to do any pointers, because that is too much
3362306a36Sopenharmony_ci * of a performance impact. Thus we have a few rather ugly macros here,
3462306a36Sopenharmony_ci * and hide all the uglyness from the user.
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci * The "__xxx" versions of the user access functions are versions that
3762306a36Sopenharmony_ci * do not verify the address space, that must have been done previously
3862306a36Sopenharmony_ci * with a separate "access_ok()" call (this is used when we do multiple
3962306a36Sopenharmony_ci * accesses to the same area of user memory).
4062306a36Sopenharmony_ci *
4162306a36Sopenharmony_ci * As we use the same address space for kernel and user data on the
4262306a36Sopenharmony_ci * PowerPC, we can just do these as direct assignments.  (Of course, the
4362306a36Sopenharmony_ci * exception handling means that it's no longer "just"...)
4462306a36Sopenharmony_ci */
4562306a36Sopenharmony_ci#define get_user(x, ptr) \
4662306a36Sopenharmony_ci	__get_user_check((x), (ptr), sizeof(*(ptr)))
4762306a36Sopenharmony_ci#define put_user(x, ptr) \
4862306a36Sopenharmony_ci	__put_user_check((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#define __get_user(x, ptr) \
5162306a36Sopenharmony_ci	__get_user_nocheck((x), (ptr), sizeof(*(ptr)))
5262306a36Sopenharmony_ci#define __put_user(x, ptr) \
5362306a36Sopenharmony_ci	__put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ciextern long __put_user_bad(void);
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#define __put_user_nocheck(x, ptr, size)		\
5862306a36Sopenharmony_ci({							\
5962306a36Sopenharmony_ci	long __pu_err;					\
6062306a36Sopenharmony_ci	__put_user_size((x), (ptr), (size), __pu_err);	\
6162306a36Sopenharmony_ci	__pu_err;					\
6262306a36Sopenharmony_ci})
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#define __put_user_check(x, ptr, size)					\
6562306a36Sopenharmony_ci({									\
6662306a36Sopenharmony_ci	long __pu_err = -EFAULT;					\
6762306a36Sopenharmony_ci	__typeof__(*(ptr)) __user *__pu_addr = (ptr);			\
6862306a36Sopenharmony_ci	if (access_ok(__pu_addr, size))			\
6962306a36Sopenharmony_ci		__put_user_size((x), __pu_addr, (size), __pu_err);	\
7062306a36Sopenharmony_ci	__pu_err;							\
7162306a36Sopenharmony_ci})
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci#define __put_user_size(x, ptr, size, retval)				\
7462306a36Sopenharmony_cido {									\
7562306a36Sopenharmony_ci	retval = 0;							\
7662306a36Sopenharmony_ci	switch (size) {							\
7762306a36Sopenharmony_ci	case 1: __put_user_asm(x, ptr, retval, "l.sb"); break;		\
7862306a36Sopenharmony_ci	case 2: __put_user_asm(x, ptr, retval, "l.sh"); break;		\
7962306a36Sopenharmony_ci	case 4: __put_user_asm(x, ptr, retval, "l.sw"); break;		\
8062306a36Sopenharmony_ci	case 8: __put_user_asm2(x, ptr, retval); break;			\
8162306a36Sopenharmony_ci	default: __put_user_bad();					\
8262306a36Sopenharmony_ci	}								\
8362306a36Sopenharmony_ci} while (0)
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistruct __large_struct {
8662306a36Sopenharmony_ci	unsigned long buf[100];
8762306a36Sopenharmony_ci};
8862306a36Sopenharmony_ci#define __m(x) (*(struct __large_struct *)(x))
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci/*
9162306a36Sopenharmony_ci * We don't tell gcc that we are accessing memory, but this is OK
9262306a36Sopenharmony_ci * because we do not write to any memory gcc knows about, so there
9362306a36Sopenharmony_ci * are no aliasing issues.
9462306a36Sopenharmony_ci */
9562306a36Sopenharmony_ci#define __put_user_asm(x, addr, err, op)			\
9662306a36Sopenharmony_ci	__asm__ __volatile__(					\
9762306a36Sopenharmony_ci		"1:	"op" 0(%2),%1\n"			\
9862306a36Sopenharmony_ci		"2:\n"						\
9962306a36Sopenharmony_ci		".section .fixup,\"ax\"\n"			\
10062306a36Sopenharmony_ci		"3:	l.addi %0,r0,%3\n"			\
10162306a36Sopenharmony_ci		"	l.j 2b\n"				\
10262306a36Sopenharmony_ci		"	l.nop\n"				\
10362306a36Sopenharmony_ci		".previous\n"					\
10462306a36Sopenharmony_ci		".section __ex_table,\"a\"\n"			\
10562306a36Sopenharmony_ci		"	.align 2\n"				\
10662306a36Sopenharmony_ci		"	.long 1b,3b\n"				\
10762306a36Sopenharmony_ci		".previous"					\
10862306a36Sopenharmony_ci		: "=r"(err)					\
10962306a36Sopenharmony_ci		: "r"(x), "r"(addr), "i"(-EFAULT), "0"(err))
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci#define __put_user_asm2(x, addr, err)				\
11262306a36Sopenharmony_ci	__asm__ __volatile__(					\
11362306a36Sopenharmony_ci		"1:	l.sw 0(%2),%1\n"			\
11462306a36Sopenharmony_ci		"2:	l.sw 4(%2),%H1\n"			\
11562306a36Sopenharmony_ci		"3:\n"						\
11662306a36Sopenharmony_ci		".section .fixup,\"ax\"\n"			\
11762306a36Sopenharmony_ci		"4:	l.addi %0,r0,%3\n"			\
11862306a36Sopenharmony_ci		"	l.j 3b\n"				\
11962306a36Sopenharmony_ci		"	l.nop\n"				\
12062306a36Sopenharmony_ci		".previous\n"					\
12162306a36Sopenharmony_ci		".section __ex_table,\"a\"\n"			\
12262306a36Sopenharmony_ci		"	.align 2\n"				\
12362306a36Sopenharmony_ci		"	.long 1b,4b\n"				\
12462306a36Sopenharmony_ci		"	.long 2b,4b\n"				\
12562306a36Sopenharmony_ci		".previous"					\
12662306a36Sopenharmony_ci		: "=r"(err)					\
12762306a36Sopenharmony_ci		: "r"(x), "r"(addr), "i"(-EFAULT), "0"(err))
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci#define __get_user_nocheck(x, ptr, size)			\
13062306a36Sopenharmony_ci({								\
13162306a36Sopenharmony_ci	long __gu_err;						\
13262306a36Sopenharmony_ci	__get_user_size((x), (ptr), (size), __gu_err);		\
13362306a36Sopenharmony_ci	__gu_err;						\
13462306a36Sopenharmony_ci})
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci#define __get_user_check(x, ptr, size)					\
13762306a36Sopenharmony_ci({									\
13862306a36Sopenharmony_ci	long __gu_err = -EFAULT;					\
13962306a36Sopenharmony_ci	const __typeof__(*(ptr)) __user *__gu_addr = (ptr);		\
14062306a36Sopenharmony_ci	if (access_ok(__gu_addr, size))					\
14162306a36Sopenharmony_ci		__get_user_size((x), __gu_addr, (size), __gu_err);	\
14262306a36Sopenharmony_ci	else								\
14362306a36Sopenharmony_ci		(x) = (__typeof__(*(ptr))) 0;				\
14462306a36Sopenharmony_ci	__gu_err;							\
14562306a36Sopenharmony_ci})
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ciextern long __get_user_bad(void);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci#define __get_user_size(x, ptr, size, retval)				\
15062306a36Sopenharmony_cido {									\
15162306a36Sopenharmony_ci	retval = 0;							\
15262306a36Sopenharmony_ci	switch (size) {							\
15362306a36Sopenharmony_ci	case 1: __get_user_asm(x, ptr, retval, "l.lbz"); break;		\
15462306a36Sopenharmony_ci	case 2: __get_user_asm(x, ptr, retval, "l.lhz"); break;		\
15562306a36Sopenharmony_ci	case 4: __get_user_asm(x, ptr, retval, "l.lwz"); break;		\
15662306a36Sopenharmony_ci	case 8: __get_user_asm2(x, ptr, retval); break;			\
15762306a36Sopenharmony_ci	default: (x) = (__typeof__(*(ptr)))__get_user_bad();		\
15862306a36Sopenharmony_ci	}								\
15962306a36Sopenharmony_ci} while (0)
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci#define __get_user_asm(x, addr, err, op)		\
16262306a36Sopenharmony_ci{							\
16362306a36Sopenharmony_ci	unsigned long __gu_tmp;				\
16462306a36Sopenharmony_ci	__asm__ __volatile__(				\
16562306a36Sopenharmony_ci		"1:	"op" %1,0(%2)\n"		\
16662306a36Sopenharmony_ci		"2:\n"					\
16762306a36Sopenharmony_ci		".section .fixup,\"ax\"\n"		\
16862306a36Sopenharmony_ci		"3:	l.addi %0,r0,%3\n"		\
16962306a36Sopenharmony_ci		"	l.addi %1,r0,0\n"		\
17062306a36Sopenharmony_ci		"	l.j 2b\n"			\
17162306a36Sopenharmony_ci		"	l.nop\n"			\
17262306a36Sopenharmony_ci		".previous\n"				\
17362306a36Sopenharmony_ci		".section __ex_table,\"a\"\n"		\
17462306a36Sopenharmony_ci		"	.align 2\n"			\
17562306a36Sopenharmony_ci		"	.long 1b,3b\n"			\
17662306a36Sopenharmony_ci		".previous"				\
17762306a36Sopenharmony_ci		: "=r"(err), "=r"(__gu_tmp)		\
17862306a36Sopenharmony_ci		: "r"(addr), "i"(-EFAULT), "0"(err));	\
17962306a36Sopenharmony_ci	(x) = (__typeof__(*(addr)))__gu_tmp;		\
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci#define __get_user_asm2(x, addr, err)			\
18362306a36Sopenharmony_ci{							\
18462306a36Sopenharmony_ci	unsigned long long __gu_tmp;			\
18562306a36Sopenharmony_ci	__asm__ __volatile__(				\
18662306a36Sopenharmony_ci		"1:	l.lwz %1,0(%2)\n"		\
18762306a36Sopenharmony_ci		"2:	l.lwz %H1,4(%2)\n"		\
18862306a36Sopenharmony_ci		"3:\n"					\
18962306a36Sopenharmony_ci		".section .fixup,\"ax\"\n"		\
19062306a36Sopenharmony_ci		"4:	l.addi %0,r0,%3\n"		\
19162306a36Sopenharmony_ci		"	l.addi %1,r0,0\n"		\
19262306a36Sopenharmony_ci		"	l.addi %H1,r0,0\n"		\
19362306a36Sopenharmony_ci		"	l.j 3b\n"			\
19462306a36Sopenharmony_ci		"	l.nop\n"			\
19562306a36Sopenharmony_ci		".previous\n"				\
19662306a36Sopenharmony_ci		".section __ex_table,\"a\"\n"		\
19762306a36Sopenharmony_ci		"	.align 2\n"			\
19862306a36Sopenharmony_ci		"	.long 1b,4b\n"			\
19962306a36Sopenharmony_ci		"	.long 2b,4b\n"			\
20062306a36Sopenharmony_ci		".previous"				\
20162306a36Sopenharmony_ci		: "=r"(err), "=&r"(__gu_tmp)		\
20262306a36Sopenharmony_ci		: "r"(addr), "i"(-EFAULT), "0"(err));	\
20362306a36Sopenharmony_ci	(x) = (__typeof__(*(addr)))(			\
20462306a36Sopenharmony_ci		(__typeof__((x)-(x)))__gu_tmp);		\
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci/* more complex routines */
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ciextern unsigned long __must_check
21062306a36Sopenharmony_ci__copy_tofrom_user(void *to, const void *from, unsigned long size);
21162306a36Sopenharmony_cistatic inline unsigned long
21262306a36Sopenharmony_ciraw_copy_from_user(void *to, const void __user *from, unsigned long size)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	return __copy_tofrom_user(to, (__force const void *)from, size);
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_cistatic inline unsigned long
21762306a36Sopenharmony_ciraw_copy_to_user(void __user *to, const void *from, unsigned long size)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	return __copy_tofrom_user((__force void *)to, from, size);
22062306a36Sopenharmony_ci}
22162306a36Sopenharmony_ci#define INLINE_COPY_FROM_USER
22262306a36Sopenharmony_ci#define INLINE_COPY_TO_USER
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ciextern unsigned long __clear_user(void __user *addr, unsigned long size);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cistatic inline __must_check unsigned long
22762306a36Sopenharmony_ciclear_user(void __user *addr, unsigned long size)
22862306a36Sopenharmony_ci{
22962306a36Sopenharmony_ci	if (likely(access_ok(addr, size)))
23062306a36Sopenharmony_ci		size = __clear_user(addr, size);
23162306a36Sopenharmony_ci	return size;
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ciextern long strncpy_from_user(char *dest, const char __user *src, long count);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ciextern __must_check long strnlen_user(const char __user *str, long n);
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci#endif /* __ASM_OPENRISC_UACCESS_H */
239