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