support.s revision 1445
1/*-
2 * Copyright (c) 1993 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 *	$Id: support.s,v 1.6 1994/04/02 07:00:29 davidg Exp $
34 */
35
36#include "assym.s"				/* system definitions */
37#include "errno.h"				/* error return codes */
38#include "machine/asmacros.h"			/* miscellaneous asm macros */
39#include "machine/cputypes.h"			/* types of CPUs */
40
41#define KDSEL		0x10			/* kernel data selector */
42#define IDXSHIFT	10
43
44/*
45 * Support routines for GCC, general C-callable functions
46 */
47ENTRY(__udivsi3)
48	movl 4(%esp),%eax
49	xorl %edx,%edx
50	divl 8(%esp)
51	ret
52
53ENTRY(__divsi3)
54	movl 4(%esp),%eax
55	cltd
56	idivl 8(%esp)
57	ret
58
59	/*
60	 * I/O bus instructions via C
61	 */
62ENTRY(inb)					/* val = inb(port) */
63	movl	4(%esp),%edx
64	subl	%eax,%eax
65	inb	%dx,%al
66	NOP
67	ret
68
69ENTRY(inw)					/* val = inw(port) */
70	movl	4(%esp),%edx
71	subl	%eax,%eax
72	inw	%dx,%ax
73	NOP
74	ret
75
76ENTRY(insb)					/* insb(port, addr, cnt) */
77	pushl	%edi
78	movw	8(%esp),%dx
79	movl	12(%esp),%edi
80	movl	16(%esp),%ecx
81	cld
82	rep
83	insb
84	NOP
85	movl	%edi,%eax
86	popl	%edi
87	ret
88
89ENTRY(insw)					/* insw(port, addr, cnt) */
90	pushl	%edi
91	movw	8(%esp),%dx
92	movl	12(%esp),%edi
93	movl	16(%esp),%ecx
94	cld
95	rep
96	insw
97	NOP
98	movl	%edi,%eax
99	popl	%edi
100	ret
101
102ENTRY(insl)					/* insl(port, addr, cnt) */
103	pushl	%edi
104	movw	8(%esp),%dx
105	movl	12(%esp),%edi
106	movl	16(%esp),%ecx
107	cld
108	rep
109	insl
110	NOP
111	movl	%edi,%eax
112	popl	%edi
113	ret
114
115ENTRY(rtcin)					/* rtcin(val) */
116	movl	4(%esp),%eax
117	outb	%al,$0x70
118	NOP
119	xorl	%eax,%eax
120	inb	$0x71,%al
121	NOP
122	ret
123
124ENTRY(outb)					/* outb(port, val) */
125	movl	4(%esp),%edx
126	movl	8(%esp),%eax
127	outb	%al,%dx
128	NOP
129	ret
130
131ENTRY(outw)					/* outw(port, val) */
132	movl	4(%esp),%edx
133	movl	8(%esp),%eax
134	outw	%ax,%dx
135	NOP
136	ret
137
138ENTRY(outsb)					/* outsb(port, addr, cnt) */
139	pushl	%esi
140	movw	8(%esp),%dx
141	movl	12(%esp),%esi
142	movl	16(%esp),%ecx
143	cld
144	rep
145	outsb
146	NOP
147	movl	%esi,%eax
148	popl	%esi
149	ret
150
151ENTRY(outsw)					/* outsw(port, addr, cnt) */
152	pushl	%esi
153	movw	8(%esp),%dx
154	movl	12(%esp),%esi
155	movl	16(%esp),%ecx
156	cld
157	rep
158	outsw
159	NOP
160	movl	%esi,%eax
161	popl	%esi
162	ret
163
164ENTRY(outsl)					/* outsl(port, addr, cnt) */
165	pushl	%esi
166	movw	8(%esp),%dx
167	movl	12(%esp),%esi
168	movl	16(%esp),%ecx
169	cld
170	rep
171	outsl
172	NOP
173	movl	%esi,%eax
174	popl	%esi
175	ret
176
177/*
178 * bcopy family
179 */
180/*
181 * void bzero(void *base, u_int cnt)
182 * Special code for I486 because stosl uses lots
183 * of clocks.  Makes little or no difference on DX2 type
184 * machines, but about stosl is about 1/2 as fast as
185 * memory moves on standard DX !!!!!
186 */
187
188ENTRY(bzero)
189#if defined(I486_CPU) && (defined(I386_CPU) || defined(I586_CPU))
190	cmpl	$CPUCLASS_486,_cpu_class
191	jz	1f
192#endif
193#if defined(I386_CPU) || defined(I586_CPU)
194	pushl	%edi
195	movl	8(%esp),%edi
196	movl	12(%esp),%ecx
197	xorl	%eax,%eax
198	shrl	$2,%ecx
199	cld
200	rep
201	stosl
202	movl	12(%esp),%ecx
203	andl	$3,%ecx
204	rep
205	stosb
206	popl	%edi
207	ret
208	.align	4
209#endif
210#if defined(I486_CPU)
2111:
212	movl	4(%esp),%edx
213	movl	8(%esp),%ecx
214	xorl	%eax,%eax
215/
216/ do 64 byte chunks first
217/
2182:
219	cmpl	$64,%ecx
220	jb	3f
221	movl	%eax,(%edx)
222	movl	%eax,4(%edx)
223	movl	%eax,8(%edx)
224	movl	%eax,12(%edx)
225	movl	%eax,16(%edx)
226	movl	%eax,20(%edx)
227	movl	%eax,24(%edx)
228	movl	%eax,28(%edx)
229	movl	%eax,32(%edx)
230	movl	%eax,36(%edx)
231	movl	%eax,40(%edx)
232	movl	%eax,44(%edx)
233	movl	%eax,48(%edx)
234	movl	%eax,52(%edx)
235	movl	%eax,56(%edx)
236	movl	%eax,60(%edx)
237	addl	$64,%edx
238	subl	$64,%ecx
239	jnz	2b
240	ret
241	.align	4
242/
243/ do 16 byte chunks
244/
2453:
246	cmpl	$16,%ecx
247	jb	4f
248	movl	%eax,(%edx)
249	movl	%eax,4(%edx)
250	movl	%eax,8(%edx)
251	movl	%eax,12(%edx)
252	addl	$16,%edx
253	subl	$16,%ecx
254	jnz	3b
255	ret
256	.align	4
257/
258/ do 4 byte chunks
259/
2604:	cmpl	$4,%ecx
261	jb	5f
262	movl	%eax,(%edx)
263	addl	$4,%edx
264	subl	$4,%ecx
265	jnz	4b
266	ret
267/
268/ do 1 byte chunks -- this appears to be faster than a loop
269/
270	.align	4
271jtab:	.long	do0
272	.long	do1
273	.long	do2
274	.long	do3
275
276	.align	4
2775:	jmp	jtab(,%ecx,4)
278
279	.align	2
280do3:	movb	$0,(%edx)
281	incl	%edx
282	movw	$0,(%edx)
283	ret
284	.align	2
285do2:	movw	$0,(%edx)
286	ret
287	.align	2
288do1:	movb	$0,(%edx)
289do0:	ret
290
291#endif
292
293/* fillw(pat, base, cnt) */
294ENTRY(fillw)
295	pushl	%edi
296	movl	8(%esp),%eax
297	movl	12(%esp),%edi
298	movl	16(%esp),%ecx
299	cld
300	rep
301	stosw
302	popl	%edi
303	ret
304
305/* filli(pat, base, cnt) */
306ENTRY(filli)
307	pushl	%edi
308	movl	8(%esp),%eax
309	movl	12(%esp),%edi
310	movl	16(%esp),%ecx
311	cld
312	rep
313	stosl
314	popl	%edi
315	ret
316
317ENTRY(bcopyb)
318bcopyb:
319	pushl	%esi
320	pushl	%edi
321	movl	12(%esp),%esi
322	movl	16(%esp),%edi
323	movl	20(%esp),%ecx
324	cmpl	%esi,%edi			/* potentially overlapping? */
325	jnb	1f
326	cld					/* nope, copy forwards */
327	rep
328	movsb
329	popl	%edi
330	popl	%esi
331	ret
332
333	ALIGN_TEXT
3341:
335	addl	%ecx,%edi			/* copy backwards. */
336	addl	%ecx,%esi
337	std
338	decl	%edi
339	decl	%esi
340	rep
341	movsb
342	popl	%edi
343	popl	%esi
344	cld
345	ret
346
347ENTRY(bcopyw)
348bcopyw:
349	pushl	%esi
350	pushl	%edi
351	movl	12(%esp),%esi
352	movl	16(%esp),%edi
353	movl	20(%esp),%ecx
354	cmpl	%esi,%edi			/* potentially overlapping? */
355	jnb	1f
356	cld					/* nope, copy forwards */
357	shrl	$1,%ecx				/* copy by 16-bit words */
358	rep
359	movsw
360	adc	%ecx,%ecx			/* any bytes left? */
361	rep
362	movsb
363	popl	%edi
364	popl	%esi
365	ret
366
367	ALIGN_TEXT
3681:
369	addl	%ecx,%edi			/* copy backwards */
370	addl	%ecx,%esi
371	std
372	andl	$1,%ecx				/* any fractional bytes? */
373	decl	%edi
374	decl	%esi
375	rep
376	movsb
377	movl	20(%esp),%ecx			/* copy remainder by 16-bit words */
378	shrl	$1,%ecx
379	decl	%esi
380	decl	%edi
381	rep
382	movsw
383	popl	%edi
384	popl	%esi
385	cld
386	ret
387
388ENTRY(bcopyx)
389	movl	16(%esp),%eax
390	cmpl	$2,%eax
391	je	bcopyw				/* not _bcopyw, to avoid multiple mcounts */
392	cmpl	$4,%eax
393	je	bcopy				/* XXX the shared ret's break mexitcount */
394	jmp	bcopyb
395
396/*
397 * (ov)bcopy(src, dst, cnt)
398 *  ws@tools.de     (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
399 */
400ALTENTRY(ovbcopy)
401ENTRY(bcopy)
402bcopy:
403	pushl	%esi
404	pushl	%edi
405	movl	12(%esp),%esi
406	movl	16(%esp),%edi
407	movl	20(%esp),%ecx
408	cmpl	%esi,%edi			/* potentially overlapping? */
409	jnb	1f
410	cld					/* nope, copy forwards */
411	shrl	$2,%ecx				/* copy by 32-bit words */
412	rep
413	movsl
414	movl	20(%esp),%ecx
415	andl	$3,%ecx				/* any bytes left? */
416	rep
417	movsb
418	popl	%edi
419	popl	%esi
420	ret
421
422	ALIGN_TEXT
4231:
424	addl	%ecx,%edi			/* copy backwards */
425	addl	%ecx,%esi
426	std
427	andl	$3,%ecx				/* any fractional bytes? */
428	decl	%edi
429	decl	%esi
430	rep
431	movsb
432	movl	20(%esp),%ecx			/* copy remainder by 32-bit words */
433	shrl	$2,%ecx
434	subl	$3,%esi
435	subl	$3,%edi
436	rep
437	movsl
438	popl	%edi
439	popl	%esi
440	cld
441	ret
442
443ALTENTRY(ntohl)
444ENTRY(htonl)
445	movl	4(%esp),%eax
446#ifdef i486
447/* XXX */
448/* Since Gas 1.38 does not grok bswap this has been coded as the
449 * equivalent bytes.  This can be changed back to bswap when we
450 * upgrade to a newer version of Gas
451 */
452	/* bswap	%eax */
453	.byte	0x0f
454	.byte	0xc8
455#else
456	xchgb	%al,%ah
457	roll	$16,%eax
458	xchgb	%al,%ah
459#endif
460	ret
461
462ALTENTRY(ntohs)
463ENTRY(htons)
464	movzwl	4(%esp),%eax
465	xchgb	%al,%ah
466	ret
467
468/*****************************************************************************/
469/* copyout and fubyte family                                                 */
470/*****************************************************************************/
471/*
472 * Access user memory from inside the kernel. These routines and possibly
473 * the math- and DOS emulators should be the only places that do this.
474 *
475 * We have to access the memory with user's permissions, so use a segment
476 * selector with RPL 3. For writes to user space we have to additionally
477 * check the PTE for write permission, because the 386 does not check
478 * write permissions when we are executing with EPL 0. The 486 does check
479 * this if the WP bit is set in CR0, so we can use a simpler version here.
480 *
481 * These routines set curpcb->onfault for the time they execute. When a
482 * protection violation occurs inside the functions, the trap handler
483 * returns to *curpcb->onfault instead of the function.
484 */
485
486
487ENTRY(copyout)					/* copyout(from_kernel, to_user, len) */
488	movl	_curpcb,%eax
489	movl	$copyout_fault,PCB_ONFAULT(%eax)
490	pushl	%esi
491	pushl	%edi
492	pushl	%ebx
493	movl	16(%esp),%esi
494	movl	20(%esp),%edi
495	movl	24(%esp),%ebx
496	orl	%ebx,%ebx			/* anything to do? */
497	jz	done_copyout
498
499	/*
500	 * Check explicitly for non-user addresses.  If 486 write protection
501	 * is being used, this check is essential because we are in kernel
502	 * mode so the h/w does not provide any protection against writing
503	 * kernel addresses.
504	 *
505	 * Otherwise, it saves having to load and restore %es to get the
506	 * usual segment-based protection (the destination segment for movs
507	 * is always %es).  The other explicit checks for user-writablility
508	 * are not quite sufficient.  They fail for the user area because
509	 * we mapped the user area read/write to avoid having an #ifdef in
510	 * vm_machdep.c.  They fail for user PTEs and/or PTDs!  (107
511	 * addresses including 0xff800000 and 0xfc000000).  I'm not sure if
512	 * this can be fixed.  Marking the PTEs supervisor mode and the
513	 * PDE's user mode would almost work, but there may be a problem
514	 * with the self-referential PDE.
515	 */
516	movl	%edi,%eax
517	addl	%ebx,%eax
518	jc	copyout_fault
519/*
520 * XXX STOP USING VM_MAXUSER_ADDRESS.
521 * It is an end address, not a max, so every time it is used correctly it
522 * looks like there is an off by one error, and of course it caused an off
523 * by one error in several places.
524 */
525	cmpl	$VM_MAXUSER_ADDRESS,%eax
526	ja	copyout_fault
527
528#if defined(I386_CPU)
529
530#if defined(I486_CPU) || defined(I586_CPU)
531	cmpl	$CPUCLASS_386,_cpu_class
532	jne	3f
533#endif
534/*
535 * We have to check each PTE for user write permission.
536 * The checking may cause a page fault, so it is important to set
537 * up everything for return via copyout_fault before here.
538 */
539	/* compute number of pages */
540	movl	%edi,%ecx
541	andl	$NBPG-1,%ecx
542	addl	%ebx,%ecx
543	decl	%ecx
544	shrl	$IDXSHIFT+2,%ecx
545	incl	%ecx
546
547	/* compute PTE offset for start address */
548	movl	%edi,%edx
549	shrl	$IDXSHIFT,%edx
550	andb	$0xfc,%dl
551
5521:	/* check PTE for each page */
553	movb	_PTmap(%edx),%al
554	andb	$0x07,%al			/* Pages must be VALID + USERACC + WRITABLE */
555	cmpb	$0x07,%al
556	je	2f
557
558	/* simulate a trap */
559	pushl	%edx
560	pushl	%ecx
561	shll	$IDXSHIFT,%edx
562	pushl	%edx
563	call	_trapwrite			/* trapwrite(addr) */
564	popl	%edx
565	popl	%ecx
566	popl	%edx
567
568	orl	%eax,%eax			/* if not ok, return EFAULT */
569	jnz	copyout_fault
570
5712:
572	addl	$4,%edx
573	decl	%ecx
574	jnz	1b				/* check next page */
575#endif /* I386_CPU */
576
577	/* bcopy(%esi, %edi, %ebx) */
5783:
579	cld
580	movl	%ebx,%ecx
581	shrl	$2,%ecx
582	rep
583	movsl
584	movb	%bl,%cl
585	andb	$3,%cl
586	rep
587	movsb
588
589done_copyout:
590	popl	%ebx
591	popl	%edi
592	popl	%esi
593	xorl	%eax,%eax
594	movl	_curpcb,%edx
595	movl	%eax,PCB_ONFAULT(%edx)
596	ret
597
598	ALIGN_TEXT
599copyout_fault:
600	popl	%ebx
601	popl	%edi
602	popl	%esi
603	movl	_curpcb,%edx
604	movl	$0,PCB_ONFAULT(%edx)
605	movl	$EFAULT,%eax
606	ret
607
608/* copyin(from_user, to_kernel, len) */
609ENTRY(copyin)
610	movl	_curpcb,%eax
611	movl	$copyin_fault,PCB_ONFAULT(%eax)
612	pushl	%esi
613	pushl	%edi
614	movl	12(%esp),%esi			/* caddr_t from */
615	movl	16(%esp),%edi			/* caddr_t to */
616	movl	20(%esp),%ecx			/* size_t  len */
617
618	movb	%cl,%al
619	shrl	$2,%ecx				/* copy longword-wise */
620	cld
621	gs
622	rep
623	movsl
624	movb	%al,%cl
625	andb	$3,%cl				/* copy remaining bytes */
626	gs
627	rep
628	movsb
629
630	popl	%edi
631	popl	%esi
632	xorl	%eax,%eax
633	movl	_curpcb,%edx
634	movl	%eax,PCB_ONFAULT(%edx)
635	ret
636
637	ALIGN_TEXT
638copyin_fault:
639	popl	%edi
640	popl	%esi
641	movl	_curpcb,%edx
642	movl	$0,PCB_ONFAULT(%edx)
643	movl	$EFAULT,%eax
644	ret
645
646/*
647 * fu{byte,sword,word} : fetch a byte (sword, word) from user memory
648 */
649ALTENTRY(fuiword)
650ENTRY(fuword)
651	movl	_curpcb,%ecx
652	movl	$fusufault,PCB_ONFAULT(%ecx)
653	movl	4(%esp),%edx
654	gs
655	movl	(%edx),%eax
656	movl	$0,PCB_ONFAULT(%ecx)
657	ret
658
659ENTRY(fusword)
660	movl	_curpcb,%ecx
661	movl	$fusufault,PCB_ONFAULT(%ecx)
662	movl	4(%esp),%edx
663	gs
664	movzwl	(%edx),%eax
665	movl	$0,PCB_ONFAULT(%ecx)
666	ret
667
668ALTENTRY(fuibyte)
669ENTRY(fubyte)
670	movl	_curpcb,%ecx
671	movl	$fusufault,PCB_ONFAULT(%ecx)
672	movl	4(%esp),%edx
673	gs
674	movzbl	(%edx),%eax
675	movl	$0,PCB_ONFAULT(%ecx)
676	ret
677
678	ALIGN_TEXT
679fusufault:
680	movl	_curpcb,%ecx
681	xorl	%eax,%eax
682	movl	%eax,PCB_ONFAULT(%ecx)
683	decl	%eax
684	ret
685
686/*
687 * su{byte,sword,word}: write a byte (word, longword) to user memory
688 */
689ALTENTRY(suiword)
690ENTRY(suword)
691	movl	_curpcb,%ecx
692	movl	$fusufault,PCB_ONFAULT(%ecx)
693	movl	4(%esp),%edx
694
695#if defined(I386_CPU)
696
697#if defined(I486_CPU) || defined(I586_CPU)
698	cmpl	$CPUCLASS_386,_cpu_class
699	jne	2f				/* we only have to set the right segment selector */
700#endif /* I486_CPU || I586_CPU */
701
702	/* XXX - page boundary crossing is still not handled */
703	movl	%edx,%eax
704	shrl	$IDXSHIFT,%edx
705	andb	$0xfc,%dl
706	movb	_PTmap(%edx),%dl
707	andb	$0x7,%dl			/* must be VALID + USERACC + WRITE */
708	cmpb	$0x7,%dl
709	je	1f
710
711	/* simulate a trap */
712	pushl	%eax
713	call	_trapwrite
714	popl	%edx				/* remove junk parameter from stack */
715	movl	_curpcb,%ecx			/* restore trashed register */
716	orl	%eax,%eax
717	jnz	fusufault
7181:
719	movl	4(%esp),%edx
720#endif
721
7222:
723	movl	8(%esp),%eax
724	gs
725	movl	%eax,(%edx)
726	xorl	%eax,%eax
727	movl	%eax,PCB_ONFAULT(%ecx)
728	ret
729
730ENTRY(susword)
731	movl	_curpcb,%ecx
732	movl	$fusufault,PCB_ONFAULT(%ecx)
733	movl	4(%esp),%edx
734
735#if defined(I386_CPU)
736
737#if defined(I486_CPU) || defined(I586_CPU)
738	cmpl	$CPUCLASS_386,_cpu_class
739	jne	2f
740#endif /* I486_CPU || I586_CPU */
741
742	/* XXX - page boundary crossing is still not handled */
743	movl	%edx,%eax
744	shrl	$IDXSHIFT,%edx
745	andb	$0xfc,%dl
746	movb	_PTmap(%edx),%dl
747	andb	$0x7,%dl			/* must be VALID + USERACC + WRITE */
748	cmpb	$0x7,%dl
749	je	1f
750
751	/* simulate a trap */
752	pushl	%eax
753	call	_trapwrite
754	popl	%edx				/* remove junk parameter from stack */
755	movl	_curpcb,%ecx			/* restore trashed register */
756	orl	%eax,%eax
757	jnz	fusufault
7581:
759	movl	4(%esp),%edx
760#endif
761
7622:
763	movw	8(%esp),%ax
764	gs
765	movw	%ax,(%edx)
766	xorl	%eax,%eax
767	movl	%eax,PCB_ONFAULT(%ecx)
768	ret
769
770ALTENTRY(suibyte)
771ENTRY(subyte)
772	movl	_curpcb,%ecx
773	movl	$fusufault,PCB_ONFAULT(%ecx)
774	movl	4(%esp),%edx
775
776#if defined(I386_CPU)
777
778#if defined(I486_CPU) || defined(I586_CPU)
779	cmpl	$CPUCLASS_386,_cpu_class
780	jne	2f
781#endif /* I486_CPU || I586_CPU */
782
783	movl	%edx,%eax
784	shrl	$IDXSHIFT,%edx
785	andb	$0xfc,%dl
786	movb	_PTmap(%edx),%dl
787	andb	$0x7,%dl			/* must be VALID + USERACC + WRITE */
788	cmpb	$0x7,%dl
789	je	1f
790
791	/* simulate a trap */
792	pushl	%eax
793	call	_trapwrite
794	popl	%edx				/* remove junk parameter from stack */
795	movl	_curpcb,%ecx			/* restore trashed register */
796	orl	%eax,%eax
797	jnz	fusufault
7981:
799	movl	4(%esp),%edx
800#endif
801
8022:
803	movb	8(%esp),%al
804	gs
805	movb	%al,(%edx)
806	xorl	%eax,%eax
807	movl	%eax,PCB_ONFAULT(%ecx)
808	ret
809
810/*
811 * copyoutstr(from, to, maxlen, int *lencopied)
812 *	copy a string from from to to, stop when a 0 character is reached.
813 *	return ENAMETOOLONG if string is longer than maxlen, and
814 *	EFAULT on protection violations. If lencopied is non-zero,
815 *	return the actual length in *lencopied.
816 */
817ENTRY(copyoutstr)
818	pushl	%esi
819	pushl	%edi
820	movl	_curpcb,%ecx
821	movl	$cpystrflt,PCB_ONFAULT(%ecx)
822
823	movl	12(%esp),%esi			/* %esi = from */
824	movl	16(%esp),%edi			/* %edi = to */
825	movl	20(%esp),%edx			/* %edx = maxlen */
826
827#if defined(I386_CPU)
828
829#if defined(I486_CPU) || defined(I586_CPU)
830	cmpl	$CPUCLASS_386,_cpu_class
831	jne	5f
832#endif /* I486_CPU || I586_CPU */
833
8341:
835	/*
836	 * It suffices to check that the first byte is in user space, because
837	 * we look at a page at a time and the end address is on a page
838	 * boundary.
839	 */
840	cmpl	$VM_MAXUSER_ADDRESS,%edi
841	jae	cpystrflt
842
843	movl	%edi,%eax
844	shrl	$IDXSHIFT,%eax
845	andb	$0xfc,%al
846	movb	_PTmap(%eax),%al
847	andb	$7,%al
848	cmpb	$7,%al
849	je	2f
850
851	/* simulate trap */
852	pushl	%edx
853	pushl	%edi
854	call	_trapwrite
855	popl	%edi
856	popl	%edx
857	orl	%eax,%eax
858	jnz	cpystrflt
859
8602:	/* copy up to end of this page */
861	movl	%edi,%eax
862	andl	$NBPG-1,%eax
863	movl	$NBPG,%ecx
864	subl	%eax,%ecx			/* ecx = NBPG - (src % NBPG) */
865	cmpl	%ecx,%edx
866	jae	3f
867	movl	%edx,%ecx			/* ecx = min(ecx, edx) */
8683:
869	orl	%ecx,%ecx
870	jz	4f
871	decl	%ecx
872	decl	%edx
873	lodsb
874	stosb
875	orb	%al,%al
876	jnz	3b
877
878	/* Success -- 0 byte reached */
879	decl	%edx
880	xorl	%eax,%eax
881	jmp	6f
882
8834:	/* next page */
884	orl	%edx,%edx
885	jnz	1b
886
887	/* edx is zero -- return ENAMETOOLONG */
888	movl	$ENAMETOOLONG,%eax
889	jmp	cpystrflt_x
890#endif /* I386_CPU */
891
892#if defined(I486_CPU) || defined(I586_CPU)
8935:
894	incl	%edx
8951:
896	decl	%edx
897	jz	2f
898	/*
899	 * gs override doesn't work for stosb.  Use the same explicit check
900	 * as in copyout().  It's much slower now because it is per-char.
901	 * XXX - however, it would be faster to rewrite this function to use
902	 * strlen() and copyout().
903	 */
904	cmpl	$VM_MAXUSER_ADDRESS,%edi
905	jae	cpystrflt
906
907	lodsb
908	stosb
909	orb	%al,%al
910	jnz	1b
911
912	/* Success -- 0 byte reached */
913	decl	%edx
914	xorl	%eax,%eax
915	jmp	cpystrflt_x
9162:
917	/* edx is zero -- return ENAMETOOLONG */
918	movl	$ENAMETOOLONG,%eax
919	jmp	cpystrflt_x
920
921#endif /* I486_CPU || I586_CPU */
922
923/*
924 * copyinstr(from, to, maxlen, int *lencopied)
925 *	copy a string from from to to, stop when a 0 character is reached.
926 *	return ENAMETOOLONG if string is longer than maxlen, and
927 *	EFAULT on protection violations. If lencopied is non-zero,
928 *	return the actual length in *lencopied.
929 */
930ENTRY(copyinstr)
931	pushl	%esi
932	pushl	%edi
933	movl	_curpcb,%ecx
934	movl	$cpystrflt,PCB_ONFAULT(%ecx)
935
936	movl	12(%esp),%esi			/* %esi = from */
937	movl	16(%esp),%edi			/* %edi = to */
938	movl	20(%esp),%edx			/* %edx = maxlen */
939	incl	%edx
940
9411:
942	decl	%edx
943	jz	4f
944	gs
945	lodsb
946	stosb
947	orb	%al,%al
948	jnz	1b
949
950	/* Success -- 0 byte reached */
951	decl	%edx
952	xorl	%eax,%eax
953	jmp	6f
9544:
955	/* edx is zero -- return ENAMETOOLONG */
956	movl	$ENAMETOOLONG,%eax
957	jmp	6f
958
959cpystrflt:
960	movl	$EFAULT,%eax
961cpystrflt_x:
9626:
963	/* set *lencopied and return %eax */
964	movl	_curpcb,%ecx
965	movl	$0,PCB_ONFAULT(%ecx)
966	movl	20(%esp),%ecx
967	subl	%edx,%ecx
968	movl	24(%esp),%edx
969	orl	%edx,%edx
970	jz	7f
971	movl	%ecx,(%edx)
9727:
973	popl	%edi
974	popl	%esi
975	ret
976
977
978/*
979 * copystr(from, to, maxlen, int *lencopied)
980 */
981ENTRY(copystr)
982	pushl	%esi
983	pushl	%edi
984
985	movl	12(%esp),%esi			/* %esi = from */
986	movl	16(%esp),%edi			/* %edi = to */
987	movl	20(%esp),%edx			/* %edx = maxlen */
988	incl	%edx
989
9901:
991	decl	%edx
992	jz	4f
993	lodsb
994	stosb
995	orb	%al,%al
996	jnz	1b
997
998	/* Success -- 0 byte reached */
999	decl	%edx
1000	xorl	%eax,%eax
1001	jmp	6f
10024:
1003	/* edx is zero -- return ENAMETOOLONG */
1004	movl	$ENAMETOOLONG,%eax
1005
10066:
1007	/* set *lencopied and return %eax */
1008	movl	20(%esp),%ecx
1009	subl	%edx,%ecx
1010	movl	24(%esp),%edx
1011	orl	%edx,%edx
1012	jz	7f
1013	movl	%ecx,(%edx)
10147:
1015	popl	%edi
1016	popl	%esi
1017	ret
1018
1019/*
1020 * Handling of special 386 registers and descriptor tables etc
1021 */
1022/* void lgdt(struct region_descriptor *rdp); */
1023ENTRY(lgdt)
1024	/* reload the descriptor table */
1025	movl	4(%esp),%eax
1026	lgdt	(%eax)
1027
1028	/* flush the prefetch q */
1029	jmp	1f
1030	nop
10311:
1032	/* reload "stale" selectors */
1033	movl	$KDSEL,%eax
1034	movl	%ax,%ds
1035	movl	%ax,%es
1036	movl	%ax,%ss
1037
1038	/* reload code selector by turning return into intersegmental return */
1039	movl	(%esp),%eax
1040	pushl	%eax
1041#	movl	$KCSEL,4(%esp)
1042	movl	$8,4(%esp)
1043	lret
1044
1045/*
1046 * void lidt(struct region_descriptor *rdp);
1047 */
1048ENTRY(lidt)
1049	movl	4(%esp),%eax
1050	lidt	(%eax)
1051	ret
1052
1053/*
1054 * void lldt(u_short sel)
1055 */
1056ENTRY(lldt)
1057	lldt	4(%esp)
1058	ret
1059
1060/*
1061 * void ltr(u_short sel)
1062 */
1063ENTRY(ltr)
1064	ltr	4(%esp)
1065	ret
1066
1067/* ssdtosd(*ssdp,*sdp) */
1068ENTRY(ssdtosd)
1069	pushl	%ebx
1070	movl	8(%esp),%ecx
1071	movl	8(%ecx),%ebx
1072	shll	$16,%ebx
1073	movl	(%ecx),%edx
1074	roll	$16,%edx
1075	movb	%dh,%bl
1076	movb	%dl,%bh
1077	rorl	$8,%ebx
1078	movl	4(%ecx),%eax
1079	movw	%ax,%dx
1080	andl	$0xf0000,%eax
1081	orl	%eax,%ebx
1082	movl	12(%esp),%ecx
1083	movl	%edx,(%ecx)
1084	movl	%ebx,4(%ecx)
1085	popl	%ebx
1086	ret
1087
1088#if 0
1089/* tlbflush() */
1090ENTRY(tlbflush)
1091	movl	%cr3,%eax
1092	orl	$I386_CR3PAT,%eax
1093	movl	%eax,%cr3
1094	ret
1095#endif
1096
1097/* load_cr0(cr0) */
1098ENTRY(load_cr0)
1099	movl	4(%esp),%eax
1100	movl	%eax,%cr0
1101	ret
1102
1103/* rcr0() */
1104ENTRY(rcr0)
1105	movl	%cr0,%eax
1106	ret
1107
1108/* rcr2() */
1109ENTRY(rcr2)
1110	movl	%cr2,%eax
1111	ret
1112
1113/* rcr3() */
1114ENTRY(rcr3)
1115	movl	%cr3,%eax
1116	ret
1117
1118/* void load_cr3(caddr_t cr3) */
1119ENTRY(load_cr3)
1120	movl	4(%esp),%eax
1121	orl	$I386_CR3PAT,%eax
1122	movl	%eax,%cr3
1123	ret
1124
1125
1126/*****************************************************************************/
1127/* setjump, longjump                                                         */
1128/*****************************************************************************/
1129
1130ENTRY(setjmp)
1131	movl	4(%esp),%eax
1132	movl	%ebx,(%eax)			/* save ebx */
1133	movl	%esp,4(%eax)			/* save esp */
1134	movl	%ebp,8(%eax)			/* save ebp */
1135	movl	%esi,12(%eax)			/* save esi */
1136	movl	%edi,16(%eax)			/* save edi */
1137	movl	(%esp),%edx			/* get rta */
1138	movl	%edx,20(%eax)			/* save eip */
1139	xorl	%eax,%eax			/* return(0); */
1140	ret
1141
1142ENTRY(longjmp)
1143	movl	4(%esp),%eax
1144	movl	(%eax),%ebx			/* restore ebx */
1145	movl	4(%eax),%esp			/* restore esp */
1146	movl	8(%eax),%ebp			/* restore ebp */
1147	movl	12(%eax),%esi			/* restore esi */
1148	movl	16(%eax),%edi			/* restore edi */
1149	movl	20(%eax),%edx			/* get rta */
1150	movl	%edx,(%esp)			/* put in return frame */
1151	xorl	%eax,%eax			/* return(1); */
1152	incl	%eax
1153	ret
1154