support.s revision 1688
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	shrl	$1,%ecx				/* copy by 16-bit words */
358	cld					/* nope, copy forwards */
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	andl	$1,%ecx				/* any fractional bytes? */
373	decl	%edi
374	decl	%esi
375	std
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	shrl	$2,%ecx				/* copy by 32-bit words */
412	cld					/* nope, copy forwards */
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	andl	$3,%ecx				/* any fractional bytes? */
428	decl	%edi
429	decl	%esi
430	std
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	movl	%ebx,%ecx
581	shrl	$2,%ecx
582	cld
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	cld
839
840#if defined(I386_CPU)
841
842#if defined(I486_CPU) || defined(I586_CPU)
843	cmpl	$CPUCLASS_386,_cpu_class
844	jne	5f
845#endif /* I486_CPU || I586_CPU */
846
8471:
848	/*
849	 * It suffices to check that the first byte is in user space, because
850	 * we look at a page at a time and the end address is on a page
851	 * boundary.
852	 */
853	cmpl	$VM_MAXUSER_ADDRESS,%edi
854	jae	cpystrflt
855
856	movl	%edi,%eax
857	shrl	$IDXSHIFT,%eax
858	andb	$0xfc,%al
859	movb	_PTmap(%eax),%al
860	andb	$7,%al
861	cmpb	$7,%al
862	je	2f
863
864	/* simulate trap */
865	pushl	%edx
866	pushl	%edi
867	call	_trapwrite
868	cld
869	popl	%edi
870	popl	%edx
871	orl	%eax,%eax
872	jnz	cpystrflt
873
8742:	/* copy up to end of this page */
875	movl	%edi,%eax
876	andl	$NBPG-1,%eax
877	movl	$NBPG,%ecx
878	subl	%eax,%ecx			/* ecx = NBPG - (src % NBPG) */
879	cmpl	%ecx,%edx
880	jae	3f
881	movl	%edx,%ecx			/* ecx = min(ecx, edx) */
8823:
883	orl	%ecx,%ecx
884	jz	4f
885	decl	%ecx
886	decl	%edx
887	lodsb
888	stosb
889	orb	%al,%al
890	jnz	3b
891
892	/* Success -- 0 byte reached */
893	decl	%edx
894	xorl	%eax,%eax
895	jmp	6f
896
8974:	/* next page */
898	orl	%edx,%edx
899	jnz	1b
900
901	/* edx is zero -- return ENAMETOOLONG */
902	movl	$ENAMETOOLONG,%eax
903	jmp	cpystrflt_x
904#endif /* I386_CPU */
905
906#if defined(I486_CPU) || defined(I586_CPU)
9075:
908	incl	%edx
9091:
910	decl	%edx
911	jz	2f
912	/*
913	 * gs override doesn't work for stosb.  Use the same explicit check
914	 * as in copyout().  It's much slower now because it is per-char.
915	 * XXX - however, it would be faster to rewrite this function to use
916	 * strlen() and copyout().
917	 */
918	cmpl	$VM_MAXUSER_ADDRESS,%edi
919	jae	cpystrflt
920
921	lodsb
922	stosb
923	orb	%al,%al
924	jnz	1b
925
926	/* Success -- 0 byte reached */
927	decl	%edx
928	xorl	%eax,%eax
929	jmp	cpystrflt_x
9302:
931	/* edx is zero -- return ENAMETOOLONG */
932	movl	$ENAMETOOLONG,%eax
933	jmp	cpystrflt_x
934
935#endif /* I486_CPU || I586_CPU */
936
937/*
938 * copyinstr(from, to, maxlen, int *lencopied)
939 *	copy a string from from to to, stop when a 0 character is reached.
940 *	return ENAMETOOLONG if string is longer than maxlen, and
941 *	EFAULT on protection violations. If lencopied is non-zero,
942 *	return the actual length in *lencopied.
943 */
944ENTRY(copyinstr)
945	pushl	%esi
946	pushl	%edi
947	movl	_curpcb,%ecx
948	movl	$cpystrflt,PCB_ONFAULT(%ecx)
949
950	movl	12(%esp),%esi			/* %esi = from */
951	movl	16(%esp),%edi			/* %edi = to */
952	movl	20(%esp),%edx			/* %edx = maxlen */
953	incl	%edx
954	cld
9551:
956	decl	%edx
957	jz	4f
958	gs
959	lodsb
960	stosb
961	orb	%al,%al
962	jnz	1b
963
964	/* Success -- 0 byte reached */
965	decl	%edx
966	xorl	%eax,%eax
967	jmp	6f
9684:
969	/* edx is zero -- return ENAMETOOLONG */
970	movl	$ENAMETOOLONG,%eax
971	jmp	6f
972
973cpystrflt:
974	movl	$EFAULT,%eax
975cpystrflt_x:
9766:
977	/* set *lencopied and return %eax */
978	movl	_curpcb,%ecx
979	movl	$0,PCB_ONFAULT(%ecx)
980	movl	20(%esp),%ecx
981	subl	%edx,%ecx
982	movl	24(%esp),%edx
983	orl	%edx,%edx
984	jz	7f
985	movl	%ecx,(%edx)
9867:
987	popl	%edi
988	popl	%esi
989	ret
990
991
992/*
993 * copystr(from, to, maxlen, int *lencopied)
994 */
995ENTRY(copystr)
996	pushl	%esi
997	pushl	%edi
998
999	movl	12(%esp),%esi			/* %esi = from */
1000	movl	16(%esp),%edi			/* %edi = to */
1001	movl	20(%esp),%edx			/* %edx = maxlen */
1002	incl	%edx
1003	cld
10041:
1005	decl	%edx
1006	jz	4f
1007	lodsb
1008	stosb
1009	orb	%al,%al
1010	jnz	1b
1011
1012	/* Success -- 0 byte reached */
1013	decl	%edx
1014	xorl	%eax,%eax
1015	jmp	6f
10164:
1017	/* edx is zero -- return ENAMETOOLONG */
1018	movl	$ENAMETOOLONG,%eax
1019
10206:
1021	/* set *lencopied and return %eax */
1022	movl	20(%esp),%ecx
1023	subl	%edx,%ecx
1024	movl	24(%esp),%edx
1025	orl	%edx,%edx
1026	jz	7f
1027	movl	%ecx,(%edx)
10287:
1029	popl	%edi
1030	popl	%esi
1031	ret
1032
1033/*
1034 * Handling of special 386 registers and descriptor tables etc
1035 */
1036/* void lgdt(struct region_descriptor *rdp); */
1037ENTRY(lgdt)
1038	/* reload the descriptor table */
1039	movl	4(%esp),%eax
1040	lgdt	(%eax)
1041
1042	/* flush the prefetch q */
1043	jmp	1f
1044	nop
10451:
1046	/* reload "stale" selectors */
1047	movl	$KDSEL,%eax
1048	movl	%ax,%ds
1049	movl	%ax,%es
1050	movl	%ax,%ss
1051
1052	/* reload code selector by turning return into intersegmental return */
1053	movl	(%esp),%eax
1054	pushl	%eax
1055#	movl	$KCSEL,4(%esp)
1056	movl	$8,4(%esp)
1057	lret
1058
1059/*
1060 * void lidt(struct region_descriptor *rdp);
1061 */
1062ENTRY(lidt)
1063	movl	4(%esp),%eax
1064	lidt	(%eax)
1065	ret
1066
1067/*
1068 * void lldt(u_short sel)
1069 */
1070ENTRY(lldt)
1071	lldt	4(%esp)
1072	ret
1073
1074/*
1075 * void ltr(u_short sel)
1076 */
1077ENTRY(ltr)
1078	ltr	4(%esp)
1079	ret
1080
1081/* ssdtosd(*ssdp,*sdp) */
1082ENTRY(ssdtosd)
1083	pushl	%ebx
1084	movl	8(%esp),%ecx
1085	movl	8(%ecx),%ebx
1086	shll	$16,%ebx
1087	movl	(%ecx),%edx
1088	roll	$16,%edx
1089	movb	%dh,%bl
1090	movb	%dl,%bh
1091	rorl	$8,%ebx
1092	movl	4(%ecx),%eax
1093	movw	%ax,%dx
1094	andl	$0xf0000,%eax
1095	orl	%eax,%ebx
1096	movl	12(%esp),%ecx
1097	movl	%edx,(%ecx)
1098	movl	%ebx,4(%ecx)
1099	popl	%ebx
1100	ret
1101
1102/* load_cr0(cr0) */
1103ENTRY(load_cr0)
1104	movl	4(%esp),%eax
1105	movl	%eax,%cr0
1106	ret
1107
1108/* rcr0() */
1109ENTRY(rcr0)
1110	movl	%cr0,%eax
1111	ret
1112
1113/* rcr3() */
1114ENTRY(rcr3)
1115	movl	%cr3,%eax
1116	ret
1117
1118/* void load_cr3(caddr_t cr3) */
1119ENTRY(load_cr3)
1120	movl	4(%esp),%eax
1121	orl	$I386_CR3PAT,%eax
1122	movl	%eax,%cr3
1123	ret
1124
1125
1126/*****************************************************************************/
1127/* setjump, longjump                                                         */
1128/*****************************************************************************/
1129
1130ENTRY(setjmp)
1131	movl	4(%esp),%eax
1132	movl	%ebx,(%eax)			/* save ebx */
1133	movl	%esp,4(%eax)			/* save esp */
1134	movl	%ebp,8(%eax)			/* save ebp */
1135	movl	%esi,12(%eax)			/* save esi */
1136	movl	%edi,16(%eax)			/* save edi */
1137	movl	(%esp),%edx			/* get rta */
1138	movl	%edx,20(%eax)			/* save eip */
1139	xorl	%eax,%eax			/* return(0); */
1140	ret
1141
1142ENTRY(longjmp)
1143	movl	4(%esp),%eax
1144	movl	(%eax),%ebx			/* restore ebx */
1145	movl	4(%eax),%esp			/* restore esp */
1146	movl	8(%eax),%ebp			/* restore ebp */
1147	movl	12(%eax),%esi			/* restore esi */
1148	movl	16(%eax),%edi			/* restore edi */
1149	movl	20(%eax),%edx			/* get rta */
1150	movl	%edx,(%esp)			/* put in return frame */
1151	xorl	%eax,%eax			/* return(1); */
1152	incl	%eax
1153	ret
1154