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/i386/i386/Attic/support.s,v 1.10 2004/04/03 08:21:16 dillon Exp $
39 #include <machine/asmacros.h>
40 #include <machine/cputypes.h>
41 #include <machine/pmap.h>
42 #include <machine/specialreg.h>
64 #if defined(I586_CPU) && NNPX > 0
74 * void bzero(void *buf, u_int len)
99 * do 64 byte chunks first
101 * XXX this is probably over-unrolled at least for DX2's
158 * a jump table seems to be faster than a loop or more range reductions
160 * XXX need a const section for non-text
195 #if defined(I586_CPU) && NNPX > 0
201 * The FPU register method is twice as fast as the integer register
202 * method unless the target is in the L1 cache and we pre-allocate a
203 * cache line for it (then the integer register method is 4-5 times
204 * faster). However, we never pre-allocate cache lines, since that
205 * would make the integer method 25% or more slower for the common
206 * case when the target isn't in either the L1 cache or the L2 cache.
207 * Thus we normally use the FPU register method unless the overhead
208 * would be too large.
210 cmpl $256,%ecx /* empirical; clts, fninit, smsw cost a lot */
214 * The FPU registers may belong to an application or to fastmove()
215 * or to another invocation of bcopy() or ourself in a higher level
216 * interrupt or trap handler. Preserving the registers is
217 * complicated since we avoid it if possible at all levels. We
218 * want to localize the complications even when that increases them.
219 * Here the extra work involves preserving CR0_TS in TS.
220 * `npxthread != NULL' is supposed to be the condition that all the
221 * FPU resources belong to an application, but npxthread and CR0_TS
222 * aren't set atomically enough for this condition to work in
223 * interrupt handlers.
225 * Case 1: FPU registers belong to the application: we must preserve
226 * the registers if we use them, so we only use the FPU register
227 * method if the target size is large enough to amortize the extra
228 * overhead for preserving them. CR0_TS must be preserved although
229 * it is very likely to end up as set.
231 * Case 2: FPU registers belong to fastmove(): fastmove() currently
232 * makes the registers look like they belong to an application so
233 * that cpu_switch() and savectx() don't have to know about it, so
234 * this case reduces to case 1.
236 * Case 3: FPU registers belong to the kernel: don't use the FPU
237 * register method. This case is unlikely, and supporting it would
238 * be more complicated and might take too much stack.
240 * Case 4: FPU registers don't belong to anyone: the FPU registers
241 * don't need to be preserved, so we always use the FPU register
242 * method. CR0_TS must be preserved although it is very likely to
243 * always end up as clear.
245 cmpl $0,PCPU(npxthread)
247 cmpl $256+184,%ecx /* empirical; not quite 2*108 more */
249 sarb $1,kernel_fpu_lock
258 sarb $1,kernel_fpu_lock
262 fninit /* XXX should avoid needing this */
267 * Align to an 8 byte boundary (misalignment in the main loop would
268 * cost a factor of >= 2). Avoid jumps (at little cost if it is
269 * already aligned) by always zeroing 8 bytes and using the part up
270 * to the _next_ alignment position.
273 addl %edx,%ecx /* part of %ecx -= new_%edx - %edx */
279 * Similarly align `len' to a multiple of 8.
286 * This wouldn't be any faster if it were unrolled, since the loop
287 * control instructions are much faster than the fstl and/or done
288 * in parallel with it so their overhead is insignificant.
290 fpureg_i586_bzero_loop:
295 jae fpureg_i586_bzero_loop
297 cmpl $0,PCPU(npxthread)
302 movb $0xfe,kernel_fpu_lock
308 movb $0xfe,kernel_fpu_lock
313 * `rep stos' seems to be the best method in practice for small
314 * counts. Fancy methods usually take too long to start up due
315 * to cache and BTB misses.
335 #endif /* I586_CPU && NNPX > 0 */
387 /* fillw(pat, base, cnt) */
407 cmpl %ecx,%eax /* overlapping && src < dst? */
409 cld /* nope, copy forwards */
418 addl %ecx,%edi /* copy backwards. */
439 * generic_bcopy(src, dst, cnt)
440 * ws@tools.de (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
443 pushl %ebp /* debugging */
453 cmpl %ecx,%eax /* overlapping && src < dst? */
456 shrl $2,%ecx /* copy by 32-bit words */
457 cld /* nope, copy forwards */
461 andl $3,%ecx /* any bytes left? */
471 addl %ecx,%edi /* copy backwards */
475 andl $3,%ecx /* any fractional bytes? */
479 movl 24(%esp),%ecx /* copy remainder by 32-bit words */
491 #if defined(I586_CPU) && NNPX > 0
501 cmpl %ecx,%eax /* overlapping && src < dst? */
507 sarb $1,kernel_fpu_lock
509 cmpl $0,PCPU(npxthread)
520 fninit /* XXX should avoid needing this */
525 #define DCACHE_SIZE 8192
526 cmpl $(DCACHE_SIZE-512)/2,%ecx
528 movl $(DCACHE_SIZE-512)/2,%ecx
532 jb 5f /* XXX should prefetch if %ecx >= 32 */
553 large_i586_bcopy_loop:
574 jae large_i586_bcopy_loop
580 cmpl $0,PCPU(npxthread)
586 movb $0xfe,kernel_fpu_lock
589 * This is a duplicate of the main part of generic_bcopy. See the comments
590 * there. Jumping into generic_bcopy would cost a whole 0-1 cycles and
591 * would mess up high resolution profiling.
627 #endif /* I586_CPU && NNPX > 0 */
630 * Note: memcpy does not support overlapping copies
639 shrl $2,%ecx /* copy by 32-bit words */
640 cld /* nope, copy forwards */
644 andl $3,%ecx /* any bytes left? */
652 /*****************************************************************************/
653 /* copyout and fubyte family */
654 /*****************************************************************************/
656 * Access user memory from inside the kernel. These routines and possibly
657 * the math- and DOS emulators should be the only places that do this.
659 * We have to access the memory with user's permissions, so use a segment
660 * selector with RPL 3. For writes to user space we have to additionally
661 * check the PTE for write permission, because the 386 does not check
662 * write permissions when we are executing with EPL 0. The 486 does check
663 * this if the WP bit is set in CR0, so we can use a simpler version here.
665 * These routines set curpcb->onfault for the time they execute. When a
666 * protection violation occurs inside the functions, the trap handler
667 * returns to *curpcb->onfault instead of the function.
671 * copyout(from_kernel, to_user, len) - MP SAFE (if not I386_CPU)
677 ENTRY(generic_copyout)
678 movl PCPU(curthread),%eax
679 movl TD_PCB(%eax),%eax
680 movl $copyout_fault,PCB_ONFAULT(%eax)
687 testl %ebx,%ebx /* anything to do? */
691 * Check explicitly for non-user addresses. If 486 write protection
692 * is being used, this check is essential because we are in kernel
693 * mode so the h/w does not provide any protection against writing
698 * First, prevent address wrapping.
704 * XXX STOP USING VM_MAXUSER_ADDRESS.
705 * It is an end address, not a max, so every time it is used correctly it
706 * looks like there is an off by one error, and of course it caused an off
707 * by one error in several places.
709 cmpl $VM_MAXUSER_ADDRESS,%eax
712 #if defined(I386_CPU)
714 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
715 cmpl $CPUCLASS_386,cpu_class
719 * We have to check each PTE for user write permission.
720 * The checking may cause a page fault, so it is important to set
721 * up everything for return via copyout_fault before here.
723 /* compute number of pages */
728 shrl $IDXSHIFT+2,%ecx
731 /* compute PTE offset for start address */
737 /* check PTE for each page */
738 leal PTmap(%edx),%eax
741 testb $PG_V,PTmap(%eax) /* PTE page must be valid */
744 andb $PG_V|PG_RW|PG_U,%al /* page must be valid and user writable */
745 cmpb $PG_V|PG_RW|PG_U,%al
749 /* simulate a trap */
754 call trapwrite /* trapwrite(addr) */
759 testl %eax,%eax /* if not ok, return EFAULT */
765 jnz 1b /* check next page */
766 #endif /* I386_CPU */
768 /* bcopy(%esi, %edi, %ebx) */
772 #if defined(I586_CPU) && NNPX > 0
790 movl PCPU(curthread),%edx
791 movl TD_PCB(%edx),%edx
792 movl %eax,PCB_ONFAULT(%edx)
800 movl PCPU(curthread),%edx
801 movl TD_PCB(%edx),%edx
802 movl $0,PCB_ONFAULT(%edx)
806 #if defined(I586_CPU) && NNPX > 0
809 * Duplicated from generic_copyout. Could be done a bit better.
811 movl PCPU(curthread),%eax
812 movl TD_PCB(%eax),%eax
813 movl $copyout_fault,PCB_ONFAULT(%eax)
820 testl %ebx,%ebx /* anything to do? */
824 * Check explicitly for non-user addresses. If 486 write protection
825 * is being used, this check is essential because we are in kernel
826 * mode so the h/w does not provide any protection against writing
831 * First, prevent address wrapping.
837 * XXX STOP USING VM_MAXUSER_ADDRESS.
838 * It is an end address, not a max, so every time it is used correctly it
839 * looks like there is an off by one error, and of course it caused an off
840 * by one error in several places.
842 cmpl $VM_MAXUSER_ADDRESS,%eax
845 /* bcopy(%esi, %edi, %ebx) */
849 * End of duplicated code.
859 #endif /* I586_CPU && NNPX > 0 */
862 * copyin(from_user, to_kernel, len) - MP SAFE
868 ENTRY(generic_copyin)
869 movl PCPU(curthread),%eax
870 movl TD_PCB(%eax),%eax
871 movl $copyin_fault,PCB_ONFAULT(%eax)
874 movl 12(%esp),%esi /* caddr_t from */
875 movl 16(%esp),%edi /* caddr_t to */
876 movl 20(%esp),%ecx /* size_t len */
879 * make sure address is valid
884 cmpl $VM_MAXUSER_ADDRESS,%edx
887 #if defined(I586_CPU) && NNPX > 0
892 shrl $2,%ecx /* copy longword-wise */
897 andb $3,%cl /* copy remaining bytes */
901 #if defined(I586_CPU) && NNPX > 0
908 movl PCPU(curthread),%edx
909 movl TD_PCB(%edx),%edx
910 movl %eax,PCB_ONFAULT(%edx)
917 movl PCPU(curthread),%edx
918 movl TD_PCB(%edx),%edx
919 movl $0,PCB_ONFAULT(%edx)
923 #if defined(I586_CPU) && NNPX > 0
926 * Duplicated from generic_copyin. Could be done a bit better.
928 movl PCPU(curthread),%eax
929 movl TD_PCB(%eax),%eax
930 movl $copyin_fault,PCB_ONFAULT(%eax)
933 movl 12(%esp),%esi /* caddr_t from */
934 movl 16(%esp),%edi /* caddr_t to */
935 movl 20(%esp),%ecx /* size_t len */
938 * make sure address is valid
943 cmpl $VM_MAXUSER_ADDRESS,%edx
946 * End of duplicated code.
952 pushl %ebx /* XXX prepare for fastmove_fault */
957 #endif /* I586_CPU && NNPX > 0 */
959 #if defined(I586_CPU) && NNPX > 0
960 /* fastmove(src, dst, len)
963 len in %ecx XXX changed to on stack for profiling
964 uses %eax and %edx for tmp. storage
966 /* XXX use ENTRY() to get profiling. fastmove() is actually a non-entry. */
970 subl $PCB_SAVE87_SIZE+3*4,%esp
976 testl $7,%esi /* check if src addr is multiple of 8 */
979 testl $7,%edi /* check if dst addr is multiple of 8 */
982 /* if (npxthread != NULL) { */
983 cmpl $0,PCPU(npxthread)
985 /* fnsave(&curpcb->pcb_savefpu); */
986 movl PCPU(curthread),%eax
987 movl TD_PCB(%eax),%eax
988 fnsave PCB_SAVEFPU(%eax)
989 /* npxthread = NULL; */
990 movl $0,PCPU(npxthread)
993 /* now we own the FPU. */
996 * The process' FP state is saved in the pcb, but if we get
997 * switched, the cpu_switch() will store our FP state in the
998 * pcb. It should be possible to avoid all the copying for
999 * this, e.g., by setting a flag to tell cpu_switch() to
1000 * save the state somewhere else.
1002 /* tmp = curpcb->pcb_savefpu; */
1007 movl PCPU(curthread),%esi
1008 movl TD_PCB(%esi),%esi
1009 addl $PCB_SAVEFPU,%esi
1011 movl $PCB_SAVE87_SIZE>>2,%ecx
1017 /* stop_emulating(); */
1019 /* npxthread = curthread; */
1020 movl PCPU(curthread),%eax
1021 movl %eax,PCPU(npxthread)
1022 movl PCPU(curthread),%eax
1023 movl TD_PCB(%eax),%eax
1024 movl $fastmove_fault,PCB_ONFAULT(%eax)
1081 /* curpcb->pcb_savefpu = tmp; */
1085 movl PCPU(curthread),%edi
1086 movl TD_PCB(%edi),%edi
1087 addl $PCB_SAVEFPU,%edi
1090 movl $PCB_SAVE87_SIZE>>2,%ecx
1097 /* start_emulating(); */
1101 /* npxthread = NULL; */
1102 movl $0,PCPU(npxthread)
1106 movl PCPU(curthread),%eax
1107 movl TD_PCB(%eax),%eax
1108 movl $fastmove_tail_fault,PCB_ONFAULT(%eax)
1111 shrl $2,%ecx /* copy longword-wise */
1116 andb $3,%cl /* copy remaining bytes */
1126 movl PCPU(curthread),%edi
1127 movl TD_PCB(%edi),%edi
1128 addl $PCB_SAVEFPU,%edi
1131 movl $PCB_SAVE87_SIZE>>2,%ecx
1138 movl $0,PCPU(npxthread)
1140 fastmove_tail_fault:
1147 movl PCPU(curthread),%edx
1148 movl TD_PCB(%edx),%edx
1149 movl $0,PCB_ONFAULT(%edx)
1152 #endif /* I586_CPU && NNPX > 0 */
1155 * fu{byte,sword,word} - MP SAFE
1157 * Fetch a byte (sword, word) from user memory
1160 movl PCPU(curthread),%ecx
1161 movl TD_PCB(%ecx),%ecx
1162 movl $fusufault,PCB_ONFAULT(%ecx)
1163 movl 4(%esp),%edx /* from */
1165 cmpl $VM_MAXUSER_ADDRESS-4,%edx /* verify address is valid */
1169 movl $0,PCB_ONFAULT(%ecx)
1173 * These two routines are called from the profiling code, potentially
1174 * at interrupt time. If they fail, that's okay, good things will
1175 * happen later. Fail all the time for now - until the trap code is
1176 * able to deal with this.
1187 movl PCPU(curthread),%ecx
1188 movl TD_PCB(%ecx),%ecx
1189 movl $fusufault,PCB_ONFAULT(%ecx)
1192 cmpl $VM_MAXUSER_ADDRESS-2,%edx
1196 movl $0,PCB_ONFAULT(%ecx)
1203 movl PCPU(curthread),%ecx
1204 movl TD_PCB(%ecx),%ecx
1205 movl $fusufault,PCB_ONFAULT(%ecx)
1208 cmpl $VM_MAXUSER_ADDRESS-1,%edx
1212 movl $0,PCB_ONFAULT(%ecx)
1217 movl PCPU(curthread),%ecx
1218 movl TD_PCB(%ecx),%ecx
1220 movl %eax,PCB_ONFAULT(%ecx)
1225 * su{byte,sword,word} - MP SAFE (if not I386_CPU)
1227 * Write a byte (word, longword) to user memory
1230 movl PCPU(curthread),%ecx
1231 movl TD_PCB(%ecx),%ecx
1232 movl $fusufault,PCB_ONFAULT(%ecx)
1235 #if defined(I386_CPU)
1237 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
1238 cmpl $CPUCLASS_386,cpu_class
1239 jne 2f /* we only have to set the right segment selector */
1240 #endif /* I486_CPU || I586_CPU || I686_CPU */
1242 /* XXX - page boundary crossing is still not handled */
1247 leal PTmap(%edx),%ecx
1250 testb $PG_V,PTmap(%ecx) /* PTE page must be valid */
1252 movb PTmap(%edx),%dl
1253 andb $PG_V|PG_RW|PG_U,%dl /* page must be valid and user writable */
1254 cmpb $PG_V|PG_RW|PG_U,%dl
1258 /* simulate a trap */
1261 popl %edx /* remove junk parameter from stack */
1269 cmpl $VM_MAXUSER_ADDRESS-4,%edx /* verify address validity */
1275 movl PCPU(curthread),%ecx
1276 movl TD_PCB(%ecx),%ecx
1277 movl %eax,PCB_ONFAULT(%ecx)
1281 * susword - MP SAFE (if not I386_CPU)
1284 movl PCPU(curthread),%ecx
1285 movl TD_PCB(%ecx),%ecx
1286 movl $fusufault,PCB_ONFAULT(%ecx)
1289 #if defined(I386_CPU)
1291 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
1292 cmpl $CPUCLASS_386,cpu_class
1294 #endif /* I486_CPU || I586_CPU || I686_CPU */
1296 /* XXX - page boundary crossing is still not handled */
1301 leal PTmap(%edx),%ecx
1304 testb $PG_V,PTmap(%ecx) /* PTE page must be valid */
1306 movb PTmap(%edx),%dl
1307 andb $PG_V|PG_RW|PG_U,%dl /* page must be valid and user writable */
1308 cmpb $PG_V|PG_RW|PG_U,%dl
1312 /* simulate a trap */
1315 popl %edx /* remove junk parameter from stack */
1323 cmpl $VM_MAXUSER_ADDRESS-2,%edx /* verify address validity */
1329 movl PCPU(curthread),%ecx /* restore trashed register */
1330 movl TD_PCB(%ecx),%ecx
1331 movl %eax,PCB_ONFAULT(%ecx)
1335 * su[i]byte - MP SAFE (if not I386_CPU)
1339 movl PCPU(curthread),%ecx
1340 movl TD_PCB(%ecx),%ecx
1341 movl $fusufault,PCB_ONFAULT(%ecx)
1344 #if defined(I386_CPU)
1346 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
1347 cmpl $CPUCLASS_386,cpu_class
1349 #endif /* I486_CPU || I586_CPU || I686_CPU */
1355 leal PTmap(%edx),%ecx
1358 testb $PG_V,PTmap(%ecx) /* PTE page must be valid */
1360 movb PTmap(%edx),%dl
1361 andb $PG_V|PG_RW|PG_U,%dl /* page must be valid and user writable */
1362 cmpb $PG_V|PG_RW|PG_U,%dl
1366 /* simulate a trap */
1369 popl %edx /* remove junk parameter from stack */
1377 cmpl $VM_MAXUSER_ADDRESS-1,%edx /* verify address validity */
1383 movl PCPU(curthread),%ecx /* restore trashed register */
1384 movl TD_PCB(%ecx),%ecx
1385 movl %eax,PCB_ONFAULT(%ecx)
1389 * copyinstr(from, to, maxlen, int *lencopied) - MP SAFE
1391 * copy a string from from to to, stop when a 0 character is reached.
1392 * return ENAMETOOLONG if string is longer than maxlen, and
1393 * EFAULT on protection violations. If lencopied is non-zero,
1394 * return the actual length in *lencopied.
1399 movl PCPU(curthread),%ecx
1400 movl TD_PCB(%ecx),%ecx
1401 movl $cpystrflt,PCB_ONFAULT(%ecx)
1403 movl 12(%esp),%esi /* %esi = from */
1404 movl 16(%esp),%edi /* %edi = to */
1405 movl 20(%esp),%edx /* %edx = maxlen */
1407 movl $VM_MAXUSER_ADDRESS,%eax
1409 /* make sure 'from' is within bounds */
1413 /* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
1431 /* Success -- 0 byte reached */
1436 /* edx is zero - return ENAMETOOLONG or EFAULT */
1437 cmpl $VM_MAXUSER_ADDRESS,%esi
1440 movl $ENAMETOOLONG,%eax
1447 /* set *lencopied and return %eax */
1448 movl PCPU(curthread),%ecx
1449 movl TD_PCB(%ecx),%ecx
1450 movl $0,PCB_ONFAULT(%ecx)
1464 * copystr(from, to, maxlen, int *lencopied) - MP SAFE
1470 movl 12(%esp),%esi /* %esi = from */
1471 movl 16(%esp),%edi /* %edi = to */
1472 movl 20(%esp),%edx /* %edx = maxlen */
1483 /* Success -- 0 byte reached */
1488 /* edx is zero -- return ENAMETOOLONG */
1489 movl $ENAMETOOLONG,%eax
1492 /* set *lencopied and return %eax */
1514 cld /* compare forwards */
1533 * Handling of special 386 registers and descriptor tables etc
1535 /* void lgdt(struct region_descriptor *rdp); */
1537 /* reload the descriptor table */
1541 /* flush the prefetch q */
1545 /* reload "stale" selectors */
1554 /* reload code selector by turning return into intersegmental return */
1561 * void lidt(struct region_descriptor *rdp);
1569 * void lldt(u_short sel)
1576 * void ltr(u_short sel)
1582 /* ssdtosd(*ssdp,*sdp) */
1619 /* void load_cr3(caddr_t cr3) */
1621 #if defined(SWTCH_OPTIM_STATS)
1622 incl _tlb_flush_count
1633 /* void load_cr4(caddr_t cr4) */
1639 /* void reset_dbregs() */
1642 movl %eax,%dr7 /* disable all breapoints first */
1650 /*****************************************************************************/
1651 /* setjump, longjump */
1652 /*****************************************************************************/
1656 movl %ebx,(%eax) /* save ebx */
1657 movl %esp,4(%eax) /* save esp */
1658 movl %ebp,8(%eax) /* save ebp */
1659 movl %esi,12(%eax) /* save esi */
1660 movl %edi,16(%eax) /* save edi */
1661 movl (%esp),%edx /* get rta */
1662 movl %edx,20(%eax) /* save eip */
1663 xorl %eax,%eax /* return(0); */
1668 movl (%eax),%ebx /* restore ebx */
1669 movl 4(%eax),%esp /* restore esp */
1670 movl 8(%eax),%ebp /* restore ebp */
1671 movl 12(%eax),%esi /* restore esi */
1672 movl 16(%eax),%edi /* restore edi */
1673 movl 20(%eax),%edx /* get rta */
1674 movl %edx,(%esp) /* put in return frame */
1675 xorl %eax,%eax /* return(1); */
1680 * Support for BB-profiling (gcc -a). The kernbb program will extract
1681 * the data from the kernel.
1691 NON_GPROF_ENTRY(__bb_init_func)
1697 .byte 0xc3 /* avoid macro for `ret' */