xref: /netbsd/sys/arch/m68k/m68k/copy.s (revision bf9ec67e)
1/*	$NetBSD: copy.s,v 1.37 2001/07/28 13:08:34 tsutsui Exp $	*/
2
3/*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum and by Jason R. Thorpe.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 *        This product includes software developed by the NetBSD
21 *        Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 *    contributors may be used to endorse or promote products derived
24 *    from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39/*-
40 * Copyright (c) 1990 The Regents of the University of California.
41 * All rights reserved.
42 *
43 * This code is derived from software contributed to Berkeley by
44 * the Systems Programming Group of the University of Utah Computer
45 * Science Department.
46 *
47 * Redistribution and use in source and binary forms, with or without
48 * modification, are permitted provided that the following conditions
49 * are met:
50 * 1. Redistributions of source code must retain the above copyright
51 *    notice, this list of conditions and the following disclaimer.
52 * 2. Redistributions in binary form must reproduce the above copyright
53 *    notice, this list of conditions and the following disclaimer in the
54 *    documentation and/or other materials provided with the distribution.
55 * 3. All advertising materials mentioning features or use of this software
56 *    must display the following acknowledgement:
57 *	This product includes software developed by the University of
58 *	California, Berkeley and its contributors.
59 * 4. Neither the name of the University nor the names of its contributors
60 *    may be used to endorse or promote products derived from this software
61 *    without specific prior written permission.
62 *
63 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
64 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
65 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
66 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
67 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
68 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
69 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
70 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
71 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
72 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
73 * SUCH DAMAGE.
74 */
75
76/*
77 * This file contains the functions for user-space access:
78 * copyin/copyout, fuword/suword, etc.
79 */
80
81#include <sys/errno.h>
82#include <machine/asm.h>
83
84#include "assym.h"
85
86	.file	"copy.s"
87	.text
88
89#ifdef	DIAGNOSTIC
90/*
91 * The following routines all use the "moves" instruction to access
92 * memory with "user" privilege while running in supervisor mode.
93 * The "function code" registers actually determine what type of
94 * access "moves" does, and the kernel arranges to leave them set
95 * for "user data" access when these functions are called.
96 *
97 * The diagnostics:  CHECK_SFC,  CHECK_DFC
98 * will verify that the sfc/dfc register values are correct.
99 */
100Lbadfc:
101	PANIC("copy.s: bad sfc or dfc")
102	bra	Lbadfc
103#define	CHECK_SFC	movec %sfc,%d0; subql #FC_USERD,%d0; bne Lbadfc
104#define	CHECK_DFC	movec %dfc,%d0; subql #FC_USERD,%d0; bne Lbadfc
105#else	/* DIAGNOSTIC */
106#define	CHECK_SFC
107#define	CHECK_DFC
108#endif	/* DIAGNOSTIC */
109
110/*
111 * copyin(caddr_t from, caddr_t to, size_t len);
112 * Copy len bytes from the user's address space.
113 *
114 * This is probably not the best we can do, but it is still 2-10 times
115 * faster than the C version in the portable gen directory.
116 *
117 * Things that might help:
118 *	- unroll the longword copy loop (might not be good for a 68020)
119 *	- longword align when possible (only on the 68020)
120 */
121ENTRY(copyin)
122	CHECK_SFC
123	movl	%sp@(12),%d0		| check count
124	beq	Lciret			| == 0, don't do anything
125#ifdef MAPPEDCOPY
126	cmpl	_C_LABEL(mappedcopysize),%d0 | size >= mappedcopysize
127	bcc	_C_LABEL(mappedcopyin)	| yes, go do it the new way
128#endif
129	movl	%d2,%sp@-		| save scratch register
130	movl	_C_LABEL(curpcb),%a0	| set fault handler
131	movl	#Lcifault,%a0@(PCB_ONFAULT)
132	movl	%sp@(8),%a0		| src address
133	movl	%sp@(12),%a1		| dest address
134	movl	%a0,%d1
135	btst	#0,%d1			| src address odd?
136	beq	Lcieven			| no, skip alignment
137	movsb	%a0@+,%d2		| yes, copy a byte
138	movb	%d2,%a1@+
139	subql	#1,%d0			| adjust count
140	beq	Lcidone			| count 0, all done
141Lcieven:
142	movl	%a1,%d1
143	btst	#0,%d1			| dest address odd?
144	bne	Lcibytes		| yes, must copy bytes
145	movl	%d0,%d1			| OK, both even.  Get count
146	lsrl	#2,%d1			|   and convert to longwords
147	beq	Lcibytes		| count 0, skip longword loop
148	subql	#1,%d1			| predecrement for dbf
149Lcilloop:
150	movsl	%a0@+,%d2		| copy a longword
151	movl	%d2,%a1@+
152	dbf	%d1,Lcilloop		| decrement low word of count
153	subil	#0x10000,%d1		| decrement high word of count
154	bcc	Lcilloop
155	andl	#3,%d0			| what remains
156	beq	Lcidone			| nothing, all done
157Lcibytes:
158	subql	#1,%d0			| predecrement for dbf
159Lcibloop:
160	movsb	%a0@+,%d2		| copy a byte
161	movb	%d2,%a1@+
162	dbf	%d0,Lcibloop		| decrement low word of count
163	subil	#0x10000,%d0		| decrement high word of count
164	bcc	Lcibloop
165	clrl	%d0			| no error
166Lcidone:
167	movl	_C_LABEL(curpcb),%a0	| clear fault handler
168	clrl	%a0@(PCB_ONFAULT)
169	movl	%sp@+,%d2		| restore scratch register
170Lciret:
171	rts
172Lcifault:
173	moveq	#EFAULT,%d0		| got a fault
174	bra	Lcidone
175
176/*
177 * copyout(caddr_t from, caddr_t to, size_t len);
178 * Copy len bytes into the user's address space.
179 *
180 * This is probably not the best we can do, but it is still 2-10 times
181 * faster than the C version in the portable gen directory.
182 *
183 * Things that might help:
184 *	- unroll the longword copy loop (might not be good for a 68020)
185 *	- longword align when possible (only on the 68020)
186 */
187ENTRY(copyout)
188	CHECK_DFC
189	movl	%sp@(12),%d0		| check count
190	beq	Lcoret			| == 0, don't do anything
191#ifdef MAPPEDCOPY
192	cmpl	_C_LABEL(mappedcopysize),%d0 | size >= mappedcopysize
193	bcc	_C_LABEL(mappedcopyout)	| yes, go do it the new way
194#endif
195	movl	%d2,%sp@-		| save scratch register
196	movl	_C_LABEL(curpcb),%a0	| set fault handler
197	movl	#Lcofault,%a0@(PCB_ONFAULT)
198	movl	%sp@(8),%a0		| src address
199	movl	%sp@(12),%a1		| dest address
200	movl	%a0,%d1
201	btst	#0,%d1			| src address odd?
202	beq	Lcoeven			| no, skip alignment
203	movb	%a0@+,%d2		| yes, copy a byte
204	movsb	%d2,%a1@+
205	subql	#1,%d0			| adjust count
206	beq	Lcodone			| count 0, all done
207Lcoeven:
208	movl	%a1,%d1
209	btst	#0,%d1			| dest address odd?
210	bne	Lcobytes		| yes, must copy bytes
211	movl	%d0,%d1			| OK, both even.  Get count
212	lsrl	#2,%d1			|   and convert to longwords
213	beq	Lcobytes		| count 0, skip longword loop
214	subql	#1,%d1			| predecrement for dbf
215Lcolloop:
216	movl	%a0@+,%d2			| copy a longword
217	movsl	%d2,%a1@+
218	dbf	%d1,Lcolloop		| decrement low word of count
219	subil	#0x10000,%d1		| decrement high word of count
220	bcc	Lcolloop
221	andl	#3,%d0			| what remains
222	beq	Lcodone			| nothing, all done
223Lcobytes:
224	subql	#1,%d0			| predecrement for dbf
225Lcobloop:
226	movb	%a0@+,%d2		| copy a byte
227	movsb	%d2,%a1@+
228	dbf	%d0,Lcobloop		| decrement low word of count
229	subil	#0x10000,%d0		| decrement high word of count
230	bcc	Lcobloop
231	clrl	%d0			| no error
232Lcodone:
233	movl	_C_LABEL(curpcb),%a0	| clear fault handler
234	clrl	%a0@(PCB_ONFAULT)
235	movl	%sp@+,%d2		| restore scratch register
236Lcoret:
237	rts
238Lcofault:
239	moveq	#EFAULT,%d0
240	bra	Lcodone
241
242/*
243 * copystr(caddr_t from, caddr_t to, size_t maxlen, size_t *lencopied);
244 * Copy a NUL-terminated string, at most maxlen characters long.  Return the
245 * number of characters copied (including the NUL) in *lencopied.  If the
246 * string is too long, return ENAMETOOLONG; else return 0.
247 */
248ENTRY(copystr)
249	movl	%sp@(4),%a0		| a0 = fromaddr
250	movl	%sp@(8),%a1		| a1 = toaddr
251	clrl	%d0
252	movl	%sp@(12),%d1		| count
253	beq	Lcstoolong		| nothing to copy
254	subql	#1,%d1			| predecrement for dbeq
255Lcsloop:
256	movb	%a0@+,%a1@+		| copy a byte
257	dbeq	%d1,Lcsloop		| decrement low word of count
258	beq	Lcsdone			| copied null, exit
259	subil	#0x10000,%d1		| decrement high word of count
260	bcc	Lcsloop			| more room, keep going
261Lcstoolong:
262	moveq	#ENAMETOOLONG,%d0	| ran out of space
263Lcsdone:
264	tstl	%sp@(16)		| length desired?
265	beq	Lcsret
266	subl	%sp@(4),%a0		| yes, calculate length copied
267	movl	%sp@(16),%a1		| store at return location
268	movl	%a0,%a1@
269Lcsret:
270	rts
271
272/*
273 * copyinstr(caddr_t from, caddr_t to, size_t maxlen, size_t *lencopied);
274 * Copy a NUL-terminated string, at most maxlen characters long, from the
275 * user's address space.  Return the number of characters copied (including
276 * the NUL) in *lencopied.  If the string is too long, return ENAMETOOLONG;
277 * else return 0 or EFAULT.
278 */
279ENTRY(copyinstr)
280	CHECK_SFC
281	movl	_C_LABEL(curpcb),%a0	| set fault handler
282	movl	#Lcisfault,%a0@(PCB_ONFAULT)
283	movl	%sp@(4),%a0		| a0 = fromaddr
284	movl	%sp@(8),%a1		| a1 = toaddr
285	clrl	%d0
286	movl	%sp@(12),%d1		| count
287	beq	Lcistoolong		| nothing to copy
288	subql	#1,%d1			| predecrement for dbeq
289Lcisloop:
290	movsb	%a0@+,%d0		| copy a byte
291	movb	%d0,%a1@+
292	dbeq	%d1,Lcisloop		| decrement low word of count
293	beq	Lcisdone		| copied null, exit
294	subil	#0x10000,%d1		| decrement high word of count
295	bcc	Lcisloop		| more room, keep going
296Lcistoolong:
297	moveq	#ENAMETOOLONG,%d0	| ran out of space
298Lcisdone:
299	tstl	%sp@(16)		| length desired?
300	beq	Lcisexit
301	subl	%sp@(4),%a0		| yes, calculate length copied
302	movl	%sp@(16),%a1		| store at return location
303	movl	%a0,%a1@
304Lcisexit:
305	movl	_C_LABEL(curpcb),%a0	| clear fault handler
306	clrl	%a0@(PCB_ONFAULT)
307	rts
308Lcisfault:
309	moveq	#EFAULT,%d0
310	bra	Lcisdone
311
312/*
313 * copyoutstr(caddr_t from, caddr_t to, size_t maxlen, size_t *lencopied);
314 * Copy a NUL-terminated string, at most maxlen characters long, into the
315 * user's address space.  Return the number of characters copied (including
316 * the NUL) in *lencopied.  If the string is too long, return ENAMETOOLONG;
317 * else return 0 or EFAULT.
318 */
319ENTRY(copyoutstr)
320	CHECK_DFC
321	movl	_C_LABEL(curpcb),%a0	| set fault handler
322	movl	#Lcosfault,%a0@(PCB_ONFAULT)
323	movl	%sp@(4),%a0		| a0 = fromaddr
324	movl	%sp@(8),%a1		| a1 = toaddr
325	clrl	%d0
326	movl	%sp@(12),%d1		| count
327	beq	Lcostoolong		| nothing to copy
328	subql	#1,%d1			| predecrement for dbeq
329Lcosloop:
330	movb	%a0@+,%d0		| copy a byte
331	movsb	%d0,%a1@+
332	dbeq	%d1,Lcosloop		| decrement low word of count
333	beq	Lcosdone		| copied null, exit
334	subil	#0x10000,%d1		| decrement high word of count
335	bcc	Lcosloop		| more room, keep going
336Lcostoolong:
337	moveq	#ENAMETOOLONG,%d0	| ran out of space
338Lcosdone:
339	tstl	%sp@(16)		| length desired?
340	beq	Lcosexit
341	subl	%sp@(4),%a0		| yes, calculate length copied
342	movl	%sp@(16),%a1		| store at return location
343	movl	%a0,%a1@
344Lcosexit:
345	movl	_C_LABEL(curpcb),%a0	| clear fault handler
346	clrl	%a0@(PCB_ONFAULT)
347	rts
348Lcosfault:
349	moveq	#EFAULT,%d0
350	bra	Lcosdone
351
352/*
353 * kcopy(const void *src, void *dst, size_t len);
354 *
355 * Copy len bytes from src to dst, aborting if we encounter a fatal
356 * page fault.
357 *
358 * kcopy() _must_ save and restore the old fault handler since it is
359 * called by uiomove(), which may be in the path of servicing a non-fatal
360 * page fault.
361 */
362ENTRY(kcopy)
363	link	%a6,#-4
364	movl	_C_LABEL(curpcb),%a0	 | set fault handler
365	movl	%a0@(PCB_ONFAULT),%a6@(-4) | save old handler first
366	movl	#Lkcfault,%a0@(PCB_ONFAULT)
367	movl	%a6@(16),%sp@-		| push len
368	movl	%a6@(8),%sp@-		| push src
369	movl	%a6@(12),%sp@-		| push dst
370	jbsr	_C_LABEL(memcpy)	| copy it
371	addl	#12,%sp			| pop args
372	clrl	%d0			| success!
373Lkcdone:
374	movl	_C_LABEL(curpcb),%a0	| restore fault handler
375	movl	%a6@(-4),%a0@(PCB_ONFAULT)
376	unlk	%a6
377	rts
378Lkcfault:
379	addl	#16,%sp			| pop args and return address
380	moveq	#EFAULT,%d0		| indicate a fault
381	bra	Lkcdone
382
383/*
384 * fuword(caddr_t uaddr);
385 * Fetch an int from the user's address space.
386 */
387ENTRY(fuword)
388	CHECK_SFC
389	movl	%sp@(4),%a0		| address to read
390	movl	_C_LABEL(curpcb),%a1	| set fault handler
391	movl	#Lferr,%a1@(PCB_ONFAULT)
392	movsl	%a0@,%d0		| do read from user space
393	bra	Lfdone
394
395/*
396 * fusword(caddr_t uaddr);
397 * Fetch a short from the user's address space.
398 */
399ENTRY(fusword)
400	CHECK_SFC
401	movl	%sp@(4),%a0		| address to read
402	movl	_C_LABEL(curpcb),%a1	| set fault handler
403	movl	#Lferr,%a1@(PCB_ONFAULT)
404	moveq	#0,%d0
405	movsw	%a0@,%d0		| do read from user space
406	bra	Lfdone
407
408/*
409 * fuswintr(caddr_t uaddr);
410 * Fetch a short from the user's address space.
411 * Can be called during an interrupt.
412 */
413ENTRY(fuswintr)
414	CHECK_SFC
415	movl	%sp@(4),%a0		| address to read
416	movl	_C_LABEL(curpcb),%a1	| set fault handler
417	movl	#_C_LABEL(fubail),%a1@(PCB_ONFAULT)
418	moveq	#0,%d0
419	movsw	%a0@,%d0		| do read from user space
420	bra	Lfdone
421
422/*
423 * fubyte(caddr_t uaddr);
424 * Fetch a byte from the user's address space.
425 */
426ENTRY(fubyte)
427	CHECK_SFC
428	movl	%sp@(4),%a0		| address to read
429	movl	_C_LABEL(curpcb),%a1	| set fault handler
430	movl	#Lferr,%a1@(PCB_ONFAULT)
431	moveq	#0,%d0
432	movsb	%a0@,%d0		| do read from user space
433	bra	Lfdone
434
435/*
436 * Error routine for fuswintr.  The fault handler in trap.c
437 * checks for pcb_onfault set to this fault handler and
438 * "bails out" before calling the VM fault handler.
439 * (We can not call VM code from interrupt level.)
440 * Same code as Lferr but must have a different address.
441 */
442ENTRY(fubail)
443	nop
444Lferr:
445	moveq	#-1,%d0			| error indicator
446Lfdone:
447	clrl	%a1@(PCB_ONFAULT) 	| clear fault handler
448	rts
449
450/*
451 * suword(caddr_t uaddr, int x);
452 * Store an int in the user's address space.
453 */
454ENTRY(suword)
455	CHECK_DFC
456	movl	%sp@(4),%a0		| address to write
457	movl	%sp@(8),%d0		| value to put there
458	movl	_C_LABEL(curpcb),%a1	| set fault handler
459	movl	#Lserr,%a1@(PCB_ONFAULT)
460	movsl	%d0,%a0@		| do write to user space
461	moveq	#0,%d0			| indicate no fault
462	bra	Lsdone
463
464/*
465 * susword(caddr_t uaddr, short x);
466 * Store a short in the user's address space.
467 */
468ENTRY(susword)
469	CHECK_DFC
470	movl	%sp@(4),%a0		| address to write
471	movw	%sp@(10),%d0		| value to put there
472	movl	_C_LABEL(curpcb),%a1	| set fault handler
473	movl	#Lserr,%a1@(PCB_ONFAULT)
474	movsw	%d0,%a0@		| do write to user space
475	moveq	#0,%d0			| indicate no fault
476	bra	Lsdone
477
478/*
479 * suswintr(caddr_t uaddr, short x);
480 * Store a short in the user's address space.
481 * Can be called during an interrupt.
482 */
483ENTRY(suswintr)
484	CHECK_DFC
485	movl	%sp@(4),%a0		| address to write
486	movw	%sp@(10),%d0		| value to put there
487	movl	_C_LABEL(curpcb),%a1	| set fault handler
488	movl	#_C_LABEL(subail),%a1@(PCB_ONFAULT)
489	movsw	%d0,%a0@		| do write to user space
490	moveq	#0,%d0			| indicate no fault
491	bra	Lsdone
492
493/*
494 * subyte(caddr_t uaddr, char x);
495 * Store a byte in the user's address space.
496 */
497ENTRY(subyte)
498	CHECK_DFC
499	movl	%sp@(4),%a0		| address to write
500	movb	%sp@(11),%d0		| value to put there
501	movl	_C_LABEL(curpcb),%a1	| set fault handler
502	movl	#Lserr,%a1@(PCB_ONFAULT)
503	movsb	%d0,%a0@		| do write to user space
504	moveq	#0,%d0			| indicate no fault
505	bra	Lsdone
506
507/*
508 * Error routine for suswintr.  The fault handler in trap.c
509 * checks for pcb_onfault set to this fault handler and
510 * "bails out" before calling the VM fault handler.
511 * (We can not call VM code from interrupt level.)
512 * Same code as Lserr but must have a different address.
513 */
514ENTRY(subail)
515	nop
516Lserr:
517	moveq	#-1,%d0			| error indicator
518Lsdone:
519	clrl	%a1@(PCB_ONFAULT) 	| clear fault handler
520	rts
521