2 * Copyright (c) 1993 The Regents of the University of California.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
33 * $FreeBSD: src/sys/i386/i386/support.s,v 1.67.2.5 2001/08/15 01:23:50 peter Exp $
34 * $DragonFly: src/sys/platform/pc32/i386/support.s,v 1.13 2006/09/30 19:25:13 swildner Exp $
39 #include <machine/asmacros.h>
40 #include <machine/cputypes.h>
41 #include <machine/pmap.h>
42 #include <machine/specialreg.h>
52 .long asm_generic_memcpy
56 .long asm_generic_bcopy
68 .long asm_generic_bcopy
72 /* fillw(pat, base, cnt) */
85 * void bcopy(const void *s, void *d, size_t count)
87 * Normal bcopy() vector, an optimized bcopy may be installed in
93 movl 4+8(%esp),%esi /* caddr_t from */
94 movl 8+8(%esp),%edi /* caddr_t to */
95 movl 12+8(%esp),%ecx /* size_t len */
102 * Generic (integer-only) bcopy() vector.
107 movl 4+8(%esp),%esi /* caddr_t from */
108 movl 8+8(%esp),%edi /* caddr_t to */
109 movl 12+8(%esp),%ecx /* size_t len */
110 call asm_generic_bcopy
118 movl 4+8(%esp),%esi /* caddr_t from */
119 movl 8+8(%esp),%edi /* caddr_t to */
120 movl 12+8(%esp),%ecx /* size_t len */
127 * void *memcpy(void *d, const void *s, size_t count)
129 * Note: memcpy does not have to support overlapping copies.
131 * Note: (d, s) arguments reversed from bcopy, and memcpy() returns d
132 * while bcopy() returns void.
147 * A stack-based on-fault routine is used for more complex PCB_ONFAULT
148 * situations (such as memcpy/bcopy/bzero). In this case the on-fault
149 * routine must be pushed on the stack.
154 /*****************************************************************************/
155 /* copyout and fubyte family */
156 /*****************************************************************************/
158 * Access user memory from inside the kernel. These routines and possibly
159 * the math- and DOS emulators should be the only places that do this.
161 * We have to access the memory with user's permissions, so use a segment
162 * selector with RPL 3. For writes to user space we have to additionally
163 * check the PTE for write permission, because the 386 does not check
164 * write permissions when we are executing with EPL 0. The 486 does check
165 * this if the WP bit is set in CR0, so we can use a simpler version here.
167 * These routines set curpcb->onfault for the time they execute. When a
168 * protection violation occurs inside the functions, the trap handler
169 * returns to *curpcb->onfault instead of the function.
173 * copyout(from_kernel, to_user, len) - MP SAFE (if not I386_CPU)
176 movl PCPU(curthread),%eax
177 movl TD_PCB(%eax),%eax
181 pushl $copyout_fault2
182 movl $stack_onfault,PCB_ONFAULT(%eax)
185 movl 12+16(%esp),%ebx
186 testl %ebx,%ebx /* anything to do? */
190 * Check explicitly for non-user addresses. If 486 write protection
191 * is being used, this check is essential because we are in kernel
192 * mode so the h/w does not provide any protection against writing
197 * First, prevent address wrapping.
203 * XXX STOP USING VM_MAXUSER_ADDRESS.
204 * It is an end address, not a max, so every time it is used correctly it
205 * looks like there is an off by one error, and of course it caused an off
206 * by one error in several places.
208 cmpl $VM_MAXUSER_ADDRESS,%eax
211 #if defined(I386_CPU)
213 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
214 cmpl $CPUCLASS_386,cpu_class
218 * We have to check each PTE for user write permission.
219 * The checking may cause a page fault, so it is important to set
220 * up everything for return via copyout_fault before here.
222 /* compute number of pages */
227 shrl $IDXSHIFT+2,%ecx
230 /* compute PTE offset for start address */
236 /* check PTE for each page */
237 leal PTmap(%edx),%eax
240 testb $PG_V,PTmap(%eax) /* PTE page must be valid */
243 andb $PG_V|PG_RW|PG_U,%al /* page must be valid and user writable */
244 cmpb $PG_V|PG_RW|PG_U,%al
248 /* simulate a trap */
253 call trapwrite /* trapwrite(addr) */
258 testl %eax,%eax /* if not ok, return EFAULT */
264 jnz 1b /* check next page */
265 #endif /* I386_CPU */
268 * Convert copyout to memcpy_vector(dest:%edi, src:%esi, conut:%ecx)
279 movl PCPU(curthread),%edx
281 movl TD_PCB(%edx),%edx
285 movl %eax,PCB_ONFAULT(%edx)
290 addl $4,%esp /* skip pushed copyout_fault vector */
295 movl PCPU(curthread),%edx
296 movl TD_PCB(%edx),%edx
297 movl $0,PCB_ONFAULT(%edx)
302 * copyin(from_user, to_kernel, len) - MP SAFE
306 movl PCPU(curthread),%eax
307 movl TD_PCB(%eax),%eax
311 movl $stack_onfault,PCB_ONFAULT(%eax)
312 movl 4+12(%esp),%esi /* caddr_t from */
313 movl 8+12(%esp),%edi /* caddr_t to */
314 movl 12+12(%esp),%ecx /* size_t len */
317 * make sure address is valid
322 cmpl $VM_MAXUSER_ADDRESS,%edx
326 * Call memcpy(destination:%edi, source:%esi, bytes:%ecx)
331 * return 0 (no error)
334 movl PCPU(curthread),%edx
336 movl TD_PCB(%edx),%edx
339 movl %eax,PCB_ONFAULT(%edx)
347 addl $4,%esp /* skip pushed copyin_fault vector */
351 movl PCPU(curthread),%edx
352 movl TD_PCB(%edx),%edx
353 movl $0,PCB_ONFAULT(%edx)
358 * fu{byte,sword,word} - MP SAFE
360 * Fetch a byte (sword, word) from user memory
363 movl PCPU(curthread),%ecx
364 movl TD_PCB(%ecx),%ecx
365 movl $fusufault,PCB_ONFAULT(%ecx)
366 movl 4(%esp),%edx /* from */
368 cmpl $VM_MAXUSER_ADDRESS-4,%edx /* verify address is valid */
372 movl $0,PCB_ONFAULT(%ecx)
376 * These two routines are called from the profiling code, potentially
377 * at interrupt time. If they fail, that's okay, good things will
378 * happen later. Fail all the time for now - until the trap code is
379 * able to deal with this.
390 movl PCPU(curthread),%ecx
391 movl TD_PCB(%ecx),%ecx
392 movl $fusufault,PCB_ONFAULT(%ecx)
395 cmpl $VM_MAXUSER_ADDRESS-2,%edx
399 movl $0,PCB_ONFAULT(%ecx)
406 movl PCPU(curthread),%ecx
407 movl TD_PCB(%ecx),%ecx
408 movl $fusufault,PCB_ONFAULT(%ecx)
411 cmpl $VM_MAXUSER_ADDRESS-1,%edx
415 movl $0,PCB_ONFAULT(%ecx)
420 movl PCPU(curthread),%ecx
421 movl TD_PCB(%ecx),%ecx
423 movl %eax,PCB_ONFAULT(%ecx)
428 * su{byte,sword,word} - MP SAFE (if not I386_CPU)
430 * Write a byte (word, longword) to user memory
433 movl PCPU(curthread),%ecx
434 movl TD_PCB(%ecx),%ecx
435 movl $fusufault,PCB_ONFAULT(%ecx)
438 #if defined(I386_CPU)
440 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
441 cmpl $CPUCLASS_386,cpu_class
442 jne 2f /* we only have to set the right segment selector */
443 #endif /* I486_CPU || I586_CPU || I686_CPU */
445 /* XXX - page boundary crossing is still not handled */
450 leal PTmap(%edx),%ecx
453 testb $PG_V,PTmap(%ecx) /* PTE page must be valid */
456 andb $PG_V|PG_RW|PG_U,%dl /* page must be valid and user writable */
457 cmpb $PG_V|PG_RW|PG_U,%dl
461 /* simulate a trap */
464 popl %edx /* remove junk parameter from stack */
472 cmpl $VM_MAXUSER_ADDRESS-4,%edx /* verify address validity */
478 movl PCPU(curthread),%ecx
479 movl TD_PCB(%ecx),%ecx
480 movl %eax,PCB_ONFAULT(%ecx)
484 * susword - MP SAFE (if not I386_CPU)
487 movl PCPU(curthread),%ecx
488 movl TD_PCB(%ecx),%ecx
489 movl $fusufault,PCB_ONFAULT(%ecx)
492 #if defined(I386_CPU)
494 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
495 cmpl $CPUCLASS_386,cpu_class
497 #endif /* I486_CPU || I586_CPU || I686_CPU */
499 /* XXX - page boundary crossing is still not handled */
504 leal PTmap(%edx),%ecx
507 testb $PG_V,PTmap(%ecx) /* PTE page must be valid */
510 andb $PG_V|PG_RW|PG_U,%dl /* page must be valid and user writable */
511 cmpb $PG_V|PG_RW|PG_U,%dl
515 /* simulate a trap */
518 popl %edx /* remove junk parameter from stack */
526 cmpl $VM_MAXUSER_ADDRESS-2,%edx /* verify address validity */
532 movl PCPU(curthread),%ecx /* restore trashed register */
533 movl TD_PCB(%ecx),%ecx
534 movl %eax,PCB_ONFAULT(%ecx)
538 * su[i]byte - MP SAFE (if not I386_CPU)
542 movl PCPU(curthread),%ecx
543 movl TD_PCB(%ecx),%ecx
544 movl $fusufault,PCB_ONFAULT(%ecx)
547 #if defined(I386_CPU)
549 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
550 cmpl $CPUCLASS_386,cpu_class
552 #endif /* I486_CPU || I586_CPU || I686_CPU */
558 leal PTmap(%edx),%ecx
561 testb $PG_V,PTmap(%ecx) /* PTE page must be valid */
564 andb $PG_V|PG_RW|PG_U,%dl /* page must be valid and user writable */
565 cmpb $PG_V|PG_RW|PG_U,%dl
569 /* simulate a trap */
572 popl %edx /* remove junk parameter from stack */
580 cmpl $VM_MAXUSER_ADDRESS-1,%edx /* verify address validity */
586 movl PCPU(curthread),%ecx /* restore trashed register */
587 movl TD_PCB(%ecx),%ecx
588 movl %eax,PCB_ONFAULT(%ecx)
592 * copyinstr(from, to, maxlen, int *lencopied) - MP SAFE
594 * copy a string from from to to, stop when a 0 character is reached.
595 * return ENAMETOOLONG if string is longer than maxlen, and
596 * EFAULT on protection violations. If lencopied is non-zero,
597 * return the actual length in *lencopied.
602 movl PCPU(curthread),%ecx
603 movl TD_PCB(%ecx),%ecx
604 movl $cpystrflt,PCB_ONFAULT(%ecx)
606 movl 12(%esp),%esi /* %esi = from */
607 movl 16(%esp),%edi /* %edi = to */
608 movl 20(%esp),%edx /* %edx = maxlen */
610 movl $VM_MAXUSER_ADDRESS,%eax
612 /* make sure 'from' is within bounds */
616 /* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
634 /* Success -- 0 byte reached */
639 /* edx is zero - return ENAMETOOLONG or EFAULT */
640 cmpl $VM_MAXUSER_ADDRESS,%esi
643 movl $ENAMETOOLONG,%eax
650 /* set *lencopied and return %eax */
651 movl PCPU(curthread),%ecx
652 movl TD_PCB(%ecx),%ecx
653 movl $0,PCB_ONFAULT(%ecx)
667 * copystr(from, to, maxlen, int *lencopied) - MP SAFE
673 movl 12(%esp),%esi /* %esi = from */
674 movl 16(%esp),%edi /* %edi = to */
675 movl 20(%esp),%edx /* %edx = maxlen */
686 /* Success -- 0 byte reached */
691 /* edx is zero -- return ENAMETOOLONG */
692 movl $ENAMETOOLONG,%eax
695 /* set *lencopied and return %eax */
717 cld /* compare forwards */
736 * Handling of special 386 registers and descriptor tables etc
738 /* void lgdt(struct region_descriptor *rdp); */
740 /* reload the descriptor table */
744 /* flush the prefetch q */
748 /* reload "stale" selectors */
757 /* reload code selector by turning return into intersegmental return */
764 * void lidt(struct region_descriptor *rdp);
772 * void lldt(u_short sel)
779 * void ltr(u_short sel)
785 /* ssdtosd(*ssdp,*sdp) */
822 /* void load_cr3(caddr_t cr3) */
824 #if defined(SWTCH_OPTIM_STATS)
825 incl _tlb_flush_count
836 /* void load_cr4(caddr_t cr4) */
842 /* void reset_dbregs() */
845 movl %eax,%dr7 /* disable all breapoints first */
853 /*****************************************************************************/
854 /* setjump, longjump */
855 /*****************************************************************************/
859 movl %ebx,(%eax) /* save ebx */
860 movl %esp,4(%eax) /* save esp */
861 movl %ebp,8(%eax) /* save ebp */
862 movl %esi,12(%eax) /* save esi */
863 movl %edi,16(%eax) /* save edi */
864 movl (%esp),%edx /* get rta */
865 movl %edx,20(%eax) /* save eip */
866 xorl %eax,%eax /* return(0); */
871 movl (%eax),%ebx /* restore ebx */
872 movl 4(%eax),%esp /* restore esp */
873 movl 8(%eax),%ebp /* restore ebp */
874 movl 12(%eax),%esi /* restore esi */
875 movl 16(%eax),%edi /* restore edi */
876 movl 20(%eax),%edx /* get rta */
877 movl %edx,(%esp) /* put in return frame */
878 xorl %eax,%eax /* return(1); */
883 * Support for BB-profiling (gcc -a). The kernbb program will extract
884 * the data from the kernel.
894 NON_GPROF_ENTRY(__bb_init_func)
900 .byte 0xc3 /* avoid macro for `ret' */