support.s revision 1058
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.3 1994/01/31 23:47: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(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/* void bzero(void *base, u_int cnt) */
155ENTRY(bzero)
156	pushl	%edi
157	movl	8(%esp),%edi
158	movl	12(%esp),%ecx
159	xorl	%eax,%eax
160	shrl	$2,%ecx
161	cld
162	rep
163	stosl
164	movl	12(%esp),%ecx
165	andl	$3,%ecx
166	rep
167	stosb
168	popl	%edi
169	ret
170
171/* fillw(pat, base, cnt) */
172ENTRY(fillw)
173	pushl	%edi
174	movl	8(%esp),%eax
175	movl	12(%esp),%edi
176	movl	16(%esp),%ecx
177	cld
178	rep
179	stosw
180	popl	%edi
181	ret
182
183/* filli(pat, base, cnt) */
184ENTRY(filli)
185filli:
186	pushl	%edi
187	movl	8(%esp),%eax
188	movl	12(%esp),%edi
189	movl	16(%esp),%ecx
190	cld
191	rep
192	stosl
193	popl	%edi
194	ret
195
196ENTRY(bcopyb)
197bcopyb:
198	pushl	%esi
199	pushl	%edi
200	movl	12(%esp),%esi
201	movl	16(%esp),%edi
202	movl	20(%esp),%ecx
203	cmpl	%esi,%edi			/* potentially overlapping? */
204	jnb	1f
205	cld					/* nope, copy forwards */
206	rep
207	movsb
208	popl	%edi
209	popl	%esi
210	ret
211
212	ALIGN_TEXT
2131:
214	addl	%ecx,%edi			/* copy backwards. */
215	addl	%ecx,%esi
216	std
217	decl	%edi
218	decl	%esi
219	rep
220	movsb
221	popl	%edi
222	popl	%esi
223	cld
224	ret
225
226ENTRY(bcopyw)
227bcopyw:
228	pushl	%esi
229	pushl	%edi
230	movl	12(%esp),%esi
231	movl	16(%esp),%edi
232	movl	20(%esp),%ecx
233	cmpl	%esi,%edi			/* potentially overlapping? */
234	jnb	1f
235	cld					/* nope, copy forwards */
236	shrl	$1,%ecx				/* copy by 16-bit words */
237	rep
238	movsw
239	adc	%ecx,%ecx			/* any bytes left? */
240	rep
241	movsb
242	popl	%edi
243	popl	%esi
244	ret
245
246	ALIGN_TEXT
2471:
248	addl	%ecx,%edi			/* copy backwards */
249	addl	%ecx,%esi
250	std
251	andl	$1,%ecx				/* any fractional bytes? */
252	decl	%edi
253	decl	%esi
254	rep
255	movsb
256	movl	20(%esp),%ecx			/* copy remainder by 16-bit words */
257	shrl	$1,%ecx
258	decl	%esi
259	decl	%edi
260	rep
261	movsw
262	popl	%edi
263	popl	%esi
264	cld
265	ret
266
267ENTRY(bcopyx)
268	movl	16(%esp),%eax
269	cmpl	$2,%eax
270	je	bcopyw				/* not _bcopyw, to avoid multiple mcounts */
271	cmpl	$4,%eax
272	je	bcopy
273	jmp	bcopyb
274
275/*
276 * (ov)bcopy(src, dst, cnt)
277 *  ws@tools.de     (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
278 */
279ALTENTRY(ovbcopy)
280ENTRY(bcopy)
281bcopy:
282	pushl	%esi
283	pushl	%edi
284	movl	12(%esp),%esi
285	movl	16(%esp),%edi
286	movl	20(%esp),%ecx
287	cmpl	%esi,%edi			/* potentially overlapping? */
288	jnb	1f
289	cld					/* nope, copy forwards */
290	shrl	$2,%ecx				/* copy by 32-bit words */
291	rep
292	movsl
293	movl	20(%esp),%ecx
294	andl	$3,%ecx				/* any bytes left? */
295	rep
296	movsb
297	popl	%edi
298	popl	%esi
299	ret
300
301	ALIGN_TEXT
3021:
303	addl	%ecx,%edi			/* copy backwards */
304	addl	%ecx,%esi
305	std
306	andl	$3,%ecx				/* any fractional bytes? */
307	decl	%edi
308	decl	%esi
309	rep
310	movsb
311	movl	20(%esp),%ecx			/* copy remainder by 32-bit words */
312	shrl	$2,%ecx
313	subl	$3,%esi
314	subl	$3,%edi
315	rep
316	movsl
317	popl	%edi
318	popl	%esi
319	cld
320	ret
321
322ALTENTRY(ntohl)
323ENTRY(htonl)
324	movl	4(%esp),%eax
325#ifdef i486
326/* XXX */
327/* Since Gas 1.38 does not grok bswap this has been coded as the
328 * equivalent bytes.  This can be changed back to bswap when we
329 * upgrade to a newer version of Gas
330 */
331	/* bswap	%eax */
332	.byte	0x0f
333	.byte	0xc8
334#else
335	xchgb	%al,%ah
336	roll	$16,%eax
337	xchgb	%al,%ah
338#endif
339	ret
340
341ALTENTRY(ntohs)
342ENTRY(htons)
343	movzwl	4(%esp),%eax
344	xchgb	%al,%ah
345	ret
346
347/*****************************************************************************/
348/* copyout and fubyte family                                                 */
349/*****************************************************************************/
350/*
351 * Access user memory from inside the kernel. These routines and possibly
352 * the math- and DOS emulators should be the only places that do this.
353 *
354 * We have to access the memory with user's permissions, so use a segment
355 * selector with RPL 3. For writes to user space we have to additionally
356 * check the PTE for write permission, because the 386 does not check
357 * write permissions when we are executing with EPL 0. The 486 does check
358 * this if the WP bit is set in CR0, so we can use a simpler version here.
359 *
360 * These routines set curpcb->onfault for the time they execute. When a
361 * protection violation occurs inside the functions, the trap handler
362 * returns to *curpcb->onfault instead of the function.
363 */
364
365
366ENTRY(copyout)					/* copyout(from_kernel, to_user, len) */
367	movl	_curpcb,%eax
368	movl	$copyout_fault,PCB_ONFAULT(%eax)
369	pushl	%esi
370	pushl	%edi
371	pushl	%ebx
372	movl	16(%esp),%esi
373	movl	20(%esp),%edi
374	movl	24(%esp),%ebx
375	orl	%ebx,%ebx			/* anything to do? */
376	jz	done_copyout
377
378	/*
379	 * Check explicitly for non-user addresses.  If 486 write protection
380	 * is being used, this check is essential because we are in kernel
381	 * mode so the h/w does not provide any protection against writing
382	 * kernel addresses.
383	 *
384	 * Otherwise, it saves having to load and restore %es to get the
385	 * usual segment-based protection (the destination segment for movs
386	 * is always %es).  The other explicit checks for user-writablility
387	 * are not quite sufficient.  They fail for the user area because
388	 * we mapped the user area read/write to avoid having an #ifdef in
389	 * vm_machdep.c.  They fail for user PTEs and/or PTDs!  (107
390	 * addresses including 0xff800000 and 0xfc000000).  I'm not sure if
391	 * this can be fixed.  Marking the PTEs supervisor mode and the
392	 * PDE's user mode would almost work, but there may be a problem
393	 * with the self-referential PDE.
394	 */
395	movl	%edi,%eax
396	addl	%ebx,%eax
397	jc	copyout_fault
398	cmpl	$VM_MAXUSER_ADDRESS,%eax
399	ja	copyout_fault
400
401#if defined(I386_CPU)
402
403#if defined(I486_CPU) || defined(I586_CPU)
404	cmpl	$CPUCLASS_386,_cpu_class
405	jne	3f
406#endif
407/*
408 * We have to check each PTE for user write permission.
409 * The checking may cause a page fault, so it is important to set
410 * up everything for return via copyout_fault before here.
411 */
412	/* compute number of pages */
413	movl	%edi,%ecx
414	andl	$NBPG-1,%ecx
415	addl	%ebx,%ecx
416	decl	%ecx
417	shrl	$IDXSHIFT+2,%ecx
418	incl	%ecx
419
420	/* compute PTE offset for start address */
421	movl	%edi,%edx
422	shrl	$IDXSHIFT,%edx
423	andb	$0xfc,%dl
424
4251:	/* check PTE for each page */
426	movb	_PTmap(%edx),%al
427	andb	$0x07,%al			/* Pages must be VALID + USERACC + WRITABLE */
428	cmpb	$0x07,%al
429	je	2f
430
431	/* simulate a trap */
432	pushl	%edx
433	pushl	%ecx
434	shll	$IDXSHIFT,%edx
435	pushl	%edx
436	call	_trapwrite			/* trapwrite(addr) */
437	popl	%edx
438	popl	%ecx
439	popl	%edx
440
441	orl	%eax,%eax			/* if not ok, return EFAULT */
442	jnz	copyout_fault
443
4442:
445	addl	$4,%edx
446	decl	%ecx
447	jnz	1b				/* check next page */
448#endif /* I386_CPU */
449
450	/* bcopy(%esi, %edi, %ebx) */
4513:
452	cld
453	movl	%ebx,%ecx
454	shrl	$2,%ecx
455	rep
456	movsl
457	movb	%bl,%cl
458	andb	$3,%cl				/* XXX can we trust the rest of %ecx on clones? */
459	rep
460	movsb
461
462done_copyout:
463	popl	%ebx
464	popl	%edi
465	popl	%esi
466	xorl	%eax,%eax
467	movl	_curpcb,%edx
468	movl	%eax,PCB_ONFAULT(%edx)
469	ret
470
471	ALIGN_TEXT
472copyout_fault:
473	popl	%ebx
474	popl	%edi
475	popl	%esi
476	movl	_curpcb,%edx
477	movl	$0,PCB_ONFAULT(%edx)
478	movl	$EFAULT,%eax
479	ret
480
481/* copyin(from_user, to_kernel, len) */
482ENTRY(copyin)
483	movl	_curpcb,%eax
484	movl	$copyin_fault,PCB_ONFAULT(%eax)
485	pushl	%esi
486	pushl	%edi
487	movl	12(%esp),%esi			/* caddr_t from */
488	movl	16(%esp),%edi			/* caddr_t to */
489	movl	20(%esp),%ecx			/* size_t  len */
490
491	movb	%cl,%al
492	shrl	$2,%ecx				/* copy longword-wise */
493	cld
494	gs
495	rep
496	movsl
497	movb	%al,%cl
498	andb	$3,%cl				/* copy remaining bytes */
499	gs
500	rep
501	movsb
502
503	popl	%edi
504	popl	%esi
505	xorl	%eax,%eax
506	movl	_curpcb,%edx
507	movl	%eax,PCB_ONFAULT(%edx)
508	ret
509
510	ALIGN_TEXT
511copyin_fault:
512	popl	%edi
513	popl	%esi
514	movl	_curpcb,%edx
515	movl	$0,PCB_ONFAULT(%edx)
516	movl	$EFAULT,%eax
517	ret
518
519/*
520 * fu{byte,sword,word} : fetch a byte(sword, word) from user memory
521 */
522ALTENTRY(fuiword)
523ENTRY(fuword)
524	movl	__udatasel,%ax
525	movl	%ax,%gs
526	movl	_curpcb,%ecx
527	movl	$fusufault,PCB_ONFAULT(%ecx)
528	movl	4(%esp),%edx
529	gs
530	movl	(%edx),%eax
531	movl	$0,PCB_ONFAULT(%ecx)
532	ret
533
534ENTRY(fusword)
535	movl	__udatasel,%ax
536	movl	%ax,%gs
537	movl	_curpcb,%ecx
538	movl	$fusufault,PCB_ONFAULT(%ecx)
539	movl	4(%esp),%edx
540	gs
541	movzwl	(%edx),%eax
542	movl	$0,PCB_ONFAULT(%ecx)
543	ret
544
545ALTENTRY(fuibyte)
546ENTRY(fubyte)
547	movl	__udatasel,%ax
548	movl	%ax,%gs
549	movl	_curpcb,%ecx
550	movl	$fusufault,PCB_ONFAULT(%ecx)
551	movl	4(%esp),%edx
552	gs
553	movzbl	(%edx),%eax
554	movl	$0,PCB_ONFAULT(%ecx)
555	ret
556
557	ALIGN_TEXT
558fusufault:
559	movl	_curpcb,%ecx
560	xorl	%eax,%eax
561	movl	%eax,PCB_ONFAULT(%ecx)
562	decl	%eax
563	ret
564
565/*
566 * su{byte,sword,word}: write a byte(word, longword) to user memory
567 */
568/*
569 * we only have to set the right segment selector.
570 */
571ALTENTRY(suiword)
572ENTRY(suword)
573	movl	__udatasel,%ax
574	movl	%ax,%gs
575	movl	_curpcb,%ecx
576	movl	$fusufault,PCB_ONFAULT(%ecx)
577	movl	4(%esp),%edx
578
579#if defined(I386_CPU)
580
581#if defined(I486_CPU) || defined(I586_CPU)
582	cmpl	$CPUCLASS_386,_cpu_class
583	jne	2f
584#endif /* I486_CPU || I586_CPU */
585
586	movl	%edx,%eax
587	shrl	$IDXSHIFT,%edx
588	andb	$0xfc,%dl
589	movb	_PTmap(%edx),%dl
590	andb	$0x7,%dl			/* must be VALID + USERACC + WRITE */
591	cmpb	$0x7,%dl
592	je	1f
593
594	/* simulate a trap */
595	pushl	%eax
596	call	_trapwrite
597	popl	%edx				/* remove junk parameter from stack */
598	movl	_curpcb,%ecx			/* restore trashed register */
599	orl	%eax,%eax
600	jnz	fusufault
6011:
602	movl	4(%esp),%edx
603#endif
604
6052:
606	movl	8(%esp),%eax
607	gs
608	movl	%eax,(%edx)
609	xorl	%eax,%eax
610	movl	%eax,PCB_ONFAULT(%ecx)
611	ret
612
613ENTRY(susword)
614	movl	__udatasel,%eax
615	movl	%ax,%gs
616	movl	_curpcb,%ecx
617	movl	$fusufault,PCB_ONFAULT(%ecx)
618	movl	4(%esp),%edx
619
620#if defined(I386_CPU)
621
622#if defined(I486_CPU) || defined(I586_CPU)
623	cmpl	$CPUCLASS_386,_cpu_class
624	jne	2f
625#endif /* I486_CPU || I586_CPU */
626
627	movl	%edx,%eax
628	shrl	$IDXSHIFT,%edx
629	andb	$0xfc,%dl
630	movb	_PTmap(%edx),%dl
631	andb	$0x7,%dl			/* must be VALID + USERACC + WRITE */
632	cmpb	$0x7,%dl
633	je	1f
634
635	/* simulate a trap */
636	pushl	%eax
637	call	_trapwrite
638	popl	%edx				/* remove junk parameter from stack */
639	movl	_curpcb,%ecx			/* restore trashed register */
640	orl	%eax,%eax
641	jnz	fusufault
6421:
643	movl	4(%esp),%edx
644#endif
645
6462:
647	movw	8(%esp),%ax
648	gs
649	movw	%ax,(%edx)
650	xorl	%eax,%eax
651	movl	%eax,PCB_ONFAULT(%ecx)
652	ret
653
654ALTENTRY(suibyte)
655ENTRY(subyte)
656	movl	_curpcb,%ecx
657	movl	$fusufault,PCB_ONFAULT(%ecx)
658	movl	4(%esp),%edx
659
660#if defined(I386_CPU)
661
662#if defined(I486_CPU) || defined(I586_CPU)
663	cmpl	$CPUCLASS_386,_cpu_class
664	jne	2f
665#endif /* I486_CPU || I586_CPU */
666
667	movl	%edx,%eax
668	shrl	$IDXSHIFT,%edx
669	andb	$0xfc,%dl
670	movb	_PTmap(%edx),%dl
671	andb	$0x7,%dl			/* must be VALID + USERACC + WRITE */
672	cmpb	$0x7,%dl
673	je	1f
674
675	/* simulate a trap */
676	pushl	%eax
677	call	_trapwrite
678	popl	%edx				/* remove junk parameter from stack */
679	movl	_curpcb,%ecx			/* restore trashed register */
680	orl	%eax,%eax
681	jnz	fusufault
6821:
683	movl	4(%esp),%edx
684#endif
685
6862:
687	movb	8(%esp),%al
688	gs
689	movb	%al,(%edx)
690	xorl	%eax,%eax
691	movl	%eax,PCB_ONFAULT(%ecx)
692	ret
693
694/*
695 * copyoutstr(from, to, maxlen, int *lencopied)
696 *	copy a string from from to to, stop when a 0 character is reached.
697 *	return ENAMETOOLONG if string is longer than maxlen, and
698 *	EFAULT on protection violations. If lencopied is non-zero,
699 *	return the actual length in *lencopied.
700 */
701ENTRY(copyoutstr)
702	pushl	%esi
703	pushl	%edi
704	movl	_curpcb,%ecx
705	movl	$cpystrflt,PCB_ONFAULT(%ecx)
706
707	movl	12(%esp),%esi			/* %esi = from */
708	movl	16(%esp),%edi			/* %edi = to */
709	movl	20(%esp),%edx			/* %edx = maxlen */
710
711#if defined(I386_CPU)
712
713#if defined(I486_CPU) || defined(I586_CPU)
714	cmpl	$CPUCLASS_386,_cpu_class
715	jne	5f
716#endif /* I486_CPU || I586_CPU */
717
7181:
719	/*
720	 * It suffices to check that the first byte is in user space, because
721	 * we look at a page at a time and the end address is on a page
722	 * boundary.
723	 */
724	cmpl	$VM_MAXUSER_ADDRESS,%edi
725	jae	cpystrflt
726
727	movl	%edi,%eax
728	shrl	$IDXSHIFT,%eax
729	andb	$0xfc,%al
730	movb	_PTmap(%eax),%al
731	andb	$7,%al
732	cmpb	$7,%al
733	je	2f
734
735	/* simulate trap */
736	pushl	%edx
737	pushl	%edi
738	call	_trapwrite
739	popl	%edi
740	popl	%edx
741	orl	%eax,%eax
742	jnz	cpystrflt
743
7442:	/* copy up to end of this page */
745	movl	%edi,%eax
746	andl	$NBPG-1,%eax
747	movl	$NBPG,%ecx
748	subl	%eax,%ecx			/* ecx = NBPG - (src % NBPG) */
749	cmpl	%ecx,%edx
750	jge	3f
751	movl	%edx,%ecx			/* ecx = min(ecx, edx) */
7523:
753	orl	%ecx,%ecx
754	jz	4f
755	decl	%ecx
756	decl	%edx
757	lodsb
758	stosb
759	orb	%al,%al
760	jnz	3b
761
762	/* Success -- 0 byte reached */
763	decl	%edx
764	xorl	%eax,%eax
765	jmp	6f
766
7674:	/* next page */
768	orl	%edx,%edx
769	jnz	1b
770
771	/* edx is zero -- return ENAMETOOLONG */
772	movl	$ENAMETOOLONG,%eax
773	jmp	cpystrflt_x
774#endif /* I386_CPU */
775
776#if defined(I486_CPU) || defined(I586_CPU)
7775:
778	incl	%edx
7791:
780	decl	%edx
781	jz	2f
782	/*
783	 * gs override doesn't work for stosb.  Use the same explicit check
784	 * as in copyout().  It's much slower now because it is per-char.
785	 * XXX - however, it would be faster to rewrite this function to use
786	 * strlen() and copyout().
787	 */
788	cmpl	$VM_MAXUSER_ADDRESS,%edi
789	jae	cpystrflt
790
791	lodsb
792	stosb
793	orb	%al,%al
794	jnz	1b
795
796	/* Success -- 0 byte reached */
797	decl	%edx
798	xorl	%eax,%eax
799	jmp	cpystrflt_x
8002:
801	/* edx is zero -- return ENAMETOOLONG */
802	movl	$ENAMETOOLONG,%eax
803	jmp	cpystrflt_x
804
805#endif /* I486_CPU || I586_CPU */
806
807/*
808 * copyinstr(from, to, maxlen, int *lencopied)
809 *	copy a string from from to to, stop when a 0 character is reached.
810 *	return ENAMETOOLONG if string is longer than maxlen, and
811 *	EFAULT on protection violations. If lencopied is non-zero,
812 *	return the actual length in *lencopied.
813 */
814ENTRY(copyinstr)
815	pushl	%esi
816	pushl	%edi
817	movl	_curpcb,%ecx
818	movl	$cpystrflt,PCB_ONFAULT(%ecx)
819
820	movl	12(%esp),%esi			/* %esi = from */
821	movl	16(%esp),%edi			/* %edi = to */
822	movl	20(%esp),%edx			/* %edx = maxlen */
823	movl	__udatasel,%eax
824	movl	%ax,%gs
825	incl	%edx
826
8271:
828	decl	%edx
829	jz	4f
830	gs
831	lodsb
832	stosb
833	orb	%al,%al
834	jnz	1b
835
836	/* Success -- 0 byte reached */
837	decl	%edx
838	xorl	%eax,%eax
839	jmp	6f
8404:
841	/* edx is zero -- return ENAMETOOLONG */
842	movl	$ENAMETOOLONG,%eax
843	jmp	6f
844
845cpystrflt:
846	movl	$EFAULT,%eax
847cpystrflt_x:
8486:
849	/* set *lencopied and return %eax */
850	movl	_curpcb,%ecx
851	movl	$0,PCB_ONFAULT(%ecx)
852	movl	20(%esp),%ecx
853	subl	%edx,%ecx
854	movl	24(%esp),%edx
855	orl	%edx,%edx
856	jz	7f
857	movl	%ecx,(%edx)
8587:
859	popl	%edi
860	popl	%esi
861	ret
862
863
864/*
865 * copystr(from, to, maxlen, int *lencopied)
866 */
867ENTRY(copystr)
868	pushl	%esi
869	pushl	%edi
870
871	movl	12(%esp),%esi			/* %esi = from */
872	movl	16(%esp),%edi			/* %edi = to */
873	movl	20(%esp),%edx			/* %edx = maxlen */
874	incl	%edx
875
8761:
877	decl	%edx
878	jz	4f
879	lodsb
880	stosb
881	orb	%al,%al
882	jnz	1b
883
884	/* Success -- 0 byte reached */
885	decl	%edx
886	xorl	%eax,%eax
887	jmp	6f
8884:
889	/* edx is zero -- return ENAMETOOLONG */
890	movl	$ENAMETOOLONG,%eax
891
8926:
893	/* set *lencopied and return %eax */
894	movl	20(%esp),%ecx
895	subl	%edx,%ecx
896	movl	24(%esp),%edx
897	orl	%edx,%edx
898	jz	7f
899	movl	%ecx,(%edx)
9007:
901	popl	%edi
902	popl	%esi
903	ret
904
905/*
906 * Handling of special 386 registers and descriptor tables etc
907 */
908/* void lgdt(struct region_descriptor *rdp); */
909ENTRY(lgdt)
910	/* reload the descriptor table */
911	movl	4(%esp),%eax
912	lgdt	(%eax)
913
914	/* flush the prefetch q */
915	jmp	1f
916	nop
9171:
918	/* reload "stale" selectors */
919	movl	$KDSEL,%eax
920	movl	%ax,%ds
921	movl	%ax,%es
922	movl	%ax,%ss
923
924	/* reload code selector by turning return into intersegmental return */
925	movl	(%esp),%eax
926	pushl	%eax
927#	movl	$KCSEL,4(%esp)
928	movl	$8,4(%esp)
929	lret
930
931/*
932 * void lidt(struct region_descriptor *rdp);
933 */
934ENTRY(lidt)
935	movl	4(%esp),%eax
936	lidt	(%eax)
937	ret
938
939/*
940 * void lldt(u_short sel)
941 */
942ENTRY(lldt)
943	lldt	4(%esp)
944	ret
945
946/*
947 * void ltr(u_short sel)
948 */
949ENTRY(ltr)
950	ltr	4(%esp)
951	ret
952
953/* ssdtosd(*ssdp,*sdp) */
954ENTRY(ssdtosd)
955	pushl	%ebx
956	movl	8(%esp),%ecx
957	movl	8(%ecx),%ebx
958	shll	$16,%ebx
959	movl	(%ecx),%edx
960	roll	$16,%edx
961	movb	%dh,%bl
962	movb	%dl,%bh
963	rorl	$8,%ebx
964	movl	4(%ecx),%eax
965	movw	%ax,%dx
966	andl	$0xf0000,%eax
967	orl	%eax,%ebx
968	movl	12(%esp),%ecx
969	movl	%edx,(%ecx)
970	movl	%ebx,4(%ecx)
971	popl	%ebx
972	ret
973
974#if 0
975/* tlbflush() */
976ENTRY(tlbflush)
977	movl	%cr3,%eax
978	orl	$I386_CR3PAT,%eax
979	movl	%eax,%cr3
980	ret
981#endif
982
983/* load_cr0(cr0) */
984ENTRY(load_cr0)
985	movl	4(%esp),%eax
986	movl	%eax,%cr0
987	ret
988
989/* rcr0() */
990ENTRY(rcr0)
991	movl	%cr0,%eax
992	ret
993
994/* rcr2() */
995ENTRY(rcr2)
996	movl	%cr2,%eax
997	ret
998
999/* rcr3() */
1000ENTRY(rcr3)
1001	movl	%cr3,%eax
1002	ret
1003
1004/* void load_cr3(caddr_t cr3) */
1005ENTRY(load_cr3)
1006	movl	4(%esp),%eax
1007	orl	$I386_CR3PAT,%eax
1008	movl	%eax,%cr3
1009	ret
1010
1011
1012/*****************************************************************************/
1013/* setjump, longjump                                                         */
1014/*****************************************************************************/
1015
1016ENTRY(setjmp)
1017	movl	4(%esp),%eax
1018	movl	%ebx,(%eax)			/* save ebx */
1019	movl	%esp,4(%eax)			/* save esp */
1020	movl	%ebp,8(%eax)			/* save ebp */
1021	movl	%esi,12(%eax)			/* save esi */
1022	movl	%edi,16(%eax)			/* save edi */
1023	movl	(%esp),%edx			/* get rta */
1024	movl	%edx,20(%eax)			/* save eip */
1025	xorl	%eax,%eax			/* return(0); */
1026	ret
1027
1028ENTRY(longjmp)
1029	movl	4(%esp),%eax
1030	movl	(%eax),%ebx			/* restore ebx */
1031	movl	4(%eax),%esp			/* restore esp */
1032	movl	8(%eax),%ebp			/* restore ebp */
1033	movl	12(%eax),%esi			/* restore esi */
1034	movl	16(%eax),%edi			/* restore edi */
1035	movl	20(%eax),%edx			/* get rta */
1036	movl	%edx,(%esp)			/* put in return frame */
1037	xorl	%eax,%eax			/* return(1); */
1038	incl	%eax
1039	ret
1040
1041