1 /*
2  * Authors:    Bjorn Wesen (bjornw@axis.com)
3  *	       Hans-Peter Nilsson (hp@axis.com)
4  *
5  * $Log: uaccess.h,v $
6  * Revision 1.12  2003/06/17 14:00:42  starvik
7  * Merge of Linux 2.4.21
8  *
9  * Revision 1.11  2003/06/04 19:36:45  hp
10  * Remove unused copy-pasted register clobber from __asm_clear
11  *
12  * Revision 1.10  2003/04/09 08:22:38  pkj
13  * Typo correction (taken from Linux 2.5).
14  *
15  * Revision 1.9  2002/11/20 18:20:17  hp
16  * Make all static inline functions extern inline.
17  *
18  * Revision 1.8  2001/10/29 13:01:48  bjornw
19  * Removed unused variable tmp2 in strnlen_user
20  *
21  * Revision 1.7  2001/10/02 12:44:52  hp
22  * Add support for 64-bit put_user/get_user
23  *
24  * Revision 1.6  2001/10/01 14:51:17  bjornw
25  * Added register prefixes and removed underscores
26  *
27  * Revision 1.5  2000/10/25 03:33:21  hp
28  * - Provide implementation for everything else but get_user and put_user;
29  *   copying inline to/from user for constant length 0..16, 20, 24, and
30  *   clearing for 0..4, 8, 12, 16, 20, 24, strncpy_from_user and strnlen_user
31  *   always inline.
32  * - Constraints for destination addr in get_user cannot be memory, only reg.
33  * - Correct labels for PC at expected fault points.
34  * - Nits with assembly code.
35  * - Don't use statement expressions without value; use "do {} while (0)".
36  * - Return correct values from __generic_... functions.
37  *
38  * Revision 1.4  2000/09/12 16:28:25  bjornw
39  * * Removed comments from the get/put user asm code
40  * * Constrains for destination addr in put_user cannot be memory, only reg
41  *
42  * Revision 1.3  2000/09/12 14:30:20  bjornw
43  * MAX_ADDR_USER does not exist anymore
44  *
45  * Revision 1.2  2000/07/13 15:52:48  bjornw
46  * New user-access functions
47  *
48  * Revision 1.1.1.1  2000/07/10 16:32:31  bjornw
49  * CRIS architecture, working draft
50  *
51  *
52  *
53  */
54 
55 /* Asm:s have been tweaked (within the domain of correctness) to give
56    satisfactory results for "gcc version 2.96 20000427 (experimental)".
57 
58    Check regularly...
59 
60    Register $r9 is chosen for temporaries, being a call-clobbered register
61    first in line to be used (notably for local blocks), not colliding with
62    parameter registers.  */
63 
64 #ifndef _CRIS_UACCESS_H
65 #define _CRIS_UACCESS_H
66 
67 #ifndef __ASSEMBLY__
68 #include <linux/sched.h>
69 #include <linux/errno.h>
70 #include <asm/processor.h>
71 #include <asm/page.h>
72 
73 #define VERIFY_READ	0
74 #define VERIFY_WRITE	1
75 
76 /*
77  * The fs value determines whether argument validity checking should be
78  * performed or not.  If get_fs() == USER_DS, checking is performed, with
79  * get_fs() == KERNEL_DS, checking is bypassed.
80  *
81  * For historical reasons, these macros are grossly misnamed.
82  */
83 
84 #define MAKE_MM_SEG(s)	((mm_segment_t) { (s) })
85 
86 /* addr_limit is the maximum accessible address for the task. we misuse
87  * the KERNEL_DS and USER_DS values to both assign and compare the
88  * addr_limit values through the equally misnamed get/set_fs macros.
89  * (see above)
90  */
91 
92 #define KERNEL_DS	MAKE_MM_SEG(0xFFFFFFFF)
93 #define USER_DS		MAKE_MM_SEG(TASK_SIZE)
94 
95 #define get_ds()	(KERNEL_DS)
96 #define get_fs()	(current->addr_limit)
97 #define set_fs(x)	(current->addr_limit = (x))
98 
99 #define segment_eq(a,b)	((a).seg == (b).seg)
100 
101 #define __kernel_ok (segment_eq(get_fs(), KERNEL_DS))
102 #define __user_ok(addr,size) (((size) <= TASK_SIZE)&&((addr) <= TASK_SIZE-(size)))
103 #define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size)))
104 #define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size))
105 
verify_area(int type,const void * addr,unsigned long size)106 extern inline int verify_area(int type, const void * addr, unsigned long size)
107 {
108 	return access_ok(type,addr,size) ? 0 : -EFAULT;
109 }
110 
111 
112 /*
113  * The exception table consists of pairs of addresses: the first is the
114  * address of an instruction that is allowed to fault, and the second is
115  * the address at which the program should continue.  No registers are
116  * modified, so it is entirely up to the continuation code to figure out
117  * what to do.
118  *
119  * All the routines below use bits of fixup code that are out of line
120  * with the main instruction path.  This means when everything is well,
121  * we don't even have to jump over them.  Further, they do not intrude
122  * on our cache or tlb entries.
123  */
124 
125 struct exception_table_entry
126 {
127 	unsigned long insn, fixup;
128 };
129 
130 /* Returns 0 if exception not found and fixup otherwise.  */
131 extern unsigned long search_exception_table(unsigned long);
132 
133 
134 /*
135  * These are the main single-value transfer routines.  They automatically
136  * use the right size if we just have the right pointer type.
137  *
138  * This gets kind of ugly. We want to return _two_ values in "get_user()"
139  * and yet we don't want to do any pointers, because that is too much
140  * of a performance impact. Thus we have a few rather ugly macros here,
141  * and hide all the ugliness from the user.
142  *
143  * The "__xxx" versions of the user access functions are versions that
144  * do not verify the address space, that must have been done previously
145  * with a separate "access_ok()" call (this is used when we do multiple
146  * accesses to the same area of user memory).
147  *
148  * As we use the same address space for kernel and user data on
149  * CRIS, we can just do these as direct assignments.  (Of course, the
150  * exception handling means that it's no longer "just"...)
151  */
152 #define get_user(x,ptr) \
153   __get_user_check((x),(ptr),sizeof(*(ptr)))
154 #define put_user(x,ptr) \
155   __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
156 
157 #define __get_user(x,ptr) \
158   __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
159 #define __put_user(x,ptr) \
160   __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
161 
162 extern long __put_user_bad(void);
163 
164 #define __put_user_nocheck(x,ptr,size)			\
165 ({							\
166 	long __pu_err;					\
167 	__put_user_size((x),(ptr),(size),__pu_err);	\
168 	__pu_err;					\
169 })
170 
171 #define __put_user_check(x,ptr,size)				\
172 ({								\
173 	long __pu_err = -EFAULT;				\
174 	__typeof__(*(ptr)) *__pu_addr = (ptr);			\
175 	if (access_ok(VERIFY_WRITE,__pu_addr,size))		\
176 		__put_user_size((x),__pu_addr,(size),__pu_err);	\
177 	__pu_err;						\
178 })
179 
180 #define __put_user_size(x,ptr,size,retval)			\
181 do {								\
182 	retval = 0;						\
183 	switch (size) {						\
184 	  case 1: __put_user_asm(x,ptr,retval,"move.b"); break;	\
185 	  case 2: __put_user_asm(x,ptr,retval,"move.w"); break;	\
186 	  case 4: __put_user_asm(x,ptr,retval,"move.d"); break;	\
187 	  case 8: __put_user_asm_64(x,ptr,retval); break;	\
188 	  default: __put_user_bad();				\
189 	}							\
190 } while (0)
191 
192 struct __large_struct { unsigned long buf[100]; };
193 #define __m(x) (*(struct __large_struct *)(x))
194 
195 /*
196  * We don't tell gcc that we are accessing memory, but this is OK
197  * because we do not write to any memory gcc knows about, so there
198  * are no aliasing issues.
199  *
200  * Note that PC at a fault is the address *after* the faulting
201  * instruction.
202  */
203 #define __put_user_asm(x, addr, err, op)			\
204 	__asm__ __volatile__(					\
205 		"	"op" %1,[%2]\n"				\
206 		"2:\n"						\
207 		"	.section .fixup,\"ax\"\n"		\
208 		"3:	move.d %3,%0\n"				\
209 		"	jump 2b\n"				\
210 		"	.previous\n"				\
211 		"	.section __ex_table,\"a\"\n"		\
212 		"	.dword 2b,3b\n"				\
213 		"	.previous\n"				\
214 		: "=r" (err)					\
215 		: "r" (x), "r" (addr), "g" (-EFAULT), "0" (err))
216 
217 #define __put_user_asm_64(x, addr, err)				\
218 	__asm__ __volatile__(					\
219 		"	move.d %M1,[%2]\n"			\
220 		"2:	move.d %H1,[%2+4]\n"			\
221 		"4:\n"						\
222 		"	.section .fixup,\"ax\"\n"		\
223 		"3:	move.d %3,%0\n"				\
224 		"	jump 4b\n"				\
225 		"	.previous\n"				\
226 		"	.section __ex_table,\"a\"\n"		\
227 		"	.dword 2b,3b\n"				\
228 		"	.dword 4b,3b\n"				\
229 		"	.previous\n"				\
230 		: "=r" (err)					\
231 		: "r" (x), "r" (addr), "g" (-EFAULT), "0" (err))
232 
233 
234 #define __get_user_nocheck(x,ptr,size)				\
235 ({								\
236 	long __gu_err, __gu_val;				\
237 	__get_user_size(__gu_val,(ptr),(size),__gu_err);	\
238 	(x) = (__typeof__(*(ptr)))__gu_val;			\
239 	__gu_err;						\
240 })
241 
242 #define __get_user_check(x,ptr,size)					\
243 ({									\
244 	long __gu_err = -EFAULT, __gu_val = 0;				\
245 	const __typeof__(*(ptr)) *__gu_addr = (ptr);			\
246 	if (access_ok(VERIFY_READ,__gu_addr,size))			\
247 		__get_user_size(__gu_val,__gu_addr,(size),__gu_err);	\
248 	(x) = (__typeof__(*(ptr)))__gu_val;				\
249 	__gu_err;							\
250 })
251 
252 extern long __get_user_bad(void);
253 
254 #define __get_user_size(x,ptr,size,retval)			\
255 do {								\
256 	retval = 0;						\
257 	switch (size) {						\
258 	  case 1: __get_user_asm(x,ptr,retval,"move.b"); break;	\
259 	  case 2: __get_user_asm(x,ptr,retval,"move.w"); break;	\
260 	  case 4: __get_user_asm(x,ptr,retval,"move.d"); break;	\
261 	  case 8: __get_user_asm_64(x,ptr,retval); break;	\
262 	  default: (x) = __get_user_bad();			\
263 	}							\
264 } while (0)
265 
266 /* See comment before __put_user_asm.  */
267 
268 #define __get_user_asm(x, addr, err, op)		\
269 	__asm__ __volatile__(				\
270 		"	"op" [%2],%1\n"			\
271 		"2:\n"					\
272 		"	.section .fixup,\"ax\"\n"	\
273 		"3:	move.d %3,%0\n"			\
274 		"	moveq 0,%1\n"			\
275 		"	jump 2b\n"			\
276 		"	.previous\n"			\
277 		"	.section __ex_table,\"a\"\n"	\
278 		"	.dword 2b,3b\n"			\
279 		"	.previous\n"			\
280 		: "=r" (err), "=r" (x)			\
281 		: "r" (addr), "g" (-EFAULT), "0" (err))
282 
283 #define __get_user_asm_64(x, addr, err)			\
284 	__asm__ __volatile__(				\
285 		"	move.d [%2],%M1\n"		\
286 		"2:	move.d [%2+4],%H1\n"		\
287 		"4:\n"					\
288 		"	.section .fixup,\"ax\"\n"	\
289 		"3:	move.d %3,%0\n"			\
290 		"	moveq 0,%1\n"			\
291 		"	jump 4b\n"			\
292 		"	.previous\n"			\
293 		"	.section __ex_table,\"a\"\n"	\
294 		"	.dword 2b,3b\n"			\
295 		"	.dword 4b,3b\n"			\
296 		"	.previous\n"			\
297 		: "=r" (err), "=r" (x)			\
298 		: "r" (addr), "g" (-EFAULT), "0" (err))
299 
300 /* More complex functions.  Most are inline, but some call functions that
301    live in lib/usercopy.c  */
302 
303 extern unsigned long __copy_user(void *to, const void *from, unsigned long n);
304 extern unsigned long __copy_user_zeroing(void *to, const void *from, unsigned long n);
305 extern unsigned long __do_clear_user(void *to, unsigned long n);
306 
307 /*
308  * Copy a null terminated string from userspace.
309  *
310  * Must return:
311  * -EFAULT		for an exception
312  * count		if we hit the buffer limit
313  * bytes copied		if we hit a null byte
314  * (without the null byte)
315  */
316 
317 extern inline long
__do_strncpy_from_user(char * dst,const char * src,long count)318 __do_strncpy_from_user(char *dst, const char *src, long count)
319 {
320 	long res;
321 
322 	if (count == 0)
323 		return 0;
324 
325 	/*
326 	 * Currently, in 2.4.0-test9, most ports use a simple byte-copy loop.
327 	 *  So do we.
328 	 *
329 	 *  This code is deduced from:
330 	 *
331 	 *	char tmp2;
332 	 *	long tmp1, tmp3
333 	 *	tmp1 = count;
334 	 *	while ((*dst++ = (tmp2 = *src++)) != 0
335 	 *	       && --tmp1)
336 	 *	  ;
337 	 *
338 	 *	res = count - tmp1;
339 	 *
340 	 *  with tweaks.
341 	 */
342 
343 	__asm__ __volatile__ (
344 		"	move.d %3,%0\n"
345 		"	move.b [%2+],$r9\n"
346 		"1:	beq 2f\n"
347 		"	move.b $r9,[%1+]\n"
348 
349 		"	subq 1,%0\n"
350 		"	bne 1b\n"
351 		"	move.b [%2+],$r9\n"
352 
353 		"2:	sub.d %3,%0\n"
354 		"	neg.d %0,%0\n"
355 		"3:\n"
356 		"	.section .fixup,\"ax\"\n"
357 		"4:	move.d %7,%0\n"
358 		"	jump 3b\n"
359 
360 		/* There's one address for a fault at the first move, and
361 		   two possible PC values for a fault at the second move,
362 		   being a delay-slot filler.  However, the branch-target
363 		   for the second move is the same as the first address.
364 		   Just so you don't get confused...  */
365 		"	.previous\n"
366 		"	.section __ex_table,\"a\"\n"
367 		"	.dword 1b,4b\n"
368 		"	.dword 2b,4b\n"
369 		"	.previous"
370 		: "=r" (res), "=r" (dst), "=r" (src), "=r" (count)
371 		: "3" (count), "1" (dst), "2" (src), "g" (-EFAULT)
372 		: "r9");
373 
374 	return res;
375 }
376 
377 extern inline unsigned long
__generic_copy_to_user(void * to,const void * from,unsigned long n)378 __generic_copy_to_user(void *to, const void *from, unsigned long n)
379 {
380 	if (access_ok(VERIFY_WRITE, to, n))
381 		return __copy_user(to,from,n);
382 	return n;
383 }
384 
385 extern inline unsigned long
__generic_copy_from_user(void * to,const void * from,unsigned long n)386 __generic_copy_from_user(void *to, const void *from, unsigned long n)
387 {
388 	if (access_ok(VERIFY_READ, from, n))
389 		return __copy_user_zeroing(to,from,n);
390 	return n;
391 }
392 
393 extern inline unsigned long
__generic_clear_user(void * to,unsigned long n)394 __generic_clear_user(void *to, unsigned long n)
395 {
396 	if (access_ok(VERIFY_WRITE, to, n))
397 		return __do_clear_user(to,n);
398 	return n;
399 }
400 
401 extern inline long
__strncpy_from_user(char * dst,const char * src,long count)402 __strncpy_from_user(char *dst, const char *src, long count)
403 {
404 	return __do_strncpy_from_user(dst, src, count);
405 }
406 
407 extern inline long
strncpy_from_user(char * dst,const char * src,long count)408 strncpy_from_user(char *dst, const char *src, long count)
409 {
410 	long res = -EFAULT;
411 	if (access_ok(VERIFY_READ, src, 1))
412 		res = __do_strncpy_from_user(dst, src, count);
413 	return res;
414 }
415 
416 /* A few copy asms to build up the more complex ones from.
417 
418    Note again, a post-increment is performed regardless of whether a bus
419    fault occurred in that instruction, and PC for a faulted insn is the
420    address *after* the insn.  */
421 
422 #define __asm_copy_user_cont(to, from, ret, COPY, FIXUP, TENTRY) \
423 	__asm__ __volatile__ (				\
424 			COPY				\
425 		"1:\n"					\
426 		"	.section .fixup,\"ax\"\n"	\
427 			FIXUP				\
428 		"	jump 1b\n"			\
429 		"	.previous\n"			\
430 		"	.section __ex_table,\"a\"\n"	\
431 			TENTRY				\
432 		"	.previous\n"			\
433 		: "=r" (to), "=r" (from), "=r" (ret)	\
434 		: "0" (to), "1" (from), "2" (ret)	\
435 		: "r9", "memory")
436 
437 #define __asm_copy_from_user_1(to, from, ret) \
438 	__asm_copy_user_cont(to, from, ret,	\
439 		"	move.b [%1+],$r9\n"	\
440 		"2:	move.b $r9,[%0+]\n",	\
441 		"3:	addq 1,%2\n"		\
442 		"	clear.b [%0+]\n",	\
443 		"	.dword 2b,3b\n")
444 
445 #define __asm_copy_from_user_2x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
446 	__asm_copy_user_cont(to, from, ret,		\
447 		"	move.w [%1+],$r9\n"		\
448 		"2:	move.w $r9,[%0+]\n" COPY,	\
449 		"3:	addq 2,%2\n"			\
450 		"	clear.w [%0+]\n" FIXUP,		\
451 		"	.dword 2b,3b\n" TENTRY)
452 
453 #define __asm_copy_from_user_2(to, from, ret) \
454 	__asm_copy_from_user_2x_cont(to, from, ret, "", "", "")
455 
456 #define __asm_copy_from_user_3(to, from, ret)		\
457 	__asm_copy_from_user_2x_cont(to, from, ret,	\
458 		"	move.b [%1+],$r9\n"		\
459 		"4:	move.b $r9,[%0+]\n",		\
460 		"5:	addq 1,%2\n"			\
461 		"	clear.b [%0+]\n",		\
462 		"	.dword 4b,5b\n")
463 
464 #define __asm_copy_from_user_4x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
465 	__asm_copy_user_cont(to, from, ret,		\
466 		"	move.d [%1+],$r9\n"		\
467 		"2:	move.d $r9,[%0+]\n" COPY,	\
468 		"3:	addq 4,%2\n"			\
469 		"	clear.d [%0+]\n" FIXUP,		\
470 		"	.dword 2b,3b\n" TENTRY)
471 
472 #define __asm_copy_from_user_4(to, from, ret) \
473 	__asm_copy_from_user_4x_cont(to, from, ret, "", "", "")
474 
475 #define __asm_copy_from_user_5(to, from, ret) \
476 	__asm_copy_from_user_4x_cont(to, from, ret,	\
477 		"	move.b [%1+],$r9\n"		\
478 		"4:	move.b $r9,[%0+]\n",		\
479 		"5:	addq 1,%2\n"			\
480 		"	clear.b [%0+]\n",		\
481 		"	.dword 4b,5b\n")
482 
483 #define __asm_copy_from_user_6x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
484 	__asm_copy_from_user_4x_cont(to, from, ret,	\
485 		"	move.w [%1+],$r9\n"		\
486 		"4:	move.w $r9,[%0+]\n" COPY,	\
487 		"5:	addq 2,%2\n"			\
488 		"	clear.w [%0+]\n" FIXUP,		\
489 		"	.dword 4b,5b\n" TENTRY)
490 
491 #define __asm_copy_from_user_6(to, from, ret) \
492 	__asm_copy_from_user_6x_cont(to, from, ret, "", "", "")
493 
494 #define __asm_copy_from_user_7(to, from, ret) \
495 	__asm_copy_from_user_6x_cont(to, from, ret,	\
496 		"	move.b [%1+],$r9\n"		\
497 		"6:	move.b $r9,[%0+]\n",		\
498 		"7:	addq 1,%2\n"			\
499 		"	clear.b [%0+]\n",		\
500 		"	.dword 6b,7b\n")
501 
502 #define __asm_copy_from_user_8x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
503 	__asm_copy_from_user_4x_cont(to, from, ret,	\
504 		"	move.d [%1+],$r9\n"		\
505 		"4:	move.d $r9,[%0+]\n" COPY,	\
506 		"5:	addq 4,%2\n"			\
507 		"	clear.d [%0+]\n" FIXUP,		\
508 		"	.dword 4b,5b\n" TENTRY)
509 
510 #define __asm_copy_from_user_8(to, from, ret) \
511 	__asm_copy_from_user_8x_cont(to, from, ret, "", "", "")
512 
513 #define __asm_copy_from_user_9(to, from, ret) \
514 	__asm_copy_from_user_8x_cont(to, from, ret,	\
515 		"	move.b [%1+],$r9\n"		\
516 		"6:	move.b $r9,[%0+]\n",		\
517 		"7:	addq 1,%2\n"			\
518 		"	clear.b [%0+]\n",		\
519 		"	.dword 6b,7b\n")
520 
521 #define __asm_copy_from_user_10x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
522 	__asm_copy_from_user_8x_cont(to, from, ret,	\
523 		"	move.w [%1+],$r9\n"		\
524 		"6:	move.w $r9,[%0+]\n" COPY,	\
525 		"7:	addq 2,%2\n"			\
526 		"	clear.w [%0+]\n" FIXUP,		\
527 		"	.dword 6b,7b\n" TENTRY)
528 
529 #define __asm_copy_from_user_10(to, from, ret) \
530 	__asm_copy_from_user_10x_cont(to, from, ret, "", "", "")
531 
532 #define __asm_copy_from_user_11(to, from, ret)		\
533 	__asm_copy_from_user_10x_cont(to, from, ret,	\
534 		"	move.b [%1+],$r9\n"		\
535 		"8:	move.b $r9,[%0+]\n",		\
536 		"9:	addq 1,%2\n"			\
537 		"	clear.b [%0+]\n",		\
538 		"	.dword 8b,9b\n")
539 
540 #define __asm_copy_from_user_12x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
541 	__asm_copy_from_user_8x_cont(to, from, ret,	\
542 		"	move.d [%1+],$r9\n"		\
543 		"6:	move.d $r9,[%0+]\n" COPY,	\
544 		"7:	addq 4,%2\n"			\
545 		"	clear.d [%0+]\n" FIXUP,		\
546 		"	.dword 6b,7b\n" TENTRY)
547 
548 #define __asm_copy_from_user_12(to, from, ret) \
549 	__asm_copy_from_user_12x_cont(to, from, ret, "", "", "")
550 
551 #define __asm_copy_from_user_13(to, from, ret) \
552 	__asm_copy_from_user_12x_cont(to, from, ret,	\
553 		"	move.b [%1+],$r9\n"		\
554 		"8:	move.b $r9,[%0+]\n",		\
555 		"9:	addq 1,%2\n"			\
556 		"	clear.b [%0+]\n",		\
557 		"	.dword 8b,9b\n")
558 
559 #define __asm_copy_from_user_14x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
560 	__asm_copy_from_user_12x_cont(to, from, ret,	\
561 		"	move.w [%1+],$r9\n"		\
562 		"8:	move.w $r9,[%0+]\n" COPY,	\
563 		"9:	addq 2,%2\n"			\
564 		"	clear.w [%0+]\n" FIXUP,		\
565 		"	.dword 8b,9b\n" TENTRY)
566 
567 #define __asm_copy_from_user_14(to, from, ret) \
568 	__asm_copy_from_user_14x_cont(to, from, ret, "", "", "")
569 
570 #define __asm_copy_from_user_15(to, from, ret) \
571 	__asm_copy_from_user_14x_cont(to, from, ret,	\
572 		"	move.b [%1+],$r9\n"		\
573 		"10:	move.b $r9,[%0+]\n",		\
574 		"11:	addq 1,%2\n"			\
575 		"	clear.b [%0+]\n",		\
576 		"	.dword 10b,11b\n")
577 
578 #define __asm_copy_from_user_16x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
579 	__asm_copy_from_user_12x_cont(to, from, ret,	\
580 		"	move.d [%1+],$r9\n"		\
581 		"8:	move.d $r9,[%0+]\n" COPY,	\
582 		"9:	addq 4,%2\n"			\
583 		"	clear.d [%0+]\n" FIXUP,		\
584 		"	.dword 8b,9b\n" TENTRY)
585 
586 #define __asm_copy_from_user_16(to, from, ret) \
587 	__asm_copy_from_user_16x_cont(to, from, ret, "", "", "")
588 
589 #define __asm_copy_from_user_20x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
590 	__asm_copy_from_user_16x_cont(to, from, ret,	\
591 		"	move.d [%1+],$r9\n"		\
592 		"10:	move.d $r9,[%0+]\n" COPY,	\
593 		"11:	addq 4,%2\n"			\
594 		"	clear.d [%0+]\n" FIXUP,		\
595 		"	.dword 10b,11b\n" TENTRY)
596 
597 #define __asm_copy_from_user_20(to, from, ret) \
598 	__asm_copy_from_user_20x_cont(to, from, ret, "", "", "")
599 
600 #define __asm_copy_from_user_24x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
601 	__asm_copy_from_user_20x_cont(to, from, ret,	\
602 		"	move.d [%1+],$r9\n"		\
603 		"12:	move.d $r9,[%0+]\n" COPY,	\
604 		"13:	addq 4,%2\n"			\
605 		"	clear.d [%0+]\n" FIXUP,		\
606 		"	.dword 12b,13b\n" TENTRY)
607 
608 #define __asm_copy_from_user_24(to, from, ret) \
609 	__asm_copy_from_user_24x_cont(to, from, ret, "", "", "")
610 
611 /* And now, the to-user ones.  */
612 
613 #define __asm_copy_to_user_1(to, from, ret)	\
614 	__asm_copy_user_cont(to, from, ret,	\
615 		"	move.b [%1+],$r9\n"	\
616 		"	move.b $r9,[%0+]\n2:\n",	\
617 		"3:	addq 1,%2\n",		\
618 		"	.dword 2b,3b\n")
619 
620 #define __asm_copy_to_user_2x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
621 	__asm_copy_user_cont(to, from, ret,		\
622 		"	move.w [%1+],$r9\n"		\
623 		"	move.w $r9,[%0+]\n2:\n" COPY,	\
624 		"3:	addq 2,%2\n" FIXUP,		\
625 		"	.dword 2b,3b\n" TENTRY)
626 
627 #define __asm_copy_to_user_2(to, from, ret) \
628 	__asm_copy_to_user_2x_cont(to, from, ret, "", "", "")
629 
630 #define __asm_copy_to_user_3(to, from, ret) \
631 	__asm_copy_to_user_2x_cont(to, from, ret,	\
632 		"	move.b [%1+],$r9\n"		\
633 		"	move.b $r9,[%0+]\n4:\n",		\
634 		"5:	addq 1,%2\n",			\
635 		"	.dword 4b,5b\n")
636 
637 #define __asm_copy_to_user_4x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
638 	__asm_copy_user_cont(to, from, ret,		\
639 		"	move.d [%1+],$r9\n"		\
640 		"	move.d $r9,[%0+]\n2:\n" COPY,	\
641 		"3:	addq 4,%2\n" FIXUP,		\
642 		"	.dword 2b,3b\n" TENTRY)
643 
644 #define __asm_copy_to_user_4(to, from, ret) \
645 	__asm_copy_to_user_4x_cont(to, from, ret, "", "", "")
646 
647 #define __asm_copy_to_user_5(to, from, ret) \
648 	__asm_copy_to_user_4x_cont(to, from, ret,	\
649 		"	move.b [%1+],$r9\n"		\
650 		"	move.b $r9,[%0+]\n4:\n",		\
651 		"5:	addq 1,%2\n",			\
652 		"	.dword 4b,5b\n")
653 
654 #define __asm_copy_to_user_6x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
655 	__asm_copy_to_user_4x_cont(to, from, ret,	\
656 		"	move.w [%1+],$r9\n"		\
657 		"	move.w $r9,[%0+]\n4:\n" COPY,	\
658 		"5:	addq 2,%2\n" FIXUP,		\
659 		"	.dword 4b,5b\n" TENTRY)
660 
661 #define __asm_copy_to_user_6(to, from, ret) \
662 	__asm_copy_to_user_6x_cont(to, from, ret, "", "", "")
663 
664 #define __asm_copy_to_user_7(to, from, ret) \
665 	__asm_copy_to_user_6x_cont(to, from, ret,	\
666 		"	move.b [%1+],$r9\n"		\
667 		"	move.b $r9,[%0+]\n6:\n",		\
668 		"7:	addq 1,%2\n",			\
669 		"	.dword 6b,7b\n")
670 
671 #define __asm_copy_to_user_8x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
672 	__asm_copy_to_user_4x_cont(to, from, ret,	\
673 		"	move.d [%1+],$r9\n"		\
674 		"	move.d $r9,[%0+]\n4:\n" COPY,	\
675 		"5:	addq 4,%2\n"  FIXUP,		\
676 		"	.dword 4b,5b\n" TENTRY)
677 
678 #define __asm_copy_to_user_8(to, from, ret) \
679 	__asm_copy_to_user_8x_cont(to, from, ret, "", "", "")
680 
681 #define __asm_copy_to_user_9(to, from, ret) \
682 	__asm_copy_to_user_8x_cont(to, from, ret,	\
683 		"	move.b [%1+],$r9\n"		\
684 		"	move.b $r9,[%0+]\n6:\n",		\
685 		"7:	addq 1,%2\n",			\
686 		"	.dword 6b,7b\n")
687 
688 #define __asm_copy_to_user_10x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
689 	__asm_copy_to_user_8x_cont(to, from, ret,	\
690 		"	move.w [%1+],$r9\n"		\
691 		"	move.w $r9,[%0+]\n6:\n" COPY,	\
692 		"7:	addq 2,%2\n" FIXUP,		\
693 		"	.dword 6b,7b\n" TENTRY)
694 
695 #define __asm_copy_to_user_10(to, from, ret) \
696 	__asm_copy_to_user_10x_cont(to, from, ret, "", "", "")
697 
698 #define __asm_copy_to_user_11(to, from, ret) \
699 	__asm_copy_to_user_10x_cont(to, from, ret,	\
700 		"	move.b [%1+],$r9\n"		\
701 		"	move.b $r9,[%0+]\n8:\n",		\
702 		"9:	addq 1,%2\n",			\
703 		"	.dword 8b,9b\n")
704 
705 #define __asm_copy_to_user_12x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
706 	__asm_copy_to_user_8x_cont(to, from, ret,	\
707 		"	move.d [%1+],$r9\n"		\
708 		"	move.d $r9,[%0+]\n6:\n" COPY,	\
709 		"7:	addq 4,%2\n" FIXUP,		\
710 		"	.dword 6b,7b\n" TENTRY)
711 
712 #define __asm_copy_to_user_12(to, from, ret) \
713 	__asm_copy_to_user_12x_cont(to, from, ret, "", "", "")
714 
715 #define __asm_copy_to_user_13(to, from, ret) \
716 	__asm_copy_to_user_12x_cont(to, from, ret,	\
717 		"	move.b [%1+],$r9\n"		\
718 		"	move.b $r9,[%0+]\n8:\n",		\
719 		"9:	addq 1,%2\n",			\
720 		"	.dword 8b,9b\n")
721 
722 #define __asm_copy_to_user_14x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
723 	__asm_copy_to_user_12x_cont(to, from, ret,	\
724 		"	move.w [%1+],$r9\n"		\
725 		"	move.w $r9,[%0+]\n8:\n" COPY,	\
726 		"9:	addq 2,%2\n" FIXUP,		\
727 		"	.dword 8b,9b\n" TENTRY)
728 
729 #define __asm_copy_to_user_14(to, from, ret)	\
730 	__asm_copy_to_user_14x_cont(to, from, ret, "", "", "")
731 
732 #define __asm_copy_to_user_15(to, from, ret) \
733 	__asm_copy_to_user_14x_cont(to, from, ret,	\
734 		"	move.b [%1+],$r9\n"		\
735 		"	move.b $r9,[%0+]\n10:\n",		\
736 		"11:	addq 1,%2\n",			\
737 		"	.dword 10b,11b\n")
738 
739 #define __asm_copy_to_user_16x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
740 	__asm_copy_to_user_12x_cont(to, from, ret,	\
741 		"	move.d [%1+],$r9\n"		\
742 		"	move.d $r9,[%0+]\n8:\n" COPY,	\
743 		"9:	addq 4,%2\n" FIXUP,		\
744 		"	.dword 8b,9b\n" TENTRY)
745 
746 #define __asm_copy_to_user_16(to, from, ret) \
747 	__asm_copy_to_user_16x_cont(to, from, ret, "", "", "")
748 
749 #define __asm_copy_to_user_20x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
750 	__asm_copy_to_user_16x_cont(to, from, ret,	\
751 		"	move.d [%1+],$r9\n"		\
752 		"	move.d $r9,[%0+]\n10:\n" COPY,	\
753 		"11:	addq 4,%2\n" FIXUP,		\
754 		"	.dword 10b,11b\n" TENTRY)
755 
756 #define __asm_copy_to_user_20(to, from, ret) \
757 	__asm_copy_to_user_20x_cont(to, from, ret, "", "", "")
758 
759 #define __asm_copy_to_user_24x_cont(to, from, ret, COPY, FIXUP, TENTRY)	\
760 	__asm_copy_to_user_20x_cont(to, from, ret,	\
761 		"	move.d [%1+],$r9\n"		\
762 		"	move.d $r9,[%0+]\n12:\n" COPY,	\
763 		"13:	addq 4,%2\n" FIXUP,		\
764 		"	.dword 12b,13b\n" TENTRY)
765 
766 #define __asm_copy_to_user_24(to, from, ret)	\
767 	__asm_copy_to_user_24x_cont(to, from, ret, "", "", "")
768 
769 /* Define a few clearing asms with exception handlers.  */
770 
771 /* This frame-asm is like the __asm_copy_user_cont one, but has one less
772    input.  */
773 
774 #define __asm_clear(to, ret, CLEAR, FIXUP, TENTRY) \
775 	__asm__ __volatile__ (				\
776 			CLEAR				\
777 		"1:\n"					\
778 		"	.section .fixup,\"ax\"\n"	\
779 			FIXUP				\
780 		"	jump 1b\n"			\
781 		"	.previous\n"			\
782 		"	.section __ex_table,\"a\"\n"	\
783 			TENTRY				\
784 		"	.previous"			\
785 		: "=r" (to), "=r" (ret)			\
786 		: "0" (to), "1" (ret)			\
787 		: "memory")
788 
789 #define __asm_clear_1(to, ret) \
790 	__asm_clear(to, ret,			\
791 		"	clear.b [%0+]\n2:\n",	\
792 		"3:	addq 1,%1\n",		\
793 		"	.dword 2b,3b\n")
794 
795 #define __asm_clear_2(to, ret) \
796 	__asm_clear(to, ret,			\
797 		"	clear.w [%0+]\n2:\n",	\
798 		"3:	addq 2,%1\n",		\
799 		"	.dword 2b,3b\n")
800 
801 #define __asm_clear_3(to, ret) \
802      __asm_clear(to, ret,			\
803 		 "	clear.w [%0+]\n"	\
804 		 "2:	clear.b [%0+]\n3:\n",	\
805 		 "4:	addq 2,%1\n"		\
806 		 "5:	addq 1,%1\n",		\
807 		 "	.dword 2b,4b\n"		\
808 		 "	.dword 3b,5b\n")
809 
810 #define __asm_clear_4x_cont(to, ret, CLEAR, FIXUP, TENTRY) \
811 	__asm_clear(to, ret,				\
812 		"	clear.d [%0+]\n2:\n" CLEAR,	\
813 		"3:	addq 4,%1\n" FIXUP,		\
814 		"	.dword 2b,3b\n" TENTRY)
815 
816 #define __asm_clear_4(to, ret) \
817 	__asm_clear_4x_cont(to, ret, "", "", "")
818 
819 #define __asm_clear_8x_cont(to, ret, CLEAR, FIXUP, TENTRY) \
820 	__asm_clear_4x_cont(to, ret,			\
821 		"	clear.d [%0+]\n4:\n" CLEAR,	\
822 		"5:	addq 4,%1\n" FIXUP,		\
823 		"	.dword 4b,5b\n" TENTRY)
824 
825 #define __asm_clear_8(to, ret) \
826 	__asm_clear_8x_cont(to, ret, "", "", "")
827 
828 #define __asm_clear_12x_cont(to, ret, CLEAR, FIXUP, TENTRY) \
829 	__asm_clear_8x_cont(to, ret,			\
830 		"	clear.d [%0+]\n6:\n" CLEAR,	\
831 		"7:	addq 4,%1\n" FIXUP,		\
832 		"	.dword 6b,7b\n" TENTRY)
833 
834 #define __asm_clear_12(to, ret) \
835 	__asm_clear_12x_cont(to, ret, "", "", "")
836 
837 #define __asm_clear_16x_cont(to, ret, CLEAR, FIXUP, TENTRY) \
838 	__asm_clear_12x_cont(to, ret,			\
839 		"	clear.d [%0+]\n8:\n" CLEAR,	\
840 		"9:	addq 4,%1\n" FIXUP,		\
841 		"	.dword 8b,9b\n" TENTRY)
842 
843 #define __asm_clear_16(to, ret) \
844 	__asm_clear_16x_cont(to, ret, "", "", "")
845 
846 #define __asm_clear_20x_cont(to, ret, CLEAR, FIXUP, TENTRY) \
847 	__asm_clear_16x_cont(to, ret,			\
848 		"	clear.d [%0+]\n10:\n" CLEAR,	\
849 		"11:	addq 4,%1\n" FIXUP,		\
850 		"	.dword 10b,11b\n" TENTRY)
851 
852 #define __asm_clear_20(to, ret) \
853 	__asm_clear_20x_cont(to, ret, "", "", "")
854 
855 #define __asm_clear_24x_cont(to, ret, CLEAR, FIXUP, TENTRY) \
856 	__asm_clear_20x_cont(to, ret,			\
857 		"	clear.d [%0+]\n12:\n" CLEAR,	\
858 		"13:	addq 4,%1\n" FIXUP,		\
859 		"	.dword 12b,13b\n" TENTRY)
860 
861 #define __asm_clear_24(to, ret) \
862 	__asm_clear_24x_cont(to, ret, "", "", "")
863 
864 /* Note that if these expand awfully if made into switch constructs, so
865    don't do that.  */
866 
867 extern inline unsigned long
__constant_copy_from_user(void * to,const void * from,unsigned long n)868 __constant_copy_from_user(void *to, const void *from, unsigned long n)
869 {
870 	unsigned long ret = 0;
871 	if (n == 0)
872 		;
873 	else if (n == 1)
874 		__asm_copy_from_user_1(to, from, ret);
875 	else if (n == 2)
876 		__asm_copy_from_user_2(to, from, ret);
877 	else if (n == 3)
878 		__asm_copy_from_user_3(to, from, ret);
879 	else if (n == 4)
880 		__asm_copy_from_user_4(to, from, ret);
881 	else if (n == 5)
882 		__asm_copy_from_user_5(to, from, ret);
883 	else if (n == 6)
884 		__asm_copy_from_user_6(to, from, ret);
885 	else if (n == 7)
886 		__asm_copy_from_user_7(to, from, ret);
887 	else if (n == 8)
888 		__asm_copy_from_user_8(to, from, ret);
889 	else if (n == 9)
890 		__asm_copy_from_user_9(to, from, ret);
891 	else if (n == 10)
892 		__asm_copy_from_user_10(to, from, ret);
893 	else if (n == 11)
894 		__asm_copy_from_user_11(to, from, ret);
895 	else if (n == 12)
896 		__asm_copy_from_user_12(to, from, ret);
897 	else if (n == 13)
898 		__asm_copy_from_user_13(to, from, ret);
899 	else if (n == 14)
900 		__asm_copy_from_user_14(to, from, ret);
901 	else if (n == 15)
902 		__asm_copy_from_user_15(to, from, ret);
903 	else if (n == 16)
904 		__asm_copy_from_user_16(to, from, ret);
905 	else if (n == 20)
906 		__asm_copy_from_user_20(to, from, ret);
907 	else if (n == 24)
908 		__asm_copy_from_user_24(to, from, ret);
909 	else
910 		ret = __generic_copy_from_user(to, from, n);
911 
912 	return ret;
913 }
914 
915 /* Ditto, don't make a switch out of this.  */
916 
917 extern inline unsigned long
__constant_copy_to_user(void * to,const void * from,unsigned long n)918 __constant_copy_to_user(void *to, const void *from, unsigned long n)
919 {
920 	unsigned long ret = 0;
921 	if (n == 0)
922 		;
923 	else if (n == 1)
924 		__asm_copy_to_user_1(to, from, ret);
925 	else if (n == 2)
926 		__asm_copy_to_user_2(to, from, ret);
927 	else if (n == 3)
928 		__asm_copy_to_user_3(to, from, ret);
929 	else if (n == 4)
930 		__asm_copy_to_user_4(to, from, ret);
931 	else if (n == 5)
932 		__asm_copy_to_user_5(to, from, ret);
933 	else if (n == 6)
934 		__asm_copy_to_user_6(to, from, ret);
935 	else if (n == 7)
936 		__asm_copy_to_user_7(to, from, ret);
937 	else if (n == 8)
938 		__asm_copy_to_user_8(to, from, ret);
939 	else if (n == 9)
940 		__asm_copy_to_user_9(to, from, ret);
941 	else if (n == 10)
942 		__asm_copy_to_user_10(to, from, ret);
943 	else if (n == 11)
944 		__asm_copy_to_user_11(to, from, ret);
945 	else if (n == 12)
946 		__asm_copy_to_user_12(to, from, ret);
947 	else if (n == 13)
948 		__asm_copy_to_user_13(to, from, ret);
949 	else if (n == 14)
950 		__asm_copy_to_user_14(to, from, ret);
951 	else if (n == 15)
952 		__asm_copy_to_user_15(to, from, ret);
953 	else if (n == 16)
954 		__asm_copy_to_user_16(to, from, ret);
955 	else if (n == 20)
956 		__asm_copy_to_user_20(to, from, ret);
957 	else if (n == 24)
958 		__asm_copy_to_user_24(to, from, ret);
959 	else
960 		ret = __generic_copy_to_user(to, from, n);
961 
962 	return ret;
963 }
964 
965 /* No switch, please.  */
966 
967 extern inline unsigned long
__constant_clear_user(void * to,unsigned long n)968 __constant_clear_user(void *to, unsigned long n)
969 {
970 	unsigned long ret = 0;
971 	if (n == 0)
972 		;
973 	else if (n == 1)
974 		__asm_clear_1(to, ret);
975 	else if (n == 2)
976 		__asm_clear_2(to, ret);
977 	else if (n == 3)
978 		__asm_clear_3(to, ret);
979 	else if (n == 4)
980 		__asm_clear_4(to, ret);
981 	else if (n == 8)
982 		__asm_clear_8(to, ret);
983 	else if (n == 12)
984 		__asm_clear_12(to, ret);
985 	else if (n == 16)
986 		__asm_clear_16(to, ret);
987 	else if (n == 20)
988 		__asm_clear_20(to, ret);
989 	else if (n == 24)
990 		__asm_clear_24(to, ret);
991 	else
992 		ret = __generic_clear_user(to, n);
993 
994 	return ret;
995 }
996 
997 
998 #define clear_user(to, n)			\
999 (__builtin_constant_p(n) ?			\
1000  __constant_clear_user(to, n) :			\
1001  __generic_clear_user(to, n))
1002 
1003 #define copy_from_user(to, from, n)		\
1004 (__builtin_constant_p(n) ?			\
1005  __constant_copy_from_user(to, from, n) :	\
1006  __generic_copy_from_user(to, from, n))
1007 
1008 #define copy_to_user(to, from, n)		\
1009 (__builtin_constant_p(n) ?			\
1010  __constant_copy_to_user(to, from, n) :		\
1011  __generic_copy_to_user(to, from, n))
1012 
1013 /* We let the __ versions of copy_from/to_user inline, because they're often
1014  * used in fast paths and have only a small space overhead.
1015  */
1016 
1017 extern inline unsigned long
__generic_copy_from_user_nocheck(void * to,const void * from,unsigned long n)1018 __generic_copy_from_user_nocheck(void *to, const void *from, unsigned long n)
1019 {
1020 	return __copy_user_zeroing(to,from,n);
1021 }
1022 
1023 extern inline unsigned long
__generic_copy_to_user_nocheck(void * to,const void * from,unsigned long n)1024 __generic_copy_to_user_nocheck(void *to, const void *from, unsigned long n)
1025 {
1026 	return __copy_user(to,from,n);
1027 }
1028 
1029 extern inline unsigned long
__generic_clear_user_nocheck(void * to,unsigned long n)1030 __generic_clear_user_nocheck(void *to, unsigned long n)
1031 {
1032 	return __do_clear_user(to,n);
1033 }
1034 
1035 /* without checking */
1036 
1037 #define __copy_to_user(to,from,n)   __generic_copy_to_user_nocheck((to),(from),(n))
1038 #define __copy_from_user(to,from,n) __generic_copy_from_user_nocheck((to),(from),(n))
1039 #define __clear_user(to,n) __generic_clear_user_nocheck((to),(n))
1040 
1041 /*
1042  * Return the size of a string (including the ending 0)
1043  *
1044  * Return length of string in userspace including terminating 0
1045  * or 0 for error.  Return a value greater than N if too long.
1046  */
1047 
1048 extern inline long
strnlen_user(const char * s,long n)1049 strnlen_user(const char *s, long n)
1050 {
1051 	long res, tmp1;
1052 
1053 	if (!access_ok(VERIFY_READ, s, 0))
1054 		return 0;
1055 
1056 	/*
1057 	 * This code is deduced from:
1058 	 *
1059 	 *	tmp1 = n;
1060 	 *	while (tmp1-- > 0 && *s++)
1061 	 *	  ;
1062 	 *
1063 	 *	res = n - tmp1;
1064 	 *
1065 	 *  (with tweaks).
1066 	 */
1067 
1068 	__asm__ __volatile__ (
1069 		"	move.d %1,$r9\n"
1070 		"0:\n"
1071 		"	ble 1f\n"
1072 		"	subq 1,$r9\n"
1073 
1074 		"	test.b [%0+]\n"
1075 		"	bne 0b\n"
1076 		"	test.d $r9\n"
1077 		"1:\n"
1078 		"	move.d %1,%0\n"
1079 		"	sub.d $r9,%0\n"
1080 		"2:\n"
1081 		"	.section .fixup,\"ax\"\n"
1082 
1083 		"3:	clear.d %0\n"
1084 		"	jump 2b\n"
1085 
1086 		/* There's one address for a fault at the first move, and
1087 		   two possible PC values for a fault at the second move,
1088 		   being a delay-slot filler.  However, the branch-target
1089 		   for the second move is the same as the first address.
1090 		   Just so you don't get confused...  */
1091 		"	.previous\n"
1092 		"	.section __ex_table,\"a\"\n"
1093 		"	.dword 0b,3b\n"
1094 		"	.dword 1b,3b\n"
1095 		"	.previous\n"
1096 		: "=r" (res), "=r" (tmp1)
1097 		: "0" (s), "1" (n)
1098 		: "r9");
1099 
1100 	return res;
1101 }
1102 
1103 #define strlen_user(str)	strnlen_user((str), 0x7ffffffe)
1104 
1105 #endif  /* __ASSEMBLY__ */
1106 
1107 #endif	/* _CRIS_UACCESS_H */
1108