support.s revision 18207
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.37 1996/06/13 07:17:20 asami Exp $
34 */
35
36#include <sys/errno.h>
37
38#include <machine/asmacros.h>
39#include <machine/cputypes.h>
40#include <machine/specialreg.h>
41
42#include "assym.s"
43
44#define KDSEL		0x10			/* kernel data selector */
45#define IDXSHIFT	10
46
47
48	.data
49	.globl	_bzero
50_bzero:	.long	_generic_bzero
51
52	.text
53
54/*
55 * bcopy family
56 * void bzero(void *base, u_int cnt)
57 */
58
59ENTRY(generic_bzero)
60	pushl	%edi
61	movl	8(%esp),%edi
62	movl	12(%esp),%ecx
63	xorl	%eax,%eax
64	shrl	$2,%ecx
65	cld
66	rep
67	stosl
68	movl	12(%esp),%ecx
69	andl	$3,%ecx
70	rep
71	stosb
72	popl	%edi
73	ret
74
75#if defined(I486_CPU)
76ENTRY(i486_bzero)
77	movl	4(%esp),%edx
78	movl	8(%esp),%ecx
79	xorl	%eax,%eax
80/*
81 * do 64 byte chunks first
82 *
83 * XXX this is probably over-unrolled at least for DX2's
84 */
852:
86	cmpl	$64,%ecx
87	jb	3f
88	movl	%eax,(%edx)
89	movl	%eax,4(%edx)
90	movl	%eax,8(%edx)
91	movl	%eax,12(%edx)
92	movl	%eax,16(%edx)
93	movl	%eax,20(%edx)
94	movl	%eax,24(%edx)
95	movl	%eax,28(%edx)
96	movl	%eax,32(%edx)
97	movl	%eax,36(%edx)
98	movl	%eax,40(%edx)
99	movl	%eax,44(%edx)
100	movl	%eax,48(%edx)
101	movl	%eax,52(%edx)
102	movl	%eax,56(%edx)
103	movl	%eax,60(%edx)
104	addl	$64,%edx
105	subl	$64,%ecx
106	jnz	2b
107	ret
108
109/*
110 * do 16 byte chunks
111 */
112	SUPERALIGN_TEXT
1133:
114	cmpl	$16,%ecx
115	jb	4f
116	movl	%eax,(%edx)
117	movl	%eax,4(%edx)
118	movl	%eax,8(%edx)
119	movl	%eax,12(%edx)
120	addl	$16,%edx
121	subl	$16,%ecx
122	jnz	3b
123	ret
124
125/*
126 * do 4 byte chunks
127 */
128	SUPERALIGN_TEXT
1294:
130	cmpl	$4,%ecx
131	jb	5f
132	movl	%eax,(%edx)
133	addl	$4,%edx
134	subl	$4,%ecx
135	jnz	4b
136	ret
137
138/*
139 * do 1 byte chunks
140 * a jump table seems to be faster than a loop or more range reductions
141 *
142 * XXX need a const section for non-text
143 */
144	SUPERALIGN_TEXT
145jtab:
146	.long	do0
147	.long	do1
148	.long	do2
149	.long	do3
150
151	SUPERALIGN_TEXT
1525:
153	jmp	jtab(,%ecx,4)
154
155	SUPERALIGN_TEXT
156do3:
157	movw	%ax,(%edx)
158	movb	%al,2(%edx)
159	ret
160
161	SUPERALIGN_TEXT
162do2:
163	movw	%ax,(%edx)
164	ret
165
166	SUPERALIGN_TEXT
167do1:
168	movb	%al,(%edx)
169
170	SUPERALIGN_TEXT
171do0:
172	ret
173#endif
174
175#if 0	/* Actually lowers performance in real-world cases */
176#if defined(I586_CPU) || defined(I686_CPU)
177ALTENTRY(i586_bzero)
178ENTRY(i686_bzero)
179	pushl	%edi
180	movl	8(%esp),%edi	/* destination pointer */
181	movl	12(%esp),%edx	/* size (in 8-bit words) */
182
183	xorl	%eax,%eax	/* store data */
184	cld
185
186/* If less than 100 bytes to write, skip tricky code.  */
187	cmpl	$100,%edx
188	movl	%edx,%ecx	/* needed when branch is taken! */
189	jl	2f
190
191/* First write 0-3 bytes to make the pointer 32-bit aligned.  */
192	movl	%edi,%ecx	/* Copy ptr to ecx... */
193	negl	%ecx		/* ...and negate that and... */
194	andl	$3,%ecx		/* ...mask to get byte count.  */
195	subl	%ecx,%edx	/* adjust global byte count */
196	rep
197	stosb
198
199	subl	$32,%edx	/* offset count for unrolled loop */
200	movl	(%edi),%ecx	/* Fetch destination cache line */
201
202	.align	2,0x90		/* supply 0x90 for broken assemblers */
2031:
204	movl	28(%edi),%ecx	/* allocate cache line for destination */
205	subl	$32,%edx	/* decr loop count */
206	movl	%eax,0(%edi)	/* store words pairwise */
207	movl	%eax,4(%edi)
208	movl	%eax,8(%edi)
209	movl	%eax,12(%edi)
210	movl	%eax,16(%edi)
211	movl	%eax,20(%edi)
212	movl	%eax,24(%edi)
213	movl	%eax,28(%edi)
214
215	leal	32(%edi),%edi	/* update destination pointer */
216	jge	1b
217	leal	32(%edx),%ecx
218
219/* Write last 0-7 full 32-bit words (up to 8 words if loop was skipped).  */
2202:
221	shrl	$2,%ecx
222	rep
223	stosl
224
225/* Finally write the last 0-3 bytes.  */
226	movl	%edx,%ecx
227	andl	$3,%ecx
228	rep
229	stosb
230
231	popl	%edi
232	ret
233#endif
234#endif
235
236/* fillw(pat, base, cnt) */
237ENTRY(fillw)
238	pushl	%edi
239	movl	8(%esp),%eax
240	movl	12(%esp),%edi
241	movl	16(%esp),%ecx
242	cld
243	rep
244	stosw
245	popl	%edi
246	ret
247
248ENTRY(bcopyb)
249bcopyb:
250	pushl	%esi
251	pushl	%edi
252	movl	12(%esp),%esi
253	movl	16(%esp),%edi
254	movl	20(%esp),%ecx
255	movl	%edi,%eax
256	subl	%esi,%eax
257	cmpl	%ecx,%eax			/* overlapping? */
258	jb	1f
259	cld					/* nope, copy forwards */
260	rep
261	movsb
262	popl	%edi
263	popl	%esi
264	ret
265
266	ALIGN_TEXT
2671:
268	addl	%ecx,%edi			/* copy backwards. */
269	addl	%ecx,%esi
270	decl	%edi
271	decl	%esi
272	std
273	rep
274	movsb
275	popl	%edi
276	popl	%esi
277	cld
278	ret
279
280/*
281 * (ov)bcopy(src, dst, cnt)
282 *  ws@tools.de     (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
283 */
284ALTENTRY(ovbcopy)
285ENTRY(bcopy)
286bcopy:
287	pushl	%esi
288	pushl	%edi
289	movl	12(%esp),%esi
290	movl	16(%esp),%edi
291	movl	20(%esp),%ecx
292
293	movl	%edi,%eax
294	subl	%esi,%eax
295	cmpl	%ecx,%eax			/* overlapping? */
296	jb	1f
297	shrl	$2,%ecx				/* copy by 32-bit words */
298	cld					/* nope, copy forwards */
299	rep
300	movsl
301	movl	20(%esp),%ecx
302	andl	$3,%ecx				/* any bytes left? */
303	rep
304	movsb
305	popl	%edi
306	popl	%esi
307	ret
308
309	ALIGN_TEXT
3101:
311	addl	%ecx,%edi			/* copy backwards */
312	addl	%ecx,%esi
313	decl	%edi
314	decl	%esi
315	andl	$3,%ecx				/* any fractional bytes? */
316	std
317	rep
318	movsb
319	movl	20(%esp),%ecx			/* copy remainder by 32-bit words */
320	shrl	$2,%ecx
321	subl	$3,%esi
322	subl	$3,%edi
323	rep
324	movsl
325	popl	%edi
326	popl	%esi
327	cld
328	ret
329
330
331/*
332 * Note: memcpy does not support overlapping copies
333 */
334ENTRY(memcpy)
335	pushl	%edi
336	pushl	%esi
337	movl	12(%esp),%edi
338	movl	16(%esp),%esi
339	movl	20(%esp),%ecx
340	movl	%edi,%eax
341	shrl	$2,%ecx				/* copy by 32-bit words */
342	cld					/* nope, copy forwards */
343	rep
344	movsl
345	movl	20(%esp),%ecx
346	andl	$3,%ecx				/* any bytes left? */
347	rep
348	movsb
349	popl	%esi
350	popl	%edi
351	ret
352
353
354/*****************************************************************************/
355/* copyout and fubyte family                                                 */
356/*****************************************************************************/
357/*
358 * Access user memory from inside the kernel. These routines and possibly
359 * the math- and DOS emulators should be the only places that do this.
360 *
361 * We have to access the memory with user's permissions, so use a segment
362 * selector with RPL 3. For writes to user space we have to additionally
363 * check the PTE for write permission, because the 386 does not check
364 * write permissions when we are executing with EPL 0. The 486 does check
365 * this if the WP bit is set in CR0, so we can use a simpler version here.
366 *
367 * These routines set curpcb->onfault for the time they execute. When a
368 * protection violation occurs inside the functions, the trap handler
369 * returns to *curpcb->onfault instead of the function.
370 */
371
372
373ENTRY(copyout)					/* copyout(from_kernel, to_user, len) */
374	movl	_curpcb,%eax
375	movl	$copyout_fault,PCB_ONFAULT(%eax)
376	pushl	%esi
377	pushl	%edi
378	pushl	%ebx
379	movl	16(%esp),%esi
380	movl	20(%esp),%edi
381	movl	24(%esp),%ebx
382	testl	%ebx,%ebx			/* anything to do? */
383	jz	done_copyout
384
385	/*
386	 * Check explicitly for non-user addresses.  If 486 write protection
387	 * is being used, this check is essential because we are in kernel
388	 * mode so the h/w does not provide any protection against writing
389	 * kernel addresses.
390	 */
391
392	/*
393	 * First, prevent address wrapping.
394	 */
395	movl	%edi,%eax
396	addl	%ebx,%eax
397	jc	copyout_fault
398/*
399 * XXX STOP USING VM_MAXUSER_ADDRESS.
400 * It is an end address, not a max, so every time it is used correctly it
401 * looks like there is an off by one error, and of course it caused an off
402 * by one error in several places.
403 */
404	cmpl	$VM_MAXUSER_ADDRESS,%eax
405	ja	copyout_fault
406
407#if defined(I386_CPU)
408
409#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
410	cmpl	$CPUCLASS_386,_cpu_class
411	jne	3f
412#endif
413/*
414 * We have to check each PTE for user write permission.
415 * The checking may cause a page fault, so it is important to set
416 * up everything for return via copyout_fault before here.
417 */
418	/* compute number of pages */
419	movl	%edi,%ecx
420	andl	$PAGE_MASK,%ecx
421	addl	%ebx,%ecx
422	decl	%ecx
423	shrl	$IDXSHIFT+2,%ecx
424	incl	%ecx
425
426	/* compute PTE offset for start address */
427	movl	%edi,%edx
428	shrl	$IDXSHIFT,%edx
429	andb	$0xfc,%dl
430
4311:	/* check PTE for each page */
432	movb	_PTmap(%edx),%al
433	andb	$0x07,%al			/* Pages must be VALID + USERACC + WRITABLE */
434	cmpb	$0x07,%al
435	je	2f
436
437	/* simulate a trap */
438	pushl	%edx
439	pushl	%ecx
440	shll	$IDXSHIFT,%edx
441	pushl	%edx
442	call	_trapwrite			/* trapwrite(addr) */
443	popl	%edx
444	popl	%ecx
445	popl	%edx
446
447	testl	%eax,%eax			/* if not ok, return EFAULT */
448	jnz	copyout_fault
449
4502:
451	addl	$4,%edx
452	decl	%ecx
453	jnz	1b				/* check next page */
454#endif /* I386_CPU */
455
456	/* bcopy(%esi, %edi, %ebx) */
4573:
458	movl	%ebx,%ecx
459#if defined(I586_CPU) && defined(I586_FAST_BCOPY)
460	cmpl	$1024,%ecx
461	jbe	slow_copyout
462
463#if defined(I386_CPU) || defined(I486_CPU) || defined(I686_CPU)
464	cmpl	$CPUCLASS_586,_cpu_class
465	jne	slow_copyout
466#endif /* I386_CPU || I486_CPU || I686_CPU */
467
468	call	fastmove
469	jmp	done_copyout
470
471	ALIGN_TEXT
472slow_copyout:
473#endif /* I586_CPU && I586_FAST_BCOPY */
474	shrl	$2,%ecx
475	cld
476	rep
477	movsl
478	movb	%bl,%cl
479	andb	$3,%cl
480	rep
481	movsb
482
483done_copyout:
484	popl	%ebx
485	popl	%edi
486	popl	%esi
487	xorl	%eax,%eax
488	movl	_curpcb,%edx
489	movl	%eax,PCB_ONFAULT(%edx)
490	ret
491
492	ALIGN_TEXT
493copyout_fault:
494	popl	%ebx
495	popl	%edi
496	popl	%esi
497	movl	_curpcb,%edx
498	movl	$0,PCB_ONFAULT(%edx)
499	movl	$EFAULT,%eax
500	ret
501
502/* copyin(from_user, to_kernel, len) */
503ENTRY(copyin)
504	movl	_curpcb,%eax
505	movl	$copyin_fault,PCB_ONFAULT(%eax)
506	pushl	%esi
507	pushl	%edi
508	movl	12(%esp),%esi			/* caddr_t from */
509	movl	16(%esp),%edi			/* caddr_t to */
510	movl	20(%esp),%ecx			/* size_t  len */
511
512	/*
513	 * make sure address is valid
514	 */
515	movl	%esi,%edx
516	addl	%ecx,%edx
517	jc	copyin_fault
518	cmpl	$VM_MAXUSER_ADDRESS,%edx
519	ja	copyin_fault
520
521#if defined(I586_CPU) && defined(I586_FAST_BCOPY)
522	cmpl	$1024,%ecx
523	jbe	slow_copyin
524
525#if defined(I386_CPU) || defined(I486_CPU) || defined(I686_CPU)
526	cmpl	$CPUCLASS_586,_cpu_class
527	jne	slow_copyin
528#endif /* I386_CPU || I486_CPU || I686_CPU */
529
530	call	fastmove
531	jmp	done_copyin
532
533	ALIGN_TEXT
534slow_copyin:
535#endif /* I586_CPU && I586_FAST_BCOPY */
536	movb	%cl,%al
537	shrl	$2,%ecx				/* copy longword-wise */
538	cld
539	rep
540	movsl
541	movb	%al,%cl
542	andb	$3,%cl				/* copy remaining bytes */
543	rep
544	movsb
545
546#if defined(I586_CPU) && defined(I586_FAST_BCOPY)
547	ALIGN_TEXT
548done_copyin:
549#endif /* I586_CPU && I586_FAST_BCOPY */
550	popl	%edi
551	popl	%esi
552	xorl	%eax,%eax
553	movl	_curpcb,%edx
554	movl	%eax,PCB_ONFAULT(%edx)
555	ret
556
557	ALIGN_TEXT
558copyin_fault:
559	popl	%edi
560	popl	%esi
561	movl	_curpcb,%edx
562	movl	$0,PCB_ONFAULT(%edx)
563	movl	$EFAULT,%eax
564	ret
565
566#if defined(I586_CPU) && defined(I586_FAST_BCOPY)
567/* fastmove(src, dst, len)
568	src in %esi
569	dst in %edi
570	len in %ecx
571	uses %eax and %edx for tmp. storage
572 */
573	ALIGN_TEXT
574fastmove:
575	cmpl	$63,%ecx
576	jbe	8f
577
578	testl	$7,%esi	/* check if src addr is multiple of 8 */
579	jnz	8f
580
581	testl	$7,%edi	/* check if dst addr is multiple of 8 */
582	jnz	8f
583
584	pushl	%ebp
585	movl	%esp,%ebp
586	subl	$PCB_SAVEFPU_SIZE,%esp
587
588/* if (npxproc != NULL) { */
589	cmpl	$0,_npxproc
590	je	6f
591/*    fnsave(&curpcb->pcb_savefpu); */
592	movl	_curpcb,%eax
593	fnsave	PCB_SAVEFPU(%eax)
594/*   npxproc = NULL; */
595	movl	$0,_npxproc
596/* } */
5976:
598/* now we own the FPU. */
599
600/*
601 * The process' FP state is saved in the pcb, but if we get
602 * switched, the cpu_switch() will store our FP state in the
603 * pcb.  It should be possible to avoid all the copying for
604 * this, e.g., by setting a flag to tell cpu_switch() to
605 * save the state somewhere else.
606 */
607/* tmp = curpcb->pcb_savefpu; */
608	pushl	%edi
609	pushl	%esi
610	pushl	%ecx
611	leal	-PCB_SAVEFPU_SIZE(%ebp),%edi
612	movl	_curpcb,%esi
613	addl	$PCB_SAVEFPU,%esi
614	cld
615	movl	$PCB_SAVEFPU_SIZE>>2,%ecx
616	rep
617	movsl
618	popl	%ecx
619	popl	%esi
620	popl	%edi
621/* stop_emulating(); */
622	clts
623/* npxproc = curproc; */
624	movl	_curproc,%eax
625	movl	%eax,_npxproc
6264:
627	pushl	%ecx
628	cmpl	$1792,%ecx
629	jbe	2f
630	movl	$1792,%ecx
6312:
632	subl	%ecx,0(%esp)
633	cmpl	$256,%ecx
634	jb	5f
635	pushl	%esi
636	pushl	%ecx
637	ALIGN_TEXT
6383:
639	movl	0(%esi),%eax
640	movl	32(%esi),%eax
641	movl	64(%esi),%eax
642	movl	96(%esi),%eax
643	movl	128(%esi),%eax
644	movl	160(%esi),%eax
645	movl	192(%esi),%eax
646	movl	224(%esi),%eax
647	addl	$256,%esi
648	subl	$256,%ecx
649	cmpl	$256,%ecx
650	jae	3b
651	popl	%ecx
652	popl	%esi
6535:
654	ALIGN_TEXT
6557:
656	fildq	0(%esi)
657	fildq	8(%esi)
658	fildq	16(%esi)
659	fildq	24(%esi)
660	fildq	32(%esi)
661	fildq	40(%esi)
662	fildq	48(%esi)
663	fildq	56(%esi)
664	fistpq	56(%edi)
665	fistpq	48(%edi)
666	fistpq	40(%edi)
667	fistpq	32(%edi)
668	fistpq	24(%edi)
669	fistpq	16(%edi)
670	fistpq	8(%edi)
671	fistpq	0(%edi)
672	addl	$-64,%ecx
673	addl	$64,%esi
674	addl	$64,%edi
675	cmpl	$63,%ecx
676	ja	7b
677	popl	%eax
678	addl	%eax,%ecx
679	cmpl	$64,%ecx
680	jae	4b
681
682/* curpcb->pcb_savefpu = tmp; */
683	pushl	%edi
684	pushl	%esi
685	pushl	%ecx
686	movl	_curpcb,%edi
687	addl	$PCB_SAVEFPU,%edi
688	leal	-PCB_SAVEFPU_SIZE(%ebp),%esi
689	cld
690	movl	$PCB_SAVEFPU_SIZE>>2,%ecx
691	rep
692	movsl
693	popl	%ecx
694	popl	%esi
695	popl	%edi
696
697/* start_emulating(); */
698	smsw	%ax
699	orb	$CR0_TS,%al
700	lmsw	%ax
701/* npxproc = NULL; */
702	movl	$0,_npxproc
703	movl	%ebp,%esp
704	popl	%ebp
705
706	ALIGN_TEXT
7078:
708	movb	%cl,%al
709	shrl	$2,%ecx				/* copy longword-wise */
710	cld
711	rep
712	movsl
713	movb	%al,%cl
714	andb	$3,%cl				/* copy remaining bytes */
715	rep
716	movsb
717
718	ret
719#endif /* I586_CPU && I586_FAST_BCOPY */
720
721/*
722 * fu{byte,sword,word} : fetch a byte (sword, word) from user memory
723 */
724ENTRY(fuword)
725	movl	_curpcb,%ecx
726	movl	$fusufault,PCB_ONFAULT(%ecx)
727	movl	4(%esp),%edx			/* from */
728
729	cmpl	$VM_MAXUSER_ADDRESS-4,%edx	/* verify address is valid */
730	ja	fusufault
731
732	movl	(%edx),%eax
733	movl	$0,PCB_ONFAULT(%ecx)
734	ret
735
736/*
737 * These two routines are called from the profiling code, potentially
738 * at interrupt time. If they fail, that's okay, good things will
739 * happen later. Fail all the time for now - until the trap code is
740 * able to deal with this.
741 */
742ALTENTRY(suswintr)
743ENTRY(fuswintr)
744	movl	$-1,%eax
745	ret
746
747ENTRY(fusword)
748	movl	_curpcb,%ecx
749	movl	$fusufault,PCB_ONFAULT(%ecx)
750	movl	4(%esp),%edx
751
752	cmpl	$VM_MAXUSER_ADDRESS-2,%edx
753	ja	fusufault
754
755	movzwl	(%edx),%eax
756	movl	$0,PCB_ONFAULT(%ecx)
757	ret
758
759ENTRY(fubyte)
760	movl	_curpcb,%ecx
761	movl	$fusufault,PCB_ONFAULT(%ecx)
762	movl	4(%esp),%edx
763
764	cmpl	$VM_MAXUSER_ADDRESS-1,%edx
765	ja	fusufault
766
767	movzbl	(%edx),%eax
768	movl	$0,PCB_ONFAULT(%ecx)
769	ret
770
771	ALIGN_TEXT
772fusufault:
773	movl	_curpcb,%ecx
774	xorl	%eax,%eax
775	movl	%eax,PCB_ONFAULT(%ecx)
776	decl	%eax
777	ret
778
779/*
780 * su{byte,sword,word}: write a byte (word, longword) to user memory
781 */
782ENTRY(suword)
783	movl	_curpcb,%ecx
784	movl	$fusufault,PCB_ONFAULT(%ecx)
785	movl	4(%esp),%edx
786
787#if defined(I386_CPU)
788
789#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
790	cmpl	$CPUCLASS_386,_cpu_class
791	jne	2f				/* we only have to set the right segment selector */
792#endif /* I486_CPU || I586_CPU || I686_CPU */
793
794	/* XXX - page boundary crossing is still not handled */
795	movl	%edx,%eax
796	shrl	$IDXSHIFT,%edx
797	andb	$0xfc,%dl
798	movb	_PTmap(%edx),%dl
799	andb	$0x7,%dl			/* must be VALID + USERACC + WRITE */
800	cmpb	$0x7,%dl
801	je	1f
802
803	/* simulate a trap */
804	pushl	%eax
805	call	_trapwrite
806	popl	%edx				/* remove junk parameter from stack */
807	movl	_curpcb,%ecx			/* restore trashed register */
808	testl	%eax,%eax
809	jnz	fusufault
8101:
811	movl	4(%esp),%edx
812#endif
813
8142:
815	cmpl	$VM_MAXUSER_ADDRESS-4,%edx	/* verify address validity */
816	ja	fusufault
817
818	movl	8(%esp),%eax
819	movl	%eax,(%edx)
820	xorl	%eax,%eax
821	movl	%eax,PCB_ONFAULT(%ecx)
822	ret
823
824ENTRY(susword)
825	movl	_curpcb,%ecx
826	movl	$fusufault,PCB_ONFAULT(%ecx)
827	movl	4(%esp),%edx
828
829#if defined(I386_CPU)
830
831#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
832	cmpl	$CPUCLASS_386,_cpu_class
833	jne	2f
834#endif /* I486_CPU || I586_CPU || I686_CPU */
835
836	/* XXX - page boundary crossing is still not handled */
837	movl	%edx,%eax
838	shrl	$IDXSHIFT,%edx
839	andb	$0xfc,%dl
840	movb	_PTmap(%edx),%dl
841	andb	$0x7,%dl			/* must be VALID + USERACC + WRITE */
842	cmpb	$0x7,%dl
843	je	1f
844
845	/* simulate a trap */
846	pushl	%eax
847	call	_trapwrite
848	popl	%edx				/* remove junk parameter from stack */
849	movl	_curpcb,%ecx			/* restore trashed register */
850	testl	%eax,%eax
851	jnz	fusufault
8521:
853	movl	4(%esp),%edx
854#endif
855
8562:
857	cmpl	$VM_MAXUSER_ADDRESS-2,%edx	/* verify address validity */
858	ja	fusufault
859
860	movw	8(%esp),%ax
861	movw	%ax,(%edx)
862	xorl	%eax,%eax
863	movl	%eax,PCB_ONFAULT(%ecx)
864	ret
865
866ALTENTRY(suibyte)
867ENTRY(subyte)
868	movl	_curpcb,%ecx
869	movl	$fusufault,PCB_ONFAULT(%ecx)
870	movl	4(%esp),%edx
871
872#if defined(I386_CPU)
873
874#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
875	cmpl	$CPUCLASS_386,_cpu_class
876	jne	2f
877#endif /* I486_CPU || I586_CPU || I686_CPU */
878
879	movl	%edx,%eax
880	shrl	$IDXSHIFT,%edx
881	andb	$0xfc,%dl
882	movb	_PTmap(%edx),%dl
883	andb	$0x7,%dl			/* must be VALID + USERACC + WRITE */
884	cmpb	$0x7,%dl
885	je	1f
886
887	/* simulate a trap */
888	pushl	%eax
889	call	_trapwrite
890	popl	%edx				/* remove junk parameter from stack */
891	movl	_curpcb,%ecx			/* restore trashed register */
892	testl	%eax,%eax
893	jnz	fusufault
8941:
895	movl	4(%esp),%edx
896#endif
897
8982:
899	cmpl	$VM_MAXUSER_ADDRESS-1,%edx	/* verify address validity */
900	ja	fusufault
901
902	movb	8(%esp),%al
903	movb	%al,(%edx)
904	xorl	%eax,%eax
905	movl	%eax,PCB_ONFAULT(%ecx)
906	ret
907
908/*
909 * copyinstr(from, to, maxlen, int *lencopied)
910 *	copy a string from from to to, stop when a 0 character is reached.
911 *	return ENAMETOOLONG if string is longer than maxlen, and
912 *	EFAULT on protection violations. If lencopied is non-zero,
913 *	return the actual length in *lencopied.
914 */
915ENTRY(copyinstr)
916	pushl	%esi
917	pushl	%edi
918	movl	_curpcb,%ecx
919	movl	$cpystrflt,PCB_ONFAULT(%ecx)
920
921	movl	12(%esp),%esi			/* %esi = from */
922	movl	16(%esp),%edi			/* %edi = to */
923	movl	20(%esp),%edx			/* %edx = maxlen */
924
925	movl	$VM_MAXUSER_ADDRESS,%eax
926
927	/* make sure 'from' is within bounds */
928	subl	%esi,%eax
929	jbe	cpystrflt
930
931	/* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
932	cmpl	%edx,%eax
933	jae	1f
934	movl	%eax,%edx
935	movl	%eax,20(%esp)
9361:
937	incl	%edx
938	cld
939
9402:
941	decl	%edx
942	jz	3f
943
944	lodsb
945	stosb
946	orb	%al,%al
947	jnz	2b
948
949	/* Success -- 0 byte reached */
950	decl	%edx
951	xorl	%eax,%eax
952	jmp	cpystrflt_x
9533:
954	/* edx is zero - return ENAMETOOLONG or EFAULT */
955	cmpl	$VM_MAXUSER_ADDRESS,%esi
956	jae	cpystrflt
9574:
958	movl	$ENAMETOOLONG,%eax
959	jmp	cpystrflt_x
960
961cpystrflt:
962	movl	$EFAULT,%eax
963
964cpystrflt_x:
965	/* set *lencopied and return %eax */
966	movl	_curpcb,%ecx
967	movl	$0,PCB_ONFAULT(%ecx)
968	movl	20(%esp),%ecx
969	subl	%edx,%ecx
970	movl	24(%esp),%edx
971	testl	%edx,%edx
972	jz	1f
973	movl	%ecx,(%edx)
9741:
975	popl	%edi
976	popl	%esi
977	ret
978
979
980/*
981 * copystr(from, to, maxlen, int *lencopied)
982 */
983ENTRY(copystr)
984	pushl	%esi
985	pushl	%edi
986
987	movl	12(%esp),%esi			/* %esi = from */
988	movl	16(%esp),%edi			/* %edi = to */
989	movl	20(%esp),%edx			/* %edx = maxlen */
990	incl	%edx
991	cld
9921:
993	decl	%edx
994	jz	4f
995	lodsb
996	stosb
997	orb	%al,%al
998	jnz	1b
999
1000	/* Success -- 0 byte reached */
1001	decl	%edx
1002	xorl	%eax,%eax
1003	jmp	6f
10044:
1005	/* edx is zero -- return ENAMETOOLONG */
1006	movl	$ENAMETOOLONG,%eax
1007
10086:
1009	/* set *lencopied and return %eax */
1010	movl	20(%esp),%ecx
1011	subl	%edx,%ecx
1012	movl	24(%esp),%edx
1013	testl	%edx,%edx
1014	jz	7f
1015	movl	%ecx,(%edx)
10167:
1017	popl	%edi
1018	popl	%esi
1019	ret
1020
1021ENTRY(bcmp)
1022	pushl	%edi
1023	pushl	%esi
1024	movl	12(%esp),%edi
1025	movl	16(%esp),%esi
1026	movl	20(%esp),%edx
1027	xorl	%eax,%eax
1028
1029	movl	%edx,%ecx
1030	shrl	$2,%ecx
1031	cld					/* compare forwards */
1032	repe
1033	cmpsl
1034	jne	1f
1035
1036	movl	%edx,%ecx
1037	andl	$3,%ecx
1038	repe
1039	cmpsb
1040	je	2f
10411:
1042	incl	%eax
10432:
1044	popl	%esi
1045	popl	%edi
1046	ret
1047
1048
1049/*
1050 * Handling of special 386 registers and descriptor tables etc
1051 */
1052/* void lgdt(struct region_descriptor *rdp); */
1053ENTRY(lgdt)
1054	/* reload the descriptor table */
1055	movl	4(%esp),%eax
1056	lgdt	(%eax)
1057
1058	/* flush the prefetch q */
1059	jmp	1f
1060	nop
10611:
1062	/* reload "stale" selectors */
1063	movl	$KDSEL,%eax
1064	movl	%ax,%ds
1065	movl	%ax,%es
1066	movl	%ax,%ss
1067
1068	/* reload code selector by turning return into intersegmental return */
1069	movl	(%esp),%eax
1070	pushl	%eax
1071#	movl	$KCSEL,4(%esp)
1072	movl	$8,4(%esp)
1073	lret
1074
1075/*
1076 * void lidt(struct region_descriptor *rdp);
1077 */
1078ENTRY(lidt)
1079	movl	4(%esp),%eax
1080	lidt	(%eax)
1081	ret
1082
1083/*
1084 * void lldt(u_short sel)
1085 */
1086ENTRY(lldt)
1087	lldt	4(%esp)
1088	ret
1089
1090/*
1091 * void ltr(u_short sel)
1092 */
1093ENTRY(ltr)
1094	ltr	4(%esp)
1095	ret
1096
1097/* ssdtosd(*ssdp,*sdp) */
1098ENTRY(ssdtosd)
1099	pushl	%ebx
1100	movl	8(%esp),%ecx
1101	movl	8(%ecx),%ebx
1102	shll	$16,%ebx
1103	movl	(%ecx),%edx
1104	roll	$16,%edx
1105	movb	%dh,%bl
1106	movb	%dl,%bh
1107	rorl	$8,%ebx
1108	movl	4(%ecx),%eax
1109	movw	%ax,%dx
1110	andl	$0xf0000,%eax
1111	orl	%eax,%ebx
1112	movl	12(%esp),%ecx
1113	movl	%edx,(%ecx)
1114	movl	%ebx,4(%ecx)
1115	popl	%ebx
1116	ret
1117
1118/* load_cr0(cr0) */
1119ENTRY(load_cr0)
1120	movl	4(%esp),%eax
1121	movl	%eax,%cr0
1122	ret
1123
1124/* rcr0() */
1125ENTRY(rcr0)
1126	movl	%cr0,%eax
1127	ret
1128
1129/* rcr3() */
1130ENTRY(rcr3)
1131	movl	%cr3,%eax
1132	ret
1133
1134/* void load_cr3(caddr_t cr3) */
1135ENTRY(load_cr3)
1136	movl	4(%esp),%eax
1137	movl	%eax,%cr3
1138	ret
1139
1140
1141/*****************************************************************************/
1142/* setjump, longjump                                                         */
1143/*****************************************************************************/
1144
1145ENTRY(setjmp)
1146	movl	4(%esp),%eax
1147	movl	%ebx,(%eax)			/* save ebx */
1148	movl	%esp,4(%eax)			/* save esp */
1149	movl	%ebp,8(%eax)			/* save ebp */
1150	movl	%esi,12(%eax)			/* save esi */
1151	movl	%edi,16(%eax)			/* save edi */
1152	movl	(%esp),%edx			/* get rta */
1153	movl	%edx,20(%eax)			/* save eip */
1154	xorl	%eax,%eax			/* return(0); */
1155	ret
1156
1157ENTRY(longjmp)
1158	movl	4(%esp),%eax
1159	movl	(%eax),%ebx			/* restore ebx */
1160	movl	4(%eax),%esp			/* restore esp */
1161	movl	8(%eax),%ebp			/* restore ebp */
1162	movl	12(%eax),%esi			/* restore esi */
1163	movl	16(%eax),%edi			/* restore edi */
1164	movl	20(%eax),%edx			/* get rta */
1165	movl	%edx,(%esp)			/* put in return frame */
1166	xorl	%eax,%eax			/* return(1); */
1167	incl	%eax
1168	ret
1169
1170/*
1171 * Here for doing BB-profiling (gcc -a).
1172 * We rely on the "bbset" instead, but need a dummy function.
1173 */
1174	.text
1175	.align 2
1176.globl	___bb_init_func
1177___bb_init_func:
1178        movl 4(%esp),%eax
1179        movl $1,(%eax)
1180        ret
1181