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