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