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