xref: /netbsd/sys/arch/mips/mips/copy.S (revision c4a72b64)
1/*	$NetBSD: copy.S,v 1.1 2002/11/09 02:02:33 nisimura Exp $	*/
2
3/*
4 * Copyright (c) 1992, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Digital Equipment Corporation and Ralph Campbell.
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 University of
21 *	California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 *    may be used to endorse or promote products derived from this software
24 *    without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * Copyright (C) 1989 Digital Equipment Corporation.
39 * Permission to use, copy, modify, and distribute this software and
40 * its documentation for any purpose and without fee is hereby granted,
41 * provided that the above copyright notice appears in all copies.
42 * Digital Equipment Corporation makes no representations about the
43 * suitability of this software for any purpose.  It is provided "as is"
44 * without express or implied warranty.
45 *
46 * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/loMem.s,
47 *	v 1.1 89/07/11 17:55:04 nelson Exp  SPRITE (DECWRL)
48 * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAsm.s,
49 *	v 9.2 90/01/29 18:00:39 shirriff Exp  SPRITE (DECWRL)
50 * from: Header: /sprite/src/kernel/vm/ds3100.md/vmPmaxAsm.s,
51 *	v 1.1 89/07/10 14:27:41 nelson Exp  SPRITE (DECWRL)
52 *
53 *	@(#)locore.s	8.5 (Berkeley) 1/4/94
54 */
55
56/*
57 * copy(9) - kernel space to/from user space copy functions.
58 * fetch(9) - fetch data from user-space.
59 * store(9) - store data to user-space.
60 */
61
62#include <sys/errno.h>
63#include <mips/asm.h>
64#include "assym.h"
65
66	.set	noreorder
67/*
68 * int copystr(void *kfaddr, void *kdaddr, size_t maxlen, size_t *lencopied)
69 * Copy a NIL-terminated string, at most maxlen characters long.  Return the
70 * number of characters copied (including the NIL) in *lencopied.  If the
71 * string is too long, return ENAMETOOLONG; else return 0.
72 */
73LEAF(copystr)
74	move	t0, a2
75	beq	a2, zero, 4f
761:
77	lbu	v0, 0(a0)
78	subu	a2, a2, 1
79	beq	v0, zero, 2f
80	sb	v0, 0(a1)			# each byte until NIL
81	addu	a0, a0, 1
82	bne	a2, zero, 1b			# less than maxlen
83	addu	a1, a1, 1
844:
85	li	v0, ENAMETOOLONG		# run out of space
862:
87	beq	a3, zero, 3f			# return num. of copied bytes
88	subu	a2, t0, a2			# if the 4th arg was non-NULL
89	sw	a2, 0(a3)
903:
91	j	ra				# v0 is 0 or ENAMETOOLONG
92	nop
93END(copystr)
94
95/*
96 * int copyinstr(void *uaddr, void *kaddr, size_t maxlen, size_t *lencopied)
97 * Copy a NIL-terminated string, at most maxlen characters long, from the
98 * user's address space.  Return the number of characters copied (including
99 * the NIL) in *lencopied.  If the string is too long, return ENAMETOOLONG;
100 * else return 0 or EFAULT.
101 */
102LEAF(copyinstr)
103	lw	v1, _C_LABEL(curpcb)
104	la	v0, _C_LABEL(copystrerr)
105	blt	a0, zero, _C_LABEL(copystrerr)
106	sw	v0, U_PCB_ONFAULT(v1)
107	move	t0, a2
108	beq	a2, zero, 4f
1091:
110	lbu	v0, 0(a0)
111	subu	a2, a2, 1
112	beq	v0, zero, 2f
113	sb	v0, 0(a1)
114	addu	a0, a0, 1
115	bne	a2, zero, 1b
116	addu	a1, a1, 1
1174:
118	li	v0, ENAMETOOLONG
1192:
120	beq	a3, zero, 3f
121	subu	a2, t0, a2
122	sw	a2, 0(a3)
1233:
124	j	ra				# v0 is 0 or ENAMETOOLONG
125	sw	zero, U_PCB_ONFAULT(v1)
126END(copyinstr)
127
128/*
129 * int copyoutstr(void *uaddr, void *kaddr, size_t maxlen, size_t *lencopied);
130 * Copy a NIL-terminated string, at most maxlen characters long, into the
131 * user's address space.  Return the number of characters copied (including
132 * the NIL) in *lencopied.  If the string is too long, return ENAMETOOLONG;
133 * else return 0 or EFAULT.
134 */
135LEAF(copyoutstr)
136	lw	v1, _C_LABEL(curpcb)
137	la	v0, _C_LABEL(copystrerr)
138	blt	a1, zero, _C_LABEL(copystrerr)
139	sw	v0, U_PCB_ONFAULT(v1)
140	move	t0, a2
141	beq	a2, zero, 4f
1421:
143	lbu	v0, 0(a0)
144	subu	a2, a2, 1
145	beq	v0, zero, 2f
146	sb	v0, 0(a1)
147	addu	a0, a0, 1
148	bne	a2, zero, 1b
149	addu	a1, a1, 1
1504:
151	li	v0, ENAMETOOLONG
1522:
153	beq	a3, zero, 3f
154	subu	a2, t0, a2
155	sw	a2, 0(a3)
1563:
157	j	ra				# v0 is 0 or ENAMETOOLONG
158	sw	zero, U_PCB_ONFAULT(v1)
159END(copyoutstr)
160
161LEAF(copystrerr)
162	sw	zero, U_PCB_ONFAULT(v1)
163	j	ra
164	li	v0, EFAULT			# return EFAULT
165END(copystrerr)
166
167/*
168 * kcopy(const void *src, void *dst, size_t len);
169 *
170 * Copy len bytes from src to dst, aborting if we encounter a fatal
171 * page fault.
172 *
173 * kcopy() _must_ save and restore the old fault handler since it is
174 * called by uiomove(), which may be in the path of servicing a non-fatal
175 * page fault.
176 */
177NESTED(kcopy, 48, ra)
178	subu	sp, sp, 48			# set up stack frame
179	/* Frame contains RA (31) and S0 (16). */
180	.mask	0x80010000, -4
181	sw	ra, 44(sp)			# save ra
182	sw	s0, 32(sp)			# save s0
183	move	v0, a0				# swap a0, a1 for call to memcpy
184	move	a0, a1
185	move	a1, v0
186	lw	v1, _C_LABEL(curpcb)		# set up fault handler
187	la	v0, _C_LABEL(kcopyerr)
188	lw	s0, U_PCB_ONFAULT(v1)		# save old handler
189	jal	memcpy
190	sw	v0, U_PCB_ONFAULT(v1)
191
192	lw	v1, _C_LABEL(curpcb)		# restore the old handler
193	lw	ra, 44(sp)			# restore ra
194	sw	s0, U_PCB_ONFAULT(v1)
195	lw	s0, 32(sp)			# restore s0
196	addu	sp, sp, 48			# kill stack frame
197	j	ra
198	move	v0, zero			# success!
199END(kcopy)
200
201LEAF(kcopyerr)
202	lw	v1, _C_LABEL(curpcb)		# restore the old handler
203	lw	ra, 44(sp)			# restore ra
204	sw	s0, U_PCB_ONFAULT(v1)
205	lw	s0, 32(sp)			# restore s0
206	addu	sp, sp, 48			# kill stack frame
207	j	ra
208	li	v0, EFAULT			# return EFAULT
209END(kcopyerr)
210
211/*
212 * int copyin(void *uaddr, void *kaddr, size_t len)
213 * Copies len bytes of data from the user-space address uaddr to the
214 * kernel-space address kaddr.  copyin returns 0 on success or EFAULT
215 * if a bad address is encountered.
216 */
217NESTED(copyin, CALLFRAME_SIZ, ra)
218	subu	sp, sp, CALLFRAME_SIZ
219	.mask	0x80000000, -4
220	sw	ra, CALLFRAME_RA(sp)
221	blt	a0, zero, _C_LABEL(copyerr)
222	move	v0, a0				# swap a0, a1 for call to memcpy
223	move	a0, a1
224	move	a1, v0
225	lw	v1, _C_LABEL(curpcb)
226	la	v0, _C_LABEL(copyerr)
227	jal	memcpy
228	sw	v0, U_PCB_ONFAULT(v1)
229
230	lw	v1, _C_LABEL(curpcb)
231	lw	ra, CALLFRAME_RA(sp)
232	addu	sp, sp, CALLFRAME_SIZ
233	sw	zero, U_PCB_ONFAULT(v1)
234	j	ra
235	move	v0, zero
236END(copyin)
237
238/*
239 * int copyout(void *kaddr, void *uaddr, size_t len)
240 * Copies len bytes of data from the kernel-space address kaddr to the
241 * user-space address uaddr.  copyout returns 0 on success or EFAULT
242 * if a bad address is encountered.
243 */
244NESTED(copyout, CALLFRAME_SIZ, ra)
245	subu	sp, sp, CALLFRAME_SIZ
246	.mask	0x80000000, -4
247	sw	ra, CALLFRAME_RA(sp)
248	blt	a1, zero, _C_LABEL(copyerr)
249	move	v0, a0				# swap a0, a1 for call to memcpy
250	move	a0, a1
251	move	a1, v0
252	lw	v1, _C_LABEL(curpcb)
253	la	v0, _C_LABEL(copyerr)
254	jal	memcpy
255	sw	v0, U_PCB_ONFAULT(v1)
256
257	lw	v1, _C_LABEL(curpcb)
258	lw	ra, CALLFRAME_RA(sp)
259	addu	sp, sp, CALLFRAME_SIZ
260	sw	zero, U_PCB_ONFAULT(v1)
261	j	ra
262	move	v0, zero
263END(copyout)
264
265LEAF(copyerr)
266	lw	v1, _C_LABEL(curpcb)
267	lw	ra, CALLFRAME_RA(sp)
268	addu	sp, sp, CALLFRAME_SIZ
269	sw	zero, U_PCB_ONFAULT(v1)
270	j	ra
271	li	v0, EFAULT			# return EFAULT
272END(copyerr)
273
274/*
275 * int fuswintr(void *)
276 * Fetches a short word of data from the user-space address.
277 * This function is safe to call during an interrupt context.
278 */
279LEAF(fuswintr)
280	lw	v1, _C_LABEL(curpcb)
281	la	v0, _C_LABEL(fswintrberr)
282	lw	a2, U_PCB_ONFAULT(v1)
283	blt	a0, zero, _C_LABEL(fswintrberr)
284	sw	v0, U_PCB_ONFAULT(v1)
285	lhu	v0, 0(a0)			# fetch short
286	j	ra
287	sw	a2, U_PCB_ONFAULT(v1)
288END(fuswintr)
289
290/*
291 * int suswintr(void *, short);
292 * Stores a short word of data to the user-space address.
293 * This function is safe to call during an interrupt context.
294 */
295LEAF(suswintr)
296	lw	v1, _C_LABEL(curpcb)
297	la	v0, _C_LABEL(fswintrberr)
298	lw	a2, U_PCB_ONFAULT(v1)
299	blt	a0, zero, _C_LABEL(fswintrberr)
300	sw	v0, U_PCB_ONFAULT(v1)
301	sh	a1, 0(a0)			# store short
302	sw	a2, U_PCB_ONFAULT(v1)
303	j	ra
304	move	v0, zero
305END(suswintr)
306
307/*
308 * int fuword(void *)
309 * Fetches a word of data from the user-space address.
310 */
311LEAF(fuword)
312XLEAF(fuiword)
313	lw	v1, _C_LABEL(curpcb)
314	la	v0, _C_LABEL(fswberr)
315	blt	a0, zero, _C_LABEL(fswberr)
316	sw	v0, U_PCB_ONFAULT(v1)
317	lw	v0, 0(a0)			# fetch word
318	j	ra
319	sw	zero, U_PCB_ONFAULT(v1)
320END(fuword)
321
322/*
323 * int fusword(void *)
324 * Fetches a short word of data from the user-space address.
325 */
326LEAF(fusword)
327XLEAF(fuisword)
328	lw	v1, _C_LABEL(curpcb)
329	la	v0, _C_LABEL(fswberr)
330	blt	a0, zero, _C_LABEL(fswberr)
331	sw	v0, U_PCB_ONFAULT(v1)
332	lhu	v0, 0(a0)			# fetch short
333	j	ra
334	sw	zero, U_PCB_ONFAULT(v1)
335END(fusword)
336
337/*
338 * int fubyte(void *)
339 * Fetch a byte from the user's address space.
340 */
341LEAF(fubyte)
342XLEAF(fuibyte)
343	lw	v1, _C_LABEL(curpcb)
344	la	v0, _C_LABEL(fswberr)
345	blt	a0, zero, _C_LABEL(fswberr)
346	sw	v0, U_PCB_ONFAULT(v1)
347	lbu	v0, 0(a0)			# fetch byte
348	j	ra
349	sw	zero, U_PCB_ONFAULT(v1)
350END(fubyte)
351
352/*
353 * int suword(void *, int)
354 * Stores a word of data to the user-space address.
355 */
356LEAF(suword)
357	lw	v1, _C_LABEL(curpcb)
358	la	v0, _C_LABEL(fswberr)
359	blt	a0, zero, _C_LABEL(fswberr)
360	sw	v0, U_PCB_ONFAULT(v1)
361	sw	a1, 0(a0)			# store word
362	sw	zero, U_PCB_ONFAULT(v1)
363	j	ra
364	move	v0, zero
365END(suword)
366
367/*
368 * int suiword(void *, int)
369 * Have to flush instruction cache afterwards.
370 */
371LEAF(suiword)
372	lw	v1, _C_LABEL(curpcb)
373	la	v0, _C_LABEL(fswberr)
374	blt	a0, zero, _C_LABEL(fswberr)
375	sw	v0, U_PCB_ONFAULT(v1)
376	sw	a1, 0(a0)			# store word
377	sw	zero, U_PCB_ONFAULT(v1)
378	move	v0, zero
379	lw	v1, _C_LABEL(mips_cache_ops) + MIPSX_FLUSHICACHE
380	j	v1				# NOTE: must not clobber v0!
381	li	a1, 4				# size of word
382END(suiword)
383
384/*
385 * int susword(void *, short)
386 * Stores a short word of data to the user-space address.
387 */
388LEAF(susword)
389XLEAF(suisword)
390	lw	v1, _C_LABEL(curpcb)
391	la	v0, _C_LABEL(fswberr)
392	blt	a0, zero, _C_LABEL(fswberr)
393	sw	v0, U_PCB_ONFAULT(v1)
394	sh	a1, 0(a0)			# store short
395	sw	zero, U_PCB_ONFAULT(v1)
396	j	ra
397	move	v0, zero
398END(susword)
399
400/*
401 * int subyte(void *, int)
402 * Stores a byte of data to the user-space address.
403 */
404LEAF(subyte)
405XLEAF(suibyte)
406	lw	v1, _C_LABEL(curpcb)
407	la	v0, _C_LABEL(fswberr)
408	blt	a0, zero, _C_LABEL(fswberr)
409	sw	v0, U_PCB_ONFAULT(v1)
410	sb	a1, 0(a0)			# store byte
411	sw	zero, U_PCB_ONFAULT(v1)
412	j	ra
413	move	v0, zero
414END(subyte)
415
416/*
417 * int badaddr(void addr, int len)
418 * See if access to addr with a len type instruction causes a machine check.
419 * len is length of access (1=byte, 2=short, 4=long)
420 */
421LEAF(badaddr)
422	lw	v1, _C_LABEL(curpcb)
423	la	v0, _C_LABEL(baderr)
424	bne	a1, 1, 2f
425	sw	v0, U_PCB_ONFAULT(v1)
426	b	5f
427	lbu	v0, (a0)
4282:
429	bne	a1, 2, 4f
430	nop
431	b	5f
432	lhu	v0, (a0)
4334:
434	lw	v0, (a0)
4355:
436	sw	zero, U_PCB_ONFAULT(v1)
437	j	ra
438	move	v0, zero		# made it w/o errors
439END(badaddr)
440
441/*
442 * Error routine for {f,s}uswintr.  The fault handler in trap.c
443 * checks for pcb_onfault set to this fault handler and
444 * "bails out" before calling the VM fault handler.
445 * (We can not call VM code from interrupt level.)
446 */
447LEAF(fswintrberr)
448	nop
449	sw	a2, U_PCB_ONFAULT(v1)
450	j	ra
451	li	v0, -1
452END(fswintrberr)
453
454LEAF(fswberr)
455XLEAF(baderr)
456	sw	zero, U_PCB_ONFAULT(v1)
457	j	ra
458	li	v0, -1
459END(fswberr)
460