[legal] Add FILE_LICENCE declaration to romprefix.S
[people/lynusvaz/gpxe.git] / src / arch / i386 / prefix / romprefix.S
1 /* At entry, the processor is in 16 bit real mode and the code is being
2  * executed from an address it was not linked to. Code must be pic and
3  * 32 bit sensitive until things are fixed up.
4  *
5  * Also be very careful as the stack is at the rear end of the interrupt
6  * table so using a noticeable amount of stack space is a no-no.
7  */
8
9 FILE_LICENCE ( GPL2_OR_LATER )
10
11 #include <config/general.h>
12
13 #define PNP_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'n' << 16 ) + ( 'P' << 24 ) )
14 #define PMM_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'M' << 16 ) + ( 'M' << 24 ) )
15 #define PCI_SIGNATURE ( 'P' + ( 'C' << 8 ) + ( 'I' << 16 ) + ( ' ' << 24 ) )
16 #define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) )
17 #define PNP_GET_BBS_VERSION 0x60
18 #define PMM_ALLOCATE 0x0000
19 #define PMM_DEALLOCATE 0x0002
20
21 /* ROM banner timeout.  Based on the configurable BANNER_TIMEOUT in
22  * config.h, but converted to a number of (18Hz) timer ticks, and
23  * doubled to allow for BIOSes that switch video modes immediately
24  * beforehand, so rendering the message almost invisible to the user.
25  */
26 #define ROM_BANNER_TIMEOUT ( 2 * ( 18 * BANNER_TIMEOUT ) / 10 )
27
28         .text
29         .code16
30         .arch i386
31         .section ".prefix", "ax", @progbits
32         
33         .org    0x00
34 romheader:
35         .word   0xAA55                  /* BIOS extension signature */
36 romheader_size: .byte _filesz_sect      /* Size in 512-byte blocks */
37         jmp     init                    /* Initialisation vector */
38 checksum:
39         .byte   0
40         .org    0x16
41         .word   undiheader
42         .org    0x18
43         .word   pciheader
44         .org    0x1a
45         .word   pnpheader
46         .size romheader, . - romheader
47         
48         .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
49         .ascii  "SUBB"
50         .long   romheader_size
51         .long   512
52         .long   0
53         .previous
54
55 pciheader:
56         .ascii  "PCIR"                  /* Signature */
57         .word   pci_vendor_id           /* Vendor identification */ 
58         .word   pci_device_id           /* Device identification */
59         .word   0x0000                  /* Device list pointer */
60         .word   pciheader_len           /* PCI data structure length */
61         .byte   0x03                    /* PCI data structure revision */
62         .byte   0x02, 0x00, 0x00        /* Class code */
63 pciheader_image_length:
64         .word   _filesz_sect            /* Image length */
65         .word   0x0001                  /* Revision level */
66         .byte   0x00                    /* Code type */
67         .byte   0x80                    /* Last image indicator */
68 pciheader_runtime_length:
69         .word   _filesz_sect            /* Maximum run-time image length */
70         .word   0x0000                  /* Configuration utility code header */
71         .word   0x0000                  /* DMTF CLP entry point */
72         .equ pciheader_len, . - pciheader
73         .size pciheader, . - pciheader
74         
75         .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
76         .ascii  "SUBW"
77         .long   pciheader_image_length
78         .long   512
79         .long   0
80         .ascii  "SUBW"
81         .long   pciheader_runtime_length
82         .long   512
83         .long   0
84         .previous
85
86 pnpheader:
87         .ascii  "$PnP"                  /* Signature */
88         .byte   0x01                    /* Structure revision */
89         .byte   ( pnpheader_len / 16 )  /* Length (in 16 byte increments) */
90         .word   0x0000                  /* Offset of next header */
91         .byte   0x00                    /* Reserved */
92         .byte   0x00                    /* Checksum */
93         .long   0x00000000              /* Device identifier */
94         .word   mfgstr                  /* Manufacturer string */
95         .word   prodstr                 /* Product name */
96         .byte   0x02                    /* Device base type code */
97         .byte   0x00                    /* Device sub-type code */
98         .byte   0x00                    /* Device interface type code */
99         .byte   0xf4                    /* Device indicator */
100         .word   0x0000                  /* Boot connection vector */
101         .word   0x0000                  /* Disconnect vector */
102         .word   bev_entry               /* Boot execution vector */
103         .word   0x0000                  /* Reserved */
104         .word   0x0000                  /* Static resource information vector*/
105         .equ pnpheader_len, . - pnpheader
106         .size pnpheader, . - pnpheader
107
108 /* Manufacturer string */
109 mfgstr:
110         .asciz  "http://etherboot.org"
111         .size mfgstr, . - mfgstr
112
113 /* Product string
114  *
115  * Defaults to PRODUCT_SHORT_NAME.  If the ROM image is writable at
116  * initialisation time, it will be filled in to include the PCI
117  * bus:dev.fn number of the card as well.
118  */
119 prodstr:
120         .ascii  PRODUCT_SHORT_NAME
121 prodstr_separator:
122         .byte   0
123         .ascii  "(PCI "
124 prodstr_pci_id:
125         .asciz  "xx:xx.x)"              /* Filled in by init code */
126         .size prodstr, . - prodstr
127
128         .globl  undiheader      
129 undiheader:
130         .ascii  "UNDI"                  /* Signature */
131         .byte   undiheader_len          /* Length of structure */
132         .byte   0                       /* Checksum */
133         .byte   0                       /* Structure revision */
134         .byte   0,1,2                   /* PXE version: 2.1.0 */
135         .word   undiloader              /* Offset to loader routine */
136         .word   _data16_memsz           /* Stack segment size */
137         .word   _data16_memsz           /* Data segment size */
138         .word   _text16_memsz           /* Code segment size */
139         .ascii  "PCIR"                  /* Bus type */
140         .equ undiheader_len, . - undiheader
141         .size undiheader, . - undiheader
142
143 /* Initialisation (called once during POST)
144  *
145  * Determine whether or not this is a PnP system via a signature
146  * check.  If it is PnP, return to the PnP BIOS indicating that we are
147  * a boot-capable device; the BIOS will call our boot execution vector
148  * if it wants to boot us.  If it is not PnP, hook INT 19.
149  */
150 init:
151         /* Preserve registers, clear direction flag, set %ds=%cs */
152         pushaw
153         pushw   %ds
154         pushw   %es
155         pushw   %fs
156         pushw   %gs
157         cld
158         pushw   %cs
159         popw    %ds
160
161         /* Shuffle some registers around.  We need %di available for
162          * the print_xxx functions, and in a register that's
163          * addressable from %es, so shuffle as follows:
164          *
165          *    %di (pointer to PnP structure) => %bx
166          *    %bx (runtime segment address, for PCI 3.0) => %gs
167          */
168         movw    %bx, %gs
169         movw    %di, %bx
170
171         /* Print message as early as possible */
172         movw    $init_message, %si
173         xorw    %di, %di
174         call    print_message
175         call    print_pci_busdevfn
176
177         /* Fill in product name string, if possible */
178         movw    $prodstr_pci_id, %di
179         call    print_pci_busdevfn
180         movb    $( ' ' ), prodstr_separator
181
182         /* Print segment address */
183         movb    $( ' ' ), %al
184         xorw    %di, %di
185         call    print_character
186         movw    %cs, %ax
187         call    print_hex_word
188
189         /* Check for PCI BIOS version */
190         pushl   %ebx
191         pushl   %edx
192         pushl   %edi
193         stc
194         movw    $0xb101, %ax
195         int     $0x1a
196         jc      no_pci3
197         cmpl    $PCI_SIGNATURE, %edx
198         jne     no_pci3
199         testb   %ah, %ah
200         jnz     no_pci3
201         movw    $init_message_pci, %si
202         xorw    %di, %di
203         call    print_message
204         movb    %bh, %al
205         call    print_hex_nibble
206         movb    $( '.' ), %al
207         call    print_character
208         movb    %bl, %al
209         call    print_hex_byte
210         cmpb    $3, %bh
211         jb      no_pci3
212         /* PCI >=3.0: leave %gs as-is if sane */
213         movw    %gs, %ax
214         cmpw    $0xa000, %ax    /* Insane if %gs < 0xa000 */
215         jb      pci3_insane
216         movw    %cs, %bx        /* Sane if %cs == %gs */
217         cmpw    %bx, %ax
218         je      1f
219         movzbw  romheader_size, %cx /* Sane if %cs+len <= %gs */
220         shlw    $5, %cx
221         addw    %cx, %bx
222         cmpw    %bx, %ax
223         jae     1f
224         movw    %cs, %bx        /* Sane if %gs+len <= %cs */
225         addw    %cx, %ax
226         cmpw    %bx, %ax
227         jbe     1f
228 pci3_insane: /* PCI 3.0 with insane %gs value: print error and ignore %gs */
229         movb    $( '!' ), %al
230         call    print_character
231         movw    %gs, %ax
232         call    print_hex_word
233 no_pci3:
234         /* PCI <3.0: set %gs (runtime segment) = %cs (init-time segment) */
235         pushw   %cs
236         popw    %gs
237 1:      popl    %edi
238         popl    %edx
239         popl    %ebx
240
241         /* Check for PnP BIOS */
242         testw   $0x0f, %bx      /* PnP signature must be aligned - bochs    */
243         jnz     no_bbs          /* uses unalignment to indicate 'fake' PnP. */
244         cmpl    $PNP_SIGNATURE, %es:0(%bx)
245         jne     no_bbs
246         /* Is PnP: print PnP message */
247         movw    $init_message_pnp, %si
248         xorw    %di, %di
249         call    print_message
250         /* Check for BBS */
251         pushw   %es:0x1b(%bx)   /* Real-mode data segment */
252         pushw   %ds             /* &(bbs_version) */
253         pushw   $bbs_version
254         pushw   $PNP_GET_BBS_VERSION
255         lcall   *%es:0xd(%bx)
256         addw    $8, %sp
257         testw   %ax, %ax
258         je      got_bbs
259 no_bbs: /* Not BBS-compliant - must hook INT 19 */
260         movw    $init_message_int19, %si
261         xorw    %di, %di
262         call    print_message
263         xorw    %ax, %ax
264         movw    %ax, %es
265         pushl   %es:( 0x19 * 4 )
266         popl    orig_int19
267         pushw   %gs /* %gs contains runtime %cs */
268         pushw   $int19_entry
269         popl    %es:( 0x19 * 4 )
270         jmp     bbs_done
271 got_bbs: /* BBS compliant - no need to hook INT 19 */
272         movw    $init_message_bbs, %si
273         xorw    %di, %di
274         call    print_message
275 bbs_done:
276
277         /* Check for PMM */
278         movw    $( 0xe000 - 1 ), %bx
279 pmm_scan:
280         incw    %bx
281         jz      no_pmm
282         movw    %bx, %es
283         cmpl    $PMM_SIGNATURE, %es:0
284         jne     pmm_scan
285         xorw    %dx, %dx
286         xorw    %si, %si
287         movzbw  %es:5, %cx
288 1:      es lodsb
289         addb    %al, %dl
290         loop    1b
291         jnz     pmm_scan
292         /* PMM found: print PMM message */
293         movw    $init_message_pmm, %si
294         xorw    %di, %di
295         call    print_message
296         /* We have PMM and so a 1kB stack: preserve upper register halves */
297         pushal
298         /* Calculate required allocation size in %esi */
299         movzbl  romheader_size, %eax
300         shll    $9, %eax
301         addl    $_textdata_memsz, %eax
302         orw     $0xffff, %ax    /* Ensure allocation size is at least 64kB */
303         bsrl    %eax, %ecx
304         subw    $15, %cx        /* Round up and convert to 64kB count */
305         movw    $1, %si
306         shlw    %cl, %si
307 pmm_loop:
308         /* Try to allocate block via PMM */
309         pushw   $0x0006         /* Aligned, extended memory */
310         pushl   $0xffffffff     /* No handle */
311         movzwl  %si, %eax
312         shll    $12, %eax
313         pushl   %eax            /* Allocation size in paragraphs */
314         pushw   $PMM_ALLOCATE
315         lcall   *%es:7
316         addw    $12, %sp
317         /* Abort if allocation fails */
318         testw   %dx, %dx        /* %ax==0 even on success, since align>=64kB */
319         jz      pmm_fail
320         /* If block has A20==1, free block and try again with twice
321          * the allocation size (and hence alignment).
322          */
323         testw   $0x0010, %dx
324         jz      got_pmm
325         pushw   %dx
326         pushw   $0
327         pushw   $PMM_DEALLOCATE
328         lcall   *%es:7
329         addw    $6, %sp
330         addw    %si, %si
331         jmp     pmm_loop
332 got_pmm: /* PMM allocation succeeded */
333         movw    %dx, ( image_source + 2 )
334         movw    %dx, %ax
335         xorw    %di, %di
336         call    print_hex_word
337         movb    $( '@' ), %al
338         call    print_character
339         movw    %si, %ax
340         call    print_hex_byte
341         /* Copy ROM to PMM block */
342         xorw    %ax, %ax
343         movw    %ax, %es
344         movl    image_source, %edi
345         xorl    %esi, %esi
346         movzbl  romheader_size, %ecx
347         shll    $9, %ecx
348         addr32 rep movsb        /* PMM presence implies flat real mode */
349         movl    %edi, decompress_to
350         /* Shrink ROM */
351         movb    $_prefix_memsz_sect, romheader_size
352 pmm_fail:
353         /* Restore upper register halves */
354         popal
355 no_pmm:
356
357         /* Update checksum */
358         xorw    %bx, %bx
359         xorw    %si, %si
360         movzbw  romheader_size, %cx
361         shlw    $9, %cx
362 1:      lodsb
363         addb    %al, %bl
364         loop    1b
365         subb    %bl, checksum
366
367         /* Copy self to option ROM space.  Required for PCI3.0, which
368          * loads us to a temporary location in low memory.  Will be a
369          * no-op for lower PCI versions.
370          */
371         movb    $( ' ' ), %al
372         xorw    %di, %di
373         call    print_character
374         movw    %gs, %ax
375         call    print_hex_word
376         movzbw  romheader_size, %cx
377         shlw    $9, %cx
378         movw    %ax, %es
379         xorw    %si, %si
380         xorw    %di, %di
381         cs rep  movsb
382
383         /* Prompt for POST-time shell */
384         movw    $init_message_prompt, %si
385         xorw    %di, %di
386         call    print_message
387         movw    $prodstr, %si
388         call    print_message
389         movw    $init_message_dots, %si
390         call    print_message
391         /* Wait for Ctrl-B */
392         movw    $0xff02, %bx
393         call    wait_for_key
394         /* Clear prompt */
395         pushf
396         xorw    %di, %di
397         call    print_kill_line
398         movw    $init_message_done, %si
399         call    print_message
400         popf
401         jnz     2f
402         /* Ctrl-B was pressed: invoke gPXE.  The keypress will be
403          * picked up by the initial shell prompt, and we will drop
404          * into a shell.
405          */
406         pushw   %cs
407         call    exec
408 2:
409         /* Restore registers */
410         popw    %gs
411         popw    %fs
412         popw    %es
413         popw    %ds
414         popaw
415
416         /* Indicate boot capability to PnP BIOS, if present */
417         movw    $0x20, %ax
418         lret
419         .size init, . - init
420
421 /*
422  * Note to hardware vendors:
423  *
424  * If you wish to brand this boot ROM, please do so by defining the
425  * strings PRODUCT_NAME and PRODUCT_SHORT_NAME in config/general.h.
426  *
427  * While nothing in the GPL prevents you from removing all references
428  * to gPXE or http://etherboot.org, we prefer you not to do so.
429  *
430  * If you have an OEM-mandated branding requirement that cannot be
431  * satisfied simply by defining PRODUCT_NAME and PRODUCT_SHORT_NAME,
432  * please contact us.
433  *
434  * [ Including an ASCII NUL in PRODUCT_NAME is considered to be
435  *   bypassing the spirit of this request! ]
436  */
437 init_message:
438         .ascii  "\n"
439         .ascii  PRODUCT_NAME
440         .ascii  "\n"
441         .asciz  "gPXE (http://etherboot.org) - "
442         .size   init_message, . - init_message
443 init_message_pci:
444         .asciz  " PCI"
445         .size   init_message_pci, . - init_message_pci
446 init_message_pnp:
447         .asciz  " PnP"
448         .size   init_message_pnp, . - init_message_pnp
449 init_message_bbs:
450         .asciz  " BBS"
451         .size   init_message_bbs, . - init_message_bbs
452 init_message_pmm:
453         .asciz  " PMM"
454         .size   init_message_pmm, . - init_message_pmm
455 init_message_int19:
456         .asciz  " INT19"
457         .size   init_message_int19, . - init_message_int19
458 init_message_prompt:
459         .asciz  "\nPress Ctrl-B to configure "
460         .size   init_message_prompt, . - init_message_prompt
461 init_message_dots:
462         .asciz  "..."
463         .size   init_message_dots, . - init_message_dots
464 init_message_done:
465         .asciz  "\n\n"
466         .size   init_message_done, . - init_message_done
467
468 /* ROM image location
469  *
470  * May be either within option ROM space, or within PMM-allocated block.
471  */
472 image_source:
473         .long   0
474         .size   image_source, . - image_source
475
476 /* Temporary decompression area
477  *
478  * May be either at HIGHMEM_LOADPOINT, or within PMM-allocated block.
479  */
480 decompress_to:
481         .long   HIGHMEM_LOADPOINT
482         .size   decompress_to, . - decompress_to
483
484 /* BBS version
485  *
486  * Filled in by BBS BIOS.  We ignore the value.
487  */
488 bbs_version:
489         .word   0
490         .size   bbs_version, . - bbs_version
491
492 /* Boot Execution Vector entry point
493  *
494  * Called by the PnP BIOS when it wants to boot us.
495  */
496 bev_entry:
497         pushw   %cs
498         call    exec
499         lret
500         .size   bev_entry, . - bev_entry
501
502 /* INT19 entry point
503  *
504  * Called via the hooked INT 19 if we detected a non-PnP BIOS.  We
505  * attempt to return via the original INT 19 vector (if we were able
506  * to store it).
507  */
508 int19_entry:
509         pushw   %cs
510         popw    %ds
511         /* Prompt user to press B to boot */
512         movw    $int19_message_prompt, %si
513         xorw    %di, %di
514         call    print_message
515         movw    $prodstr, %si
516         call    print_message
517         movw    $int19_message_dots, %si
518         call    print_message
519         movw    $0xdf4e, %bx
520         call    wait_for_key
521         pushf
522         xorw    %di, %di
523         call    print_kill_line
524         movw    $int19_message_done, %si
525         call    print_message
526         popf
527         jz      1f
528         /* Leave keypress in buffer and start gPXE.  The keypress will
529          * cause the usual initial Ctrl-B prompt to be skipped.
530          */
531         pushw   %cs
532         call    exec
533 1:      /* Try to call original INT 19 vector */
534         movl    %cs:orig_int19, %eax
535         testl   %eax, %eax
536         je      2f
537         ljmp    *%cs:orig_int19
538 2:      /* No chained vector: issue INT 18 as a last resort */
539         int     $0x18
540         .size   int19_entry, . - int19_entry
541 orig_int19:
542         .long   0
543         .size   orig_int19, . - orig_int19
544
545 int19_message_prompt:
546         .asciz  "Press N to skip booting from "
547         .size   int19_message_prompt, . - int19_message_prompt
548 int19_message_dots:
549         .asciz  "..."
550         .size   int19_message_dots, . - int19_message_dots
551 int19_message_done:
552         .asciz  "\n\n"
553         .size   int19_message_done, . - int19_message_done
554         
555 /* Execute as a boot device
556  *
557  */
558 exec:   /* Set %ds = %cs */
559         pushw   %cs
560         popw    %ds
561
562         /* Print message as soon as possible */
563         movw    $prodstr, %si
564         xorw    %di, %di
565         call    print_message
566         movw    $exec_message, %si
567         call    print_message
568
569         /* Store magic word on BIOS stack and remember BIOS %ss:sp */
570         pushl   $STACK_MAGIC
571         movw    %ss, %dx
572         movw    %sp, %bp
573
574         /* Obtain a reasonably-sized temporary stack */
575         xorw    %ax, %ax
576         movw    %ax, %ss
577         movw    $0x7c00, %sp
578
579         /* Install gPXE */
580         movl    image_source, %esi
581         movl    decompress_to, %edi
582         call    alloc_basemem
583         call    install_prealloc
584
585         /* Set up real-mode stack */
586         movw    %bx, %ss
587         movw    $_estack16, %sp
588
589         /* Jump to .text16 segment */
590         pushw   %ax
591         pushw   $1f
592         lret
593         .section ".text16", "awx", @progbits
594 1:      /* Call main() */
595         pushl   $main
596         pushw   %cs
597         call    prot_call
598         popl    %ecx /* discard */
599
600         /* Uninstall gPXE */
601         call    uninstall
602
603         /* Restore BIOS stack */
604         movw    %dx, %ss
605         movw    %bp, %sp
606
607         /* Check magic word on BIOS stack */
608         popl    %eax
609         cmpl    $STACK_MAGIC, %eax
610         jne     1f
611         /* BIOS stack OK: return to caller */
612         lret
613 1:      /* BIOS stack corrupt: use INT 18 */
614         int     $0x18
615         .previous
616
617 exec_message:
618         .asciz  " starting execution\n"
619         .size exec_message, . - exec_message
620
621 /* UNDI loader
622  *
623  * Called by an external program to load our PXE stack.
624  */
625 undiloader:
626         /* Save registers */
627         pushl   %esi
628         pushl   %edi
629         pushw   %ds
630         pushw   %es
631         pushw   %bx
632         /* ROM segment address to %ds */
633         pushw   %cs
634         popw    %ds
635         /* UNDI loader parameter structure address into %es:%di */
636         movw    %sp, %bx
637         movw    %ss:18(%bx), %di
638         movw    %ss:20(%bx), %es
639         /* Install to specified real-mode addresses */
640         pushw   %di
641         movw    %es:12(%di), %bx
642         movw    %es:14(%di), %ax
643         movl    image_source, %esi
644         movl    decompress_to, %edi
645         call    install_prealloc
646         popw    %di
647         /* Call UNDI loader C code */
648         pushl   $pxe_loader_call
649         pushw   %cs
650         pushw   $1f
651         pushw   %ax
652         pushw   $prot_call
653         lret
654 1:      popw    %bx     /* discard */
655         popw    %bx     /* discard */
656         /* Restore registers and return */
657         popw    %bx
658         popw    %es
659         popw    %ds
660         popl    %edi
661         popl    %esi
662         lret
663         .size undiloader, . - undiloader
664
665 /* Wait for key press specified by %bl (masked by %bh)
666  *
667  * Used by init and INT19 code when prompting user.  If the specified
668  * key is pressed, it is left in the keyboard buffer.
669  *
670  * Returns with ZF set iff specified key is pressed.
671  */
672 wait_for_key:
673         /* Preserve registers */
674         pushw   %cx
675         pushw   %ax
676 1:      /* Empty the keyboard buffer before waiting for input */
677         movb    $0x01, %ah
678         int     $0x16
679         jz      2f
680         xorw    %ax, %ax
681         int     $0x16
682         jmp     1b
683 2:      /* Wait for a key press */
684         movw    $ROM_BANNER_TIMEOUT, %cx
685 3:      decw    %cx
686         js      99f             /* Exit with ZF clear */
687         /* Wait for timer tick to be updated */
688         call    wait_for_tick
689         /* Check to see if a key was pressed */
690         movb    $0x01, %ah
691         int     $0x16
692         jz      3b
693         /* Check to see if key was the specified key */
694         andb    %bh, %al
695         cmpb    %al, %bl
696         je      99f             /* Exit with ZF set */
697         /* Not the specified key: remove from buffer and stop waiting */
698         pushfw
699         xorw    %ax, %ax
700         int     $0x16
701         popfw                   /* Exit with ZF clear */
702 99:     /* Restore registers and return */
703         popw    %ax
704         popw    %cx
705         ret
706         .size wait_for_key, . - wait_for_key
707
708 /* Wait for timer tick
709  *
710  * Used by wait_for_key
711  */
712 wait_for_tick:
713         pushl   %eax
714         pushw   %fs
715         movw    $0x40, %ax
716         movw    %ax, %fs
717         movl    %fs:(0x6c), %eax
718 1:      pushf
719         sti
720         hlt
721         popf
722         cmpl    %fs:(0x6c), %eax
723         je      1b
724         popw    %fs
725         popl    %eax
726         ret
727         .size wait_for_tick, . - wait_for_tick