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