uaccess.c 4.19 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file COPYING in the main directory of this archive
 * for more details.
 */

#include <linux/module.h>
#include <asm/uaccess.h>

unsigned long __generic_copy_from_user(void *to, const void __user *from,
				       unsigned long n)
{
	unsigned long tmp, res;

	asm volatile ("\n"
		"	tst.l	%0\n"
		"	jeq	2f\n"
18
		"1:	"MOVES".l	(%1)+,%3\n"
19 20 21 22 23
		"	move.l	%3,(%2)+\n"
		"	subq.l	#1,%0\n"
		"	jne	1b\n"
		"2:	btst	#1,%5\n"
		"	jeq	4f\n"
24
		"3:	"MOVES".w	(%1)+,%3\n"
25 26 27
		"	move.w	%3,(%2)+\n"
		"4:	btst	#0,%5\n"
		"	jeq	6f\n"
28
		"5:	"MOVES".b	(%1)+,%3\n"
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
		"	move.b  %3,(%2)+\n"
		"6:\n"
		"	.section .fixup,\"ax\"\n"
		"	.even\n"
		"10:	move.l	%0,%3\n"
		"7:	clr.l	(%2)+\n"
		"	subq.l	#1,%3\n"
		"	jne	7b\n"
		"	lsl.l	#2,%0\n"
		"	btst	#1,%5\n"
		"	jeq	8f\n"
		"30:	clr.w	(%2)+\n"
		"	addq.l	#2,%0\n"
		"8:	btst	#0,%5\n"
		"	jeq	6b\n"
		"50:	clr.b	(%2)+\n"
		"	addq.l	#1,%0\n"
		"	jra	6b\n"
		"	.previous\n"
		"\n"
		"	.section __ex_table,\"a\"\n"
		"	.align	4\n"
		"	.long	1b,10b\n"
		"	.long	3b,30b\n"
		"	.long	5b,50b\n"
		"	.previous"
		: "=d" (res), "+a" (from), "+a" (to), "=&r" (tmp)
		: "0" (n / 4), "d" (n & 3));

	return res;
}
EXPORT_SYMBOL(__generic_copy_from_user);

unsigned long __generic_copy_to_user(void __user *to, const void *from,
				     unsigned long n)
{
	unsigned long tmp, res;

	asm volatile ("\n"
		"	tst.l	%0\n"
		"	jeq	4f\n"
		"1:	move.l	(%1)+,%3\n"
71
		"2:	"MOVES".l	%3,(%2)+\n"
72 73 74 75 76
		"3:	subq.l	#1,%0\n"
		"	jne	1b\n"
		"4:	btst	#1,%5\n"
		"	jeq	6f\n"
		"	move.w	(%1)+,%3\n"
77
		"5:	"MOVES".w	%3,(%2)+\n"
78 79 80
		"6:	btst	#0,%5\n"
		"	jeq	8f\n"
		"	move.b	(%1)+,%3\n"
81
		"7:	"MOVES".b  %3,(%2)+\n"
82 83 84 85 86
		"8:\n"
		"	.section .fixup,\"ax\"\n"
		"	.even\n"
		"20:	lsl.l	#2,%0\n"
		"50:	add.l	%5,%0\n"
87
		"	jra	8b\n"
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
		"	.previous\n"
		"\n"
		"	.section __ex_table,\"a\"\n"
		"	.align	4\n"
		"	.long	2b,20b\n"
		"	.long	3b,20b\n"
		"	.long	5b,50b\n"
		"	.long	6b,50b\n"
		"	.long	7b,50b\n"
		"	.long	8b,50b\n"
		"	.previous"
		: "=d" (res), "+a" (from), "+a" (to), "=&r" (tmp)
		: "0" (n / 4), "d" (n & 3));

	return res;
}
EXPORT_SYMBOL(__generic_copy_to_user);

/*
 * Copy a null terminated string from userspace.
 */
long strncpy_from_user(char *dst, const char __user *src, long count)
{
	long res;
	char c;

	if (count <= 0)
		return count;

	asm volatile ("\n"
118
		"1:	"MOVES".b	(%2)+,%4\n"
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
		"	move.b	%4,(%1)+\n"
		"	jeq	2f\n"
		"	subq.l	#1,%3\n"
		"	jne	1b\n"
		"2:	sub.l	%3,%0\n"
		"3:\n"
		"	.section .fixup,\"ax\"\n"
		"	.even\n"
		"10:	move.l	%5,%0\n"
		"	jra	3b\n"
		"	.previous\n"
		"\n"
		"	.section __ex_table,\"a\"\n"
		"	.align	4\n"
		"	.long	1b,10b\n"
		"	.previous"
		: "=d" (res), "+a" (dst), "+a" (src), "+r" (count), "=&d" (c)
		: "i" (-EFAULT), "0" (count));

	return res;
}
EXPORT_SYMBOL(strncpy_from_user);

/*
 * Return the size of a string (including the ending 0)
 *
 * Return 0 on exception, a value greater than N if too long
 */
long strnlen_user(const char __user *src, long n)
{
	char c;
	long res;

	asm volatile ("\n"
		"1:	subq.l	#1,%1\n"
		"	jmi	3f\n"
155
		"2:	"MOVES".b	(%0)+,%2\n"
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
		"	tst.b	%2\n"
		"	jne	1b\n"
		"	jra	4f\n"
		"\n"
		"3:	addq.l	#1,%0\n"
		"4:	sub.l	%4,%0\n"
		"5:\n"
		"	.section .fixup,\"ax\"\n"
		"	.even\n"
		"20:	sub.l	%0,%0\n"
		"	jra	5b\n"
		"	.previous\n"
		"\n"
		"	.section __ex_table,\"a\"\n"
		"	.align	4\n"
		"	.long	2b,20b\n"
		"	.previous\n"
		: "=&a" (res), "+d" (n), "=&d" (c)
		: "0" (src), "r" (src));

	return res;
}
EXPORT_SYMBOL(strnlen_user);

/*
 * Zero Userspace
 */

184
unsigned long __clear_user(void __user *to, unsigned long n)
185 186 187 188 189 190
{
	unsigned long res;

	asm volatile ("\n"
		"	tst.l	%0\n"
		"	jeq	3f\n"
191
		"1:	"MOVES".l	%2,(%1)+\n"
192 193 194 195
		"2:	subq.l	#1,%0\n"
		"	jne	1b\n"
		"3:	btst	#1,%4\n"
		"	jeq	5f\n"
196
		"4:	"MOVES".w	%2,(%1)+\n"
197 198
		"5:	btst	#0,%4\n"
		"	jeq	7f\n"
199
		"6:	"MOVES".b	%2,(%1)\n"
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
		"7:\n"
		"	.section .fixup,\"ax\"\n"
		"	.even\n"
		"10:	lsl.l	#2,%0\n"
		"40:	add.l	%4,%0\n"
		"	jra	7b\n"
		"	.previous\n"
		"\n"
		"	.section __ex_table,\"a\"\n"
		"	.align	4\n"
		"	.long	1b,10b\n"
		"	.long	2b,10b\n"
		"	.long	4b,40b\n"
		"	.long	5b,40b\n"
		"	.long	6b,40b\n"
		"	.long	7b,40b\n"
		"	.previous"
		: "=d" (res), "+a" (to)
		: "r" (0), "0" (n / 4), "d" (n & 3));

    return res;
}
222
EXPORT_SYMBOL(__clear_user);