1/*
2 * Linux/PA-RISC Project (http://www.parisc-linux.org/)
3 *
4 * Assembly Language User Access Routines
5 *  Copyright (C) 2000 Hewlett-Packard (John Marvin)
6 *
7 *    This program is free software; you can redistribute it and/or modify
8 *    it under the terms of the GNU General Public License as published by
9 *    the Free Software Foundation; either version 2, or (at your option)
10 *    any later version.
11 *
12 *    This program is distributed in the hope that it will be useful,
13 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 *    GNU General Public License for more details.
16 *
17 *    You should have received a copy of the GNU General Public License
18 *    along with this program; if not, write to the Free Software
19 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22/*
23 * These routines still have plenty of room for optimization
24 * (word & doubleword load/store, dual issue, store hints, etc.).
25 */
26
27/*
28 * The following routines assume that space register 3 (sr3) contains
29 * the space id associated with the current users address space.
30 */
31
32
33	.text
34
35#include <asm/assembly.h>
36#include <asm/errno.h>
37
38	/*
39	 * get_sr gets the appropriate space value into
40	 * sr1 for kernel/user space access, depending
41	 * on the flag stored in the task structure.
42	 */
43
44	.macro  get_sr
45	mfctl       %cr30,%r1
46	ldw         TASK_SEGMENT(%r1),%r22
47	mfsp        %sr3,%r1
48	or,<>       %r22,%r0,%r0
49	copy        %r0,%r1
50	mtsp        %r1,%sr1
51	.endm
52
53	/*
54	 * unsigned long
55	 * lcopy_to_user(void *to, const void *from, unsigned long n)
56	 *
57	 * Returns 0 for success.
58	 * otherwise, returns number of bytes not transferred.
59	 */
60
61	.export lcopy_to_user,code
62lcopy_to_user:
63	.proc
64	.callinfo NO_CALLS
65	.entry
66	comib,=,n   0,%r24,$lctu_done
67	get_sr
68$lctu_loop:
69	ldbs,ma     1(%r25),%r1
70	addib,<>    -1,%r24,$lctu_loop
711:      stbs,ma     %r1,1(%sr1,%r26)
72$lctu_done:
73	bv          %r0(%r2)
74	copy        %r24,%r28
75	.exit
76
772:      b $lctu_done
78	ldo         1(%r24),%r24
79
80	.section __ex_table,"a"
81#ifdef __LP64__
82	.dword      1b,(2b-1b)
83#else
84	.word       1b,(2b-1b)
85#endif
86	.previous
87
88	.procend
89
90	/*
91	 * unsigned long
92	 * lcopy_from_user(void *to, const void *from, unsigned long n)
93	 *
94	 * Returns 0 for success.
95	 * otherwise, returns number of bytes not transferred.
96	 *
97	 * NOTE: This routine will also zero any bytes in the
98	 *       destination that were not copied due to a fault.
99	 *
100	 */
101
102	.export lcopy_from_user,code
103lcopy_from_user:
104	.proc
105	.callinfo NO_CALLS
106	.entry
107	comib,=,n   0,%r24,$lcfu_done
108	get_sr
109$lcfu_loop:
1101:      ldbs,ma     1(%sr1,%r25),%r1
111	addib,<>    -1,%r24,$lcfu_loop
112	stbs,ma     %r1,1(%r26)
113$lcfu_done:
114	bv          %r0(%r2)
115	copy        %r24,%r28
116	.exit
117
1182:      copy        %r24,%r23
119$lcfu_zero_loop:
120	addib,<>    -1,%r23,$lcfu_zero_loop
121	stbs,ma     %r0,1(%r26)
122	b           $lcfu_done
123	nop
124
125	.section __ex_table,"a"
126#ifdef __LP64__
127	.dword      1b,(2b-1b)
128#else
129	.word       1b,(2b-1b)
130#endif
131	.previous
132
133	.procend
134
135	/*
136	 * long lstrncpy_from_user(char *dst, const char *src, long n)
137	 *
138	 * Returns -EFAULT if exception before terminator,
139	 *         N if the entire buffer filled,
140	 *         otherwise strlen (i.e. excludes zero byte)
141	 */
142
143	.export lstrncpy_from_user,code
144lstrncpy_from_user:
145	.proc
146	.callinfo NO_CALLS
147	.entry
148	comib,=     0,%r24,$lsfu_done
149	copy        %r24,%r23
150	get_sr
1511:      ldbs,ma     1(%sr1,%r25),%r1
152$lsfu_loop:
153	stbs,ma     %r1,1(%r26)
154	comib,=,n   0,%r1,$lsfu_done
155	addib,<>,n  -1,%r24,$lsfu_loop
1562:      ldbs,ma     1(%sr1,%r25),%r1
157$lsfu_done:
158	sub         %r23,%r24,%r28
159$lsfu_exit:
160	bv          %r0(%r2)
161	nop
162	.exit
163
1643:      b           $lsfu_exit
165	ldi         -EFAULT,%r28
166
167	.section __ex_table,"a"
168#ifdef __LP64__
169	.dword      1b,(3b-1b)
170	.dword      2b,(3b-2b)
171#else
172	.word       1b,(3b-1b)
173	.word       2b,(3b-2b)
174#endif
175	.previous
176
177	.procend
178
179	/*
180	 * unsigned long lclear_user(void *to, unsigned long n)
181	 *
182	 * Returns 0 for success.
183	 * otherwise, returns number of bytes not transferred.
184	 */
185
186	.export lclear_user,code
187lclear_user:
188	.proc
189	.callinfo NO_CALLS
190	.entry
191	comib,=,n   0,%r25,$lclu_done
192	get_sr
193$lclu_loop:
194	addib,<>    -1,%r25,$lclu_loop
1951:      stbs,ma     %r0,1(%sr1,%r26)
196
197$lclu_done:
198	bv          %r0(%r2)
199	copy        %r25,%r28
200	.exit
201
2022:      b $lclu_done
203	ldo        1(%r25),%r25
204
205	.section __ex_table,"a"
206#ifdef __LP64__
207	.dword      1b,(2b-1b)
208#else
209	.word       1b,(2b-1b)
210#endif
211	.previous
212
213	.procend
214
215	/*
216	 * long lstrnlen_user(char *s, long n)
217	 *
218	 * Returns 0 if exception before zero byte or reaching N,
219	 *         N+1 if N would be exceeded,
220	 *         else strlen + 1 (i.e. includes zero byte).
221	 */
222
223	.export lstrnlen_user,code
224lstrnlen_user:
225	.proc
226	.callinfo NO_CALLS
227	.entry
228	comib,=     0,%r25,$lslen_nzero
229	copy	    %r26,%r24
230	get_sr
2311:      ldbs,ma     1(%sr1,%r26),%r1
232$lslen_loop:
233	comib,=,n   0,%r1,$lslen_done
234	addib,<>    -1,%r25,$lslen_loop
2352:      ldbs,ma     1(%sr1,%r26),%r1
236$lslen_done:
237	bv          %r0(%r2)
238	sub	    %r26,%r24,%r28
239	.exit
240
241$lslen_nzero:
242	b           $lslen_done
243	ldo         1(%r26),%r26 /* special case for N == 0 */
244
2453:      b           $lslen_done
246	copy        %r24,%r26    /* reset r26 so 0 is returned on fault */
247
248	.section __ex_table,"a"
249#ifdef __LP64__
250	.dword      1b,(3b-1b)
251	.dword      2b,(3b-2b)
252#else
253	.word       1b,(3b-1b)
254	.word       2b,(3b-2b)
255#endif
256	.previous
257
258	.procend
259
260	.end
261