support.s revision 21979
1178825Sdfr/*-
2178825Sdfr * Copyright (c) 1993 The Regents of the University of California.
3178825Sdfr * All rights reserved.
4178825Sdfr *
5178825Sdfr * Redistribution and use in source and binary forms, with or without
6178825Sdfr * modification, are permitted provided that the following conditions
7178825Sdfr * are met:
8178825Sdfr * 1. Redistributions of source code must retain the above copyright
9178825Sdfr *    notice, this list of conditions and the following disclaimer.
10178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright
11178825Sdfr *    notice, this list of conditions and the following disclaimer in the
12178825Sdfr *    documentation and/or other materials provided with the distribution.
13178825Sdfr * 3. All advertising materials mentioning features or use of this software
14178825Sdfr *    must display the following acknowledgement:
15178825Sdfr *	This product includes software developed by the University of
16178825Sdfr *	California, Berkeley and its contributors.
17178825Sdfr * 4. Neither the name of the University nor the names of its contributors
18178825Sdfr *    may be used to endorse or promote products derived from this software
19178825Sdfr *    without specific prior written permission.
20178825Sdfr *
21178825Sdfr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24178825Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31178825Sdfr * SUCH DAMAGE.
32178825Sdfr *
33178825Sdfr *	$FreeBSD: head/sys/i386/i386/support.s 21979 1997-01-24 20:37:57Z bde $
34178825Sdfr */
35178825Sdfr
36178825Sdfr#include "opt_cpu.h"
37178825Sdfr
38178825Sdfr#include <machine/asmacros.h>
39178825Sdfr#include <machine/cputypes.h>
40178825Sdfr#include <machine/pmap.h>
41178825Sdfr#include <machine/specialreg.h>
42178825Sdfr
43178825Sdfr#include "assym.s"
44178825Sdfr
45178825Sdfr#define KDSEL		0x10			/* kernel data selector */
46178825Sdfr#define IDXSHIFT	10
47178825Sdfr
48178825Sdfr	.data
49178825Sdfr	.globl	_bcopy_vector
50178825Sdfr_bcopy_vector:
51178825Sdfr	.long	_generic_bcopy
52178825Sdfr	.globl	_bzero
53178825Sdfr_bzero:
54178825Sdfr	.long	_generic_bzero
55178825Sdfr	.globl	_copyin_vector
56178825Sdfr_copyin_vector:
57178825Sdfr	.long	_generic_copyin
58178825Sdfr	.globl	_copyout_vector
59178825Sdfr_copyout_vector:
60178825Sdfr	.long	_generic_copyout
61178825Sdfr	.globl	_ovbcopy_vector
62178825Sdfr_ovbcopy_vector:
63178825Sdfr	.long	_generic_bcopy
64178825Sdfrkernel_fpu_lock:
65178825Sdfr	.byte	0xfe
66178825Sdfr	.space	3
67178825Sdfr
68178825Sdfr	.text
69178825Sdfr
70178825Sdfr/*
71178825Sdfr * bcopy family
72178825Sdfr * void bzero(void *buf, u_int len)
73178825Sdfr */
74178825Sdfr
75178825SdfrENTRY(generic_bzero)
76178825Sdfr	pushl	%edi
77178825Sdfr	movl	8(%esp),%edi
78178825Sdfr	movl	12(%esp),%ecx
79178825Sdfr	xorl	%eax,%eax
80178825Sdfr	shrl	$2,%ecx
81178825Sdfr	cld
82178825Sdfr	rep
83178825Sdfr	stosl
84178825Sdfr	movl	12(%esp),%ecx
85178825Sdfr	andl	$3,%ecx
86178825Sdfr	rep
87178825Sdfr	stosb
88178825Sdfr	popl	%edi
89178825Sdfr	ret
90178825Sdfr
91178825Sdfr#if defined(I486_CPU)
92178825SdfrENTRY(i486_bzero)
93178825Sdfr	movl	4(%esp),%edx
94178825Sdfr	movl	8(%esp),%ecx
95178825Sdfr	xorl	%eax,%eax
96178825Sdfr/*
97178825Sdfr * do 64 byte chunks first
98178825Sdfr *
99178825Sdfr * XXX this is probably over-unrolled at least for DX2's
100178825Sdfr */
101178825Sdfr2:
102178825Sdfr	cmpl	$64,%ecx
103178825Sdfr	jb	3f
104178825Sdfr	movl	%eax,(%edx)
105178825Sdfr	movl	%eax,4(%edx)
106178825Sdfr	movl	%eax,8(%edx)
107178825Sdfr	movl	%eax,12(%edx)
108178825Sdfr	movl	%eax,16(%edx)
109178825Sdfr	movl	%eax,20(%edx)
110178825Sdfr	movl	%eax,24(%edx)
111178825Sdfr	movl	%eax,28(%edx)
112178825Sdfr	movl	%eax,32(%edx)
113178825Sdfr	movl	%eax,36(%edx)
114178825Sdfr	movl	%eax,40(%edx)
115178825Sdfr	movl	%eax,44(%edx)
116178825Sdfr	movl	%eax,48(%edx)
117178825Sdfr	movl	%eax,52(%edx)
118178825Sdfr	movl	%eax,56(%edx)
119178825Sdfr	movl	%eax,60(%edx)
120178825Sdfr	addl	$64,%edx
121178825Sdfr	subl	$64,%ecx
122178825Sdfr	jnz	2b
123178825Sdfr	ret
124178825Sdfr
125178825Sdfr/*
126178825Sdfr * do 16 byte chunks
127178825Sdfr */
128178825Sdfr	SUPERALIGN_TEXT
129178825Sdfr3:
130178825Sdfr	cmpl	$16,%ecx
131178825Sdfr	jb	4f
132178825Sdfr	movl	%eax,(%edx)
133178825Sdfr	movl	%eax,4(%edx)
134178825Sdfr	movl	%eax,8(%edx)
135178825Sdfr	movl	%eax,12(%edx)
136178825Sdfr	addl	$16,%edx
137178825Sdfr	subl	$16,%ecx
138178825Sdfr	jnz	3b
139178825Sdfr	ret
140178825Sdfr
141178825Sdfr/*
142178825Sdfr * do 4 byte chunks
143178825Sdfr */
144178825Sdfr	SUPERALIGN_TEXT
145178825Sdfr4:
146178825Sdfr	cmpl	$4,%ecx
147178825Sdfr	jb	5f
148178825Sdfr	movl	%eax,(%edx)
149178825Sdfr	addl	$4,%edx
150178825Sdfr	subl	$4,%ecx
151178825Sdfr	jnz	4b
152178825Sdfr	ret
153178825Sdfr
154178825Sdfr/*
155178825Sdfr * do 1 byte chunks
156178825Sdfr * a jump table seems to be faster than a loop or more range reductions
157178825Sdfr *
158178825Sdfr * XXX need a const section for non-text
159178825Sdfr */
160178825Sdfr	.data
161178825Sdfrjtab:
162178825Sdfr	.long	do0
163178825Sdfr	.long	do1
164178825Sdfr	.long	do2
165178825Sdfr	.long	do3
166178825Sdfr
167178825Sdfr	.text
168178825Sdfr	SUPERALIGN_TEXT
169178825Sdfr5:
170178825Sdfr	jmp	jtab(,%ecx,4)
171178825Sdfr
172178825Sdfr	SUPERALIGN_TEXT
173178825Sdfrdo3:
174178825Sdfr	movw	%ax,(%edx)
175178825Sdfr	movb	%al,2(%edx)
176178825Sdfr	ret
177178825Sdfr
178178825Sdfr	SUPERALIGN_TEXT
179178825Sdfrdo2:
180178825Sdfr	movw	%ax,(%edx)
181178825Sdfr	ret
182178825Sdfr
183178825Sdfr	SUPERALIGN_TEXT
184178825Sdfrdo1:
185178825Sdfr	movb	%al,(%edx)
186178825Sdfr	ret
187178825Sdfr
188178825Sdfr	SUPERALIGN_TEXT
189178825Sdfrdo0:
190178825Sdfr	ret
191178825Sdfr#endif
192178825Sdfr
193178825Sdfr#ifdef I586_CPU
194178825SdfrENTRY(i586_bzero)
195178825Sdfr	movl	4(%esp),%edx
196178825Sdfr	movl	8(%esp),%ecx
197178825Sdfr
198178825Sdfr	/*
199178825Sdfr	 * The FPU register method is twice as fast as the integer register
200178825Sdfr	 * method unless the target is in the L1 cache and we pre-allocate a
201178825Sdfr	 * cache line for it (then the integer register method is 4-5 times
202178825Sdfr	 * faster).  However, we never pre-allocate cache lines, since that
203178825Sdfr	 * would make the integer method 25% or more slower for the common
204178825Sdfr	 * case when the target isn't in either the L1 cache or the L2 cache.
205178825Sdfr	 * Thus we normally use the FPU register method unless the overhead
206178825Sdfr	 * would be too large.
207178825Sdfr	 */
208178825Sdfr	cmpl	$256,%ecx	/* empirical; clts, fninit, smsw cost a lot */
209178825Sdfr	jb	intreg_i586_bzero
210178825Sdfr
211178825Sdfr	/*
212178825Sdfr	 * The FPU registers may belong to an application or to fastmove()
213178825Sdfr	 * or to another invocation of bcopy() or ourself in a higher level
214178825Sdfr	 * interrupt or trap handler.  Preserving the registers is
215178825Sdfr	 * complicated since we avoid it if possible at all levels.  We
216178825Sdfr	 * want to localize the complications even when that increases them.
217178825Sdfr	 * Here the extra work involves preserving CR0_TS in TS.
218178825Sdfr	 * `npxproc != NULL' is supposed to be the condition that all the
219178825Sdfr	 * FPU resources belong to an application, but npxproc and CR0_TS
220178825Sdfr	 * aren't set atomically enough for this condition to work in
221178825Sdfr	 * interrupt handlers.
222178825Sdfr	 *
223178825Sdfr	 * Case 1: FPU registers belong to the application: we must preserve
224178825Sdfr	 * the registers if we use them, so we only use the FPU register
225178825Sdfr	 * method if the target size is large enough to amortize the extra
226178825Sdfr	 * overhead for preserving them.  CR0_TS must be preserved although
227178825Sdfr	 * it is very likely to end up as set.
228178825Sdfr	 *
229178825Sdfr	 * Case 2: FPU registers belong to fastmove(): fastmove() currently
230178825Sdfr	 * makes the registers look like they belong to an application so
231178825Sdfr	 * that cpu_switch() and savectx() don't have to know about it, so
232178825Sdfr	 * this case reduces to case 1.
233178825Sdfr	 *
234178825Sdfr	 * Case 3: FPU registers belong to the kernel: don't use the FPU
235178825Sdfr	 * register method.  This case is unlikely, and supporting it would
236178825Sdfr	 * be more complicated and might take too much stack.
237178825Sdfr	 *
238178825Sdfr	 * Case 4: FPU registers don't belong to anyone: the FPU registers
239178825Sdfr	 * don't need to be preserved, so we always use the FPU register
240178825Sdfr	 * method.  CR0_TS must be preserved although it is very likely to
241178825Sdfr	 * always end up as clear.
242178825Sdfr	 */
243178825Sdfr	cmpl	$0,_npxproc
244178825Sdfr	je	i586_bz1
245233294Sstas	cmpl	$256+184,%ecx		/* empirical; not quite 2*108 more */
246178825Sdfr	jb	intreg_i586_bzero
247178825Sdfr	sarb	$1,kernel_fpu_lock
248178825Sdfr	jc	intreg_i586_bzero
249178825Sdfr	smsw	%ax
250178825Sdfr	clts
251178825Sdfr	subl	$108,%esp
252178825Sdfr	fnsave	0(%esp)
253178825Sdfr	jmp	i586_bz2
254178825Sdfr
255178825Sdfri586_bz1:
256178825Sdfr	sarb	$1,kernel_fpu_lock
257178825Sdfr	jc	intreg_i586_bzero
258178825Sdfr	smsw	%ax
259178825Sdfr	clts
260178825Sdfr	fninit				/* XXX should avoid needing this */
261178825Sdfri586_bz2:
262178825Sdfr	fldz
263178825Sdfr
264178825Sdfr	/*
265178825Sdfr	 * Align to an 8 byte boundary (misalignment in the main loop would
266178825Sdfr	 * cost a factor of >= 2).  Avoid jumps (at little cost if it is
267178825Sdfr	 * already aligned) by always zeroing 8 bytes and using the part up
268178825Sdfr	 * to the _next_ alignment position.
269178825Sdfr	 */
270178825Sdfr	fstl	0(%edx)
271178825Sdfr	addl	%edx,%ecx		/* part of %ecx -= new_%edx - %edx */
272178825Sdfr	addl	$8,%edx
273178825Sdfr	andl	$~7,%edx
274178825Sdfr	subl	%edx,%ecx
275178825Sdfr
276178825Sdfr	/*
277178825Sdfr	 * Similarly align `len' to a multiple of 8.
278178825Sdfr	 */
279178825Sdfr	fstl	-8(%edx,%ecx)
280178825Sdfr	decl	%ecx
281178825Sdfr	andl	$~7,%ecx
282178825Sdfr
283178825Sdfr	/*
284178825Sdfr	 * This wouldn't be any faster if it were unrolled, since the loop
285178825Sdfr	 * control instructions are much faster than the fstl and/or done
286178825Sdfr	 * in parallel with it so their overhead is insignificant.
287178825Sdfr	 */
288178825Sdfrfpureg_i586_bzero_loop:
289178825Sdfr	fstl	0(%edx)
290178825Sdfr	addl	$8,%edx
291178825Sdfr	subl	$8,%ecx
292178825Sdfr	cmpl	$8,%ecx
293178825Sdfr	jae	fpureg_i586_bzero_loop
294178825Sdfr
295178825Sdfr	cmpl	$0,_npxproc
296178825Sdfr	je	i586_bz3
297178825Sdfr	frstor	0(%esp)
298178825Sdfr	addl	$108,%esp
299178825Sdfr	lmsw	%ax
300178825Sdfr	movb	$0xfe,kernel_fpu_lock
301178825Sdfr	ret
302178825Sdfr
303178825Sdfri586_bz3:
304178825Sdfr	fstpl	%st(0)
305178825Sdfr	lmsw	%ax
306178825Sdfr	movb	$0xfe,kernel_fpu_lock
307178825Sdfr	ret
308178825Sdfr
309178825Sdfrintreg_i586_bzero:
310178825Sdfr	/*
311178825Sdfr	 * `rep stos' seems to be the best method in practice for small
312178825Sdfr	 * counts.  Fancy methods usually take too long to start up due
313178825Sdfr	 * to cache and BTB misses.
314178825Sdfr	 */
315178825Sdfr	pushl	%edi
316178825Sdfr	movl	%edx,%edi
317178825Sdfr	xorl	%eax,%eax
318178825Sdfr	shrl	$2,%ecx
319178825Sdfr	cld
320178825Sdfr	rep
321178825Sdfr	stosl
322178825Sdfr	movl	12(%esp),%ecx
323178825Sdfr	andl	$3,%ecx
324178825Sdfr	jne	1f
325178825Sdfr	popl	%edi
326178825Sdfr	ret
327178825Sdfr
328178825Sdfr1:
329178825Sdfr	rep
330178825Sdfr	stosb
331178825Sdfr	popl	%edi
332178825Sdfr	ret
333178825Sdfr#endif /* I586_CPU */
334178825Sdfr
335178825Sdfr/* fillw(pat, base, cnt) */
336178825SdfrENTRY(fillw)
337178825Sdfr	pushl	%edi
338178825Sdfr	movl	8(%esp),%eax
339178825Sdfr	movl	12(%esp),%edi
340178825Sdfr	movl	16(%esp),%ecx
341178825Sdfr	cld
342178825Sdfr	rep
343178825Sdfr	stosw
344178825Sdfr	popl	%edi
345178825Sdfr	ret
346178825Sdfr
347178825SdfrENTRY(bcopyb)
348178825Sdfrbcopyb:
349178825Sdfr	pushl	%esi
350178825Sdfr	pushl	%edi
351178825Sdfr	movl	12(%esp),%esi
352178825Sdfr	movl	16(%esp),%edi
353178825Sdfr	movl	20(%esp),%ecx
354178825Sdfr	movl	%edi,%eax
355178825Sdfr	subl	%esi,%eax
356178825Sdfr	cmpl	%ecx,%eax			/* overlapping && src < dst? */
357178825Sdfr	jb	1f
358178825Sdfr	cld					/* nope, copy forwards */
359178825Sdfr	rep
360178825Sdfr	movsb
361178825Sdfr	popl	%edi
362178825Sdfr	popl	%esi
363178825Sdfr	ret
364178825Sdfr
365178825Sdfr	ALIGN_TEXT
366178825Sdfr1:
367178825Sdfr	addl	%ecx,%edi			/* copy backwards. */
368178825Sdfr	addl	%ecx,%esi
369178825Sdfr	decl	%edi
370178825Sdfr	decl	%esi
371178825Sdfr	std
372178825Sdfr	rep
373178825Sdfr	movsb
374178825Sdfr	popl	%edi
375178825Sdfr	popl	%esi
376178825Sdfr	cld
377178825Sdfr	ret
378178825Sdfr
379178825SdfrENTRY(bcopy)
380178825Sdfr	MEXITCOUNT
381178825Sdfr	jmp	*_bcopy_vector
382178825Sdfr
383178825SdfrENTRY(ovbcopy)
384178825Sdfr	MEXITCOUNT
385178825Sdfr	jmp	*_ovbcopy_vector
386178825Sdfr
387178825Sdfr/*
388178825Sdfr * generic_bcopy(src, dst, cnt)
389178825Sdfr *  ws@tools.de     (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
390178825Sdfr */
391178825SdfrENTRY(generic_bcopy)
392178825Sdfr	pushl	%esi
393178825Sdfr	pushl	%edi
394178825Sdfr	movl	12(%esp),%esi
395178825Sdfr	movl	16(%esp),%edi
396178825Sdfr	movl	20(%esp),%ecx
397178825Sdfr
398178825Sdfr	movl	%edi,%eax
399178825Sdfr	subl	%esi,%eax
400178825Sdfr	cmpl	%ecx,%eax			/* overlapping && src < dst? */
401178825Sdfr	jb	1f
402178825Sdfr
403178825Sdfr	shrl	$2,%ecx				/* copy by 32-bit words */
404178825Sdfr	cld					/* nope, copy forwards */
405178825Sdfr	rep
406178825Sdfr	movsl
407178825Sdfr	movl	20(%esp),%ecx
408178825Sdfr	andl	$3,%ecx				/* any bytes left? */
409178825Sdfr	rep
410178825Sdfr	movsb
411178825Sdfr	popl	%edi
412178825Sdfr	popl	%esi
413178825Sdfr	ret
414178825Sdfr
415178825Sdfr	ALIGN_TEXT
416178825Sdfr1:
417178825Sdfr	addl	%ecx,%edi			/* copy backwards */
418178825Sdfr	addl	%ecx,%esi
419178825Sdfr	decl	%edi
420178825Sdfr	decl	%esi
421178825Sdfr	andl	$3,%ecx				/* any fractional bytes? */
422178825Sdfr	std
423178825Sdfr	rep
424178825Sdfr	movsb
425178825Sdfr	movl	20(%esp),%ecx			/* copy remainder by 32-bit words */
426178825Sdfr	shrl	$2,%ecx
427178825Sdfr	subl	$3,%esi
428178825Sdfr	subl	$3,%edi
429178825Sdfr	rep
430178825Sdfr	movsl
431178825Sdfr	popl	%edi
432178825Sdfr	popl	%esi
433178825Sdfr	cld
434178825Sdfr	ret
435178825Sdfr
436178825Sdfr#ifdef I586_CPU
437178825SdfrENTRY(i586_bcopy)
438178825Sdfr	pushl	%esi
439178825Sdfr	pushl	%edi
440178825Sdfr	movl	12(%esp),%esi
441178825Sdfr	movl	16(%esp),%edi
442178825Sdfr	movl	20(%esp),%ecx
443178825Sdfr
444178825Sdfr	movl	%edi,%eax
445178825Sdfr	subl	%esi,%eax
446178825Sdfr	cmpl	%ecx,%eax			/* overlapping && src < dst? */
447178825Sdfr	jb	1f
448178825Sdfr
449178825Sdfr	cmpl	$1024,%ecx
450178825Sdfr	jb	small_i586_bcopy
451178825Sdfr
452178825Sdfr	sarb	$1,kernel_fpu_lock
453178825Sdfr	jc	small_i586_bcopy
454178825Sdfr	cmpl	$0,_npxproc
455178825Sdfr	je	i586_bc1
456178825Sdfr	smsw	%dx
457178825Sdfr	clts
458178825Sdfr	subl	$108,%esp
459178825Sdfr	fnsave	0(%esp)
460178825Sdfr	jmp	4f
461178825Sdfr
462178825Sdfri586_bc1:
463178825Sdfr	smsw	%dx
464178825Sdfr	clts
465178825Sdfr	fninit				/* XXX should avoid needing this */
466178825Sdfr
467178825Sdfr	ALIGN_TEXT
468178825Sdfr4:
469178825Sdfr	pushl	%ecx
470178825Sdfr#define	DCACHE_SIZE	8192
471178825Sdfr	cmpl	$(DCACHE_SIZE-512)/2,%ecx
472178825Sdfr	jbe	2f
473178825Sdfr	movl	$(DCACHE_SIZE-512)/2,%ecx
474178825Sdfr2:
475178825Sdfr	subl	%ecx,0(%esp)
476178825Sdfr	cmpl	$256,%ecx
477178825Sdfr	jb	5f			/* XXX should prefetch if %ecx >= 32 */
478178825Sdfr	pushl	%esi
479178825Sdfr	pushl	%ecx
480178825Sdfr	ALIGN_TEXT
481178825Sdfr3:
482178825Sdfr	movl	0(%esi),%eax
483178825Sdfr	movl	32(%esi),%eax
484178825Sdfr	movl	64(%esi),%eax
485178825Sdfr	movl	96(%esi),%eax
486178825Sdfr	movl	128(%esi),%eax
487178825Sdfr	movl	160(%esi),%eax
488178825Sdfr	movl	192(%esi),%eax
489178825Sdfr	movl	224(%esi),%eax
490178825Sdfr	addl	$256,%esi
491178825Sdfr	subl	$256,%ecx
492178825Sdfr	cmpl	$256,%ecx
493178825Sdfr	jae	3b
494178825Sdfr	popl	%ecx
495178825Sdfr	popl	%esi
496178825Sdfr5:
497178825Sdfr	ALIGN_TEXT
498178825Sdfrlarge_i586_bcopy_loop:
499178825Sdfr	fildq	0(%esi)
500178825Sdfr	fildq	8(%esi)
501178825Sdfr	fildq	16(%esi)
502178825Sdfr	fildq	24(%esi)
503178825Sdfr	fildq	32(%esi)
504178825Sdfr	fildq	40(%esi)
505178825Sdfr	fildq	48(%esi)
506178825Sdfr	fildq	56(%esi)
507178825Sdfr	fistpq	56(%edi)
508178825Sdfr	fistpq	48(%edi)
509178825Sdfr	fistpq	40(%edi)
510178825Sdfr	fistpq	32(%edi)
511178825Sdfr	fistpq	24(%edi)
512178825Sdfr	fistpq	16(%edi)
513178825Sdfr	fistpq	8(%edi)
514178825Sdfr	fistpq	0(%edi)
515178825Sdfr	addl	$64,%esi
516178825Sdfr	addl	$64,%edi
517178825Sdfr	subl	$64,%ecx
518178825Sdfr	cmpl	$64,%ecx
519178825Sdfr	jae	large_i586_bcopy_loop
520178825Sdfr	popl	%eax
521178825Sdfr	addl	%eax,%ecx
522178825Sdfr	cmpl	$64,%ecx
523178825Sdfr	jae	4b
524178825Sdfr
525178825Sdfr	cmpl	$0,_npxproc
526178825Sdfr	je	i586_bc2
527178825Sdfr	frstor	0(%esp)
528178825Sdfr	addl	$108,%esp
529178825Sdfri586_bc2:
530178825Sdfr	lmsw	%dx
531178825Sdfr	movb	$0xfe,kernel_fpu_lock
532178825Sdfr
533178825Sdfr/*
534178825Sdfr * This is a duplicate of the main part of generic_bcopy.  See the comments
535178825Sdfr * there.  Jumping into generic_bcopy would cost a whole 0-1 cycles and
536178825Sdfr * would mess up high resolution profiling.
537178825Sdfr */
538178825Sdfr	ALIGN_TEXT
539178825Sdfrsmall_i586_bcopy:
540178825Sdfr	shrl	$2,%ecx
541178825Sdfr	cld
542178825Sdfr	rep
543178825Sdfr	movsl
544178825Sdfr	movl	20(%esp),%ecx
545178825Sdfr	andl	$3,%ecx
546178825Sdfr	rep
547178825Sdfr	movsb
548178825Sdfr	popl	%edi
549178825Sdfr	popl	%esi
550178825Sdfr	ret
551178825Sdfr
552178825Sdfr	ALIGN_TEXT
553178825Sdfr1:
554178825Sdfr	addl	%ecx,%edi
555178825Sdfr	addl	%ecx,%esi
556178825Sdfr	decl	%edi
557178825Sdfr	decl	%esi
558178825Sdfr	andl	$3,%ecx
559178825Sdfr	std
560178825Sdfr	rep
561178825Sdfr	movsb
562178825Sdfr	movl	20(%esp),%ecx
563178825Sdfr	shrl	$2,%ecx
564178825Sdfr	subl	$3,%esi
565178825Sdfr	subl	$3,%edi
566178825Sdfr	rep
567178825Sdfr	movsl
568178825Sdfr	popl	%edi
569178825Sdfr	popl	%esi
570178825Sdfr	cld
571178825Sdfr	ret
572178825Sdfr#endif /* I586_CPU */
573178825Sdfr
574178825Sdfr/*
575178825Sdfr * Note: memcpy does not support overlapping copies
576178825Sdfr */
577178825SdfrENTRY(memcpy)
578178825Sdfr	pushl	%edi
579178825Sdfr	pushl	%esi
580178825Sdfr	movl	12(%esp),%edi
581178825Sdfr	movl	16(%esp),%esi
582178825Sdfr	movl	20(%esp),%ecx
583178825Sdfr	movl	%edi,%eax
584178825Sdfr	shrl	$2,%ecx				/* copy by 32-bit words */
585178825Sdfr	cld					/* nope, copy forwards */
586178825Sdfr	rep
587178825Sdfr	movsl
588178825Sdfr	movl	20(%esp),%ecx
589178825Sdfr	andl	$3,%ecx				/* any bytes left? */
590178825Sdfr	rep
591178825Sdfr	movsb
592178825Sdfr	popl	%esi
593178825Sdfr	popl	%edi
594178825Sdfr	ret
595178825Sdfr
596178825Sdfr
597178825Sdfr/*****************************************************************************/
598178825Sdfr/* copyout and fubyte family                                                 */
599178825Sdfr/*****************************************************************************/
600178825Sdfr/*
601178825Sdfr * Access user memory from inside the kernel. These routines and possibly
602178825Sdfr * the math- and DOS emulators should be the only places that do this.
603178825Sdfr *
604178825Sdfr * We have to access the memory with user's permissions, so use a segment
605178825Sdfr * selector with RPL 3. For writes to user space we have to additionally
606178825Sdfr * check the PTE for write permission, because the 386 does not check
607178825Sdfr * write permissions when we are executing with EPL 0. The 486 does check
608178825Sdfr * this if the WP bit is set in CR0, so we can use a simpler version here.
609178825Sdfr *
610178825Sdfr * These routines set curpcb->onfault for the time they execute. When a
611178825Sdfr * protection violation occurs inside the functions, the trap handler
612178825Sdfr * returns to *curpcb->onfault instead of the function.
613178825Sdfr */
614178825Sdfr
615178825Sdfr/* copyout(from_kernel, to_user, len) */
616178825SdfrENTRY(copyout)
617178825Sdfr	MEXITCOUNT
618178825Sdfr	jmp	*_copyout_vector
619178825Sdfr
620178825SdfrENTRY(generic_copyout)
621178825Sdfr	movl	_curpcb,%eax
622178825Sdfr	movl	$copyout_fault,PCB_ONFAULT(%eax)
623178825Sdfr	pushl	%esi
624178825Sdfr	pushl	%edi
625178825Sdfr	pushl	%ebx
626178825Sdfr	movl	16(%esp),%esi
627178825Sdfr	movl	20(%esp),%edi
628178825Sdfr	movl	24(%esp),%ebx
629178825Sdfr	testl	%ebx,%ebx			/* anything to do? */
630178825Sdfr	jz	done_copyout
631178825Sdfr
632178825Sdfr	/*
633178825Sdfr	 * Check explicitly for non-user addresses.  If 486 write protection
634178825Sdfr	 * is being used, this check is essential because we are in kernel
635178825Sdfr	 * mode so the h/w does not provide any protection against writing
636178825Sdfr	 * kernel addresses.
637178825Sdfr	 */
638178825Sdfr
639178825Sdfr	/*
640178825Sdfr	 * First, prevent address wrapping.
641178825Sdfr	 */
642178825Sdfr	movl	%edi,%eax
643178825Sdfr	addl	%ebx,%eax
644178825Sdfr	jc	copyout_fault
645178825Sdfr/*
646178825Sdfr * XXX STOP USING VM_MAXUSER_ADDRESS.
647178825Sdfr * It is an end address, not a max, so every time it is used correctly it
648178825Sdfr * looks like there is an off by one error, and of course it caused an off
649178825Sdfr * by one error in several places.
650178825Sdfr */
651178825Sdfr	cmpl	$VM_MAXUSER_ADDRESS,%eax
652178825Sdfr	ja	copyout_fault
653178825Sdfr
654178825Sdfr#if defined(I386_CPU)
655178825Sdfr
656178825Sdfr#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
657178825Sdfr	cmpl	$CPUCLASS_386,_cpu_class
658178825Sdfr	jne	3f
659178825Sdfr#endif
660178825Sdfr/*
661178825Sdfr * We have to check each PTE for user write permission.
662178825Sdfr * The checking may cause a page fault, so it is important to set
663178825Sdfr * up everything for return via copyout_fault before here.
664178825Sdfr */
665178825Sdfr	/* compute number of pages */
666178825Sdfr	movl	%edi,%ecx
667178825Sdfr	andl	$PAGE_MASK,%ecx
668233294Sstas	addl	%ebx,%ecx
669233294Sstas	decl	%ecx
670233294Sstas	shrl	$IDXSHIFT+2,%ecx
671233294Sstas	incl	%ecx
672233294Sstas
673233294Sstas	/* compute PTE offset for start address */
674233294Sstas	movl	%edi,%edx
675233294Sstas	shrl	$IDXSHIFT,%edx
676233294Sstas	andb	$0xfc,%dl
677233294Sstas
678178825Sdfr1:
679178825Sdfr	/* check PTE for each page */
680178825Sdfr	leal	_PTmap(%edx),%eax
681178825Sdfr	shrl	$IDXSHIFT,%eax
682178825Sdfr	andb	$0xfc,%al
683178825Sdfr	testb	$PG_V,_PTmap(%eax)		/* PTE page must be valid */
684178825Sdfr	je	4f
685178825Sdfr	movb	_PTmap(%edx),%al
686178825Sdfr	andb	$PG_V|PG_RW|PG_U,%al		/* page must be valid and user writable */
687178825Sdfr	cmpb	$PG_V|PG_RW|PG_U,%al
688178825Sdfr	je	2f
689178825Sdfr
690178825Sdfr4:
691178825Sdfr	/* simulate a trap */
692178825Sdfr	pushl	%edx
693178825Sdfr	pushl	%ecx
694178825Sdfr	shll	$IDXSHIFT,%edx
695178825Sdfr	pushl	%edx
696178825Sdfr	call	_trapwrite			/* trapwrite(addr) */
697178825Sdfr	popl	%edx
698178825Sdfr	popl	%ecx
699178825Sdfr	popl	%edx
700178825Sdfr
701178825Sdfr	testl	%eax,%eax			/* if not ok, return EFAULT */
702178825Sdfr	jnz	copyout_fault
703178825Sdfr
704178825Sdfr2:
705178825Sdfr	addl	$4,%edx
706178825Sdfr	decl	%ecx
707178825Sdfr	jnz	1b				/* check next page */
708178825Sdfr#endif /* I386_CPU */
709178825Sdfr
710178825Sdfr	/* bcopy(%esi, %edi, %ebx) */
711178825Sdfr3:
712178825Sdfr	movl	%ebx,%ecx
713178825Sdfr
714178825Sdfr#ifdef I586_CPU
715178825Sdfr	ALIGN_TEXT
716178825Sdfrslow_copyout:
717178825Sdfr#endif
718178825Sdfr	shrl	$2,%ecx
719178825Sdfr	cld
720178825Sdfr	rep
721178825Sdfr	movsl
722178825Sdfr	movb	%bl,%cl
723178825Sdfr	andb	$3,%cl
724178825Sdfr	rep
725178825Sdfr	movsb
726178825Sdfr
727178825Sdfrdone_copyout:
728178825Sdfr	popl	%ebx
729178825Sdfr	popl	%edi
730178825Sdfr	popl	%esi
731178825Sdfr	xorl	%eax,%eax
732178825Sdfr	movl	_curpcb,%edx
733178825Sdfr	movl	%eax,PCB_ONFAULT(%edx)
734178825Sdfr	ret
735178825Sdfr
736178825Sdfr	ALIGN_TEXT
737178825Sdfrcopyout_fault:
738178825Sdfr	popl	%ebx
739178825Sdfr	popl	%edi
740178825Sdfr	popl	%esi
741178825Sdfr	movl	_curpcb,%edx
742178825Sdfr	movl	$0,PCB_ONFAULT(%edx)
743178825Sdfr	movl	$EFAULT,%eax
744178825Sdfr	ret
745178825Sdfr
746178825Sdfr#ifdef I586_CPU
747178825SdfrENTRY(i586_copyout)
748178825Sdfr	/*
749178825Sdfr	 * Duplicated from generic_copyout.  Could be done a bit better.
750178825Sdfr	 */
751178825Sdfr	movl	_curpcb,%eax
752178825Sdfr	movl	$copyout_fault,PCB_ONFAULT(%eax)
753178825Sdfr	pushl	%esi
754178825Sdfr	pushl	%edi
755178825Sdfr	pushl	%ebx
756178825Sdfr	movl	16(%esp),%esi
757178825Sdfr	movl	20(%esp),%edi
758178825Sdfr	movl	24(%esp),%ebx
759178825Sdfr	testl	%ebx,%ebx			/* anything to do? */
760178825Sdfr	jz	done_copyout
761178825Sdfr
762178825Sdfr	/*
763178825Sdfr	 * Check explicitly for non-user addresses.  If 486 write protection
764178825Sdfr	 * is being used, this check is essential because we are in kernel
765178825Sdfr	 * mode so the h/w does not provide any protection against writing
766178825Sdfr	 * kernel addresses.
767178825Sdfr	 */
768178825Sdfr
769178825Sdfr	/*
770178825Sdfr	 * First, prevent address wrapping.
771178825Sdfr	 */
772178825Sdfr	movl	%edi,%eax
773178825Sdfr	addl	%ebx,%eax
774178825Sdfr	jc	copyout_fault
775178825Sdfr/*
776178825Sdfr * XXX STOP USING VM_MAXUSER_ADDRESS.
777178825Sdfr * It is an end address, not a max, so every time it is used correctly it
778178825Sdfr * looks like there is an off by one error, and of course it caused an off
779178825Sdfr * by one error in several places.
780178825Sdfr */
781178825Sdfr	cmpl	$VM_MAXUSER_ADDRESS,%eax
782178825Sdfr	ja	copyout_fault
783178825Sdfr
784178825Sdfr	/* bcopy(%esi, %edi, %ebx) */
785178825Sdfr3:
786178825Sdfr	movl	%ebx,%ecx
787178825Sdfr	/*
788178825Sdfr	 * End of duplicated code.
789178825Sdfr	 */
790178825Sdfr
791178825Sdfr	cmpl	$1024,%ecx
792178825Sdfr	jb	slow_copyout
793178825Sdfr
794178825Sdfr	pushl	%ecx
795178825Sdfr	call	_fastmove
796178825Sdfr	addl	$4,%esp
797178825Sdfr	jmp	done_copyout
798178825Sdfr#endif /* I586_CPU */
799178825Sdfr
800178825Sdfr/* copyin(from_user, to_kernel, len) */
801178825SdfrENTRY(copyin)
802178825Sdfr	MEXITCOUNT
803178825Sdfr	jmp	*_copyin_vector
804178825Sdfr
805178825SdfrENTRY(generic_copyin)
806178825Sdfr	movl	_curpcb,%eax
807178825Sdfr	movl	$copyin_fault,PCB_ONFAULT(%eax)
808178825Sdfr	pushl	%esi
809178825Sdfr	pushl	%edi
810178825Sdfr	movl	12(%esp),%esi			/* caddr_t from */
811178825Sdfr	movl	16(%esp),%edi			/* caddr_t to */
812178825Sdfr	movl	20(%esp),%ecx			/* size_t  len */
813178825Sdfr
814178825Sdfr	/*
815178825Sdfr	 * make sure address is valid
816178825Sdfr	 */
817178825Sdfr	movl	%esi,%edx
818178825Sdfr	addl	%ecx,%edx
819178825Sdfr	jc	copyin_fault
820178825Sdfr	cmpl	$VM_MAXUSER_ADDRESS,%edx
821178825Sdfr	ja	copyin_fault
822178825Sdfr
823178825Sdfr#ifdef I586_CPU
824178825Sdfr	ALIGN_TEXT
825178825Sdfrslow_copyin:
826178825Sdfr#endif
827178825Sdfr	movb	%cl,%al
828178825Sdfr	shrl	$2,%ecx				/* copy longword-wise */
829178825Sdfr	cld
830178825Sdfr	rep
831178825Sdfr	movsl
832178825Sdfr	movb	%al,%cl
833178825Sdfr	andb	$3,%cl				/* copy remaining bytes */
834178825Sdfr	rep
835178825Sdfr	movsb
836178825Sdfr
837178825Sdfr#if defined(I586_CPU)
838178825Sdfr	ALIGN_TEXT
839178825Sdfrdone_copyin:
840178825Sdfr#endif /* I586_CPU */
841178825Sdfr	popl	%edi
842178825Sdfr	popl	%esi
843178825Sdfr	xorl	%eax,%eax
844178825Sdfr	movl	_curpcb,%edx
845178825Sdfr	movl	%eax,PCB_ONFAULT(%edx)
846178825Sdfr	ret
847178825Sdfr
848178825Sdfr	ALIGN_TEXT
849178825Sdfrcopyin_fault:
850178825Sdfr	popl	%edi
851178825Sdfr	popl	%esi
852178825Sdfr	movl	_curpcb,%edx
853178825Sdfr	movl	$0,PCB_ONFAULT(%edx)
854178825Sdfr	movl	$EFAULT,%eax
855178825Sdfr	ret
856178825Sdfr
857178825Sdfr#ifdef I586_CPU
858178825SdfrENTRY(i586_copyin)
859178825Sdfr	/*
860178825Sdfr	 * Duplicated from generic_copyin.  Could be done a bit better.
861178825Sdfr	 */
862178825Sdfr	movl	_curpcb,%eax
863178825Sdfr	movl	$copyin_fault,PCB_ONFAULT(%eax)
864178825Sdfr	pushl	%esi
865178825Sdfr	pushl	%edi
866178825Sdfr	movl	12(%esp),%esi			/* caddr_t from */
867178825Sdfr	movl	16(%esp),%edi			/* caddr_t to */
868178825Sdfr	movl	20(%esp),%ecx			/* size_t  len */
869178825Sdfr
870178825Sdfr	/*
871178825Sdfr	 * make sure address is valid
872178825Sdfr	 */
873178825Sdfr	movl	%esi,%edx
874178825Sdfr	addl	%ecx,%edx
875178825Sdfr	jc	copyin_fault
876178825Sdfr	cmpl	$VM_MAXUSER_ADDRESS,%edx
877178825Sdfr	ja	copyin_fault
878178825Sdfr	/*
879178825Sdfr	 * End of duplicated code.
880178825Sdfr	 */
881178825Sdfr
882178825Sdfr	cmpl	$1024,%ecx
883178825Sdfr	jb	slow_copyin
884178825Sdfr
885178825Sdfr	pushl	%ebx			/* XXX prepare for fastmove_fault */
886178825Sdfr	pushl	%ecx
887178825Sdfr	call	_fastmove
888178825Sdfr	addl	$8,%esp
889178825Sdfr	jmp	done_copyin
890178825Sdfr#endif /* I586_CPU */
891178825Sdfr
892178825Sdfr#if defined(I586_CPU)
893178825Sdfr/* fastmove(src, dst, len)
894178825Sdfr	src in %esi
895178825Sdfr	dst in %edi
896178825Sdfr	len in %ecx		XXX changed to on stack for profiling
897178825Sdfr	uses %eax and %edx for tmp. storage
898178825Sdfr */
899178825Sdfr/* XXX use ENTRY() to get profiling.  fastmove() is actually a non-entry. */
900178825SdfrENTRY(fastmove)
901178825Sdfr	pushl	%ebp
902178825Sdfr	movl	%esp,%ebp
903178825Sdfr	subl	$PCB_SAVEFPU_SIZE+3*4,%esp
904178825Sdfr
905178825Sdfr	movl	8(%ebp),%ecx
906178825Sdfr	cmpl	$63,%ecx
907178825Sdfr	jbe	fastmove_tail
908178825Sdfr
909178825Sdfr	testl	$7,%esi	/* check if src addr is multiple of 8 */
910178825Sdfr	jnz	fastmove_tail
911178825Sdfr
912178825Sdfr	testl	$7,%edi	/* check if dst addr is multiple of 8 */
913178825Sdfr	jnz	fastmove_tail
914178825Sdfr
915178825Sdfr/* if (npxproc != NULL) { */
916178825Sdfr	cmpl	$0,_npxproc
917178825Sdfr	je	6f
918178825Sdfr/*    fnsave(&curpcb->pcb_savefpu); */
919178825Sdfr	movl	_curpcb,%eax
920178825Sdfr	fnsave	PCB_SAVEFPU(%eax)
921178825Sdfr/*   npxproc = NULL; */
922178825Sdfr	movl	$0,_npxproc
923178825Sdfr/* } */
924178825Sdfr6:
925178825Sdfr/* now we own the FPU. */
926178825Sdfr
927178825Sdfr/*
928178825Sdfr * The process' FP state is saved in the pcb, but if we get
929178825Sdfr * switched, the cpu_switch() will store our FP state in the
930178825Sdfr * pcb.  It should be possible to avoid all the copying for
931178825Sdfr * this, e.g., by setting a flag to tell cpu_switch() to
932178825Sdfr * save the state somewhere else.
933178825Sdfr */
934178825Sdfr/* tmp = curpcb->pcb_savefpu; */
935178825Sdfr	movl	%ecx,-12(%ebp)
936178825Sdfr	movl	%esi,-8(%ebp)
937178825Sdfr	movl	%edi,-4(%ebp)
938178825Sdfr	movl	%esp,%edi
939178825Sdfr	movl	_curpcb,%esi
940178825Sdfr	addl	$PCB_SAVEFPU,%esi
941178825Sdfr	cld
942178825Sdfr	movl	$PCB_SAVEFPU_SIZE>>2,%ecx
943178825Sdfr	rep
944178825Sdfr	movsl
945178825Sdfr	movl	-12(%ebp),%ecx
946178825Sdfr	movl	-8(%ebp),%esi
947178825Sdfr	movl	-4(%ebp),%edi
948178825Sdfr/* stop_emulating(); */
949178825Sdfr	clts
950178825Sdfr/* npxproc = curproc; */
951178825Sdfr	movl	_curproc,%eax
952178825Sdfr	movl	%eax,_npxproc
953178825Sdfr	movl	_curpcb,%eax
954178825Sdfr	movl	$fastmove_fault,PCB_ONFAULT(%eax)
955178825Sdfr4:
956178825Sdfr	movl	%ecx,-12(%ebp)
957178825Sdfr	cmpl	$1792,%ecx
958178825Sdfr	jbe	2f
959178825Sdfr	movl	$1792,%ecx
960178825Sdfr2:
961178825Sdfr	subl	%ecx,-12(%ebp)
962178825Sdfr	cmpl	$256,%ecx
963178825Sdfr	jb	5f
964178825Sdfr	movl	%ecx,-8(%ebp)
965178825Sdfr	movl	%esi,-4(%ebp)
966178825Sdfr	ALIGN_TEXT
967178825Sdfr3:
968178825Sdfr	movl	0(%esi),%eax
969178825Sdfr	movl	32(%esi),%eax
970178825Sdfr	movl	64(%esi),%eax
971178825Sdfr	movl	96(%esi),%eax
972178825Sdfr	movl	128(%esi),%eax
973178825Sdfr	movl	160(%esi),%eax
974178825Sdfr	movl	192(%esi),%eax
975178825Sdfr	movl	224(%esi),%eax
976178825Sdfr	addl	$256,%esi
977178825Sdfr	subl	$256,%ecx
978178825Sdfr	cmpl	$256,%ecx
979178825Sdfr	jae	3b
980178825Sdfr	movl	-8(%ebp),%ecx
981178825Sdfr	movl	-4(%ebp),%esi
982178825Sdfr5:
983178825Sdfr	ALIGN_TEXT
984178825Sdfrfastmove_loop:
985178825Sdfr	fildq	0(%esi)
986178825Sdfr	fildq	8(%esi)
987178825Sdfr	fildq	16(%esi)
988178825Sdfr	fildq	24(%esi)
989178825Sdfr	fildq	32(%esi)
990178825Sdfr	fildq	40(%esi)
991178825Sdfr	fildq	48(%esi)
992178825Sdfr	fildq	56(%esi)
993178825Sdfr	fistpq	56(%edi)
994178825Sdfr	fistpq	48(%edi)
995178825Sdfr	fistpq	40(%edi)
996178825Sdfr	fistpq	32(%edi)
997178825Sdfr	fistpq	24(%edi)
998178825Sdfr	fistpq	16(%edi)
999178825Sdfr	fistpq	8(%edi)
1000178825Sdfr	fistpq	0(%edi)
1001178825Sdfr	addl	$-64,%ecx
1002178825Sdfr	addl	$64,%esi
1003178825Sdfr	addl	$64,%edi
1004178825Sdfr	cmpl	$63,%ecx
1005178825Sdfr	ja	fastmove_loop
1006178825Sdfr	movl	-12(%ebp),%eax
1007178825Sdfr	addl	%eax,%ecx
1008178825Sdfr	cmpl	$64,%ecx
1009178825Sdfr	jae	4b
1010178825Sdfr
1011178825Sdfr/* curpcb->pcb_savefpu = tmp; */
1012178825Sdfr	movl	%ecx,-12(%ebp)
1013178825Sdfr	movl	%esi,-8(%ebp)
1014178825Sdfr	movl	%edi,-4(%ebp)
1015178825Sdfr	movl	_curpcb,%edi
1016178825Sdfr	addl	$PCB_SAVEFPU,%edi
1017178825Sdfr	movl	%esp,%esi
1018178825Sdfr	cld
1019178825Sdfr	movl	$PCB_SAVEFPU_SIZE>>2,%ecx
1020178825Sdfr	rep
1021178825Sdfr	movsl
1022178825Sdfr	movl	-12(%ebp),%ecx
1023178825Sdfr	movl	-8(%ebp),%esi
1024178825Sdfr	movl	-4(%ebp),%edi
1025178825Sdfr
1026178825Sdfr/* start_emulating(); */
1027178825Sdfr	smsw	%ax
1028178825Sdfr	orb	$CR0_TS,%al
1029178825Sdfr	lmsw	%ax
1030178825Sdfr/* npxproc = NULL; */
1031178825Sdfr	movl	$0,_npxproc
1032178825Sdfr
1033178825Sdfr	ALIGN_TEXT
1034178825Sdfrfastmove_tail:
1035178825Sdfr	movl	_curpcb,%eax
1036178825Sdfr	movl	$fastmove_tail_fault,PCB_ONFAULT(%eax)
1037178825Sdfr
1038178825Sdfr	movb	%cl,%al
1039178825Sdfr	shrl	$2,%ecx				/* copy longword-wise */
1040178825Sdfr	cld
1041178825Sdfr	rep
1042178825Sdfr	movsl
1043178825Sdfr	movb	%al,%cl
1044178825Sdfr	andb	$3,%cl				/* copy remaining bytes */
1045178825Sdfr	rep
1046178825Sdfr	movsb
1047178825Sdfr
1048178825Sdfr	movl	%ebp,%esp
1049178825Sdfr	popl	%ebp
1050178825Sdfr	ret
1051178825Sdfr
1052178825Sdfr	ALIGN_TEXT
1053178825Sdfrfastmove_fault:
1054178825Sdfr	movl	_curpcb,%edi
1055178825Sdfr	addl	$PCB_SAVEFPU,%edi
1056178825Sdfr	movl	%esp,%esi
1057178825Sdfr	cld
1058178825Sdfr	movl	$PCB_SAVEFPU_SIZE>>2,%ecx
1059178825Sdfr	rep
1060178825Sdfr	movsl
1061178825Sdfr
1062178825Sdfr	smsw	%ax
1063178825Sdfr	orb	$CR0_TS,%al
1064178825Sdfr	lmsw	%ax
1065178825Sdfr	movl	$0,_npxproc
1066178825Sdfr
1067178825Sdfrfastmove_tail_fault:
1068178825Sdfr	movl	%ebp,%esp
1069178825Sdfr	popl	%ebp
1070178825Sdfr	addl	$8,%esp
1071178825Sdfr	popl	%ebx
1072178825Sdfr	popl	%edi
1073178825Sdfr	popl	%esi
1074178825Sdfr	movl	_curpcb,%edx
1075178825Sdfr	movl	$0,PCB_ONFAULT(%edx)
1076178825Sdfr	movl	$EFAULT,%eax
1077178825Sdfr	ret
1078178825Sdfr#endif /* I586_CPU */
1079178825Sdfr
1080178825Sdfr/*
1081178825Sdfr * fu{byte,sword,word} : fetch a byte (sword, word) from user memory
1082178825Sdfr */
1083178825SdfrENTRY(fuword)
1084178825Sdfr	movl	_curpcb,%ecx
1085178825Sdfr	movl	$fusufault,PCB_ONFAULT(%ecx)
1086178825Sdfr	movl	4(%esp),%edx			/* from */
1087178825Sdfr
1088178825Sdfr	cmpl	$VM_MAXUSER_ADDRESS-4,%edx	/* verify address is valid */
1089178825Sdfr	ja	fusufault
1090178825Sdfr
1091178825Sdfr	movl	(%edx),%eax
1092178825Sdfr	movl	$0,PCB_ONFAULT(%ecx)
1093178825Sdfr	ret
1094178825Sdfr
1095178825Sdfr/*
1096178825Sdfr * These two routines are called from the profiling code, potentially
1097178825Sdfr * at interrupt time. If they fail, that's okay, good things will
1098178825Sdfr * happen later. Fail all the time for now - until the trap code is
1099178825Sdfr * able to deal with this.
1100178825Sdfr */
1101178825SdfrALTENTRY(suswintr)
1102178825SdfrENTRY(fuswintr)
1103178825Sdfr	movl	$-1,%eax
1104178825Sdfr	ret
1105178825Sdfr
1106178825SdfrENTRY(fusword)
1107178825Sdfr	movl	_curpcb,%ecx
1108178825Sdfr	movl	$fusufault,PCB_ONFAULT(%ecx)
1109178825Sdfr	movl	4(%esp),%edx
1110178825Sdfr
1111178825Sdfr	cmpl	$VM_MAXUSER_ADDRESS-2,%edx
1112178825Sdfr	ja	fusufault
1113178825Sdfr
1114178825Sdfr	movzwl	(%edx),%eax
1115178825Sdfr	movl	$0,PCB_ONFAULT(%ecx)
1116178825Sdfr	ret
1117178825Sdfr
1118178825SdfrENTRY(fubyte)
1119178825Sdfr	movl	_curpcb,%ecx
1120178825Sdfr	movl	$fusufault,PCB_ONFAULT(%ecx)
1121178825Sdfr	movl	4(%esp),%edx
1122178825Sdfr
1123178825Sdfr	cmpl	$VM_MAXUSER_ADDRESS-1,%edx
1124178825Sdfr	ja	fusufault
1125178825Sdfr
1126178825Sdfr	movzbl	(%edx),%eax
1127178825Sdfr	movl	$0,PCB_ONFAULT(%ecx)
1128178825Sdfr	ret
1129178825Sdfr
1130178825Sdfr	ALIGN_TEXT
1131178825Sdfrfusufault:
1132178825Sdfr	movl	_curpcb,%ecx
1133178825Sdfr	xorl	%eax,%eax
1134178825Sdfr	movl	%eax,PCB_ONFAULT(%ecx)
1135178825Sdfr	decl	%eax
1136178825Sdfr	ret
1137178825Sdfr
1138178825Sdfr/*
1139178825Sdfr * su{byte,sword,word}: write a byte (word, longword) to user memory
1140178825Sdfr */
1141178825SdfrENTRY(suword)
1142178825Sdfr	movl	_curpcb,%ecx
1143178825Sdfr	movl	$fusufault,PCB_ONFAULT(%ecx)
1144178825Sdfr	movl	4(%esp),%edx
1145178825Sdfr
1146178825Sdfr#if defined(I386_CPU)
1147178825Sdfr
1148178825Sdfr#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
1149178825Sdfr	cmpl	$CPUCLASS_386,_cpu_class
1150178825Sdfr	jne	2f				/* we only have to set the right segment selector */
1151178825Sdfr#endif /* I486_CPU || I586_CPU || I686_CPU */
1152178825Sdfr
1153178825Sdfr	/* XXX - page boundary crossing is still not handled */
1154178825Sdfr	movl	%edx,%eax
1155178825Sdfr	shrl	$IDXSHIFT,%edx
1156178825Sdfr	andb	$0xfc,%dl
1157178825Sdfr
1158178825Sdfr	leal	_PTmap(%edx),%ecx
1159178825Sdfr	shrl	$IDXSHIFT,%ecx
1160178825Sdfr	andb	$0xfc,%cl
1161178825Sdfr	testb	$PG_V,_PTmap(%ecx)		/* PTE page must be valid */
1162178825Sdfr	je	4f
1163178825Sdfr	movb	_PTmap(%edx),%dl
1164178825Sdfr	andb	$PG_V|PG_RW|PG_U,%dl		/* page must be valid and user writable */
1165178825Sdfr	cmpb	$PG_V|PG_RW|PG_U,%dl
1166178825Sdfr	je	1f
1167178825Sdfr
1168178825Sdfr4:
1169178825Sdfr	/* simulate a trap */
1170178825Sdfr	pushl	%eax
1171178825Sdfr	call	_trapwrite
1172178825Sdfr	popl	%edx				/* remove junk parameter from stack */
1173178825Sdfr	testl	%eax,%eax
1174178825Sdfr	jnz	fusufault
1175178825Sdfr1:
1176178825Sdfr	movl	4(%esp),%edx
1177178825Sdfr#endif
1178178825Sdfr
1179178825Sdfr2:
1180178825Sdfr	cmpl	$VM_MAXUSER_ADDRESS-4,%edx	/* verify address validity */
1181178825Sdfr	ja	fusufault
1182178825Sdfr
1183178825Sdfr	movl	8(%esp),%eax
1184178825Sdfr	movl	%eax,(%edx)
1185178825Sdfr	xorl	%eax,%eax
1186178825Sdfr	movl	_curpcb,%ecx
1187178825Sdfr	movl	%eax,PCB_ONFAULT(%ecx)
1188178825Sdfr	ret
1189178825Sdfr
1190178825SdfrENTRY(susword)
1191178825Sdfr	movl	_curpcb,%ecx
1192178825Sdfr	movl	$fusufault,PCB_ONFAULT(%ecx)
1193178825Sdfr	movl	4(%esp),%edx
1194178825Sdfr
1195178825Sdfr#if defined(I386_CPU)
1196178825Sdfr
1197178825Sdfr#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
1198178825Sdfr	cmpl	$CPUCLASS_386,_cpu_class
1199178825Sdfr	jne	2f
1200178825Sdfr#endif /* I486_CPU || I586_CPU || I686_CPU */
1201178825Sdfr
1202178825Sdfr	/* XXX - page boundary crossing is still not handled */
1203178825Sdfr	movl	%edx,%eax
1204178825Sdfr	shrl	$IDXSHIFT,%edx
1205178825Sdfr	andb	$0xfc,%dl
1206178825Sdfr
1207178825Sdfr	leal	_PTmap(%edx),%ecx
1208178825Sdfr	shrl	$IDXSHIFT,%ecx
1209178825Sdfr	andb	$0xfc,%cl
1210178825Sdfr	testb	$PG_V,_PTmap(%ecx)		/* PTE page must be valid */
1211178825Sdfr	je	4f
1212178825Sdfr	movb	_PTmap(%edx),%dl
1213178825Sdfr	andb	$PG_V|PG_RW|PG_U,%dl		/* page must be valid and user writable */
1214178825Sdfr	cmpb	$PG_V|PG_RW|PG_U,%dl
1215178825Sdfr	je	1f
1216178825Sdfr
1217178825Sdfr4:
1218178825Sdfr	/* simulate a trap */
1219178825Sdfr	pushl	%eax
1220178825Sdfr	call	_trapwrite
1221178825Sdfr	popl	%edx				/* remove junk parameter from stack */
1222178825Sdfr	testl	%eax,%eax
1223178825Sdfr	jnz	fusufault
1224178825Sdfr1:
1225178825Sdfr	movl	4(%esp),%edx
1226178825Sdfr#endif
1227178825Sdfr
1228178825Sdfr2:
1229178825Sdfr	cmpl	$VM_MAXUSER_ADDRESS-2,%edx	/* verify address validity */
1230178825Sdfr	ja	fusufault
1231178825Sdfr
1232178825Sdfr	movw	8(%esp),%ax
1233178825Sdfr	movw	%ax,(%edx)
1234178825Sdfr	xorl	%eax,%eax
1235178825Sdfr	movl	_curpcb,%ecx			/* restore trashed register */
1236178825Sdfr	movl	%eax,PCB_ONFAULT(%ecx)
1237178825Sdfr	ret
1238178825Sdfr
1239178825SdfrALTENTRY(suibyte)
1240178825SdfrENTRY(subyte)
1241178825Sdfr	movl	_curpcb,%ecx
1242178825Sdfr	movl	$fusufault,PCB_ONFAULT(%ecx)
1243178825Sdfr	movl	4(%esp),%edx
1244178825Sdfr
1245178825Sdfr#if defined(I386_CPU)
1246178825Sdfr
1247178825Sdfr#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
1248178825Sdfr	cmpl	$CPUCLASS_386,_cpu_class
1249178825Sdfr	jne	2f
1250178825Sdfr#endif /* I486_CPU || I586_CPU || I686_CPU */
1251178825Sdfr
1252178825Sdfr	movl	%edx,%eax
1253178825Sdfr	shrl	$IDXSHIFT,%edx
1254178825Sdfr	andb	$0xfc,%dl
1255178825Sdfr
1256178825Sdfr	leal	_PTmap(%edx),%ecx
1257178825Sdfr	shrl	$IDXSHIFT,%ecx
1258178825Sdfr	andb	$0xfc,%cl
1259178825Sdfr	testb	$PG_V,_PTmap(%ecx)		/* PTE page must be valid */
1260178825Sdfr	je	4f
1261178825Sdfr	movb	_PTmap(%edx),%dl
1262178825Sdfr	andb	$PG_V|PG_RW|PG_U,%dl		/* page must be valid and user writable */
1263178825Sdfr	cmpb	$PG_V|PG_RW|PG_U,%dl
1264178825Sdfr	je	1f
1265178825Sdfr
1266178825Sdfr4:
1267178825Sdfr	/* simulate a trap */
1268178825Sdfr	pushl	%eax
1269178825Sdfr	call	_trapwrite
1270178825Sdfr	popl	%edx				/* remove junk parameter from stack */
1271178825Sdfr	testl	%eax,%eax
1272178825Sdfr	jnz	fusufault
1273178825Sdfr1:
1274178825Sdfr	movl	4(%esp),%edx
1275178825Sdfr#endif
1276178825Sdfr
1277178825Sdfr2:
1278178825Sdfr	cmpl	$VM_MAXUSER_ADDRESS-1,%edx	/* verify address validity */
1279178825Sdfr	ja	fusufault
1280178825Sdfr
1281178825Sdfr	movb	8(%esp),%al
1282178825Sdfr	movb	%al,(%edx)
1283178825Sdfr	xorl	%eax,%eax
1284178825Sdfr	movl	_curpcb,%ecx			/* restore trashed register */
1285178825Sdfr	movl	%eax,PCB_ONFAULT(%ecx)
1286178825Sdfr	ret
1287178825Sdfr
1288178825Sdfr/*
1289178825Sdfr * copyinstr(from, to, maxlen, int *lencopied)
1290178825Sdfr *	copy a string from from to to, stop when a 0 character is reached.
1291178825Sdfr *	return ENAMETOOLONG if string is longer than maxlen, and
1292178825Sdfr *	EFAULT on protection violations. If lencopied is non-zero,
1293178825Sdfr *	return the actual length in *lencopied.
1294178825Sdfr */
1295178825SdfrENTRY(copyinstr)
1296178825Sdfr	pushl	%esi
1297178825Sdfr	pushl	%edi
1298178825Sdfr	movl	_curpcb,%ecx
1299178825Sdfr	movl	$cpystrflt,PCB_ONFAULT(%ecx)
1300178825Sdfr
1301178825Sdfr	movl	12(%esp),%esi			/* %esi = from */
1302178825Sdfr	movl	16(%esp),%edi			/* %edi = to */
1303178825Sdfr	movl	20(%esp),%edx			/* %edx = maxlen */
1304178825Sdfr
1305178825Sdfr	movl	$VM_MAXUSER_ADDRESS,%eax
1306178825Sdfr
1307178825Sdfr	/* make sure 'from' is within bounds */
1308178825Sdfr	subl	%esi,%eax
1309178825Sdfr	jbe	cpystrflt
1310178825Sdfr
1311178825Sdfr	/* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
1312178825Sdfr	cmpl	%edx,%eax
1313178825Sdfr	jae	1f
1314178825Sdfr	movl	%eax,%edx
1315178825Sdfr	movl	%eax,20(%esp)
1316178825Sdfr1:
1317178825Sdfr	incl	%edx
1318178825Sdfr	cld
1319178825Sdfr
1320178825Sdfr2:
1321178825Sdfr	decl	%edx
1322178825Sdfr	jz	3f
1323178825Sdfr
1324178825Sdfr	lodsb
1325178825Sdfr	stosb
1326178825Sdfr	orb	%al,%al
1327178825Sdfr	jnz	2b
1328178825Sdfr
1329178825Sdfr	/* Success -- 0 byte reached */
1330178825Sdfr	decl	%edx
1331178825Sdfr	xorl	%eax,%eax
1332178825Sdfr	jmp	cpystrflt_x
1333178825Sdfr3:
1334178825Sdfr	/* edx is zero - return ENAMETOOLONG or EFAULT */
1335178825Sdfr	cmpl	$VM_MAXUSER_ADDRESS,%esi
1336178825Sdfr	jae	cpystrflt
1337178825Sdfr4:
1338178825Sdfr	movl	$ENAMETOOLONG,%eax
1339178825Sdfr	jmp	cpystrflt_x
1340178825Sdfr
1341178825Sdfrcpystrflt:
1342178825Sdfr	movl	$EFAULT,%eax
1343178825Sdfr
1344178825Sdfrcpystrflt_x:
1345178825Sdfr	/* set *lencopied and return %eax */
1346178825Sdfr	movl	_curpcb,%ecx
1347178825Sdfr	movl	$0,PCB_ONFAULT(%ecx)
1348178825Sdfr	movl	20(%esp),%ecx
1349178825Sdfr	subl	%edx,%ecx
1350178825Sdfr	movl	24(%esp),%edx
1351178825Sdfr	testl	%edx,%edx
1352178825Sdfr	jz	1f
1353178825Sdfr	movl	%ecx,(%edx)
1354178825Sdfr1:
1355178825Sdfr	popl	%edi
1356178825Sdfr	popl	%esi
1357178825Sdfr	ret
1358178825Sdfr
1359178825Sdfr
1360178825Sdfr/*
1361178825Sdfr * copystr(from, to, maxlen, int *lencopied)
1362178825Sdfr */
1363178825SdfrENTRY(copystr)
1364178825Sdfr	pushl	%esi
1365178825Sdfr	pushl	%edi
1366178825Sdfr
1367178825Sdfr	movl	12(%esp),%esi			/* %esi = from */
1368178825Sdfr	movl	16(%esp),%edi			/* %edi = to */
1369178825Sdfr	movl	20(%esp),%edx			/* %edx = maxlen */
1370178825Sdfr	incl	%edx
1371178825Sdfr	cld
1372178825Sdfr1:
1373178825Sdfr	decl	%edx
1374178825Sdfr	jz	4f
1375178825Sdfr	lodsb
1376178825Sdfr	stosb
1377178825Sdfr	orb	%al,%al
1378178825Sdfr	jnz	1b
1379178825Sdfr
1380178825Sdfr	/* Success -- 0 byte reached */
1381178825Sdfr	decl	%edx
1382178825Sdfr	xorl	%eax,%eax
1383178825Sdfr	jmp	6f
1384178825Sdfr4:
1385178825Sdfr	/* edx is zero -- return ENAMETOOLONG */
1386178825Sdfr	movl	$ENAMETOOLONG,%eax
1387178825Sdfr
1388178825Sdfr6:
1389178825Sdfr	/* set *lencopied and return %eax */
1390178825Sdfr	movl	20(%esp),%ecx
1391178825Sdfr	subl	%edx,%ecx
1392178825Sdfr	movl	24(%esp),%edx
1393178825Sdfr	testl	%edx,%edx
1394178825Sdfr	jz	7f
1395178825Sdfr	movl	%ecx,(%edx)
1396178825Sdfr7:
1397178825Sdfr	popl	%edi
1398178825Sdfr	popl	%esi
1399178825Sdfr	ret
1400178825Sdfr
1401178825SdfrENTRY(bcmp)
1402178825Sdfr	pushl	%edi
1403178825Sdfr	pushl	%esi
1404178825Sdfr	movl	12(%esp),%edi
1405178825Sdfr	movl	16(%esp),%esi
1406178825Sdfr	movl	20(%esp),%edx
1407178825Sdfr	xorl	%eax,%eax
1408178825Sdfr
1409178825Sdfr	movl	%edx,%ecx
1410178825Sdfr	shrl	$2,%ecx
1411178825Sdfr	cld					/* compare forwards */
1412178825Sdfr	repe
1413178825Sdfr	cmpsl
1414178825Sdfr	jne	1f
1415178825Sdfr
1416178825Sdfr	movl	%edx,%ecx
1417178825Sdfr	andl	$3,%ecx
1418178825Sdfr	repe
1419178825Sdfr	cmpsb
1420178825Sdfr	je	2f
1421178825Sdfr1:
1422178825Sdfr	incl	%eax
1423178825Sdfr2:
1424178825Sdfr	popl	%esi
1425178825Sdfr	popl	%edi
1426178825Sdfr	ret
1427178825Sdfr
1428178825Sdfr
1429178825Sdfr/*
1430178825Sdfr * Handling of special 386 registers and descriptor tables etc
1431178825Sdfr */
1432178825Sdfr/* void lgdt(struct region_descriptor *rdp); */
1433178825SdfrENTRY(lgdt)
1434178825Sdfr	/* reload the descriptor table */
1435178825Sdfr	movl	4(%esp),%eax
1436178825Sdfr	lgdt	(%eax)
1437178825Sdfr
1438178825Sdfr	/* flush the prefetch q */
1439178825Sdfr	jmp	1f
1440178825Sdfr	nop
1441178825Sdfr1:
1442178825Sdfr	/* reload "stale" selectors */
1443178825Sdfr	movl	$KDSEL,%eax
1444178825Sdfr	movl	%ax,%ds
1445178825Sdfr	movl	%ax,%es
1446178825Sdfr	movl	%ax,%ss
1447178825Sdfr
1448178825Sdfr	/* reload code selector by turning return into intersegmental return */
1449178825Sdfr	movl	(%esp),%eax
1450178825Sdfr	pushl	%eax
1451178825Sdfr#	movl	$KCSEL,4(%esp)
1452178825Sdfr	movl	$8,4(%esp)
1453178825Sdfr	lret
1454178825Sdfr
1455178825Sdfr/*
1456178825Sdfr * void lidt(struct region_descriptor *rdp);
1457178825Sdfr */
1458178825SdfrENTRY(lidt)
1459178825Sdfr	movl	4(%esp),%eax
1460178825Sdfr	lidt	(%eax)
1461178825Sdfr	ret
1462178825Sdfr
1463178825Sdfr/*
1464178825Sdfr * void lldt(u_short sel)
1465178825Sdfr */
1466178825SdfrENTRY(lldt)
1467178825Sdfr	lldt	4(%esp)
1468178825Sdfr	ret
1469178825Sdfr
1470178825Sdfr/*
1471178825Sdfr * void ltr(u_short sel)
1472178825Sdfr */
1473178825SdfrENTRY(ltr)
1474178825Sdfr	ltr	4(%esp)
1475178825Sdfr	ret
1476178825Sdfr
1477178825Sdfr/* ssdtosd(*ssdp,*sdp) */
1478178825SdfrENTRY(ssdtosd)
1479178825Sdfr	pushl	%ebx
1480178825Sdfr	movl	8(%esp),%ecx
1481178825Sdfr	movl	8(%ecx),%ebx
1482178825Sdfr	shll	$16,%ebx
1483178825Sdfr	movl	(%ecx),%edx
1484178825Sdfr	roll	$16,%edx
1485178825Sdfr	movb	%dh,%bl
1486178825Sdfr	movb	%dl,%bh
1487178825Sdfr	rorl	$8,%ebx
1488178825Sdfr	movl	4(%ecx),%eax
1489178825Sdfr	movw	%ax,%dx
1490178825Sdfr	andl	$0xf0000,%eax
1491178825Sdfr	orl	%eax,%ebx
1492178825Sdfr	movl	12(%esp),%ecx
1493178825Sdfr	movl	%edx,(%ecx)
1494178825Sdfr	movl	%ebx,4(%ecx)
1495178825Sdfr	popl	%ebx
1496178825Sdfr	ret
1497178825Sdfr
1498178825Sdfr/* load_cr0(cr0) */
1499178825SdfrENTRY(load_cr0)
1500178825Sdfr	movl	4(%esp),%eax
1501178825Sdfr	movl	%eax,%cr0
1502178825Sdfr	ret
1503178825Sdfr
1504178825Sdfr/* rcr0() */
1505178825SdfrENTRY(rcr0)
1506178825Sdfr	movl	%cr0,%eax
1507178825Sdfr	ret
1508178825Sdfr
1509178825Sdfr/* rcr3() */
1510178825SdfrENTRY(rcr3)
1511178825Sdfr	movl	%cr3,%eax
1512178825Sdfr	ret
1513178825Sdfr
1514178825Sdfr/* void load_cr3(caddr_t cr3) */
1515178825SdfrENTRY(load_cr3)
1516178825Sdfr	movl	4(%esp),%eax
1517178825Sdfr	movl	%eax,%cr3
1518178825Sdfr	ret
1519178825Sdfr
1520178825Sdfr
1521178825Sdfr/*****************************************************************************/
1522178825Sdfr/* setjump, longjump                                                         */
1523178825Sdfr/*****************************************************************************/
1524178825Sdfr
1525178825SdfrENTRY(setjmp)
1526178825Sdfr	movl	4(%esp),%eax
1527178825Sdfr	movl	%ebx,(%eax)			/* save ebx */
1528178825Sdfr	movl	%esp,4(%eax)			/* save esp */
1529178825Sdfr	movl	%ebp,8(%eax)			/* save ebp */
1530178825Sdfr	movl	%esi,12(%eax)			/* save esi */
1531178825Sdfr	movl	%edi,16(%eax)			/* save edi */
1532178825Sdfr	movl	(%esp),%edx			/* get rta */
1533178825Sdfr	movl	%edx,20(%eax)			/* save eip */
1534178825Sdfr	xorl	%eax,%eax			/* return(0); */
1535178825Sdfr	ret
1536178825Sdfr
1537178825SdfrENTRY(longjmp)
1538178825Sdfr	movl	4(%esp),%eax
1539178825Sdfr	movl	(%eax),%ebx			/* restore ebx */
1540178825Sdfr	movl	4(%eax),%esp			/* restore esp */
1541178825Sdfr	movl	8(%eax),%ebp			/* restore ebp */
1542178825Sdfr	movl	12(%eax),%esi			/* restore esi */
1543178825Sdfr	movl	16(%eax),%edi			/* restore edi */
1544178825Sdfr	movl	20(%eax),%edx			/* get rta */
1545178825Sdfr	movl	%edx,(%esp)			/* put in return frame */
1546178825Sdfr	xorl	%eax,%eax			/* return(1); */
1547178825Sdfr	incl	%eax
1548178825Sdfr	ret
1549178825Sdfr
1550178825Sdfr/*
1551178825Sdfr * Here for doing BB-profiling (gcc -a).
1552178825Sdfr * We rely on the "bbset" instead, but need a dummy function.
1553178825Sdfr */
1554178825SdfrNON_GPROF_ENTRY(__bb_init_func)
1555178825Sdfr	movl	4(%esp),%eax
1556178825Sdfr	movl	$1,(%eax)
1557178825Sdfr	.byte	0xc3				/* avoid macro for `ret' */
1558178825Sdfr