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