support.s revision 8214
1/*-
2 * Copyright (c) 1993 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 *	$Id: support.s,v 1.21 1995/03/11 03:49:50 phk Exp $
34 */
35
36#include "assym.s"				/* system definitions */
37#include "errno.h"				/* error return codes */
38#include "machine/asmacros.h"			/* miscellaneous asm macros */
39#include "machine/cputypes.h"			/* types of CPUs */
40
41#define KDSEL		0x10			/* kernel data selector */
42#define IDXSHIFT	10
43
44/*
45 * Support routines for GCC, general C-callable functions
46 */
47ENTRY(__udivsi3)
48	movl 4(%esp),%eax
49	xorl %edx,%edx
50	divl 8(%esp)
51	ret
52
53ENTRY(__divsi3)
54	movl 4(%esp),%eax
55	cltd
56	idivl 8(%esp)
57	ret
58
59/*
60 * Support for reading real time clock registers
61 */
62ENTRY(rtcin)					/* rtcin(val) */
63	movl	4(%esp),%eax
64	outb	%al,$0x70
65	NOP
66	xorl	%eax,%eax
67	inb	$0x71,%al
68	NOP
69	ret
70
71/*
72 * bcopy family
73 */
74
75/*
76 * void bzero(void *base, u_int cnt)
77 * Special code for I486 because stosl uses lots
78 * of clocks.  Makes little or no difference on DX2 type
79 * machines, but stosl is about 1/2 as fast as
80 * memory moves on a standard DX !!!!!
81 */
82ALTENTRY(blkclr)
83ENTRY(bzero)
84#if defined(I486_CPU)
85	cmpl	$CPUCLASS_486,_cpu_class
86	jz	1f
87#endif
88
89	pushl	%edi
90	movl	8(%esp),%edi
91	movl	12(%esp),%ecx
92	xorl	%eax,%eax
93	shrl	$2,%ecx
94	cld
95	rep
96	stosl
97	movl	12(%esp),%ecx
98	andl	$3,%ecx
99	rep
100	stosb
101	popl	%edi
102	ret
103
104#if defined(I486_CPU)
105	SUPERALIGN_TEXT
1061:
107	movl	4(%esp),%edx
108	movl	8(%esp),%ecx
109	xorl	%eax,%eax
110/
111/ do 64 byte chunks first
112/
113/ XXX this is probably over-unrolled at least for DX2's
114/
1152:
116	cmpl	$64,%ecx
117	jb	3f
118	movl	%eax,(%edx)
119	movl	%eax,4(%edx)
120	movl	%eax,8(%edx)
121	movl	%eax,12(%edx)
122	movl	%eax,16(%edx)
123	movl	%eax,20(%edx)
124	movl	%eax,24(%edx)
125	movl	%eax,28(%edx)
126	movl	%eax,32(%edx)
127	movl	%eax,36(%edx)
128	movl	%eax,40(%edx)
129	movl	%eax,44(%edx)
130	movl	%eax,48(%edx)
131	movl	%eax,52(%edx)
132	movl	%eax,56(%edx)
133	movl	%eax,60(%edx)
134	addl	$64,%edx
135	subl	$64,%ecx
136	jnz	2b
137	ret
138
139/
140/ do 16 byte chunks
141/
142	SUPERALIGN_TEXT
1433:
144	cmpl	$16,%ecx
145	jb	4f
146	movl	%eax,(%edx)
147	movl	%eax,4(%edx)
148	movl	%eax,8(%edx)
149	movl	%eax,12(%edx)
150	addl	$16,%edx
151	subl	$16,%ecx
152	jnz	3b
153	ret
154
155/
156/ do 4 byte chunks
157/
158	SUPERALIGN_TEXT
1594:
160	cmpl	$4,%ecx
161	jb	5f
162	movl	%eax,(%edx)
163	addl	$4,%edx
164	subl	$4,%ecx
165	jnz	4b
166	ret
167
168/
169/ do 1 byte chunks
170/ a jump table seems to be faster than a loop or more range reductions
171/
172/ XXX need a const section for non-text
173/
174	SUPERALIGN_TEXT
175jtab:
176	.long	do0
177	.long	do1
178	.long	do2
179	.long	do3
180
181	SUPERALIGN_TEXT
1825:
183	jmp	jtab(,%ecx,4)
184
185	SUPERALIGN_TEXT
186do3:
187	movw	%ax,(%edx)
188	movb	%al,2(%edx)
189	ret
190
191	SUPERALIGN_TEXT
192do2:
193	movw	%ax,(%edx)
194	ret
195
196	SUPERALIGN_TEXT
197do1:
198	movb	%al,(%edx)
199
200	SUPERALIGN_TEXT
201do0:
202	ret
203#endif /* I486_CPU */
204
205/* fillw(pat, base, cnt) */
206ENTRY(fillw)
207	pushl	%edi
208	movl	8(%esp),%eax
209	movl	12(%esp),%edi
210	movl	16(%esp),%ecx
211	cld
212	rep
213	stosw
214	popl	%edi
215	ret
216
217/* filli(pat, base, cnt) */
218ENTRY(filli)
219	pushl	%edi
220	movl	8(%esp),%eax
221	movl	12(%esp),%edi
222	movl	16(%esp),%ecx
223	cld
224	rep
225	stosl
226	popl	%edi
227	ret
228
229ENTRY(bcopyb)
230bcopyb:
231	pushl	%esi
232	pushl	%edi
233	movl	12(%esp),%esi
234	movl	16(%esp),%edi
235	movl	20(%esp),%ecx
236	cmpl	%esi,%edi			/* potentially overlapping? */
237	jnb	1f
238	cld					/* nope, copy forwards */
239	rep
240	movsb
241	popl	%edi
242	popl	%esi
243	ret
244
245	ALIGN_TEXT
2461:
247	addl	%ecx,%edi			/* copy backwards. */
248	addl	%ecx,%esi
249	std
250	decl	%edi
251	decl	%esi
252	rep
253	movsb
254	popl	%edi
255	popl	%esi
256	cld
257	ret
258
259ENTRY(bcopyw)
260bcopyw:
261	pushl	%esi
262	pushl	%edi
263	movl	12(%esp),%esi
264	movl	16(%esp),%edi
265	movl	20(%esp),%ecx
266	cmpl	%esi,%edi			/* potentially overlapping? */
267	jnb	1f
268	shrl	$1,%ecx				/* copy by 16-bit words */
269	cld					/* nope, copy forwards */
270	rep
271	movsw
272	adc	%ecx,%ecx			/* any bytes left? */
273	rep
274	movsb
275	popl	%edi
276	popl	%esi
277	ret
278
279	ALIGN_TEXT
2801:
281	addl	%ecx,%edi			/* copy backwards */
282	addl	%ecx,%esi
283	andl	$1,%ecx				/* any fractional bytes? */
284	decl	%edi
285	decl	%esi
286	std
287	rep
288	movsb
289	movl	20(%esp),%ecx			/* copy remainder by 16-bit words */
290	shrl	$1,%ecx
291	decl	%esi
292	decl	%edi
293	rep
294	movsw
295	popl	%edi
296	popl	%esi
297	cld
298	ret
299
300ENTRY(bcopyx)
301	movl	16(%esp),%eax
302	cmpl	$2,%eax
303	je	bcopyw				/* not _bcopyw, to avoid multiple mcounts */
304	cmpl	$4,%eax
305	je	bcopy				/* XXX the shared ret's break mexitcount */
306	jmp	bcopyb
307
308/*
309 * (ov)bcopy(src, dst, cnt)
310 *  ws@tools.de     (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
311 */
312ALTENTRY(ovbcopy)
313ENTRY(bcopy)
314bcopy:
315	pushl	%esi
316	pushl	%edi
317	movl	12(%esp),%esi
318	movl	16(%esp),%edi
319	movl	20(%esp),%ecx
320	cmpl	%esi,%edi			/* potentially overlapping? */
321	jnb	1f
322	shrl	$2,%ecx				/* copy by 32-bit words */
323	cld					/* nope, copy forwards */
324	rep
325	movsl
326	movl	20(%esp),%ecx
327	andl	$3,%ecx				/* any bytes left? */
328	rep
329	movsb
330	popl	%edi
331	popl	%esi
332	ret
333
334	ALIGN_TEXT
3351:
336	addl	%ecx,%edi			/* copy backwards */
337	addl	%ecx,%esi
338	andl	$3,%ecx				/* any fractional bytes? */
339	decl	%edi
340	decl	%esi
341	std
342	rep
343	movsb
344	movl	20(%esp),%ecx			/* copy remainder by 32-bit words */
345	shrl	$2,%ecx
346	subl	$3,%esi
347	subl	$3,%edi
348	rep
349	movsl
350	popl	%edi
351	popl	%esi
352	cld
353	ret
354
355
356/*
357 * Note: memcpy does not support overlapping copies
358 */
359ENTRY(memcpy)
360	pushl	%edi
361	pushl	%esi
362	movl	12(%esp),%edi
363	movl	16(%esp),%esi
364	movl	20(%esp),%ecx
365	movl	%edi,%eax
366	shrl	$2,%ecx				/* copy by 32-bit words */
367	cld					/* nope, copy forwards */
368	rep
369	movsl
370	movl	20(%esp),%ecx
371	andl	$3,%ecx				/* any bytes left? */
372	rep
373	movsb
374	popl	%esi
375	popl	%edi
376	ret
377
378
379/*****************************************************************************/
380/* copyout and fubyte family                                                 */
381/*****************************************************************************/
382/*
383 * Access user memory from inside the kernel. These routines and possibly
384 * the math- and DOS emulators should be the only places that do this.
385 *
386 * We have to access the memory with user's permissions, so use a segment
387 * selector with RPL 3. For writes to user space we have to additionally
388 * check the PTE for write permission, because the 386 does not check
389 * write permissions when we are executing with EPL 0. The 486 does check
390 * this if the WP bit is set in CR0, so we can use a simpler version here.
391 *
392 * These routines set curpcb->onfault for the time they execute. When a
393 * protection violation occurs inside the functions, the trap handler
394 * returns to *curpcb->onfault instead of the function.
395 */
396
397
398ENTRY(copyout)					/* copyout(from_kernel, to_user, len) */
399	movl	_curpcb,%eax
400	movl	$copyout_fault,PCB_ONFAULT(%eax)
401	pushl	%esi
402	pushl	%edi
403	pushl	%ebx
404	movl	16(%esp),%esi
405	movl	20(%esp),%edi
406	movl	24(%esp),%ebx
407	testl	%ebx,%ebx			/* anything to do? */
408	jz	done_copyout
409
410	/*
411	 * Check explicitly for non-user addresses.  If 486 write protection
412	 * is being used, this check is essential because we are in kernel
413	 * mode so the h/w does not provide any protection against writing
414	 * kernel addresses.
415	 */
416
417	/*
418	 * First, prevent address wrapping.
419	 */
420	movl	%edi,%eax
421	addl	%ebx,%eax
422	jc	copyout_fault
423/*
424 * XXX STOP USING VM_MAXUSER_ADDRESS.
425 * It is an end address, not a max, so every time it is used correctly it
426 * looks like there is an off by one error, and of course it caused an off
427 * by one error in several places.
428 */
429	cmpl	$VM_MAXUSER_ADDRESS,%eax
430	ja	copyout_fault
431
432#if defined(I386_CPU)
433
434#if defined(I486_CPU) || defined(I586_CPU)
435	cmpl	$CPUCLASS_386,_cpu_class
436	jne	3f
437#endif
438/*
439 * We have to check each PTE for user write permission.
440 * The checking may cause a page fault, so it is important to set
441 * up everything for return via copyout_fault before here.
442 */
443	/* compute number of pages */
444	movl	%edi,%ecx
445	andl	$NBPG-1,%ecx
446	addl	%ebx,%ecx
447	decl	%ecx
448	shrl	$IDXSHIFT+2,%ecx
449	incl	%ecx
450
451	/* compute PTE offset for start address */
452	movl	%edi,%edx
453	shrl	$IDXSHIFT,%edx
454	andb	$0xfc,%dl
455
4561:	/* check PTE for each page */
457	movb	_PTmap(%edx),%al
458	andb	$0x07,%al			/* Pages must be VALID + USERACC + WRITABLE */
459	cmpb	$0x07,%al
460	je	2f
461
462	/* simulate a trap */
463	pushl	%edx
464	pushl	%ecx
465	shll	$IDXSHIFT,%edx
466	pushl	%edx
467	call	_trapwrite			/* trapwrite(addr) */
468	popl	%edx
469	popl	%ecx
470	popl	%edx
471
472	testl	%eax,%eax			/* if not ok, return EFAULT */
473	jnz	copyout_fault
474
4752:
476	addl	$4,%edx
477	decl	%ecx
478	jnz	1b				/* check next page */
479#endif /* I386_CPU */
480
481	/* bcopy(%esi, %edi, %ebx) */
4823:
483	movl	%ebx,%ecx
484	shrl	$2,%ecx
485	cld
486	rep
487	movsl
488	movb	%bl,%cl
489	andb	$3,%cl
490	rep
491	movsb
492
493done_copyout:
494	popl	%ebx
495	popl	%edi
496	popl	%esi
497	xorl	%eax,%eax
498	movl	_curpcb,%edx
499	movl	%eax,PCB_ONFAULT(%edx)
500	ret
501
502	ALIGN_TEXT
503copyout_fault:
504	popl	%ebx
505	popl	%edi
506	popl	%esi
507	movl	_curpcb,%edx
508	movl	$0,PCB_ONFAULT(%edx)
509	movl	$EFAULT,%eax
510	ret
511
512/* copyin(from_user, to_kernel, len) */
513ENTRY(copyin)
514	movl	_curpcb,%eax
515	movl	$copyin_fault,PCB_ONFAULT(%eax)
516	pushl	%esi
517	pushl	%edi
518	movl	12(%esp),%esi			/* caddr_t from */
519	movl	16(%esp),%edi			/* caddr_t to */
520	movl	20(%esp),%ecx			/* size_t  len */
521
522	/*
523	 * make sure address is valid
524	 */
525	movl	%esi,%edx
526	addl	%ecx,%edx
527	jc	copyin_fault
528	cmpl	$VM_MAXUSER_ADDRESS,%edx
529	ja	copyin_fault
530
531	movb	%cl,%al
532	shrl	$2,%ecx				/* copy longword-wise */
533	cld
534	rep
535	movsl
536	movb	%al,%cl
537	andb	$3,%cl				/* copy remaining bytes */
538	rep
539	movsb
540
541	popl	%edi
542	popl	%esi
543	xorl	%eax,%eax
544	movl	_curpcb,%edx
545	movl	%eax,PCB_ONFAULT(%edx)
546	ret
547
548	ALIGN_TEXT
549copyin_fault:
550	popl	%edi
551	popl	%esi
552	movl	_curpcb,%edx
553	movl	$0,PCB_ONFAULT(%edx)
554	movl	$EFAULT,%eax
555	ret
556
557/*
558 * fu{byte,sword,word} : fetch a byte (sword, word) from user memory
559 */
560ALTENTRY(fuiword)
561ENTRY(fuword)
562	movl	_curpcb,%ecx
563	movl	$fusufault,PCB_ONFAULT(%ecx)
564	movl	4(%esp),%edx			/* from */
565
566	cmpl	$VM_MAXUSER_ADDRESS-4,%edx	/* verify address is valid */
567	ja	fusufault
568
569	movl	(%edx),%eax
570	movl	$0,PCB_ONFAULT(%ecx)
571	ret
572
573/*
574 * These two routines are called from the profiling code, potentially
575 * at interrupt time. If they fail, that's okay, good things will
576 * happen later. Fail all the time for now - until the trap code is
577 * able to deal with this.
578 */
579ALTENTRY(suswintr)
580ENTRY(fuswintr)
581	movl	$-1,%eax
582	ret
583
584ENTRY(fusword)
585	movl	_curpcb,%ecx
586	movl	$fusufault,PCB_ONFAULT(%ecx)
587	movl	4(%esp),%edx
588
589	cmpl	$VM_MAXUSER_ADDRESS-2,%edx
590	ja	fusufault
591
592	movzwl	(%edx),%eax
593	movl	$0,PCB_ONFAULT(%ecx)
594	ret
595
596ALTENTRY(fuibyte)
597ENTRY(fubyte)
598	movl	_curpcb,%ecx
599	movl	$fusufault,PCB_ONFAULT(%ecx)
600	movl	4(%esp),%edx
601
602	cmpl	$VM_MAXUSER_ADDRESS-1,%edx
603	ja	fusufault
604
605	movzbl	(%edx),%eax
606	movl	$0,PCB_ONFAULT(%ecx)
607	ret
608
609	ALIGN_TEXT
610fusufault:
611	movl	_curpcb,%ecx
612	xorl	%eax,%eax
613	movl	%eax,PCB_ONFAULT(%ecx)
614	decl	%eax
615	ret
616
617/*
618 * su{byte,sword,word}: write a byte (word, longword) to user memory
619 */
620ALTENTRY(suiword)
621ENTRY(suword)
622	movl	_curpcb,%ecx
623	movl	$fusufault,PCB_ONFAULT(%ecx)
624	movl	4(%esp),%edx
625
626#if defined(I386_CPU)
627
628#if defined(I486_CPU) || defined(I586_CPU)
629	cmpl	$CPUCLASS_386,_cpu_class
630	jne	2f				/* we only have to set the right segment selector */
631#endif /* I486_CPU || I586_CPU */
632
633	/* XXX - page boundary crossing is still not handled */
634	movl	%edx,%eax
635	shrl	$IDXSHIFT,%edx
636	andb	$0xfc,%dl
637	movb	_PTmap(%edx),%dl
638	andb	$0x7,%dl			/* must be VALID + USERACC + WRITE */
639	cmpb	$0x7,%dl
640	je	1f
641
642	/* simulate a trap */
643	pushl	%eax
644	call	_trapwrite
645	popl	%edx				/* remove junk parameter from stack */
646	movl	_curpcb,%ecx			/* restore trashed register */
647	testl	%eax,%eax
648	jnz	fusufault
6491:
650	movl	4(%esp),%edx
651#endif
652
6532:
654	cmpl	$VM_MAXUSER_ADDRESS-4,%edx	/* verify address validity */
655	ja	fusufault
656
657	movl	8(%esp),%eax
658	movl	%eax,(%edx)
659	xorl	%eax,%eax
660	movl	%eax,PCB_ONFAULT(%ecx)
661	ret
662
663ENTRY(susword)
664	movl	_curpcb,%ecx
665	movl	$fusufault,PCB_ONFAULT(%ecx)
666	movl	4(%esp),%edx
667
668#if defined(I386_CPU)
669
670#if defined(I486_CPU) || defined(I586_CPU)
671	cmpl	$CPUCLASS_386,_cpu_class
672	jne	2f
673#endif /* I486_CPU || I586_CPU */
674
675	/* XXX - page boundary crossing is still not handled */
676	movl	%edx,%eax
677	shrl	$IDXSHIFT,%edx
678	andb	$0xfc,%dl
679	movb	_PTmap(%edx),%dl
680	andb	$0x7,%dl			/* must be VALID + USERACC + WRITE */
681	cmpb	$0x7,%dl
682	je	1f
683
684	/* simulate a trap */
685	pushl	%eax
686	call	_trapwrite
687	popl	%edx				/* remove junk parameter from stack */
688	movl	_curpcb,%ecx			/* restore trashed register */
689	testl	%eax,%eax
690	jnz	fusufault
6911:
692	movl	4(%esp),%edx
693#endif
694
6952:
696	cmpl	$VM_MAXUSER_ADDRESS-2,%edx	/* verify address validity */
697	ja	fusufault
698
699	movw	8(%esp),%ax
700	movw	%ax,(%edx)
701	xorl	%eax,%eax
702	movl	%eax,PCB_ONFAULT(%ecx)
703	ret
704
705ALTENTRY(suibyte)
706ENTRY(subyte)
707	movl	_curpcb,%ecx
708	movl	$fusufault,PCB_ONFAULT(%ecx)
709	movl	4(%esp),%edx
710
711#if defined(I386_CPU)
712
713#if defined(I486_CPU) || defined(I586_CPU)
714	cmpl	$CPUCLASS_386,_cpu_class
715	jne	2f
716#endif /* I486_CPU || I586_CPU */
717
718	movl	%edx,%eax
719	shrl	$IDXSHIFT,%edx
720	andb	$0xfc,%dl
721	movb	_PTmap(%edx),%dl
722	andb	$0x7,%dl			/* must be VALID + USERACC + WRITE */
723	cmpb	$0x7,%dl
724	je	1f
725
726	/* simulate a trap */
727	pushl	%eax
728	call	_trapwrite
729	popl	%edx				/* remove junk parameter from stack */
730	movl	_curpcb,%ecx			/* restore trashed register */
731	testl	%eax,%eax
732	jnz	fusufault
7331:
734	movl	4(%esp),%edx
735#endif
736
7372:
738	cmpl	$VM_MAXUSER_ADDRESS-1,%edx	/* verify address validity */
739	ja	fusufault
740
741	movb	8(%esp),%al
742	movb	%al,(%edx)
743	xorl	%eax,%eax
744	movl	%eax,PCB_ONFAULT(%ecx)
745	ret
746
747/*
748 * copyoutstr(from, to, maxlen, int *lencopied)
749 *	copy a string from from to to, stop when a 0 character is reached.
750 *	return ENAMETOOLONG if string is longer than maxlen, and
751 *	EFAULT on protection violations. If lencopied is non-zero,
752 *	return the actual length in *lencopied.
753 */
754ENTRY(copyoutstr)
755	pushl	%esi
756	pushl	%edi
757	movl	_curpcb,%ecx
758	movl	$cpystrflt,PCB_ONFAULT(%ecx)	/* XXX rename copyoutstr_fault */
759
760	movl	12(%esp),%esi			/* %esi = from */
761	movl	16(%esp),%edi			/* %edi = to */
762	movl	20(%esp),%edx			/* %edx = maxlen */
763	cld
764
765#if defined(I386_CPU)
766
767#if defined(I486_CPU) || defined(I586_CPU)
768	cmpl	$CPUCLASS_386,_cpu_class
769	jne	5f
770#endif /* I486_CPU || I586_CPU */
771
7721:
773	/*
774	 * It suffices to check that the first byte is in user space, because
775	 * we look at a page at a time and the end address is on a page
776	 * boundary.
777	 */
778	cmpl	$VM_MAXUSER_ADDRESS-1,%edi
779	ja	cpystrflt
780
781	movl	%edi,%eax
782	shrl	$IDXSHIFT,%eax
783	andb	$0xfc,%al
784	movb	_PTmap(%eax),%al
785	andb	$7,%al
786	cmpb	$7,%al
787	je	2f
788
789	/* simulate trap */
790	pushl	%edx
791	pushl	%edi
792	call	_trapwrite
793	cld
794	popl	%edi
795	popl	%edx
796	testl	%eax,%eax
797	jnz	cpystrflt
798
7992:	/* copy up to end of this page */
800	movl	%edi,%eax
801	andl	$NBPG-1,%eax
802	movl	$NBPG,%ecx
803	subl	%eax,%ecx			/* ecx = NBPG - (src % NBPG) */
804	cmpl	%ecx,%edx
805	jae	3f
806	movl	%edx,%ecx			/* ecx = min(ecx, edx) */
8073:
808	testl	%ecx,%ecx
809	jz	4f
810	decl	%ecx
811	decl	%edx
812	lodsb
813	stosb
814	orb	%al,%al
815	jnz	3b
816
817	/* Success -- 0 byte reached */
818	decl	%edx
819	xorl	%eax,%eax
820	jmp	6f
821
8224:	/* next page */
823	testl	%edx,%edx
824	jnz	1b
825
826	/* edx is zero -- return ENAMETOOLONG */
827	movl	$ENAMETOOLONG,%eax
828	jmp	cpystrflt_x
829#endif /* I386_CPU */
830
831#if defined(I486_CPU) || defined(I586_CPU)
8325:
833	incl	%edx
8341:
835	decl	%edx
836	jz	2f
837	/*
838	 * XXX - would be faster to rewrite this function to use
839	 * strlen() and copyout().
840	 */
841	cmpl	$VM_MAXUSER_ADDRESS-1,%edi
842	ja	cpystrflt
843
844	lodsb
845	stosb
846	orb	%al,%al
847	jnz	1b
848
849	/* Success -- 0 byte reached */
850	decl	%edx
851	xorl	%eax,%eax
852	jmp	cpystrflt_x
8532:
854	/* edx is zero -- return ENAMETOOLONG */
855	movl	$ENAMETOOLONG,%eax
856	jmp	cpystrflt_x
857
858#endif /* I486_CPU || I586_CPU */
859
860
861/*
862 * copyinstr(from, to, maxlen, int *lencopied)
863 *	copy a string from from to to, stop when a 0 character is reached.
864 *	return ENAMETOOLONG if string is longer than maxlen, and
865 *	EFAULT on protection violations. If lencopied is non-zero,
866 *	return the actual length in *lencopied.
867 */
868ENTRY(copyinstr)
869	pushl	%esi
870	pushl	%edi
871	movl	_curpcb,%ecx
872	movl	$cpystrflt,PCB_ONFAULT(%ecx)
873
874	movl	12(%esp),%esi			/* %esi = from */
875	movl	16(%esp),%edi			/* %edi = to */
876	movl	20(%esp),%edx			/* %edx = maxlen */
877
878	movl	$VM_MAXUSER_ADDRESS,%eax
879
880	/* make sure 'from' is within bounds */
881	subl	%esi,%eax
882	jbe	cpystrflt
883
884	/* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
885	cmpl	%edx,%eax
886	jae	1f
887	movl	%eax,%edx
888	movl	%eax,20(%esp)
8891:
890	incl	%edx
891	cld
892
8932:
894	decl	%edx
895	jz	3f
896
897	lodsb
898	stosb
899	orb	%al,%al
900	jnz	2b
901
902	/* Success -- 0 byte reached */
903	decl	%edx
904	xorl	%eax,%eax
905	jmp	cpystrflt_x
9063:
907	/* edx is zero - return ENAMETOOLONG or EFAULT */
908	cmpl	$VM_MAXUSER_ADDRESS,%esi
909	jae	cpystrflt
9104:
911	movl	$ENAMETOOLONG,%eax
912	jmp	cpystrflt_x
913
914cpystrflt:
915	movl	$EFAULT,%eax
916
917cpystrflt_x:
918	/* set *lencopied and return %eax */
919	movl	_curpcb,%ecx
920	movl	$0,PCB_ONFAULT(%ecx)
921	movl	20(%esp),%ecx
922	subl	%edx,%ecx
923	movl	24(%esp),%edx
924	testl	%edx,%edx
925	jz	1f
926	movl	%ecx,(%edx)
9271:
928	popl	%edi
929	popl	%esi
930	ret
931
932
933/*
934 * copystr(from, to, maxlen, int *lencopied)
935 */
936ENTRY(copystr)
937	pushl	%esi
938	pushl	%edi
939
940	movl	12(%esp),%esi			/* %esi = from */
941	movl	16(%esp),%edi			/* %edi = to */
942	movl	20(%esp),%edx			/* %edx = maxlen */
943	incl	%edx
944	cld
9451:
946	decl	%edx
947	jz	4f
948	lodsb
949	stosb
950	orb	%al,%al
951	jnz	1b
952
953	/* Success -- 0 byte reached */
954	decl	%edx
955	xorl	%eax,%eax
956	jmp	6f
9574:
958	/* edx is zero -- return ENAMETOOLONG */
959	movl	$ENAMETOOLONG,%eax
960
9616:
962	/* set *lencopied and return %eax */
963	movl	20(%esp),%ecx
964	subl	%edx,%ecx
965	movl	24(%esp),%edx
966	testl	%edx,%edx
967	jz	7f
968	movl	%ecx,(%edx)
9697:
970	popl	%edi
971	popl	%esi
972	ret
973
974/*
975 * Miscellaneous kernel support functions
976 */
977ENTRY(ffs)
978	bsfl	4(%esp),%eax
979	jz	1f
980	incl	%eax
981	ret
9821:
983	xorl	%eax,%eax
984	ret
985
986ENTRY(bcmp)
987	pushl	%edi
988	pushl	%esi
989	movl	12(%esp),%edi
990	movl	16(%esp),%esi
991	movl	20(%esp),%edx
992	xorl	%eax,%eax
993
994	movl	%edx,%ecx
995	shrl	$2,%ecx
996	cld					/* compare forwards */
997	repe
998	cmpsl
999	jne	1f
1000
1001	movl	%edx,%ecx
1002	andl	$3,%ecx
1003	repe
1004	cmpsb
1005	je	2f
10061:
1007	incl	%eax
10082:
1009	popl	%esi
1010	popl	%edi
1011	ret
1012
1013
1014/*
1015 * Handling of special 386 registers and descriptor tables etc
1016 */
1017/* void lgdt(struct region_descriptor *rdp); */
1018ENTRY(lgdt)
1019	/* reload the descriptor table */
1020	movl	4(%esp),%eax
1021	lgdt	(%eax)
1022
1023	/* flush the prefetch q */
1024	jmp	1f
1025	nop
10261:
1027	/* reload "stale" selectors */
1028	movl	$KDSEL,%eax
1029	movl	%ax,%ds
1030	movl	%ax,%es
1031	movl	%ax,%ss
1032
1033	/* reload code selector by turning return into intersegmental return */
1034	movl	(%esp),%eax
1035	pushl	%eax
1036#	movl	$KCSEL,4(%esp)
1037	movl	$8,4(%esp)
1038	lret
1039
1040/*
1041 * void lidt(struct region_descriptor *rdp);
1042 */
1043ENTRY(lidt)
1044	movl	4(%esp),%eax
1045	lidt	(%eax)
1046	ret
1047
1048/*
1049 * void lldt(u_short sel)
1050 */
1051ENTRY(lldt)
1052	lldt	4(%esp)
1053	ret
1054
1055/*
1056 * void ltr(u_short sel)
1057 */
1058ENTRY(ltr)
1059	ltr	4(%esp)
1060	ret
1061
1062/* ssdtosd(*ssdp,*sdp) */
1063ENTRY(ssdtosd)
1064	pushl	%ebx
1065	movl	8(%esp),%ecx
1066	movl	8(%ecx),%ebx
1067	shll	$16,%ebx
1068	movl	(%ecx),%edx
1069	roll	$16,%edx
1070	movb	%dh,%bl
1071	movb	%dl,%bh
1072	rorl	$8,%ebx
1073	movl	4(%ecx),%eax
1074	movw	%ax,%dx
1075	andl	$0xf0000,%eax
1076	orl	%eax,%ebx
1077	movl	12(%esp),%ecx
1078	movl	%edx,(%ecx)
1079	movl	%ebx,4(%ecx)
1080	popl	%ebx
1081	ret
1082
1083/* load_cr0(cr0) */
1084ENTRY(load_cr0)
1085	movl	4(%esp),%eax
1086	movl	%eax,%cr0
1087	ret
1088
1089/* rcr0() */
1090ENTRY(rcr0)
1091	movl	%cr0,%eax
1092	ret
1093
1094/* rcr3() */
1095ENTRY(rcr3)
1096	movl	%cr3,%eax
1097	ret
1098
1099/* void load_cr3(caddr_t cr3) */
1100ENTRY(load_cr3)
1101	movl	4(%esp),%eax
1102	movl	%eax,%cr3
1103	ret
1104
1105
1106/*****************************************************************************/
1107/* setjump, longjump                                                         */
1108/*****************************************************************************/
1109
1110ENTRY(setjmp)
1111	movl	4(%esp),%eax
1112	movl	%ebx,(%eax)			/* save ebx */
1113	movl	%esp,4(%eax)			/* save esp */
1114	movl	%ebp,8(%eax)			/* save ebp */
1115	movl	%esi,12(%eax)			/* save esi */
1116	movl	%edi,16(%eax)			/* save edi */
1117	movl	(%esp),%edx			/* get rta */
1118	movl	%edx,20(%eax)			/* save eip */
1119	xorl	%eax,%eax			/* return(0); */
1120	ret
1121
1122ENTRY(longjmp)
1123	movl	4(%esp),%eax
1124	movl	(%eax),%ebx			/* restore ebx */
1125	movl	4(%eax),%esp			/* restore esp */
1126	movl	8(%eax),%ebp			/* restore ebp */
1127	movl	12(%eax),%esi			/* restore esi */
1128	movl	16(%eax),%edi			/* restore edi */
1129	movl	20(%eax),%edx			/* get rta */
1130	movl	%edx,(%esp)			/* put in return frame */
1131	xorl	%eax,%eax			/* return(1); */
1132	incl	%eax
1133	ret
1134
1135/*
1136 * Here for doing BB-profiling (gcc -a).
1137 * We rely on the "bbset" instead, but need a dummy function.
1138 */
1139	.text
1140	.align 2
1141.globl	___bb_init_func
1142___bb_init_func:
1143        movl 4(%esp),%eax
1144        movl $1,(%eax)
1145        ret
1146