Annotation of sys/arch/m68k/m68k/copy.s, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: copy.s,v 1.18 2006/11/29 13:22:07 miod Exp $ */
2: /* $NetBSD: copy.s,v 1.30 1998/03/04 06:39:14 thorpej Exp $ */
3:
4: /*-
5: * Copyright (c) 1998 Jason R. Thorpe. All rights reserved.
6: * Copyright (c) 1994, 1995 Charles Hannum.
7: * Copyright (c) 1990 The Regents of the University of California.
8: * All rights reserved.
9: *
10: * This code is derived from software contributed to Berkeley by
11: * the Systems Programming Group of the University of Utah Computer
12: * Science Department.
13: *
14: * Redistribution and use in source and binary forms, with or without
15: * modification, are permitted provided that the following conditions
16: * are met:
17: * 1. Redistributions of source code must retain the above copyright
18: * notice, this list of conditions and the following disclaimer.
19: * 2. Redistributions in binary form must reproduce the above copyright
20: * notice, this list of conditions and the following disclaimer in the
21: * documentation and/or other materials provided with the distribution.
22: * 3. 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:
39: /*
40: * This file contains the functions for user-space access:
41: * copyin/copyout, etc.
42: */
43:
44: #include <machine/asm.h>
45:
46: #include "assym.h"
47:
48: .file "copy.s"
49: .text
50:
51: #ifdef DEBUG
52: /*
53: * The following routines all use the "moves" instruction to access
54: * memory with "user" privilege while running in supervisor mode.
55: * The "function code" registers actually determine what type of
56: * access "moves" does, and the kernel arranges to leave them set
57: * for "user data" access when these functions are called.
58: *
59: * The diagnostics: CHECK_SFC, CHECK_DFC
60: * will verify that the sfc/dfc register values are correct.
61: */
62: Lbadfc:
63: PANIC("copy.s: bad sfc or dfc")
64: bra Lbadfc
65: #define CHECK_SFC movec sfc,d0; subql #FC_USERD,d0; bne Lbadfc
66: #define CHECK_DFC movec dfc,d0; subql #FC_USERD,d0; bne Lbadfc
67: #else /* DEBUG */
68: #define CHECK_SFC
69: #define CHECK_DFC
70: #endif /* DEBUG */
71:
72: /*
73: * copyin(caddr_t from, caddr_t to, size_t len);
74: * Copy len bytes from the user's address space.
75: *
76: * This is probably not the best we can do, but it is still 2-10 times
77: * faster than the C version in the portable gen directory.
78: *
79: * Things that might help:
80: * - unroll the longword copy loop (might not be good for a 68020)
81: * - longword align when possible (only on the 68020)
82: */
83: ENTRY(copyin)
84: CHECK_SFC
85: movl sp@(12),d0 | check count
86: beq Lciret | == 0, don't do anything
87: movl d2,sp@- | save scratch register
88: movl _C_LABEL(curpcb),a0 | set fault handler
89: movl #Lcifault,a0@(PCB_ONFAULT)
90: movl sp@(8),a0 | src address
91: movl sp@(12),a1 | dest address
92: movl a0,d1
93: btst #0,d1 | src address odd?
94: beq Lcieven | no, skip alignment
95: movsb a0@+,d2 | yes, copy a byte
96: movb d2,a1@+
97: subql #1,d0 | adjust count
98: beq Lcidone | count 0, all done
99: Lcieven:
100: movl a1,d1
101: btst #0,d1 | dest address odd?
102: bne Lcibytes | yes, must copy bytes
103: movl d0,d1 | OK, both even. Get count
104: lsrl #2,d1 | and convert to longwords
105: beq Lcibytes | count 0, skip longword loop
106: subql #1,d1 | predecrement for dbf
107: Lcilloop:
108: movsl a0@+,d2 | copy a longword
109: movl d2,a1@+
110: dbf d1,Lcilloop | decrement low word of count
111: subil #0x10000,d1 | decrement high word of count
112: bcc Lcilloop
113: andl #3,d0 | what remains
114: beq Lcidone | nothing, all done
115: Lcibytes:
116: subql #1,d0 | predecrement for dbf
117: Lcibloop:
118: movsb a0@+,d2 | copy a byte
119: movb d2,a1@+
120: dbf d0,Lcibloop | decrement low word of count
121: subil #0x10000,d0 | decrement high word of count
122: bcc Lcibloop
123: clrl d0 | no error
124: Lcidone:
125: movl _C_LABEL(curpcb),a0 | clear fault handler
126: clrl a0@(PCB_ONFAULT)
127: movl sp@+,d2 | restore scratch register
128: Lciret:
129: rts
130: Lcifault:
131: moveq #EFAULT,d0 | got a fault
132: bra Lcidone
133:
134: /*
135: * copyout(caddr_t from, caddr_t to, size_t len);
136: * Copy len bytes into the user's address space.
137: *
138: * This is probably not the best we can do, but it is still 2-10 times
139: * faster than the C version in the portable gen directory.
140: *
141: * Things that might help:
142: * - unroll the longword copy loop (might not be good for a 68020)
143: * - longword align when possible (only on the 68020)
144: */
145: ENTRY(copyout)
146: CHECK_DFC
147: movl sp@(12),d0 | check count
148: beq Lcoret | == 0, don't do anything
149: movl d2,sp@- | save scratch register
150: movl _C_LABEL(curpcb),a0 | set fault handler
151: movl #Lcofault,a0@(PCB_ONFAULT)
152: movl sp@(8),a0 | src address
153: movl sp@(12),a1 | dest address
154: movl a0,d1
155: btst #0,d1 | src address odd?
156: beq Lcoeven | no, skip alignment
157: movb a0@+,d2 | yes, copy a byte
158: movsb d2,a1@+
159: subql #1,d0 | adjust count
160: beq Lcodone | count 0, all done
161: Lcoeven:
162: movl a1,d1
163: btst #0,d1 | dest address odd?
164: bne Lcobytes | yes, must copy bytes
165: movl d0,d1 | OK, both even. Get count
166: lsrl #2,d1 | and convert to longwords
167: beq Lcobytes | count 0, skip longword loop
168: subql #1,d1 | predecrement for dbf
169: Lcolloop:
170: movl a0@+,d2 | copy a longword
171: movsl d2,a1@+
172: dbf d1,Lcolloop | decrement low word of count
173: subil #0x10000,d1 | decrement high word of count
174: bcc Lcolloop
175: andl #3,d0 | what remains
176: beq Lcodone | nothing, all done
177: Lcobytes:
178: subql #1,d0 | predecrement for dbf
179: Lcobloop:
180: movb a0@+,d2 | copy a byte
181: movsb d2,a1@+
182: dbf d0,Lcobloop | decrement low word of count
183: subil #0x10000,d0 | decrement high word of count
184: bcc Lcobloop
185: clrl d0 | no error
186: Lcodone:
187: movl _C_LABEL(curpcb),a0 | clear fault handler
188: clrl a0@(PCB_ONFAULT)
189: movl sp@+,d2 | restore scratch register
190: Lcoret:
191: rts
192: Lcofault:
193: moveq #EFAULT,d0
194: bra Lcodone
195:
196: /*
197: * copystr(caddr_t from, caddr_t to, size_t maxlen, size_t *lencopied);
198: * Copy a NUL-terminated string, at most maxlen characters long. Return the
199: * number of characters copied (including the NUL) in *lencopied. If the
200: * string is too long, return ENAMETOOLONG; else return 0.
201: */
202: ENTRY(copystr)
203: movl sp@(4),a0 | a0 = fromaddr
204: movl sp@(8),a1 | a1 = toaddr
205: clrl d0
206: movl sp@(12),d1 | count
207: beq Lcsdone | nothing to copy
208: subql #1,d1 | predecrement for dbeq
209: Lcsloop:
210: movb a0@+,a1@+ | copy a byte
211: dbeq d1,Lcsloop | decrement low word of count
212: beq Lcsdone | copied null, exit
213: subil #0x10000,d1 | decrement high word of count
214: bcc Lcsloop | more room, keep going
215: moveq #ENAMETOOLONG,d0 | ran out of space
216: Lcsdone:
217: tstl sp@(16) | length desired?
218: beq Lcsret
219: subl sp@(4),a0 | yes, calculate length copied
220: movl sp@(16),a1 | store at return location
221: movl a0,a1@
222: Lcsret:
223: rts
224:
225: /*
226: * copyinstr(caddr_t from, caddr_t to, size_t maxlen, size_t *lencopied);
227: * Copy a NUL-terminated string, at most maxlen characters long, from the
228: * user's address space. Return the number of characters copied (including
229: * the NUL) in *lencopied. If the string is too long, return ENAMETOOLONG;
230: * else return 0 or EFAULT.
231: */
232: ENTRY(copyinstr)
233: CHECK_SFC
234: movl _C_LABEL(curpcb),a0 | set fault handler
235: movl #Lcisfault,a0@(PCB_ONFAULT)
236: movl sp@(4),a0 | a0 = fromaddr
237: movl sp@(8),a1 | a1 = toaddr
238: clrl d0
239: movl sp@(12),d1 | count
240: beq Lcistoolong | nothing to copy
241: subql #1,d1 | predecrement for dbeq
242: Lcisloop:
243: movsb a0@+,d0 | copy a byte
244: movb d0,a1@+
245: dbeq d1,Lcisloop | decrement low word of count
246: beq Lcisdone | copied null, exit
247: subil #0x10000,d1 | decrement high word of count
248: bcc Lcisloop | more room, keep going
249: Lcistoolong:
250: moveq #ENAMETOOLONG,d0 | ran out of space
251: Lcisnull:
252: cmpl sp@(8),a1 | do not attempt to clear last byte
253: beq Lcisdone | if we faulted on first write
254: subql #1, a1
255: clrb a1@+ | clear last byte
256: Lcisdone:
257: tstl sp@(16) | length desired?
258: beq Lcisexit
259: subl sp@(4),a0 | yes, calculate length copied
260: movl sp@(16),a1 | store at return location
261: movl a0,a1@
262: Lcisexit:
263: movl _C_LABEL(curpcb),a0 | clear fault handler
264: clrl a0@(PCB_ONFAULT)
265: rts
266: Lcisfault:
267: moveq #EFAULT,d0
268: bra Lcisnull
269:
270: /*
271: * copyoutstr(caddr_t from, caddr_t to, size_t maxlen, size_t *lencopied);
272: * Copy a NUL-terminated string, at most maxlen characters long, into the
273: * user's address space. Return the number of characters copied (including
274: * the NUL) in *lencopied. If the string is too long, return ENAMETOOLONG;
275: * else return 0 or EFAULT.
276: */
277: ENTRY(copyoutstr)
278: CHECK_DFC
279: movl _C_LABEL(curpcb),a0 | set fault handler
280: movl #Lcosfault,a0@(PCB_ONFAULT)
281: movl sp@(4),a0 | a0 = fromaddr
282: movl sp@(8),a1 | a1 = toaddr
283: clrl d0
284: movl sp@(12),d1 | count
285: beq Lcostoolong | nothing to copy
286: subql #1,d1 | predecrement for dbeq
287: Lcosloop:
288: movb a0@+,d0 | copy a byte
289: movsb d0,a1@+
290: dbeq d1,Lcosloop | decrement low word of count
291: beq Lcosdone | copied null, exit
292: subil #0x10000,d1 | decrement high word of count
293: bcc Lcosloop | more room, keep going
294: Lcostoolong:
295: moveq #ENAMETOOLONG,d0 | ran out of space
296: Lcosdone:
297: tstl sp@(16) | length desired?
298: beq Lcosexit
299: subl sp@(4),a0 | yes, calculate length copied
300: movl sp@(16),a1 | store at return location
301: movl a0,a1@
302: Lcosexit:
303: movl _C_LABEL(curpcb),a0 | clear fault handler
304: clrl a0@(PCB_ONFAULT)
305: rts
306: Lcosfault:
307: moveq #EFAULT,d0
308: bra Lcosdone
309:
310: /*
311: * kcopy(const void *src, void *dst, size_t len);
312: *
313: * Copy len bytes from src to dst, aborting if we encounter a fatal
314: * page fault.
315: *
316: * kcopy() _must_ save and restore the old fault handler since it is
317: * called by uiomove(), which may be in the path of servicing a non-fatal
318: * page fault.
319: */
320: ENTRY(kcopy)
321: link a6,#-4
322: movl _C_LABEL(curpcb),a0 | set fault handler
323: movl a0@(PCB_ONFAULT),a6@(-4) | save old handler first
324: movl #Lkcfault,a0@(PCB_ONFAULT)
325: movl a6@(16),sp@- | push len
326: movl a6@(12),sp@- | push dst
327: movl a6@(8),sp@- | push src
328: jbsr _C_LABEL(bcopy) | copy it
329: addl #12,sp | pop args
330: clrl d0 | success!
331: Lkcdone:
332: movl _C_LABEL(curpcb),a0 | restore fault handler
333: movl a6@(-4),a0@(PCB_ONFAULT)
334: unlk a6
335: rts
336: Lkcfault:
337: addl #16,sp | pop args and return address
338: moveq #EFAULT,d0 | indicate a fault
339: bra Lkcdone
CVSweb