Merge tag 'drm-next-2024-05-25' of https://gitlab.freedesktop.org/drm/kernel
[linux-2.6-block.git] / arch / microblaze / include / asm / uaccess.h
CommitLineData
4726dd60 1/* SPDX-License-Identifier: GPL-2.0 */
2660663f 2/*
0d6de953
MS
3 * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
4 * Copyright (C) 2008-2009 PetaLogix
2660663f 5 * Copyright (C) 2006 Atmark Techno, Inc.
2660663f
MS
6 */
7
8#ifndef _ASM_MICROBLAZE_UACCESS_H
9#define _ASM_MICROBLAZE_UACCESS_H
10
2660663f 11#include <linux/kernel.h>
2660663f
MS
12
13#include <asm/mmu.h>
14#include <asm/page.h>
ca5999fd 15#include <linux/pgtable.h>
730132e7 16#include <asm/extable.h>
2660663f 17#include <linux/string.h>
12700c17 18#include <asm-generic/access_ok.h>
40b1156d 19
40b1156d
MS
20# define __FIXUP_SECTION ".section .fixup,\"ax\"\n"
21# define __EX_TABLE_SECTION ".section __ex_table,\"a\"\n"
40b1156d 22
94804a9b
MS
23extern unsigned long __copy_tofrom_user(void __user *to,
24 const void __user *from, unsigned long size);
25
527bdb52
MS
26/* Return: number of not copied bytes, i.e. 0 if OK or non-zero if fail. */
27static inline unsigned long __must_check __clear_user(void __user *to,
28 unsigned long n)
29{
30 /* normal memset with two words to __ex_table */
31 __asm__ __volatile__ ( \
6f3946b4 32 "1: sb r0, %1, r0;" \
527bdb52
MS
33 " addik %0, %0, -1;" \
34 " bneid %0, 1b;" \
6f3946b4 35 " addik %1, %1, 1;" \
527bdb52
MS
36 "2: " \
37 __EX_TABLE_SECTION \
38 ".word 1b,2b;" \
39 ".previous;" \
6f3946b4
SM
40 : "=r"(n), "=r"(to) \
41 : "0"(n), "1"(to)
527bdb52
MS
42 );
43 return n;
44}
45
46static inline unsigned long __must_check clear_user(void __user *to,
47 unsigned long n)
48{
ac093f8d 49 might_fault();
96d4f267 50 if (unlikely(!access_ok(to, n)))
527bdb52
MS
51 return n;
52
53 return __clear_user(to, n);
54}
55
cca79120 56/* put_user and get_user macros */
3a6d7724
MS
57extern long __user_bad(void);
58
59#define __get_user_asm(insn, __gu_ptr, __gu_val, __gu_err) \
60({ \
61 __asm__ __volatile__ ( \
62 "1:" insn " %1, %2, r0;" \
63 " addk %0, r0, r0;" \
64 "2: " \
65 __FIXUP_SECTION \
66 "3: brid 2b;" \
67 " addik %0, r0, %3;" \
68 ".previous;" \
69 __EX_TABLE_SECTION \
70 ".word 1b,3b;" \
71 ".previous;" \
72 : "=&r"(__gu_err), "=r"(__gu_val) \
73 : "r"(__gu_ptr), "i"(-EFAULT) \
74 ); \
75})
76
77/**
78 * get_user: - Get a simple variable from user space.
79 * @x: Variable to store result.
80 * @ptr: Source address, in user space.
81 *
b3c395ef
DH
82 * Context: User context only. This function may sleep if pagefaults are
83 * enabled.
3a6d7724
MS
84 *
85 * This macro copies a single simple variable from user space to kernel
86 * space. It supports simple types like char and int, but not larger
87 * data types like structures or arrays.
88 *
89 * @ptr must have pointer-to-simple-variable type, and the result of
90 * dereferencing @ptr must be assignable to @x without a cast.
91 *
92 * Returns zero on success, or -EFAULT on error.
93 * On error, the variable @x is set to zero.
94 */
6a090e97
RD
95#define get_user(x, ptr) ({ \
96 const typeof(*(ptr)) __user *__gu_ptr = (ptr); \
97 access_ok(__gu_ptr, sizeof(*__gu_ptr)) ? \
98 __get_user(x, __gu_ptr) : -EFAULT; \
538722ca 99})
838d2406 100
3a6d7724
MS
101#define __get_user(x, ptr) \
102({ \
3a6d7724
MS
103 long __gu_err; \
104 switch (sizeof(*(ptr))) { \
105 case 1: \
a97b693c 106 __get_user_asm("lbu", (ptr), x, __gu_err); \
3a6d7724
MS
107 break; \
108 case 2: \
a97b693c 109 __get_user_asm("lhu", (ptr), x, __gu_err); \
3a6d7724
MS
110 break; \
111 case 4: \
a97b693c 112 __get_user_asm("lw", (ptr), x, __gu_err); \
3a6d7724 113 break; \
a97b693c
AB
114 case 8: { \
115 __u64 __x = 0; \
116 __gu_err = raw_copy_from_user(&__x, ptr, 8) ? \
117 -EFAULT : 0; \
118 (x) = (typeof(x))(typeof((x) - (x)))__x; \
6a090e97 119 break; \
a97b693c 120 } \
3a6d7724
MS
121 default: \
122 /* __gu_val = 0; __gu_err = -EINVAL;*/ __gu_err = __user_bad();\
123 } \
3a6d7724 124 __gu_err; \
0d6de953 125})
2660663f 126
3a6d7724 127
ef4e277b
MS
128#define __put_user_asm(insn, __gu_ptr, __gu_val, __gu_err) \
129({ \
130 __asm__ __volatile__ ( \
131 "1:" insn " %1, %2, r0;" \
132 " addk %0, r0, r0;" \
133 "2: " \
134 __FIXUP_SECTION \
135 "3: brid 2b;" \
136 " addik %0, r0, %3;" \
137 ".previous;" \
138 __EX_TABLE_SECTION \
139 ".word 1b,3b;" \
140 ".previous;" \
141 : "=&r"(__gu_err) \
142 : "r"(__gu_val), "r"(__gu_ptr), "i"(-EFAULT) \
143 ); \
144})
2660663f 145
ef4e277b 146#define __put_user_asm_8(__gu_ptr, __gu_val, __gu_err) \
0d6de953 147({ \
ef4e277b
MS
148 __asm__ __volatile__ (" lwi %0, %1, 0;" \
149 "1: swi %0, %2, 0;" \
150 " lwi %0, %1, 4;" \
151 "2: swi %0, %2, 4;" \
152 " addk %0, r0, r0;" \
153 "3: " \
154 __FIXUP_SECTION \
155 "4: brid 3b;" \
156 " addik %0, r0, %3;" \
157 ".previous;" \
158 __EX_TABLE_SECTION \
159 ".word 1b,4b,2b,4b;" \
160 ".previous;" \
161 : "=&r"(__gu_err) \
162 : "r"(&__gu_val), "r"(__gu_ptr), "i"(-EFAULT) \
163 ); \
0d6de953 164})
2660663f 165
cca79120
MS
166/**
167 * put_user: - Write a simple value into user space.
168 * @x: Value to copy to user space.
169 * @ptr: Destination address, in user space.
170 *
b3c395ef
DH
171 * Context: User context only. This function may sleep if pagefaults are
172 * enabled.
cca79120
MS
173 *
174 * This macro copies a single simple value from kernel space to user
175 * space. It supports simple types like char and int, but not larger
176 * data types like structures or arrays.
177 *
178 * @ptr must have pointer-to-simple-variable type, and @x must be assignable
179 * to the result of dereferencing @ptr.
180 *
181 * Returns zero on success, or -EFAULT on error.
182 */
538722ca
SM
183#define put_user(x, ptr) \
184 __put_user_check((x), (ptr), sizeof(*(ptr)))
185
186#define __put_user_check(x, ptr, size) \
187({ \
132d5dfc 188 typeof(*(ptr)) volatile __pu_val = x; \
538722ca
SM
189 typeof(*(ptr)) __user *__pu_addr = (ptr); \
190 int __pu_err = 0; \
191 \
96d4f267 192 if (access_ok(__pu_addr, size)) { \
538722ca
SM
193 switch (size) { \
194 case 1: \
195 __put_user_asm("sb", __pu_addr, __pu_val, \
196 __pu_err); \
197 break; \
198 case 2: \
199 __put_user_asm("sh", __pu_addr, __pu_val, \
200 __pu_err); \
201 break; \
202 case 4: \
203 __put_user_asm("sw", __pu_addr, __pu_val, \
204 __pu_err); \
205 break; \
206 case 8: \
207 __put_user_asm_8(__pu_addr, __pu_val, __pu_err);\
208 break; \
209 default: \
210 __pu_err = __user_bad(); \
211 break; \
212 } \
213 } else { \
214 __pu_err = -EFAULT; \
215 } \
216 __pu_err; \
217})
cca79120 218
ef4e277b
MS
219#define __put_user(x, ptr) \
220({ \
221 __typeof__(*(ptr)) volatile __gu_val = (x); \
222 long __gu_err = 0; \
223 switch (sizeof(__gu_val)) { \
224 case 1: \
225 __put_user_asm("sb", (ptr), __gu_val, __gu_err); \
226 break; \
227 case 2: \
228 __put_user_asm("sh", (ptr), __gu_val, __gu_err); \
229 break; \
230 case 4: \
231 __put_user_asm("sw", (ptr), __gu_val, __gu_err); \
232 break; \
233 case 8: \
234 __put_user_asm_8((ptr), __gu_val, __gu_err); \
235 break; \
236 default: \
237 /*__gu_err = -EINVAL;*/ __gu_err = __user_bad(); \
238 } \
239 __gu_err; \
240})
2660663f 241
d491afb8
AV
242static inline unsigned long
243raw_copy_from_user(void *to, const void __user *from, unsigned long n)
4270690b 244{
d491afb8 245 return __copy_tofrom_user((__force void __user *)to, from, n);
4270690b
MS
246}
247
d491afb8
AV
248static inline unsigned long
249raw_copy_to_user(void __user *to, const void *from, unsigned long n)
cc5a428b 250{
d491afb8 251 return __copy_tofrom_user(to, (__force const void __user *)from, n);
89ae9753 252}
d491afb8
AV
253#define INLINE_COPY_FROM_USER
254#define INLINE_COPY_TO_USER
89ae9753
MS
255
256/*
257 * Copy a null terminated string from userspace.
258 */
b26b1816
AB
259__must_check long strncpy_from_user(char *dst, const char __user *src,
260 long count);
89ae9753
MS
261
262/*
263 * Return the size of a string (including the ending 0)
264 *
265 * Return 0 on exception, a value greater than N if too long
266 */
b26b1816 267__must_check long strnlen_user(const char __user *sstr, long len);
cc5a428b 268
2660663f 269#endif /* _ASM_MICROBLAZE_UACCESS_H */