162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
462306a36Sopenharmony_ci * Copyright (C) 2008-2009 PetaLogix
562306a36Sopenharmony_ci * Copyright (C) 2006 Atmark Techno, Inc.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#ifndef _ASM_MICROBLAZE_UACCESS_H
962306a36Sopenharmony_ci#define _ASM_MICROBLAZE_UACCESS_H
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <asm/mmu.h>
1462306a36Sopenharmony_ci#include <asm/page.h>
1562306a36Sopenharmony_ci#include <linux/pgtable.h>
1662306a36Sopenharmony_ci#include <asm/extable.h>
1762306a36Sopenharmony_ci#include <linux/string.h>
1862306a36Sopenharmony_ci#include <asm-generic/access_ok.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci# define __FIXUP_SECTION	".section .fixup,\"ax\"\n"
2162306a36Sopenharmony_ci# define __EX_TABLE_SECTION	".section __ex_table,\"a\"\n"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ciextern unsigned long __copy_tofrom_user(void __user *to,
2462306a36Sopenharmony_ci		const void __user *from, unsigned long size);
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/* Return: number of not copied bytes, i.e. 0 if OK or non-zero if fail. */
2762306a36Sopenharmony_cistatic inline unsigned long __must_check __clear_user(void __user *to,
2862306a36Sopenharmony_ci							unsigned long n)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	/* normal memset with two words to __ex_table */
3162306a36Sopenharmony_ci	__asm__ __volatile__ (				\
3262306a36Sopenharmony_ci			"1:	sb	r0, %1, r0;"	\
3362306a36Sopenharmony_ci			"	addik	%0, %0, -1;"	\
3462306a36Sopenharmony_ci			"	bneid	%0, 1b;"	\
3562306a36Sopenharmony_ci			"	addik	%1, %1, 1;"	\
3662306a36Sopenharmony_ci			"2:			"	\
3762306a36Sopenharmony_ci			__EX_TABLE_SECTION		\
3862306a36Sopenharmony_ci			".word	1b,2b;"			\
3962306a36Sopenharmony_ci			".previous;"			\
4062306a36Sopenharmony_ci		: "=r"(n), "=r"(to)			\
4162306a36Sopenharmony_ci		: "0"(n), "1"(to)
4262306a36Sopenharmony_ci	);
4362306a36Sopenharmony_ci	return n;
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic inline unsigned long __must_check clear_user(void __user *to,
4762306a36Sopenharmony_ci							unsigned long n)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	might_fault();
5062306a36Sopenharmony_ci	if (unlikely(!access_ok(to, n)))
5162306a36Sopenharmony_ci		return n;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	return __clear_user(to, n);
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci/* put_user and get_user macros */
5762306a36Sopenharmony_ciextern long __user_bad(void);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci#define __get_user_asm(insn, __gu_ptr, __gu_val, __gu_err)	\
6062306a36Sopenharmony_ci({								\
6162306a36Sopenharmony_ci	__asm__ __volatile__ (					\
6262306a36Sopenharmony_ci			"1:"	insn	" %1, %2, r0;"		\
6362306a36Sopenharmony_ci			"	addk	%0, r0, r0;"		\
6462306a36Sopenharmony_ci			"2:			"		\
6562306a36Sopenharmony_ci			__FIXUP_SECTION				\
6662306a36Sopenharmony_ci			"3:	brid	2b;"			\
6762306a36Sopenharmony_ci			"	addik	%0, r0, %3;"		\
6862306a36Sopenharmony_ci			".previous;"				\
6962306a36Sopenharmony_ci			__EX_TABLE_SECTION			\
7062306a36Sopenharmony_ci			".word	1b,3b;"				\
7162306a36Sopenharmony_ci			".previous;"				\
7262306a36Sopenharmony_ci		: "=&r"(__gu_err), "=r"(__gu_val)		\
7362306a36Sopenharmony_ci		: "r"(__gu_ptr), "i"(-EFAULT)			\
7462306a36Sopenharmony_ci	);							\
7562306a36Sopenharmony_ci})
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/**
7862306a36Sopenharmony_ci * get_user: - Get a simple variable from user space.
7962306a36Sopenharmony_ci * @x:   Variable to store result.
8062306a36Sopenharmony_ci * @ptr: Source address, in user space.
8162306a36Sopenharmony_ci *
8262306a36Sopenharmony_ci * Context: User context only. This function may sleep if pagefaults are
8362306a36Sopenharmony_ci *          enabled.
8462306a36Sopenharmony_ci *
8562306a36Sopenharmony_ci * This macro copies a single simple variable from user space to kernel
8662306a36Sopenharmony_ci * space.  It supports simple types like char and int, but not larger
8762306a36Sopenharmony_ci * data types like structures or arrays.
8862306a36Sopenharmony_ci *
8962306a36Sopenharmony_ci * @ptr must have pointer-to-simple-variable type, and the result of
9062306a36Sopenharmony_ci * dereferencing @ptr must be assignable to @x without a cast.
9162306a36Sopenharmony_ci *
9262306a36Sopenharmony_ci * Returns zero on success, or -EFAULT on error.
9362306a36Sopenharmony_ci * On error, the variable @x is set to zero.
9462306a36Sopenharmony_ci */
9562306a36Sopenharmony_ci#define get_user(x, ptr) ({				\
9662306a36Sopenharmony_ci	const typeof(*(ptr)) __user *__gu_ptr = (ptr);	\
9762306a36Sopenharmony_ci	access_ok(__gu_ptr, sizeof(*__gu_ptr)) ?	\
9862306a36Sopenharmony_ci		__get_user(x, __gu_ptr) : -EFAULT;	\
9962306a36Sopenharmony_ci})
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci#define __get_user(x, ptr)						\
10262306a36Sopenharmony_ci({									\
10362306a36Sopenharmony_ci	long __gu_err;							\
10462306a36Sopenharmony_ci	switch (sizeof(*(ptr))) {					\
10562306a36Sopenharmony_ci	case 1:								\
10662306a36Sopenharmony_ci		__get_user_asm("lbu", (ptr), x, __gu_err);		\
10762306a36Sopenharmony_ci		break;							\
10862306a36Sopenharmony_ci	case 2:								\
10962306a36Sopenharmony_ci		__get_user_asm("lhu", (ptr), x, __gu_err);		\
11062306a36Sopenharmony_ci		break;							\
11162306a36Sopenharmony_ci	case 4:								\
11262306a36Sopenharmony_ci		__get_user_asm("lw", (ptr), x, __gu_err);		\
11362306a36Sopenharmony_ci		break;							\
11462306a36Sopenharmony_ci	case 8: {							\
11562306a36Sopenharmony_ci		__u64 __x = 0;						\
11662306a36Sopenharmony_ci		__gu_err = raw_copy_from_user(&__x, ptr, 8) ?		\
11762306a36Sopenharmony_ci							-EFAULT : 0;	\
11862306a36Sopenharmony_ci		(x) = (typeof(x))(typeof((x) - (x)))__x;		\
11962306a36Sopenharmony_ci		break;							\
12062306a36Sopenharmony_ci	}								\
12162306a36Sopenharmony_ci	default:							\
12262306a36Sopenharmony_ci		/* __gu_val = 0; __gu_err = -EINVAL;*/ __gu_err = __user_bad();\
12362306a36Sopenharmony_ci	}								\
12462306a36Sopenharmony_ci	__gu_err;							\
12562306a36Sopenharmony_ci})
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci#define __put_user_asm(insn, __gu_ptr, __gu_val, __gu_err)	\
12962306a36Sopenharmony_ci({								\
13062306a36Sopenharmony_ci	__asm__ __volatile__ (					\
13162306a36Sopenharmony_ci			"1:"	insn	" %1, %2, r0;"		\
13262306a36Sopenharmony_ci			"	addk	%0, r0, r0;"		\
13362306a36Sopenharmony_ci			"2:			"		\
13462306a36Sopenharmony_ci			__FIXUP_SECTION				\
13562306a36Sopenharmony_ci			"3:	brid	2b;"			\
13662306a36Sopenharmony_ci			"	addik	%0, r0, %3;"		\
13762306a36Sopenharmony_ci			".previous;"				\
13862306a36Sopenharmony_ci			__EX_TABLE_SECTION			\
13962306a36Sopenharmony_ci			".word	1b,3b;"				\
14062306a36Sopenharmony_ci			".previous;"				\
14162306a36Sopenharmony_ci		: "=&r"(__gu_err)				\
14262306a36Sopenharmony_ci		: "r"(__gu_val), "r"(__gu_ptr), "i"(-EFAULT)	\
14362306a36Sopenharmony_ci	);							\
14462306a36Sopenharmony_ci})
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci#define __put_user_asm_8(__gu_ptr, __gu_val, __gu_err)		\
14762306a36Sopenharmony_ci({								\
14862306a36Sopenharmony_ci	__asm__ __volatile__ ("	lwi	%0, %1, 0;"		\
14962306a36Sopenharmony_ci			"1:	swi	%0, %2, 0;"		\
15062306a36Sopenharmony_ci			"	lwi	%0, %1, 4;"		\
15162306a36Sopenharmony_ci			"2:	swi	%0, %2, 4;"		\
15262306a36Sopenharmony_ci			"	addk	%0, r0, r0;"		\
15362306a36Sopenharmony_ci			"3:			"		\
15462306a36Sopenharmony_ci			__FIXUP_SECTION				\
15562306a36Sopenharmony_ci			"4:	brid	3b;"			\
15662306a36Sopenharmony_ci			"	addik	%0, r0, %3;"		\
15762306a36Sopenharmony_ci			".previous;"				\
15862306a36Sopenharmony_ci			__EX_TABLE_SECTION			\
15962306a36Sopenharmony_ci			".word	1b,4b,2b,4b;"			\
16062306a36Sopenharmony_ci			".previous;"				\
16162306a36Sopenharmony_ci		: "=&r"(__gu_err)				\
16262306a36Sopenharmony_ci		: "r"(&__gu_val), "r"(__gu_ptr), "i"(-EFAULT)	\
16362306a36Sopenharmony_ci		);						\
16462306a36Sopenharmony_ci})
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci/**
16762306a36Sopenharmony_ci * put_user: - Write a simple value into user space.
16862306a36Sopenharmony_ci * @x:   Value to copy to user space.
16962306a36Sopenharmony_ci * @ptr: Destination address, in user space.
17062306a36Sopenharmony_ci *
17162306a36Sopenharmony_ci * Context: User context only. This function may sleep if pagefaults are
17262306a36Sopenharmony_ci *          enabled.
17362306a36Sopenharmony_ci *
17462306a36Sopenharmony_ci * This macro copies a single simple value from kernel space to user
17562306a36Sopenharmony_ci * space.  It supports simple types like char and int, but not larger
17662306a36Sopenharmony_ci * data types like structures or arrays.
17762306a36Sopenharmony_ci *
17862306a36Sopenharmony_ci * @ptr must have pointer-to-simple-variable type, and @x must be assignable
17962306a36Sopenharmony_ci * to the result of dereferencing @ptr.
18062306a36Sopenharmony_ci *
18162306a36Sopenharmony_ci * Returns zero on success, or -EFAULT on error.
18262306a36Sopenharmony_ci */
18362306a36Sopenharmony_ci#define put_user(x, ptr)						\
18462306a36Sopenharmony_ci	__put_user_check((x), (ptr), sizeof(*(ptr)))
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci#define __put_user_check(x, ptr, size)					\
18762306a36Sopenharmony_ci({									\
18862306a36Sopenharmony_ci	typeof(*(ptr)) volatile __pu_val = x;				\
18962306a36Sopenharmony_ci	typeof(*(ptr)) __user *__pu_addr = (ptr);			\
19062306a36Sopenharmony_ci	int __pu_err = 0;						\
19162306a36Sopenharmony_ci									\
19262306a36Sopenharmony_ci	if (access_ok(__pu_addr, size)) {			\
19362306a36Sopenharmony_ci		switch (size) {						\
19462306a36Sopenharmony_ci		case 1:							\
19562306a36Sopenharmony_ci			__put_user_asm("sb", __pu_addr, __pu_val,	\
19662306a36Sopenharmony_ci				       __pu_err);			\
19762306a36Sopenharmony_ci			break;						\
19862306a36Sopenharmony_ci		case 2:							\
19962306a36Sopenharmony_ci			__put_user_asm("sh", __pu_addr, __pu_val,	\
20062306a36Sopenharmony_ci				       __pu_err);			\
20162306a36Sopenharmony_ci			break;						\
20262306a36Sopenharmony_ci		case 4:							\
20362306a36Sopenharmony_ci			__put_user_asm("sw", __pu_addr, __pu_val,	\
20462306a36Sopenharmony_ci				       __pu_err);			\
20562306a36Sopenharmony_ci			break;						\
20662306a36Sopenharmony_ci		case 8:							\
20762306a36Sopenharmony_ci			__put_user_asm_8(__pu_addr, __pu_val, __pu_err);\
20862306a36Sopenharmony_ci			break;						\
20962306a36Sopenharmony_ci		default:						\
21062306a36Sopenharmony_ci			__pu_err = __user_bad();			\
21162306a36Sopenharmony_ci			break;						\
21262306a36Sopenharmony_ci		}							\
21362306a36Sopenharmony_ci	} else {							\
21462306a36Sopenharmony_ci		__pu_err = -EFAULT;					\
21562306a36Sopenharmony_ci	}								\
21662306a36Sopenharmony_ci	__pu_err;							\
21762306a36Sopenharmony_ci})
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci#define __put_user(x, ptr)						\
22062306a36Sopenharmony_ci({									\
22162306a36Sopenharmony_ci	__typeof__(*(ptr)) volatile __gu_val = (x);			\
22262306a36Sopenharmony_ci	long __gu_err = 0;						\
22362306a36Sopenharmony_ci	switch (sizeof(__gu_val)) {					\
22462306a36Sopenharmony_ci	case 1:								\
22562306a36Sopenharmony_ci		__put_user_asm("sb", (ptr), __gu_val, __gu_err);	\
22662306a36Sopenharmony_ci		break;							\
22762306a36Sopenharmony_ci	case 2:								\
22862306a36Sopenharmony_ci		__put_user_asm("sh", (ptr), __gu_val, __gu_err);	\
22962306a36Sopenharmony_ci		break;							\
23062306a36Sopenharmony_ci	case 4:								\
23162306a36Sopenharmony_ci		__put_user_asm("sw", (ptr), __gu_val, __gu_err);	\
23262306a36Sopenharmony_ci		break;							\
23362306a36Sopenharmony_ci	case 8:								\
23462306a36Sopenharmony_ci		__put_user_asm_8((ptr), __gu_val, __gu_err);		\
23562306a36Sopenharmony_ci		break;							\
23662306a36Sopenharmony_ci	default:							\
23762306a36Sopenharmony_ci		/*__gu_err = -EINVAL;*/	__gu_err = __user_bad();	\
23862306a36Sopenharmony_ci	}								\
23962306a36Sopenharmony_ci	__gu_err;							\
24062306a36Sopenharmony_ci})
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_cistatic inline unsigned long
24362306a36Sopenharmony_ciraw_copy_from_user(void *to, const void __user *from, unsigned long n)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	return __copy_tofrom_user((__force void __user *)to, from, n);
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic inline unsigned long
24962306a36Sopenharmony_ciraw_copy_to_user(void __user *to, const void *from, unsigned long n)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	return __copy_tofrom_user(to, (__force const void __user *)from, n);
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci#define INLINE_COPY_FROM_USER
25462306a36Sopenharmony_ci#define INLINE_COPY_TO_USER
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci/*
25762306a36Sopenharmony_ci * Copy a null terminated string from userspace.
25862306a36Sopenharmony_ci */
25962306a36Sopenharmony_ci__must_check long strncpy_from_user(char *dst, const char __user *src,
26062306a36Sopenharmony_ci				    long count);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci/*
26362306a36Sopenharmony_ci * Return the size of a string (including the ending 0)
26462306a36Sopenharmony_ci *
26562306a36Sopenharmony_ci * Return 0 on exception, a value greater than N if too long
26662306a36Sopenharmony_ci */
26762306a36Sopenharmony_ci__must_check long strnlen_user(const char __user *sstr, long len);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci#endif /* _ASM_MICROBLAZE_UACCESS_H */
270