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 $
36 #include <machine/asmacros.h>
37 #include <machine/cputypes.h>
38 #include <machine/pmap.h>
39 #include <machine/specialreg.h>
49 .long asm_generic_memcpy
53 .long asm_generic_bcopy
57 .long asm_generic_bcopy
61 /* fillw(pat, base, cnt) */
74 * void bcopy(const void *s, void *d, size_t count)
76 * Normal bcopy() vector, an optimized bcopy may be installed in
82 movl 4+8(%esp),%esi /* caddr_t from */
83 movl 8+8(%esp),%edi /* caddr_t to */
84 movl 12+8(%esp),%ecx /* size_t len */
91 * Generic (integer-only) bcopy() vector.
96 movl 4+8(%esp),%esi /* caddr_t from */
97 movl 8+8(%esp),%edi /* caddr_t to */
98 movl 12+8(%esp),%ecx /* size_t len */
99 call asm_generic_bcopy
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 */
116 * void *memcpy(void *d, const void *s, size_t count)
118 * Note: memcpy does not have to support overlapping copies.
120 * Note: (d, s) arguments reversed from bcopy, and memcpy() returns d
121 * while bcopy() returns void.
136 * A stack-based on-fault routine is used for more complex PCB_ONFAULT
137 * situations (such as memcpy/bcopy/bzero). In this case the on-fault
138 * routine must be pushed on the stack.
143 /*****************************************************************************/
144 /* copyout and fubyte family */
145 /*****************************************************************************/
147 * Access user memory from inside the kernel. These routines and possibly
148 * the math- and DOS emulators should be the only places that do this.
150 * We have to access the memory with user's permissions, so use a segment
151 * selector with RPL 3. For writes to user space we have to additionally
152 * check the PTE for write permission, because the 386 does not check
153 * write permissions when we are executing with EPL 0. The 486 does check
154 * this if the WP bit is set in CR0, so we can use a simpler version here.
156 * These routines set curpcb->onfault for the time they execute. When a
157 * protection violation occurs inside the functions, the trap handler
158 * returns to *curpcb->onfault instead of the function.
162 * copyout(from_kernel, to_user, len) - MP SAFE
165 movl PCPU(curthread),%eax
166 movl TD_PCB(%eax),%eax
170 pushl $copyout_fault2
171 movl $stack_onfault,PCB_ONFAULT(%eax)
172 movl %esp,PCB_ONFAULT_SP(%eax)
173 subl $12,PCB_ONFAULT_SP(%eax) /* call,ebx,stackedfault */
174 /* for *memcpy_vector */
177 movl 12+16(%esp),%ebx
178 testl %ebx,%ebx /* anything to do? */
182 * Check explicitly for non-user addresses. If 486 write protection
183 * is being used, this check is essential because we are in kernel
184 * mode so the h/w does not provide any protection against writing
189 * First, prevent address wrapping.
195 * XXX STOP USING VM_MAX_USER_ADDRESS.
196 * It is an end address, not a max, so every time it is used correctly it
197 * looks like there is an off by one error, and of course it caused an off
198 * by one error in several places.
200 cmpl $VM_MAX_USER_ADDRESS,%eax
204 * Convert copyout to memcpy_vector(dest:%edi, src:%esi, count:%ecx)
214 movl PCPU(curthread),%edx
216 movl TD_PCB(%edx),%edx
220 movl %eax,PCB_ONFAULT(%edx)
225 addl $4,%esp /* skip pushed copyout_fault vector */
230 movl PCPU(curthread),%edx
231 movl TD_PCB(%edx),%edx
232 movl $0,PCB_ONFAULT(%edx)
237 * copyin(from_user, to_kernel, len) - MP SAFE
241 movl PCPU(curthread),%eax
242 movl TD_PCB(%eax),%eax
246 movl $stack_onfault,PCB_ONFAULT(%eax)
247 movl %esp,PCB_ONFAULT_SP(%eax)
248 subl $12,PCB_ONFAULT_SP(%eax) /* call,ebx,stackedfault */
249 /* for *memcpy_vector */
250 movl 4+12(%esp),%esi /* caddr_t from */
251 movl 8+12(%esp),%edi /* caddr_t to */
252 movl 12+12(%esp),%ecx /* size_t len */
255 * make sure address is valid
260 cmpl $VM_MAX_USER_ADDRESS,%edx
264 * Call memcpy(destination:%edi, source:%esi, bytes:%ecx)
269 * return 0 (no error)
272 movl PCPU(curthread),%edx
274 movl TD_PCB(%edx),%edx
277 movl %eax,PCB_ONFAULT(%edx)
285 addl $4,%esp /* skip pushed copyin_fault vector */
289 movl PCPU(curthread),%edx
290 movl TD_PCB(%edx),%edx
291 movl $0,PCB_ONFAULT(%edx)
296 * casuword. Compare and set user word. Returns -1 or the current value.
300 movl PCPU(curthread),%ecx
301 movl TD_PCB(%ecx),%ecx
302 movl $fusufault,PCB_ONFAULT(%ecx)
303 movl %esp,PCB_ONFAULT_SP(%ecx)
304 movl 4(%esp),%edx /* dst */
305 movl 8(%esp),%eax /* old */
306 movl 12(%esp),%ecx /* new */
308 cmpl $VM_MAX_USER_ADDRESS-4,%edx /* verify address is valid */
312 cmpxchgl %ecx,(%edx) /* Compare and set. */
315 * The old value is in %eax. If the store succeeded it will be the
316 * value we expected (old) from before the store, otherwise it will
317 * be the current value.
320 movl PCPU(curthread),%ecx
321 movl TD_PCB(%ecx),%ecx
322 movl $0,PCB_ONFAULT(%ecx)
327 * fu{byte,sword,word} - MP SAFE
329 * Fetch a byte (sword, word) from user memory
332 movl PCPU(curthread),%ecx
333 movl TD_PCB(%ecx),%ecx
334 movl $fusufault,PCB_ONFAULT(%ecx)
335 movl %esp,PCB_ONFAULT_SP(%ecx)
336 movl 4(%esp),%edx /* from */
338 cmpl $VM_MAX_USER_ADDRESS-4,%edx /* verify address is valid */
342 movl $0,PCB_ONFAULT(%ecx)
349 movl PCPU(curthread),%ecx
350 movl TD_PCB(%ecx),%ecx
351 movl $fusufault,PCB_ONFAULT(%ecx)
352 movl %esp,PCB_ONFAULT_SP(%ecx)
355 cmpl $VM_MAX_USER_ADDRESS-2,%edx
359 movl $0,PCB_ONFAULT(%ecx)
366 movl PCPU(curthread),%ecx
367 movl TD_PCB(%ecx),%ecx
368 movl $fusufault,PCB_ONFAULT(%ecx)
369 movl %esp,PCB_ONFAULT_SP(%ecx)
372 cmpl $VM_MAX_USER_ADDRESS-1,%edx
376 movl $0,PCB_ONFAULT(%ecx)
381 movl PCPU(curthread),%ecx
382 movl TD_PCB(%ecx),%ecx
384 movl %eax,PCB_ONFAULT(%ecx)
389 * su{byte,sword,word,word32} - MP SAFE
391 * Write a long to user memory
394 movl PCPU(curthread),%ecx
395 movl TD_PCB(%ecx),%ecx
396 movl $fusufault,PCB_ONFAULT(%ecx)
397 movl %esp,PCB_ONFAULT_SP(%ecx)
400 cmpl $VM_MAX_USER_ADDRESS-4,%edx /* verify address validity */
406 movl PCPU(curthread),%ecx
407 movl TD_PCB(%ecx),%ecx
408 movl %eax,PCB_ONFAULT(%ecx)
412 * Write an integer to user memory
415 movl PCPU(curthread),%ecx
416 movl TD_PCB(%ecx),%ecx
417 movl $fusufault,PCB_ONFAULT(%ecx)
418 movl %esp,PCB_ONFAULT_SP(%ecx)
421 cmpl $VM_MAX_USER_ADDRESS-4,%edx /* verify address validity */
427 movl PCPU(curthread),%ecx
428 movl TD_PCB(%ecx),%ecx
429 movl %eax,PCB_ONFAULT(%ecx)
436 movl PCPU(curthread),%ecx
437 movl TD_PCB(%ecx),%ecx
438 movl $fusufault,PCB_ONFAULT(%ecx)
439 movl %esp,PCB_ONFAULT_SP(%ecx)
442 cmpl $VM_MAX_USER_ADDRESS-2,%edx /* verify address validity */
448 movl PCPU(curthread),%ecx /* restore trashed register */
449 movl TD_PCB(%ecx),%ecx
450 movl %eax,PCB_ONFAULT(%ecx)
457 movl PCPU(curthread),%ecx
458 movl TD_PCB(%ecx),%ecx
459 movl $fusufault,PCB_ONFAULT(%ecx)
460 movl %esp,PCB_ONFAULT_SP(%ecx)
463 cmpl $VM_MAX_USER_ADDRESS-1,%edx /* verify address validity */
469 movl PCPU(curthread),%ecx /* restore trashed register */
470 movl TD_PCB(%ecx),%ecx
471 movl %eax,PCB_ONFAULT(%ecx)
475 * copyinstr(from, to, maxlen, int *lencopied) - MP SAFE
477 * copy a string from from to to, stop when a 0 character is reached.
478 * return ENAMETOOLONG if string is longer than maxlen, and
479 * EFAULT on protection violations. If lencopied is non-zero,
480 * return the actual length in *lencopied.
485 movl PCPU(curthread),%ecx
486 movl TD_PCB(%ecx),%ecx
487 movl $cpystrflt,PCB_ONFAULT(%ecx)
488 movl %esp,PCB_ONFAULT_SP(%ecx)
490 movl 12(%esp),%esi /* %esi = from */
491 movl 16(%esp),%edi /* %edi = to */
492 movl 20(%esp),%edx /* %edx = maxlen */
494 movl $VM_MAX_USER_ADDRESS,%eax
496 /* make sure 'from' is within bounds */
500 /* restrict maxlen to <= VM_MAX_USER_ADDRESS-from */
518 /* Success -- 0 byte reached */
523 /* edx is zero - return ENAMETOOLONG or EFAULT */
524 cmpl $VM_MAX_USER_ADDRESS,%esi
527 movl $ENAMETOOLONG,%eax
534 /* set *lencopied and return %eax */
535 movl PCPU(curthread),%ecx
536 movl TD_PCB(%ecx),%ecx
537 movl $0,PCB_ONFAULT(%ecx)
551 * copystr(from, to, maxlen, int *lencopied) - MP SAFE
557 movl 12(%esp),%esi /* %esi = from */
558 movl 16(%esp),%edi /* %edi = to */
559 movl 20(%esp),%edx /* %edx = maxlen */
570 /* Success -- 0 byte reached */
575 /* edx is zero -- return ENAMETOOLONG */
576 movl $ENAMETOOLONG,%eax
579 /* set *lencopied and return %eax */
601 cld /* compare forwards */
620 * Handling of special 386 registers and descriptor tables etc
622 /* void lgdt(struct region_descriptor *rdp); */
624 /* reload the descriptor table */
628 /* flush the prefetch q */
632 /* reload "stale" selectors */
642 /* reload code selector by turning return into intersegmental return */
649 * void lidt(struct region_descriptor *rdp);
657 * void lldt(u_short sel)
664 * void ltr(u_short sel)
670 /* ssdtosd(*ssdp,*sdp) */
707 /* void load_cr3(caddr_t cr3) */
709 #if defined(SWTCH_OPTIM_STATS)
710 incl _tlb_flush_count
721 /* void load_cr4(caddr_t cr4) */
727 /* void reset_dbregs() */
730 movl %eax,%dr7 /* disable all breapoints first */
738 /*****************************************************************************/
739 /* setjump, longjump */
740 /*****************************************************************************/
744 movl %ebx,(%eax) /* save ebx */
745 movl %esp,4(%eax) /* save esp */
746 movl %ebp,8(%eax) /* save ebp */
747 movl %esi,12(%eax) /* save esi */
748 movl %edi,16(%eax) /* save edi */
749 movl (%esp),%edx /* get rta */
750 movl %edx,20(%eax) /* save eip */
751 xorl %eax,%eax /* return(0); */
756 movl (%eax),%ebx /* restore ebx */
757 movl 4(%eax),%esp /* restore esp */
758 movl 8(%eax),%ebp /* restore ebp */
759 movl 12(%eax),%esi /* restore esi */
760 movl 16(%eax),%edi /* restore edi */
761 movl 20(%eax),%edx /* get rta */
762 movl %edx,(%esp) /* put in return frame */
763 xorl %eax,%eax /* return(1); */
768 * Support for reading MSRs in the safe manner.
771 /* int rdmsr_safe(u_int msr, uint64_t *data) */
772 movl PCPU(curthread),%ecx
773 movl TD_PCB(%ecx), %ecx
774 movl $msr_onfault,PCB_ONFAULT(%ecx)
775 movl %esp,PCB_ONFAULT_SP(%ecx)
784 movl PCPU(curthread),%ecx
785 movl TD_PCB(%ecx), %ecx
786 movl %eax,PCB_ONFAULT(%ecx)
791 * MSR operations fault handler
795 movl PCPU(curthread),%ecx
796 movl TD_PCB(%ecx), %ecx
797 movl $0,PCB_ONFAULT(%ecx)
802 * Support for BB-profiling (gcc -a). The kernbb program will extract
803 * the data from the kernel.
813 NON_GPROF_ENTRY(__bb_init_func)
819 .byte 0xc3 /* avoid macro for `ret' */