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