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