support.s revision 6325
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.19 1994/09/25 21:31:47 davidg 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/* copyout and fubyte family                                                 */
358/*****************************************************************************/
359/*
360 * Access user memory from inside the kernel. These routines and possibly
361 * the math- and DOS emulators should be the only places that do this.
362 *
363 * We have to access the memory with user's permissions, so use a segment
364 * selector with RPL 3. For writes to user space we have to additionally
365 * check the PTE for write permission, because the 386 does not check
366 * write permissions when we are executing with EPL 0. The 486 does check
367 * this if the WP bit is set in CR0, so we can use a simpler version here.
368 *
369 * These routines set curpcb->onfault for the time they execute. When a
370 * protection violation occurs inside the functions, the trap handler
371 * returns to *curpcb->onfault instead of the function.
372 */
373
374
375ENTRY(copyout)					/* copyout(from_kernel, to_user, len) */
376	movl	_curpcb,%eax
377	movl	$copyout_fault,PCB_ONFAULT(%eax)
378	pushl	%esi
379	pushl	%edi
380	pushl	%ebx
381	movl	16(%esp),%esi
382	movl	20(%esp),%edi
383	movl	24(%esp),%ebx
384	testl	%ebx,%ebx			/* anything to do? */
385	jz	done_copyout
386
387	/*
388	 * Check explicitly for non-user addresses.  If 486 write protection
389	 * is being used, this check is essential because we are in kernel
390	 * mode so the h/w does not provide any protection against writing
391	 * kernel addresses.
392	 */
393
394	/*
395	 * First, prevent address wrapping.
396	 */
397	movl	%edi,%eax
398	addl	%ebx,%eax
399	jc	copyout_fault
400/*
401 * XXX STOP USING VM_MAXUSER_ADDRESS.
402 * It is an end address, not a max, so every time it is used correctly it
403 * looks like there is an off by one error, and of course it caused an off
404 * by one error in several places.
405 */
406	cmpl	$VM_MAXUSER_ADDRESS,%eax
407	ja	copyout_fault
408
409#if defined(I386_CPU)
410
411#if defined(I486_CPU) || defined(I586_CPU)
412	cmpl	$CPUCLASS_386,_cpu_class
413	jne	3f
414#endif
415/*
416 * We have to check each PTE for user write permission.
417 * The checking may cause a page fault, so it is important to set
418 * up everything for return via copyout_fault before here.
419 */
420	/* compute number of pages */
421	movl	%edi,%ecx
422	andl	$NBPG-1,%ecx
423	addl	%ebx,%ecx
424	decl	%ecx
425	shrl	$IDXSHIFT+2,%ecx
426	incl	%ecx
427
428	/* compute PTE offset for start address */
429	movl	%edi,%edx
430	shrl	$IDXSHIFT,%edx
431	andb	$0xfc,%dl
432
4331:	/* check PTE for each page */
434	movb	_PTmap(%edx),%al
435	andb	$0x07,%al			/* Pages must be VALID + USERACC + WRITABLE */
436	cmpb	$0x07,%al
437	je	2f
438
439	/* simulate a trap */
440	pushl	%edx
441	pushl	%ecx
442	shll	$IDXSHIFT,%edx
443	pushl	%edx
444	call	_trapwrite			/* trapwrite(addr) */
445	popl	%edx
446	popl	%ecx
447	popl	%edx
448
449	testl	%eax,%eax			/* if not ok, return EFAULT */
450	jnz	copyout_fault
451
4522:
453	addl	$4,%edx
454	decl	%ecx
455	jnz	1b				/* check next page */
456#endif /* I386_CPU */
457
458	/* bcopy(%esi, %edi, %ebx) */
4593:
460	movl	%ebx,%ecx
461	shrl	$2,%ecx
462	cld
463	rep
464	movsl
465	movb	%bl,%cl
466	andb	$3,%cl
467	rep
468	movsb
469
470done_copyout:
471	popl	%ebx
472	popl	%edi
473	popl	%esi
474	xorl	%eax,%eax
475	movl	_curpcb,%edx
476	movl	%eax,PCB_ONFAULT(%edx)
477	ret
478
479	ALIGN_TEXT
480copyout_fault:
481	popl	%ebx
482	popl	%edi
483	popl	%esi
484	movl	_curpcb,%edx
485	movl	$0,PCB_ONFAULT(%edx)
486	movl	$EFAULT,%eax
487	ret
488
489/* copyin(from_user, to_kernel, len) */
490ENTRY(copyin)
491	movl	_curpcb,%eax
492	movl	$copyin_fault,PCB_ONFAULT(%eax)
493	pushl	%esi
494	pushl	%edi
495	movl	12(%esp),%esi			/* caddr_t from */
496	movl	16(%esp),%edi			/* caddr_t to */
497	movl	20(%esp),%ecx			/* size_t  len */
498
499	/*
500	 * make sure address is valid
501	 */
502	movl	%esi,%edx
503	addl	%ecx,%edx
504	jc	copyin_fault
505	cmpl	$VM_MAXUSER_ADDRESS,%edx
506	ja	copyin_fault
507
508	movb	%cl,%al
509	shrl	$2,%ecx				/* copy longword-wise */
510	cld
511	rep
512	movsl
513	movb	%al,%cl
514	andb	$3,%cl				/* copy remaining bytes */
515	rep
516	movsb
517
518	popl	%edi
519	popl	%esi
520	xorl	%eax,%eax
521	movl	_curpcb,%edx
522	movl	%eax,PCB_ONFAULT(%edx)
523	ret
524
525	ALIGN_TEXT
526copyin_fault:
527	popl	%edi
528	popl	%esi
529	movl	_curpcb,%edx
530	movl	$0,PCB_ONFAULT(%edx)
531	movl	$EFAULT,%eax
532	ret
533
534/*
535 * fu{byte,sword,word} : fetch a byte (sword, word) from user memory
536 */
537ALTENTRY(fuiword)
538ENTRY(fuword)
539	movl	_curpcb,%ecx
540	movl	$fusufault,PCB_ONFAULT(%ecx)
541	movl	4(%esp),%edx			/* from */
542
543	cmpl	$VM_MAXUSER_ADDRESS-4,%edx	/* verify address is valid */
544	ja	fusufault
545
546	movl	(%edx),%eax
547	movl	$0,PCB_ONFAULT(%ecx)
548	ret
549
550/*
551 * These two routines are called from the profiling code, potentially
552 * at interrupt time. If they fail, that's okay, good things will
553 * happen later. Fail all the time for now - until the trap code is
554 * able to deal with this.
555 */
556ALTENTRY(suswintr)
557ENTRY(fuswintr)
558	movl	$-1,%eax
559	ret
560
561ENTRY(fusword)
562	movl	_curpcb,%ecx
563	movl	$fusufault,PCB_ONFAULT(%ecx)
564	movl	4(%esp),%edx
565
566	cmpl	$VM_MAXUSER_ADDRESS-2,%edx
567	ja	fusufault
568
569	movzwl	(%edx),%eax
570	movl	$0,PCB_ONFAULT(%ecx)
571	ret
572
573ALTENTRY(fuibyte)
574ENTRY(fubyte)
575	movl	_curpcb,%ecx
576	movl	$fusufault,PCB_ONFAULT(%ecx)
577	movl	4(%esp),%edx
578
579	cmpl	$VM_MAXUSER_ADDRESS-1,%edx
580	ja	fusufault
581
582	movzbl	(%edx),%eax
583	movl	$0,PCB_ONFAULT(%ecx)
584	ret
585
586	ALIGN_TEXT
587fusufault:
588	movl	_curpcb,%ecx
589	xorl	%eax,%eax
590	movl	%eax,PCB_ONFAULT(%ecx)
591	decl	%eax
592	ret
593
594/*
595 * su{byte,sword,word}: write a byte (word, longword) to user memory
596 */
597ALTENTRY(suiword)
598ENTRY(suword)
599	movl	_curpcb,%ecx
600	movl	$fusufault,PCB_ONFAULT(%ecx)
601	movl	4(%esp),%edx
602
603#if defined(I386_CPU)
604
605#if defined(I486_CPU) || defined(I586_CPU)
606	cmpl	$CPUCLASS_386,_cpu_class
607	jne	2f				/* we only have to set the right segment selector */
608#endif /* I486_CPU || I586_CPU */
609
610	/* XXX - page boundary crossing is still not handled */
611	movl	%edx,%eax
612	shrl	$IDXSHIFT,%edx
613	andb	$0xfc,%dl
614	movb	_PTmap(%edx),%dl
615	andb	$0x7,%dl			/* must be VALID + USERACC + WRITE */
616	cmpb	$0x7,%dl
617	je	1f
618
619	/* simulate a trap */
620	pushl	%eax
621	call	_trapwrite
622	popl	%edx				/* remove junk parameter from stack */
623	movl	_curpcb,%ecx			/* restore trashed register */
624	testl	%eax,%eax
625	jnz	fusufault
6261:
627	movl	4(%esp),%edx
628#endif
629
6302:
631	cmpl	$VM_MAXUSER_ADDRESS-4,%edx	/* verify address validity */
632	ja	fusufault
633
634	movl	8(%esp),%eax
635	movl	%eax,(%edx)
636	xorl	%eax,%eax
637	movl	%eax,PCB_ONFAULT(%ecx)
638	ret
639
640ENTRY(susword)
641	movl	_curpcb,%ecx
642	movl	$fusufault,PCB_ONFAULT(%ecx)
643	movl	4(%esp),%edx
644
645#if defined(I386_CPU)
646
647#if defined(I486_CPU) || defined(I586_CPU)
648	cmpl	$CPUCLASS_386,_cpu_class
649	jne	2f
650#endif /* I486_CPU || I586_CPU */
651
652	/* XXX - page boundary crossing is still not handled */
653	movl	%edx,%eax
654	shrl	$IDXSHIFT,%edx
655	andb	$0xfc,%dl
656	movb	_PTmap(%edx),%dl
657	andb	$0x7,%dl			/* must be VALID + USERACC + WRITE */
658	cmpb	$0x7,%dl
659	je	1f
660
661	/* simulate a trap */
662	pushl	%eax
663	call	_trapwrite
664	popl	%edx				/* remove junk parameter from stack */
665	movl	_curpcb,%ecx			/* restore trashed register */
666	testl	%eax,%eax
667	jnz	fusufault
6681:
669	movl	4(%esp),%edx
670#endif
671
6722:
673	cmpl	$VM_MAXUSER_ADDRESS-2,%edx	/* verify address validity */
674	ja	fusufault
675
676	movw	8(%esp),%ax
677	movw	%ax,(%edx)
678	xorl	%eax,%eax
679	movl	%eax,PCB_ONFAULT(%ecx)
680	ret
681
682ALTENTRY(suibyte)
683ENTRY(subyte)
684	movl	_curpcb,%ecx
685	movl	$fusufault,PCB_ONFAULT(%ecx)
686	movl	4(%esp),%edx
687
688#if defined(I386_CPU)
689
690#if defined(I486_CPU) || defined(I586_CPU)
691	cmpl	$CPUCLASS_386,_cpu_class
692	jne	2f
693#endif /* I486_CPU || I586_CPU */
694
695	movl	%edx,%eax
696	shrl	$IDXSHIFT,%edx
697	andb	$0xfc,%dl
698	movb	_PTmap(%edx),%dl
699	andb	$0x7,%dl			/* must be VALID + USERACC + WRITE */
700	cmpb	$0x7,%dl
701	je	1f
702
703	/* simulate a trap */
704	pushl	%eax
705	call	_trapwrite
706	popl	%edx				/* remove junk parameter from stack */
707	movl	_curpcb,%ecx			/* restore trashed register */
708	testl	%eax,%eax
709	jnz	fusufault
7101:
711	movl	4(%esp),%edx
712#endif
713
7142:
715	cmpl	$VM_MAXUSER_ADDRESS-1,%edx	/* verify address validity */
716	ja	fusufault
717
718	movb	8(%esp),%al
719	movb	%al,(%edx)
720	xorl	%eax,%eax
721	movl	%eax,PCB_ONFAULT(%ecx)
722	ret
723
724/*
725 * copyoutstr(from, to, maxlen, int *lencopied)
726 *	copy a string from from to to, stop when a 0 character is reached.
727 *	return ENAMETOOLONG if string is longer than maxlen, and
728 *	EFAULT on protection violations. If lencopied is non-zero,
729 *	return the actual length in *lencopied.
730 */
731ENTRY(copyoutstr)
732	pushl	%esi
733	pushl	%edi
734	movl	_curpcb,%ecx
735	movl	$cpystrflt,PCB_ONFAULT(%ecx)	/* XXX rename copyoutstr_fault */
736
737	movl	12(%esp),%esi			/* %esi = from */
738	movl	16(%esp),%edi			/* %edi = to */
739	movl	20(%esp),%edx			/* %edx = maxlen */
740	cld
741
742#if defined(I386_CPU)
743
744#if defined(I486_CPU) || defined(I586_CPU)
745	cmpl	$CPUCLASS_386,_cpu_class
746	jne	5f
747#endif /* I486_CPU || I586_CPU */
748
7491:
750	/*
751	 * It suffices to check that the first byte is in user space, because
752	 * we look at a page at a time and the end address is on a page
753	 * boundary.
754	 */
755	cmpl	$VM_MAXUSER_ADDRESS-1,%edi
756	ja	cpystrflt
757
758	movl	%edi,%eax
759	shrl	$IDXSHIFT,%eax
760	andb	$0xfc,%al
761	movb	_PTmap(%eax),%al
762	andb	$7,%al
763	cmpb	$7,%al
764	je	2f
765
766	/* simulate trap */
767	pushl	%edx
768	pushl	%edi
769	call	_trapwrite
770	cld
771	popl	%edi
772	popl	%edx
773	testl	%eax,%eax
774	jnz	cpystrflt
775
7762:	/* copy up to end of this page */
777	movl	%edi,%eax
778	andl	$NBPG-1,%eax
779	movl	$NBPG,%ecx
780	subl	%eax,%ecx			/* ecx = NBPG - (src % NBPG) */
781	cmpl	%ecx,%edx
782	jae	3f
783	movl	%edx,%ecx			/* ecx = min(ecx, edx) */
7843:
785	testl	%ecx,%ecx
786	jz	4f
787	decl	%ecx
788	decl	%edx
789	lodsb
790	stosb
791	orb	%al,%al
792	jnz	3b
793
794	/* Success -- 0 byte reached */
795	decl	%edx
796	xorl	%eax,%eax
797	jmp	6f
798
7994:	/* next page */
800	testl	%edx,%edx
801	jnz	1b
802
803	/* edx is zero -- return ENAMETOOLONG */
804	movl	$ENAMETOOLONG,%eax
805	jmp	cpystrflt_x
806#endif /* I386_CPU */
807
808#if defined(I486_CPU) || defined(I586_CPU)
8095:
810	incl	%edx
8111:
812	decl	%edx
813	jz	2f
814	/*
815	 * XXX - would be faster to rewrite this function to use
816	 * strlen() and copyout().
817	 */
818	cmpl	$VM_MAXUSER_ADDRESS-1,%edi
819	ja	cpystrflt
820
821	lodsb
822	stosb
823	orb	%al,%al
824	jnz	1b
825
826	/* Success -- 0 byte reached */
827	decl	%edx
828	xorl	%eax,%eax
829	jmp	cpystrflt_x
8302:
831	/* edx is zero -- return ENAMETOOLONG */
832	movl	$ENAMETOOLONG,%eax
833	jmp	cpystrflt_x
834
835#endif /* I486_CPU || I586_CPU */
836
837
838/*
839 * copyinstr(from, to, maxlen, int *lencopied)
840 *	copy a string from from to to, stop when a 0 character is reached.
841 *	return ENAMETOOLONG if string is longer than maxlen, and
842 *	EFAULT on protection violations. If lencopied is non-zero,
843 *	return the actual length in *lencopied.
844 */
845ENTRY(copyinstr)
846	pushl	%esi
847	pushl	%edi
848	movl	_curpcb,%ecx
849	movl	$cpystrflt,PCB_ONFAULT(%ecx)
850
851	movl	12(%esp),%esi			/* %esi = from */
852	movl	16(%esp),%edi			/* %edi = to */
853	movl	20(%esp),%edx			/* %edx = maxlen */
854
855	movl	$VM_MAXUSER_ADDRESS,%eax
856
857	/* make sure 'from' is within bounds */
858	subl	%esi,%eax
859	jbe	cpystrflt
860
861	/* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
862	cmpl	%edx,%eax
863	jae	1f
864	movl	%eax,%edx
865	movl	%eax,20(%esp)
8661:
867	incl	%edx
868	cld
869
8702:
871	decl	%edx
872	jz	3f
873
874	lodsb
875	stosb
876	orb	%al,%al
877	jnz	2b
878
879	/* Success -- 0 byte reached */
880	decl	%edx
881	xorl	%eax,%eax
882	jmp	cpystrflt_x
8833:
884	/* edx is zero - return ENAMETOOLONG or EFAULT */
885	cmpl	$VM_MAXUSER_ADDRESS,%esi
886	jae	cpystrflt
8874:
888	movl	$ENAMETOOLONG,%eax
889	jmp	cpystrflt_x
890
891cpystrflt:
892	movl	$EFAULT,%eax
893
894cpystrflt_x:
895	/* set *lencopied and return %eax */
896	movl	_curpcb,%ecx
897	movl	$0,PCB_ONFAULT(%ecx)
898	movl	20(%esp),%ecx
899	subl	%edx,%ecx
900	movl	24(%esp),%edx
901	testl	%edx,%edx
902	jz	1f
903	movl	%ecx,(%edx)
9041:
905	popl	%edi
906	popl	%esi
907	ret
908
909
910/*
911 * copystr(from, to, maxlen, int *lencopied)
912 */
913ENTRY(copystr)
914	pushl	%esi
915	pushl	%edi
916
917	movl	12(%esp),%esi			/* %esi = from */
918	movl	16(%esp),%edi			/* %edi = to */
919	movl	20(%esp),%edx			/* %edx = maxlen */
920	incl	%edx
921	cld
9221:
923	decl	%edx
924	jz	4f
925	lodsb
926	stosb
927	orb	%al,%al
928	jnz	1b
929
930	/* Success -- 0 byte reached */
931	decl	%edx
932	xorl	%eax,%eax
933	jmp	6f
9344:
935	/* edx is zero -- return ENAMETOOLONG */
936	movl	$ENAMETOOLONG,%eax
937
9386:
939	/* set *lencopied and return %eax */
940	movl	20(%esp),%ecx
941	subl	%edx,%ecx
942	movl	24(%esp),%edx
943	testl	%edx,%edx
944	jz	7f
945	movl	%ecx,(%edx)
9467:
947	popl	%edi
948	popl	%esi
949	ret
950
951/*
952 * Miscellaneous kernel support functions
953 */
954ENTRY(ffs)
955	bsfl	4(%esp),%eax
956	jz	1f
957	incl	%eax
958	ret
9591:
960	xorl	%eax,%eax
961	ret
962
963ENTRY(bcmp)
964	pushl	%edi
965	pushl	%esi
966	movl	12(%esp),%edi
967	movl	16(%esp),%esi
968	movl	20(%esp),%edx
969	xorl	%eax,%eax
970
971	movl	%edx,%ecx
972	shrl	$2,%ecx
973	cld					/* compare forwards */
974	repe
975	cmpsl
976	jne	1f
977
978	movl	%edx,%ecx
979	andl	$3,%ecx
980	repe
981	cmpsb
982	je	2f
9831:
984	incl	%eax
9852:
986	popl	%esi
987	popl	%edi
988	ret
989
990
991/*
992 * Handling of special 386 registers and descriptor tables etc
993 */
994/* void lgdt(struct region_descriptor *rdp); */
995ENTRY(lgdt)
996	/* reload the descriptor table */
997	movl	4(%esp),%eax
998	lgdt	(%eax)
999
1000	/* flush the prefetch q */
1001	jmp	1f
1002	nop
10031:
1004	/* reload "stale" selectors */
1005	movl	$KDSEL,%eax
1006	movl	%ax,%ds
1007	movl	%ax,%es
1008	movl	%ax,%ss
1009
1010	/* reload code selector by turning return into intersegmental return */
1011	movl	(%esp),%eax
1012	pushl	%eax
1013#	movl	$KCSEL,4(%esp)
1014	movl	$8,4(%esp)
1015	lret
1016
1017/*
1018 * void lidt(struct region_descriptor *rdp);
1019 */
1020ENTRY(lidt)
1021	movl	4(%esp),%eax
1022	lidt	(%eax)
1023	ret
1024
1025/*
1026 * void lldt(u_short sel)
1027 */
1028ENTRY(lldt)
1029	lldt	4(%esp)
1030	ret
1031
1032/*
1033 * void ltr(u_short sel)
1034 */
1035ENTRY(ltr)
1036	ltr	4(%esp)
1037	ret
1038
1039/* ssdtosd(*ssdp,*sdp) */
1040ENTRY(ssdtosd)
1041	pushl	%ebx
1042	movl	8(%esp),%ecx
1043	movl	8(%ecx),%ebx
1044	shll	$16,%ebx
1045	movl	(%ecx),%edx
1046	roll	$16,%edx
1047	movb	%dh,%bl
1048	movb	%dl,%bh
1049	rorl	$8,%ebx
1050	movl	4(%ecx),%eax
1051	movw	%ax,%dx
1052	andl	$0xf0000,%eax
1053	orl	%eax,%ebx
1054	movl	12(%esp),%ecx
1055	movl	%edx,(%ecx)
1056	movl	%ebx,4(%ecx)
1057	popl	%ebx
1058	ret
1059
1060/* load_cr0(cr0) */
1061ENTRY(load_cr0)
1062	movl	4(%esp),%eax
1063	movl	%eax,%cr0
1064	ret
1065
1066/* rcr0() */
1067ENTRY(rcr0)
1068	movl	%cr0,%eax
1069	ret
1070
1071/* rcr3() */
1072ENTRY(rcr3)
1073	movl	%cr3,%eax
1074	ret
1075
1076/* void load_cr3(caddr_t cr3) */
1077ENTRY(load_cr3)
1078	movl	4(%esp),%eax
1079	movl	%eax,%cr3
1080	ret
1081
1082
1083/*****************************************************************************/
1084/* setjump, longjump                                                         */
1085/*****************************************************************************/
1086
1087ENTRY(setjmp)
1088	movl	4(%esp),%eax
1089	movl	%ebx,(%eax)			/* save ebx */
1090	movl	%esp,4(%eax)			/* save esp */
1091	movl	%ebp,8(%eax)			/* save ebp */
1092	movl	%esi,12(%eax)			/* save esi */
1093	movl	%edi,16(%eax)			/* save edi */
1094	movl	(%esp),%edx			/* get rta */
1095	movl	%edx,20(%eax)			/* save eip */
1096	xorl	%eax,%eax			/* return(0); */
1097	ret
1098
1099ENTRY(longjmp)
1100	movl	4(%esp),%eax
1101	movl	(%eax),%ebx			/* restore ebx */
1102	movl	4(%eax),%esp			/* restore esp */
1103	movl	8(%eax),%ebp			/* restore ebp */
1104	movl	12(%eax),%esi			/* restore esi */
1105	movl	16(%eax),%edi			/* restore edi */
1106	movl	20(%eax),%edx			/* get rta */
1107	movl	%edx,(%esp)			/* put in return frame */
1108	xorl	%eax,%eax			/* return(1); */
1109	incl	%eax
1110	ret
1111