Merge branch 'vendor/TEXINFO'
[dragonfly.git] / sys / platform / pc32 / i386 / support.s
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  * $FreeBSD: src/sys/i386/i386/support.s,v 1.67.2.5 2001/08/15 01:23:50 peter Exp $
34  */
35
36 #include <machine/asmacros.h>
37 #include <machine/cputypes.h>
38 #include <machine/pmap.h>
39 #include <machine/specialreg.h>
40
41 #include "assym.s"
42
43 #define IDXSHIFT        10
44
45         .data
46
47         .globl  memcpy_vector
48 memcpy_vector:
49         .long   asm_generic_memcpy
50
51         .globl  bcopy_vector
52 bcopy_vector:
53         .long   asm_generic_bcopy
54
55         .globl  ovbcopy_vector
56 ovbcopy_vector:
57         .long   asm_generic_bcopy
58
59         .text
60
61 /* fillw(pat, base, cnt) */
62 ENTRY(fillw)
63         pushl   %edi
64         movl    8(%esp),%eax
65         movl    12(%esp),%edi
66         movl    16(%esp),%ecx
67         cld
68         rep
69         stosw
70         popl    %edi
71         ret
72
73 /*
74  * void bcopy(const void *s, void *d, size_t count)
75  *
76  * Normal bcopy() vector, an optimized bcopy may be installed in
77  * bcopy_vector.
78  */
79 ENTRY(bcopy)
80         pushl   %esi
81         pushl   %edi
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 */
85         call    *bcopy_vector
86         popl    %edi
87         popl    %esi
88         ret
89
90 /*
91  * Generic (integer-only) bcopy() vector.
92  */
93 ENTRY(generic_bcopy)
94         pushl   %esi
95         pushl   %edi
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
100         popl    %edi
101         popl    %esi
102         ret
103
104 ENTRY(ovbcopy)
105         pushl   %esi
106         pushl   %edi
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    *ovbcopy_vector
111         popl    %edi
112         popl    %esi
113         ret
114
115 /*
116  * void *memcpy(void *d, const void *s, size_t count)
117  *
118  * Note: memcpy does not have to support overlapping copies.
119  *
120  * Note: (d, s) arguments reversed from bcopy, and memcpy() returns d
121  * while bcopy() returns void.
122  */
123 ENTRY(memcpy)
124         pushl   %esi
125         pushl   %edi
126         movl    4+8(%esp),%edi
127         movl    8+8(%esp),%esi
128         movl    12+8(%esp),%ecx
129         call    *memcpy_vector
130         movl    4+8(%esp),%eax
131         popl    %edi
132         popl    %esi
133         ret
134
135 /*
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.
139  */
140 stack_onfault:
141         ret
142
143 /*****************************************************************************/
144 /* copyout and fubyte family                                                 */
145 /*****************************************************************************/
146 /*
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.
149  *
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.
155  *
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.
159  */
160
161 /*
162  * copyout(from_kernel, to_user, len)  - MP SAFE
163  */
164 ENTRY(copyout)
165         movl    PCPU(curthread),%eax
166         movl    TD_PCB(%eax),%eax
167         pushl   %esi
168         pushl   %edi
169         pushl   %ebx
170         pushl   $copyout_fault2
171         movl    $stack_onfault,PCB_ONFAULT(%eax)
172         movl    4+16(%esp),%esi
173         movl    8+16(%esp),%edi
174         movl    12+16(%esp),%ebx
175         testl   %ebx,%ebx                       /* anything to do? */
176         jz      done_copyout
177
178         /*
179          * Check explicitly for non-user addresses.  If 486 write protection
180          * is being used, this check is essential because we are in kernel
181          * mode so the h/w does not provide any protection against writing
182          * kernel addresses.
183          */
184
185         /*
186          * First, prevent address wrapping.
187          */
188         movl    %edi,%eax
189         addl    %ebx,%eax
190         jc      copyout_fault1
191 /*
192  * XXX STOP USING VM_MAX_USER_ADDRESS.
193  * It is an end address, not a max, so every time it is used correctly it
194  * looks like there is an off by one error, and of course it caused an off
195  * by one error in several places.
196  */
197         cmpl    $VM_MAX_USER_ADDRESS,%eax
198         ja      copyout_fault1
199
200         /*
201          * Convert copyout to memcpy_vector(dest:%edi, src:%esi, count:%ecx)
202          */
203         movl    %ebx,%ecx
204         call    *memcpy_vector
205
206 done_copyout:
207         /*
208          * non-error return
209          */
210         addl    $4,%esp
211         movl    PCPU(curthread),%edx
212         xorl    %eax,%eax
213         movl    TD_PCB(%edx),%edx
214         popl    %ebx
215         popl    %edi
216         popl    %esi
217         movl    %eax,PCB_ONFAULT(%edx)
218         ret
219
220         ALIGN_TEXT
221 copyout_fault1:
222         addl    $4,%esp         /* skip pushed copyout_fault vector */
223 copyout_fault2:
224         popl    %ebx
225         popl    %edi
226         popl    %esi
227         movl    PCPU(curthread),%edx
228         movl    TD_PCB(%edx),%edx
229         movl    $0,PCB_ONFAULT(%edx)
230         movl    $EFAULT,%eax
231         ret
232
233 /*
234  * copyin(from_user, to_kernel, len) - MP SAFE
235  */
236
237 ENTRY(copyin)
238         movl    PCPU(curthread),%eax
239         movl    TD_PCB(%eax),%eax
240         pushl   %esi
241         pushl   %edi
242         pushl   $copyin_fault2
243         movl    $stack_onfault,PCB_ONFAULT(%eax)
244         movl    4+12(%esp),%esi                 /* caddr_t from */
245         movl    8+12(%esp),%edi                 /* caddr_t to */
246         movl    12+12(%esp),%ecx                /* size_t  len */
247
248         /*
249          * make sure address is valid
250          */
251         movl    %esi,%edx
252         addl    %ecx,%edx
253         jc      copyin_fault1
254         cmpl    $VM_MAX_USER_ADDRESS,%edx
255         ja      copyin_fault1
256
257         /*
258          * Call memcpy(destination:%edi, source:%esi, bytes:%ecx)
259          */
260         call    *memcpy_vector
261
262         /*
263          * return 0 (no error)
264          */
265         addl    $4,%esp
266         movl    PCPU(curthread),%edx
267         xorl    %eax,%eax
268         movl    TD_PCB(%edx),%edx
269         popl    %edi
270         popl    %esi
271         movl    %eax,PCB_ONFAULT(%edx)
272         ret
273
274         /*
275          * return EFAULT
276          */
277         ALIGN_TEXT
278 copyin_fault1:
279         addl    $4,%esp         /* skip pushed copyin_fault vector */
280 copyin_fault2:
281         popl    %edi
282         popl    %esi
283         movl    PCPU(curthread),%edx
284         movl    TD_PCB(%edx),%edx
285         movl    $0,PCB_ONFAULT(%edx)
286         movl    $EFAULT,%eax
287         ret
288
289 /*
290  * casuword.  Compare and set user word.  Returns -1 or the current value.
291  */
292
293 ENTRY(casuword)
294         movl    PCPU(curthread),%ecx
295         movl    TD_PCB(%ecx),%ecx
296         movl    $fusufault,PCB_ONFAULT(%ecx)
297         movl    4(%esp),%edx                    /* dst */
298         movl    8(%esp),%eax                    /* old */
299         movl    12(%esp),%ecx                   /* new */
300
301         cmpl    $VM_MAX_USER_ADDRESS-4,%edx     /* verify address is valid */
302         ja      fusufault
303
304 #ifdef SMP
305         lock
306 #endif
307         cmpxchgl %ecx,(%edx)                    /* Compare and set. */
308
309         /*
310          * The old value is in %eax.  If the store succeeded it will be the
311          * value we expected (old) from before the store, otherwise it will
312          * be the current value.
313          */
314
315         movl    PCPU(curthread),%ecx
316         movl    TD_PCB(%ecx),%ecx
317         movl    $fusufault,PCB_ONFAULT(%ecx)
318         movl    $0,PCB_ONFAULT(%ecx)
319         ret
320 END(casuword)
321
322 /*
323  * fu{byte,sword,word} - MP SAFE
324  *
325  *      Fetch a byte (sword, word) from user memory
326  */
327 ENTRY(fuword)
328         movl    PCPU(curthread),%ecx
329         movl    TD_PCB(%ecx),%ecx
330         movl    $fusufault,PCB_ONFAULT(%ecx)
331         movl    4(%esp),%edx                    /* from */
332
333         cmpl    $VM_MAX_USER_ADDRESS-4,%edx     /* verify address is valid */
334         ja      fusufault
335
336         movl    (%edx),%eax
337         movl    $0,PCB_ONFAULT(%ecx)
338         ret
339
340 /*
341  * fusword - MP SAFE
342  */
343 ENTRY(fusword)
344         movl    PCPU(curthread),%ecx
345         movl    TD_PCB(%ecx),%ecx
346         movl    $fusufault,PCB_ONFAULT(%ecx)
347         movl    4(%esp),%edx
348
349         cmpl    $VM_MAX_USER_ADDRESS-2,%edx
350         ja      fusufault
351
352         movzwl  (%edx),%eax
353         movl    $0,PCB_ONFAULT(%ecx)
354         ret
355
356 /*
357  * fubyte - MP SAFE
358  */
359 ENTRY(fubyte)
360         movl    PCPU(curthread),%ecx
361         movl    TD_PCB(%ecx),%ecx
362         movl    $fusufault,PCB_ONFAULT(%ecx)
363         movl    4(%esp),%edx
364
365         cmpl    $VM_MAX_USER_ADDRESS-1,%edx
366         ja      fusufault
367
368         movzbl  (%edx),%eax
369         movl    $0,PCB_ONFAULT(%ecx)
370         ret
371
372         ALIGN_TEXT
373 fusufault:
374         movl    PCPU(curthread),%ecx
375         movl    TD_PCB(%ecx),%ecx
376         xorl    %eax,%eax
377         movl    %eax,PCB_ONFAULT(%ecx)
378         decl    %eax
379         ret
380
381 /*
382  * su{byte,sword,word} - MP SAFE
383  *
384  *      Write a byte (word, longword) to user memory
385  */
386 ENTRY(suword)
387         movl    PCPU(curthread),%ecx
388         movl    TD_PCB(%ecx),%ecx
389         movl    $fusufault,PCB_ONFAULT(%ecx)
390         movl    4(%esp),%edx
391
392         cmpl    $VM_MAX_USER_ADDRESS-4,%edx     /* verify address validity */
393         ja      fusufault
394
395         movl    8(%esp),%eax
396         movl    %eax,(%edx)
397         xorl    %eax,%eax
398         movl    PCPU(curthread),%ecx
399         movl    TD_PCB(%ecx),%ecx
400         movl    %eax,PCB_ONFAULT(%ecx)
401         ret
402
403 /*
404  * susword - MP SAFE
405  */
406 ENTRY(susword)
407         movl    PCPU(curthread),%ecx
408         movl    TD_PCB(%ecx),%ecx
409         movl    $fusufault,PCB_ONFAULT(%ecx)
410         movl    4(%esp),%edx
411
412         cmpl    $VM_MAX_USER_ADDRESS-2,%edx     /* verify address validity */
413         ja      fusufault
414
415         movw    8(%esp),%ax
416         movw    %ax,(%edx)
417         xorl    %eax,%eax
418         movl    PCPU(curthread),%ecx                    /* restore trashed register */
419         movl    TD_PCB(%ecx),%ecx
420         movl    %eax,PCB_ONFAULT(%ecx)
421         ret
422
423 /*
424  * subyte - MP SAFE
425  */
426 ENTRY(subyte)
427         movl    PCPU(curthread),%ecx
428         movl    TD_PCB(%ecx),%ecx
429         movl    $fusufault,PCB_ONFAULT(%ecx)
430         movl    4(%esp),%edx
431
432         cmpl    $VM_MAX_USER_ADDRESS-1,%edx     /* verify address validity */
433         ja      fusufault
434
435         movb    8(%esp),%al
436         movb    %al,(%edx)
437         xorl    %eax,%eax
438         movl    PCPU(curthread),%ecx            /* restore trashed register */
439         movl    TD_PCB(%ecx),%ecx
440         movl    %eax,PCB_ONFAULT(%ecx)
441         ret
442
443 /*
444  * copyinstr(from, to, maxlen, int *lencopied) - MP SAFE
445  *
446  *      copy a string from from to to, stop when a 0 character is reached.
447  *      return ENAMETOOLONG if string is longer than maxlen, and
448  *      EFAULT on protection violations. If lencopied is non-zero,
449  *      return the actual length in *lencopied.
450  */
451 ENTRY(copyinstr)
452         pushl   %esi
453         pushl   %edi
454         movl    PCPU(curthread),%ecx
455         movl    TD_PCB(%ecx),%ecx
456         movl    $cpystrflt,PCB_ONFAULT(%ecx)
457
458         movl    12(%esp),%esi                   /* %esi = from */
459         movl    16(%esp),%edi                   /* %edi = to */
460         movl    20(%esp),%edx                   /* %edx = maxlen */
461
462         movl    $VM_MAX_USER_ADDRESS,%eax
463
464         /* make sure 'from' is within bounds */
465         subl    %esi,%eax
466         jbe     cpystrflt
467
468         /* restrict maxlen to <= VM_MAX_USER_ADDRESS-from */
469         cmpl    %edx,%eax
470         jae     1f
471         movl    %eax,%edx
472         movl    %eax,20(%esp)
473 1:
474         incl    %edx
475         cld
476
477 2:
478         decl    %edx
479         jz      3f
480
481         lodsb
482         stosb
483         orb     %al,%al
484         jnz     2b
485
486         /* Success -- 0 byte reached */
487         decl    %edx
488         xorl    %eax,%eax
489         jmp     cpystrflt_x
490 3:
491         /* edx is zero - return ENAMETOOLONG or EFAULT */
492         cmpl    $VM_MAX_USER_ADDRESS,%esi
493         jae     cpystrflt
494 4:
495         movl    $ENAMETOOLONG,%eax
496         jmp     cpystrflt_x
497
498 cpystrflt:
499         movl    $EFAULT,%eax
500
501 cpystrflt_x:
502         /* set *lencopied and return %eax */
503         movl    PCPU(curthread),%ecx
504         movl    TD_PCB(%ecx),%ecx
505         movl    $0,PCB_ONFAULT(%ecx)
506         movl    20(%esp),%ecx
507         subl    %edx,%ecx
508         movl    24(%esp),%edx
509         testl   %edx,%edx
510         jz      1f
511         movl    %ecx,(%edx)
512 1:
513         popl    %edi
514         popl    %esi
515         ret
516
517
518 /*
519  * copystr(from, to, maxlen, int *lencopied) - MP SAFE
520  */
521 ENTRY(copystr)
522         pushl   %esi
523         pushl   %edi
524
525         movl    12(%esp),%esi                   /* %esi = from */
526         movl    16(%esp),%edi                   /* %edi = to */
527         movl    20(%esp),%edx                   /* %edx = maxlen */
528         incl    %edx
529         cld
530 1:
531         decl    %edx
532         jz      4f
533         lodsb
534         stosb
535         orb     %al,%al
536         jnz     1b
537
538         /* Success -- 0 byte reached */
539         decl    %edx
540         xorl    %eax,%eax
541         jmp     6f
542 4:
543         /* edx is zero -- return ENAMETOOLONG */
544         movl    $ENAMETOOLONG,%eax
545
546 6:
547         /* set *lencopied and return %eax */
548         movl    20(%esp),%ecx
549         subl    %edx,%ecx
550         movl    24(%esp),%edx
551         testl   %edx,%edx
552         jz      7f
553         movl    %ecx,(%edx)
554 7:
555         popl    %edi
556         popl    %esi
557         ret
558
559 ENTRY(bcmp)
560         pushl   %edi
561         pushl   %esi
562         movl    12(%esp),%edi
563         movl    16(%esp),%esi
564         movl    20(%esp),%edx
565         xorl    %eax,%eax
566
567         movl    %edx,%ecx
568         shrl    $2,%ecx
569         cld                                     /* compare forwards */
570         repe
571         cmpsl
572         jne     1f
573
574         movl    %edx,%ecx
575         andl    $3,%ecx
576         repe
577         cmpsb
578         je      2f
579 1:
580         incl    %eax
581 2:
582         popl    %esi
583         popl    %edi
584         ret
585
586
587 /*
588  * Handling of special 386 registers and descriptor tables etc
589  */
590 /* void lgdt(struct region_descriptor *rdp); */
591 ENTRY(lgdt)
592         /* reload the descriptor table */
593         movl    4(%esp),%eax
594         lgdt    (%eax)
595
596         /* flush the prefetch q */
597         jmp     1f
598         nop
599 1:
600         /* reload "stale" selectors */
601         movl    $KDSEL,%eax
602         mov     %ax,%ds
603         mov     %ax,%es
604         mov     %ax,%gs
605         mov     %ax,%ss
606         movl    $KPSEL,%eax
607         mov     %ax,%fs
608         mov     %ax,%gs
609
610         /* reload code selector by turning return into intersegmental return */
611         movl    (%esp),%eax
612         pushl   %eax
613         movl    $KCSEL,4(%esp)
614         lret
615
616 /*
617  * void lidt(struct region_descriptor *rdp);
618  */
619 ENTRY(lidt)
620         movl    4(%esp),%eax
621         lidt    (%eax)
622         ret
623
624 /*
625  * void lldt(u_short sel)
626  */
627 ENTRY(lldt)
628         lldt    4(%esp)
629         ret
630
631 /*
632  * void ltr(u_short sel)
633  */
634 ENTRY(ltr)
635         ltr     4(%esp)
636         ret
637
638 /* ssdtosd(*ssdp,*sdp) */
639 ENTRY(ssdtosd)
640         pushl   %ebx
641         movl    8(%esp),%ecx
642         movl    8(%ecx),%ebx
643         shll    $16,%ebx
644         movl    (%ecx),%edx
645         roll    $16,%edx
646         movb    %dh,%bl
647         movb    %dl,%bh
648         rorl    $8,%ebx
649         movl    4(%ecx),%eax
650         movw    %ax,%dx
651         andl    $0xf0000,%eax
652         orl     %eax,%ebx
653         movl    12(%esp),%ecx
654         movl    %edx,(%ecx)
655         movl    %ebx,4(%ecx)
656         popl    %ebx
657         ret
658
659 /* load_cr0(cr0) */
660 ENTRY(load_cr0)
661         movl    4(%esp),%eax
662         movl    %eax,%cr0
663         ret
664
665 /* rcr0() */
666 ENTRY(rcr0)
667         movl    %cr0,%eax
668         ret
669
670 /* rcr3() */
671 ENTRY(rcr3)
672         movl    %cr3,%eax
673         ret
674
675 /* void load_cr3(caddr_t cr3) */
676 ENTRY(load_cr3)
677 #if defined(SWTCH_OPTIM_STATS)
678         incl    _tlb_flush_count
679 #endif
680         movl    4(%esp),%eax
681         movl    %eax,%cr3
682         ret
683
684 /* rcr4() */
685 ENTRY(rcr4)
686         movl    %cr4,%eax
687         ret
688
689 /* void load_cr4(caddr_t cr4) */
690 ENTRY(load_cr4)
691         movl    4(%esp),%eax
692         movl    %eax,%cr4
693         ret
694
695 /* void reset_dbregs() */
696 ENTRY(reset_dbregs)
697         movl    $0,%eax
698         movl    %eax,%dr7     /* disable all breapoints first */
699         movl    %eax,%dr0
700         movl    %eax,%dr1
701         movl    %eax,%dr2
702         movl    %eax,%dr3
703         movl    %eax,%dr6
704         ret
705
706 /*****************************************************************************/
707 /* setjump, longjump                                                         */
708 /*****************************************************************************/
709
710 ENTRY(setjmp)
711         movl    4(%esp),%eax
712         movl    %ebx,(%eax)                     /* save ebx */
713         movl    %esp,4(%eax)                    /* save esp */
714         movl    %ebp,8(%eax)                    /* save ebp */
715         movl    %esi,12(%eax)                   /* save esi */
716         movl    %edi,16(%eax)                   /* save edi */
717         movl    (%esp),%edx                     /* get rta */
718         movl    %edx,20(%eax)                   /* save eip */
719         xorl    %eax,%eax                       /* return(0); */
720         ret
721
722 ENTRY(longjmp)
723         movl    4(%esp),%eax
724         movl    (%eax),%ebx                     /* restore ebx */
725         movl    4(%eax),%esp                    /* restore esp */
726         movl    8(%eax),%ebp                    /* restore ebp */
727         movl    12(%eax),%esi                   /* restore esi */
728         movl    16(%eax),%edi                   /* restore edi */
729         movl    20(%eax),%edx                   /* get rta */
730         movl    %edx,(%esp)                     /* put in return frame */
731         xorl    %eax,%eax                       /* return(1); */
732         incl    %eax
733         ret
734
735 /*
736  * Support for BB-profiling (gcc -a).  The kernbb program will extract
737  * the data from the kernel.
738  */
739
740         .data
741         ALIGN_DATA
742         .globl bbhead
743 bbhead:
744         .long 0
745
746         .text
747 NON_GPROF_ENTRY(__bb_init_func)
748         movl    4(%esp),%eax
749         movl    $1,(%eax)
750         movl    bbhead,%edx
751         movl    %edx,16(%eax)
752         movl    %eax,bbhead
753         .byte   0xc3                            /* avoid macro for `ret' */