Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / 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 PMM_ALLOCATE 0x0000
18 #define PMM_FIND 0x0001
19 #define PMM_HANDLE_BASE ( ( ( 'F' - 'A' + 1 ) << 26 ) + \
20                           ( ( 'E' - 'A' + 1 ) << 21 ) + \
21                           ( ( 'N' - 'A' + 1 ) << 16 ) )
22 #define PMM_HANDLE_BASE_IMAGE_SOURCE \
23         ( PMM_HANDLE_BASE | 0x00001000 )
24 #define PMM_HANDLE_BASE_DECOMPRESS_TO \
25         ( PMM_HANDLE_BASE | 0x00002000 )
26 #define PCI_FUNC_MASK 0x07
27
28 /* ROM banner timeout, converted to a number of (18Hz) timer ticks. */
29 #define ROM_BANNER_TIMEOUT_TICKS ( ( 18 * ROM_BANNER_TIMEOUT ) / 10 )
30
31 /* Allow payload to be excluded from ROM size
32  */
33 #if ROMPREFIX_EXCLUDE_PAYLOAD
34 #define ZINFO_TYPE_ADxB "ADHB"
35 #define ZINFO_TYPE_ADxW "ADHW"
36 #else
37 #define ZINFO_TYPE_ADxB "ADDB"
38 #define ZINFO_TYPE_ADxW "ADDW"
39 #endif
40
41 /* Allow ROM to be marked as containing multiple images
42  */
43 #if ROMPREFIX_MORE_IMAGES
44 #define INDICATOR 0x00
45 #else
46 #define INDICATOR 0x80
47 #endif
48
49 /* Default to building a PCI ROM if no bus type is specified
50  */
51 #ifndef BUSTYPE
52 #define BUSTYPE "PCIR"
53 #endif
54
55         .text
56         .code16
57         .arch i386
58         .section ".prefix", "ax", @progbits
59         .globl  _rom_start
60 _rom_start:
61         
62         .org    0x00
63 romheader:
64         .word   0xAA55                  /* BIOS extension signature */
65 romheader_size: .byte 0                 /* Size in 512-byte blocks */
66         jmp     init                    /* Initialisation vector */
67 checksum:
68         .byte   0
69         .org    0x10
70         .word   ipxeheader
71         .org    0x16
72         .word   undiheader
73 .ifeqs  BUSTYPE, "PCIR"
74         .org    0x18
75         .word   pciheader
76 .endif
77         .org    0x1a
78         .word   pnpheader
79         .size romheader, . - romheader
80
81         .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
82         .ascii  ZINFO_TYPE_ADxB
83         .long   romheader_size
84         .long   512
85         .long   0
86         .previous
87
88 .ifeqs  BUSTYPE, "PCIR"
89 pciheader:
90         .ascii  "PCIR"                  /* Signature */
91         .word   pci_vendor_id           /* Vendor identification */ 
92         .word   pci_device_id           /* Device identification */
93         .word   0x0000                  /* Device list pointer */
94         .word   pciheader_len           /* PCI data structure length */
95         .byte   0x03                    /* PCI data structure revision */
96         .byte   0x02, 0x00, 0x00        /* Class code */
97 pciheader_image_length:
98         .word   0                       /* Image length */
99         .word   0x0001                  /* Revision level */
100         .byte   0x00                    /* Code type */
101         .byte   INDICATOR               /* Last image indicator */
102 pciheader_runtime_length:
103         .word   0                       /* Maximum run-time image length */
104         .word   0x0000                  /* Configuration utility code header */
105         .word   0x0000                  /* DMTF CLP entry point */
106         .equ pciheader_len, . - pciheader
107         .size pciheader, . - pciheader
108
109         .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
110         .ascii  ZINFO_TYPE_ADxW
111         .long   pciheader_image_length
112         .long   512
113         .long   0
114         .ascii  ZINFO_TYPE_ADxW
115         .long   pciheader_runtime_length
116         .long   512
117         .long   0
118         .previous
119 .endif  /* PCIR */
120
121         /* PnP doesn't require any particular alignment, but IBM
122          * BIOSes will scan on 16-byte boundaries rather than using
123          * the offset stored at 0x1a
124          */
125         .align  16
126 pnpheader:
127         .ascii  "$PnP"                  /* Signature */
128         .byte   0x01                    /* Structure revision */
129         .byte   ( pnpheader_len / 16 )  /* Length (in 16 byte increments) */
130         .word   0x0000                  /* Offset of next header */
131         .byte   0x00                    /* Reserved */
132         .byte   0x00                    /* Checksum */
133         .long   0x00000000              /* Device identifier */
134         .word   mfgstr                  /* Manufacturer string */
135         .word   prodstr                 /* Product name */
136         .byte   0x02                    /* Device base type code */
137         .byte   0x00                    /* Device sub-type code */
138         .byte   0x00                    /* Device interface type code */
139         .byte   0xf4                    /* Device indicator */
140         .word   0x0000                  /* Boot connection vector */
141         .word   0x0000                  /* Disconnect vector */
142         .word   bev_entry               /* Boot execution vector */
143         .word   0x0000                  /* Reserved */
144         .word   0x0000                  /* Static resource information vector*/
145         .equ pnpheader_len, . - pnpheader
146         .size pnpheader, . - pnpheader
147
148 /* Manufacturer string */
149 mfgstr:
150         .asciz  "http://ipxe.org"
151         .size mfgstr, . - mfgstr
152
153 /* Product string
154  *
155  * Defaults to PRODUCT_SHORT_NAME.  If the ROM image is writable at
156  * initialisation time, it will be filled in to include the PCI
157  * bus:dev.fn number of the card as well.
158  */
159 prodstr:
160         .ascii  PRODUCT_SHORT_NAME
161 .ifeqs  BUSTYPE, "PCIR"
162 prodstr_separator:
163         .byte   0
164         .ascii  "(PCI "
165 prodstr_pci_id:
166         .ascii  "xx:xx.x)"              /* Filled in by init code */
167 .endif  /* PCIR */
168         .byte   0
169         .size prodstr, . - prodstr
170
171         .globl  undiheader      
172         .weak   undiloader
173 undiheader:
174         .ascii  "UNDI"                  /* Signature */
175         .byte   undiheader_len          /* Length of structure */
176         .byte   0                       /* Checksum */
177         .byte   0                       /* Structure revision */
178         .byte   0,1,2                   /* PXE version: 2.1.0 */
179         .word   undiloader              /* Offset to loader routine */
180         .word   _data16_memsz           /* Stack segment size */
181         .word   _data16_memsz           /* Data segment size */
182         .word   _text16_memsz           /* Code segment size */
183         .ascii  BUSTYPE                 /* Bus type */
184         .equ undiheader_len, . - undiheader
185         .size undiheader, . - undiheader
186
187 ipxeheader:
188         .ascii  "iPXE"                  /* Signature */
189         .byte   ipxeheader_len          /* Length of structure */
190         .byte   0                       /* Checksum */
191 shrunk_rom_size:
192         .byte   0                       /* Shrunk size (in 512-byte blocks) */
193         .byte   0                       /* Reserved */
194 build_id:
195         .long   _build_id               /* Randomly-generated build ID */
196         .equ ipxeheader_len, . - ipxeheader
197         .size ipxeheader, . - ipxeheader
198
199         .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
200         .ascii  "ADHB"
201         .long   shrunk_rom_size
202         .long   512
203         .long   0
204         .previous
205
206 /* Initialisation (called once during POST)
207  *
208  * Determine whether or not this is a PnP system via a signature
209  * check.  If it is PnP, return to the PnP BIOS indicating that we are
210  * a boot-capable device; the BIOS will call our boot execution vector
211  * if it wants to boot us.  If it is not PnP, hook INT 19.
212  */
213 init:
214         /* Preserve registers, clear direction flag, set %ds=%cs */
215         pushaw
216         pushw   %ds
217         pushw   %es
218         pushw   %fs
219         pushw   %gs
220         cld
221         pushw   %cs
222         popw    %ds
223
224         /* Print message as early as possible */
225         movw    $init_message, %si
226         xorw    %di, %di
227         call    print_message
228
229         /* Store PCI 3.0 runtime segment address for later use, if
230          * applicable.
231          */
232 .ifeqs  BUSTYPE, "PCIR"
233         movw    %bx, %gs
234 .endif
235
236         /* Store PCI bus:dev.fn address, print PCI bus:dev.fn, and add
237          * PCI bus:dev.fn to product name string, if applicable.
238          */
239 .ifeqs  BUSTYPE, "PCIR"
240         xorw    %di, %di
241         call    print_space
242         movw    %ax, init_pci_busdevfn
243         call    print_pci_busdevfn
244         movw    $prodstr_pci_id, %di
245         call    print_pci_busdevfn
246         movb    $( ' ' ), prodstr_separator
247 .endif
248
249         /* Print segment address */
250         xorw    %di, %di
251         call    print_space
252         movw    %cs, %ax
253         call    print_hex_word
254
255         /* Check for PCI BIOS version, if applicable */
256 .ifeqs  BUSTYPE, "PCIR"
257         pushl   %ebx
258         pushl   %edx
259         pushl   %edi
260         stc
261         movw    $0xb101, %ax
262         int     $0x1a
263         jc      no_pci3
264         cmpl    $PCI_SIGNATURE, %edx
265         jne     no_pci3
266         testb   %ah, %ah
267         jnz     no_pci3
268         movw    $init_message_pci, %si
269         xorw    %di, %di
270         call    print_message
271         movb    %bh, %al
272         call    print_hex_nibble
273         movb    $( '.' ), %al
274         call    print_character
275         movb    %bl, %al
276         call    print_hex_byte
277         cmpb    $3, %bh
278         jb      no_pci3
279         /* PCI >=3.0: leave %gs as-is if sane */
280         movw    %gs, %ax
281         cmpw    $0xa000, %ax    /* Insane if %gs < 0xa000 */
282         jb      pci3_insane
283         movw    %cs, %bx        /* Sane if %cs == %gs */
284         cmpw    %bx, %ax
285         je      1f
286         movzbw  romheader_size, %cx /* Sane if %cs+len <= %gs */
287         shlw    $5, %cx
288         addw    %cx, %bx
289         cmpw    %bx, %ax
290         jae     1f
291         movw    %cs, %bx        /* Sane if %gs+len <= %cs */
292         addw    %cx, %ax
293         cmpw    %bx, %ax
294         jbe     1f
295 pci3_insane: /* PCI 3.0 with insane %gs value: print error and ignore %gs */
296         movb    $( '!' ), %al
297         call    print_character
298         movw    %gs, %ax
299         call    print_hex_word
300 no_pci3:
301         /* PCI <3.0: set %gs (runtime segment) = %cs (init-time segment) */
302         pushw   %cs
303         popw    %gs
304 1:      popl    %edi
305         popl    %edx
306         popl    %ebx
307 .endif  /* PCIR */
308
309         /* Check for PnP BIOS.  Although %es:di should point to the
310          * PnP BIOS signature on entry, some BIOSes fail to do this.
311          */
312         movw    $( 0xf000 - 1 ), %bx
313 pnp_scan:
314         incw    %bx
315         jz      no_pnp
316         movw    %bx, %es
317         cmpl    $PNP_SIGNATURE, %es:0
318         jne     pnp_scan
319         xorw    %dx, %dx
320         xorw    %si, %si
321         movzbw  %es:5, %cx
322 1:      es lodsb
323         addb    %al, %dl
324         loop    1b
325         jnz     pnp_scan
326         /* Is PnP: print PnP message */
327         movw    $init_message_pnp, %si
328         xorw    %di, %di
329         call    print_message
330         jmp     pnp_done
331 no_pnp: /* Not PnP-compliant - hook INT 19 */
332 #ifdef NONPNP_HOOK_INT19
333         movw    $init_message_int19, %si
334         xorw    %di, %di
335         call    print_message
336         xorw    %ax, %ax
337         movw    %ax, %es
338         pushl   %es:( 0x19 * 4 )
339         popl    orig_int19
340         pushw   %gs /* %gs contains runtime %cs */
341         pushw   $int19_entry
342         popl    %es:( 0x19 * 4 )
343 #endif /* NONPNP_HOOK_INT19 */
344 pnp_done:
345
346         /* Check for PMM */
347         movw    $( 0xe000 - 1 ), %bx
348 pmm_scan:
349         incw    %bx
350         jz      no_pmm
351         movw    %bx, %es
352         cmpl    $PMM_SIGNATURE, %es:0
353         jne     pmm_scan
354         xorw    %dx, %dx
355         xorw    %si, %si
356         movzbw  %es:5, %cx
357 1:      es lodsb
358         addb    %al, %dl
359         loop    1b
360         jnz     pmm_scan
361         /* PMM found: print PMM message */
362         movw    $init_message_pmm, %si
363         xorw    %di, %di
364         call    print_message
365         /* We have PMM and so a 1kB stack: preserve whole registers */
366         pushal
367         /* Allocate image source PMM block.  Round up the size to the
368          * nearest 4kB (8 512-byte sectors) to work around AMI BIOS bugs.
369          */
370         movzbl  romheader_size, %ecx
371         addw    extra_size, %cx
372         addw    $0x0007, %cx    /* Round up to multiple of 8 512-byte sectors */
373         andw    $0xfff8, %cx
374         shll    $5, %ecx
375         movl    $PMM_HANDLE_BASE_IMAGE_SOURCE, %ebx
376         movw    $get_pmm_image_source, %bp
377         call    get_pmm
378         movl    %esi, image_source
379         jz      1f
380         /* Copy ROM to image source PMM block */
381         pushw   %es
382         xorw    %ax, %ax
383         movw    %ax, %es
384         movl    %esi, %edi
385         xorl    %esi, %esi
386         movzbl  romheader_size, %ecx
387         shll    $7, %ecx
388         addr32 rep movsl        /* PMM presence implies flat real mode */
389         popw    %es
390         /* Shrink ROM */
391         movb    shrunk_rom_size, %al
392         movb    %al, romheader_size
393 1:      /* Allocate decompression PMM block.  Round up the size to the
394          * nearest 128kB and use the size within the PMM handle; this
395          * allows the same decompression area to be shared between
396          * multiple iPXE ROMs even with differing build IDs
397          */
398         movl    $_textdata_memsz_pgh, %ecx
399         addl    $0x00001fff, %ecx
400         andl    $0xffffe000, %ecx
401         movl    %ecx, %ebx
402         shrw    $12, %bx
403         orl     $PMM_HANDLE_BASE_DECOMPRESS_TO, %ebx
404         movw    $get_pmm_decompress_to, %bp
405         call    get_pmm
406         movl    %esi, decompress_to
407         /* Restore registers */
408         popal
409 no_pmm:
410
411         /* Update checksum */
412         xorw    %bx, %bx
413         xorw    %si, %si
414         movzbw  romheader_size, %cx
415         shlw    $9, %cx
416 1:      lodsb
417         addb    %al, %bl
418         loop    1b
419         subb    %bl, checksum
420
421         /* Copy self to option ROM space, if applicable.  Required for
422          * PCI3.0, which loads us to a temporary location in low
423          * memory.  Will be a no-op for lower PCI versions.
424          */
425 .ifeqs  BUSTYPE, "PCIR"
426         xorw    %di, %di
427         call    print_space
428         movw    %gs, %ax
429         call    print_hex_word
430         movzbw  romheader_size, %cx
431         shlw    $9, %cx
432         movw    %ax, %es
433         xorw    %si, %si
434         xorw    %di, %di
435         cs rep  movsb
436 .endif
437
438         /* Skip prompt if this is not the first PCI function, if applicable */
439 .ifeqs  BUSTYPE, "PCIR"
440         testb   $PCI_FUNC_MASK, init_pci_busdevfn
441         jnz     no_shell
442 .endif
443         /* Prompt for POST-time shell */
444         movw    $init_message_prompt, %si
445         xorw    %di, %di
446         call    print_message
447         movw    $prodstr, %si
448         call    print_message
449         movw    $init_message_dots, %si
450         call    print_message
451         /* Wait for Ctrl-B */
452         movw    $0xff02, %bx
453         call    wait_for_key
454         /* Clear prompt */
455         pushf
456         xorw    %di, %di
457         call    print_kill_line
458         movw    $init_message_done, %si
459         call    print_message
460         popf
461         jnz     no_shell
462         /* Ctrl-B was pressed: invoke iPXE.  The keypress will be
463          * picked up by the initial shell prompt, and we will drop
464          * into a shell.
465          */
466         xorl    %ebp, %ebp      /* Inhibit use of INT 15,e820 and INT 15,e801 */
467         pushw   %cs
468         call    exec
469 no_shell:
470         movb    $( '\n' ), %al
471         xorw    %di, %di
472         call    print_character
473
474         /* Restore registers */
475         popw    %gs
476         popw    %fs
477         popw    %es
478         popw    %ds
479         popaw
480
481         /* Indicate boot capability to PnP BIOS, if present */
482         movw    $0x20, %ax
483         lret
484         .size init, . - init
485
486 /* Attempt to find or allocate PMM block
487  *
488  * Parameters:
489  *  %ecx : size of block to allocate, in paragraphs
490  *  %ebx : PMM handle base
491  *  %bp : routine to check acceptability of found blocks
492  *  %es:0000 : PMM structure
493  * Returns:
494  *  %ebx : PMM handle
495  *  %esi : allocated block address, or zero (with ZF set) if allocation failed
496  */
497 get_pmm:
498         /* Preserve registers */
499         pushl   %eax
500         pushw   %di
501         movw    $( ' ' ), %di
502 get_pmm_find:
503         /* Try to find existing block */
504         pushl   %ebx            /* PMM handle */
505         pushw   $PMM_FIND
506         lcall   *%es:7
507         addw    $6, %sp
508         pushw   %dx
509         pushw   %ax
510         popl    %esi
511         /* Treat 0xffffffff (not supported) as 0x00000000 (not found) */
512         incl    %esi
513         jz      get_pmm_allocate
514         decl    %esi
515         jz      get_pmm_allocate
516         /* Block found - check acceptability */
517         call    *%bp
518         jnc     get_pmm_done
519         /* Block not acceptable - increment handle and retry */
520         incl    %ebx
521         jmp     get_pmm_find
522 get_pmm_allocate:
523         /* Block not found - try to allocate new block */
524         pushw   $0x0002         /* Extended memory */
525         pushl   %ebx            /* PMM handle */
526         pushl   %ecx            /* Length */
527         pushw   $PMM_ALLOCATE
528         lcall   *%es:7
529         addw    $12, %sp
530         pushw   %dx
531         pushw   %ax
532         popl    %esi
533         movw    $( '+' ), %di   /* Indicate allocation attempt */
534 get_pmm_done:
535         /* Print block address */
536         movw    %di, %ax
537         xorw    %di, %di
538         call    print_character
539         movl    %esi, %eax
540         call    print_hex_dword
541         /* Treat 0xffffffff (not supported) as 0x00000000 (allocation
542          * failed), and set ZF to indicate a zero result.
543          */
544         incl    %esi
545         jz      1f
546         decl    %esi
547 1:      /* Restore registers and return */
548         popw    %di
549         popl    %eax
550         ret
551         .size   get_pmm, . - get_pmm
552
553         /* Check acceptability of image source block */
554 get_pmm_image_source:
555         pushw   %es
556         xorw    %ax, %ax
557         movw    %ax, %es
558         movl    build_id, %eax
559         addr32 cmpl %es:build_id(%esi), %eax
560         je      1f
561         stc
562 1:      popw    %es
563         ret
564         .size   get_pmm_image_source, . - get_pmm_image_source
565
566         /* Check acceptability of decompression block */
567 get_pmm_decompress_to:
568         clc
569         ret
570         .size   get_pmm_decompress_to, . - get_pmm_decompress_to
571
572 /*
573  * Note to hardware vendors:
574  *
575  * If you wish to brand this boot ROM, please do so by defining the
576  * strings PRODUCT_NAME and PRODUCT_SHORT_NAME in config/general.h.
577  *
578  * While nothing in the GPL prevents you from removing all references
579  * to iPXE or http://ipxe.org, we prefer you not to do so.
580  *
581  * If you have an OEM-mandated branding requirement that cannot be
582  * satisfied simply by defining PRODUCT_NAME and PRODUCT_SHORT_NAME,
583  * please contact us.
584  *
585  * [ Including an ASCII NUL in PRODUCT_NAME is considered to be
586  *   bypassing the spirit of this request! ]
587  */
588 init_message:
589         .ascii  "\n"
590         .ascii  PRODUCT_NAME
591         .ascii  "\n"
592         .asciz  "iPXE (http://ipxe.org)"
593         .size   init_message, . - init_message
594 .ifeqs  BUSTYPE, "PCIR"
595 init_message_pci:
596         .asciz  " PCI"
597         .size   init_message_pci, . - init_message_pci
598 .endif  /* PCIR */
599 init_message_pnp:
600         .asciz  " PnP"
601         .size   init_message_pnp, . - init_message_pnp
602 init_message_pmm:
603         .asciz  " PMM"
604         .size   init_message_pmm, . - init_message_pmm
605 init_message_int19:
606         .asciz  " INT19"
607         .size   init_message_int19, . - init_message_int19
608 init_message_prompt:
609         .asciz  "\nPress Ctrl-B to configure "
610         .size   init_message_prompt, . - init_message_prompt
611 init_message_dots:
612         .asciz  "..."
613         .size   init_message_dots, . - init_message_dots
614 init_message_done:
615         .asciz  "\n\n"
616         .size   init_message_done, . - init_message_done
617
618 /* PCI bus:dev.fn
619  *
620  */
621 .ifeqs  BUSTYPE, "PCIR"
622 init_pci_busdevfn:
623         .word   0
624         .size   init_pci_busdevfn, . - init_pci_busdevfn
625 .endif  /* PCIR */
626
627 /* Image source area
628  *
629  * May be either zero (indicating to use option ROM space as source),
630  * or within a PMM-allocated block.
631  */
632         .globl  image_source
633 image_source:
634         .long   0
635         .size   image_source, . - image_source
636
637 /* Additional image source size (in 512-byte sectors)
638  *
639  */
640 extra_size:
641         .word   0
642         .size   extra_size, . - extra_size
643
644 /* Temporary decompression area
645  *
646  * May be either zero (indicating to use default decompression area in
647  * high memory), or within a PMM-allocated block.
648  */
649         .globl  decompress_to
650 decompress_to:
651         .long   0
652         .size   decompress_to, . - decompress_to
653
654 /* Boot Execution Vector entry point
655  *
656  * Called by the PnP BIOS when it wants to boot us.
657  */
658 bev_entry:
659         orl     $0xffffffff, %ebp       /* Allow arbitrary relocation */
660         pushw   %cs
661         call    exec
662         lret
663         .size   bev_entry, . - bev_entry
664
665 /* INT19 entry point
666  *
667  * Called via the hooked INT 19 if we detected a non-PnP BIOS.  We
668  * attempt to return via the original INT 19 vector (if we were able
669  * to store it).
670  */
671 int19_entry:
672         pushw   %cs
673         popw    %ds
674         /* Prompt user to press B to boot */
675         movw    $int19_message_prompt, %si
676         xorw    %di, %di
677         call    print_message
678         movw    $prodstr, %si
679         call    print_message
680         movw    $int19_message_dots, %si
681         call    print_message
682         movw    $0xdf4e, %bx
683         call    wait_for_key
684         pushf
685         xorw    %di, %di
686         call    print_kill_line
687         movw    $int19_message_done, %si
688         call    print_message
689         popf
690         jz      1f
691         /* Leave keypress in buffer and start iPXE.  The keypress will
692          * cause the usual initial Ctrl-B prompt to be skipped.
693          */
694         orl     $0xffffffff, %ebp       /* Allow arbitrary relocation */
695         pushw   %cs
696         call    exec
697 1:      /* Try to call original INT 19 vector */
698         movl    %cs:orig_int19, %eax
699         testl   %eax, %eax
700         je      2f
701         ljmp    *%cs:orig_int19
702 2:      /* No chained vector: issue INT 18 as a last resort */
703         int     $0x18
704         .size   int19_entry, . - int19_entry
705 orig_int19:
706         .long   0
707         .size   orig_int19, . - orig_int19
708
709 int19_message_prompt:
710         .asciz  "Press N to skip booting from "
711         .size   int19_message_prompt, . - int19_message_prompt
712 int19_message_dots:
713         .asciz  "..."
714         .size   int19_message_dots, . - int19_message_dots
715 int19_message_done:
716         .asciz  "\n\n"
717         .size   int19_message_done, . - int19_message_done
718         
719 /* Execute as a boot device
720  *
721  */
722 exec:   /* Set %ds = %cs */
723         pushw   %cs
724         popw    %ds
725
726         /* Print message as soon as possible */
727         movw    $prodstr, %si
728         xorw    %di, %di
729         call    print_message
730         movw    $exec_message_pre_install, %si
731         call    print_message
732
733         /* Store magic word on BIOS stack and remember BIOS %ss:sp */
734         pushl   $STACK_MAGIC
735         movw    %ss, %cx
736         movw    %sp, %dx
737
738         /* Obtain a reasonably-sized temporary stack */
739         xorw    %bx, %bx
740         movw    %bx, %ss
741         movw    $0x7c00, %sp
742
743         /* Install iPXE */
744         call    alloc_basemem
745         movl    image_source, %esi
746         movl    decompress_to, %edi
747         call    install_prealloc
748
749         /* Print message indicating successful installation */
750         movw    $exec_message_post_install, %si
751         xorw    %di, %di
752         call    print_message
753
754         /* Set up real-mode stack */
755         movw    %bx, %ss
756         movw    $_estack16, %sp
757
758         /* Jump to .text16 segment */
759         pushw   %ax
760         pushw   $1f
761         lret
762         .section ".text16", "awx", @progbits
763 1:
764         /* Retrieve PCI bus:dev.fn, if applicable */
765 .ifeqs  BUSTYPE, "PCIR"
766         movw    init_pci_busdevfn, %ax
767 .endif
768
769         /* Set up %ds for access to .data16 */
770         movw    %bx, %ds
771
772         /* Store PCI bus:dev.fn, if applicable */
773 .ifeqs  BUSTYPE, "PCIR"
774         movw    %ax, autoboot_busdevfn
775 .endif
776
777         /* Call main() */
778         pushl   $main
779         pushw   %cs
780         call    prot_call
781         popl    %eax /* discard */
782
783         /* Set up flat real mode for return to BIOS */
784         call    flatten_real_mode
785
786         /* Uninstall iPXE */
787         call    uninstall
788
789         /* Restore BIOS stack */
790         movw    %cx, %ss
791         movw    %dx, %sp
792
793         /* Check magic word on BIOS stack */
794         popl    %eax
795         cmpl    $STACK_MAGIC, %eax
796         jne     1f
797         /* BIOS stack OK: return to caller */
798         lret
799 1:      /* BIOS stack corrupt: use INT 18 */
800         int     $0x18
801         .previous
802
803 exec_message_pre_install:
804         .asciz  " starting execution..."
805         .size exec_message_pre_install, . - exec_message_pre_install
806 exec_message_post_install:
807         .asciz  "ok\n"
808         .size exec_message_post_install, . - exec_message_post_install
809
810 /* Wait for key press specified by %bl (masked by %bh)
811  *
812  * Used by init and INT19 code when prompting user.  If the specified
813  * key is pressed, it is left in the keyboard buffer.
814  *
815  * Returns with ZF set iff specified key is pressed.
816  */
817 wait_for_key:
818         /* Preserve registers */
819         pushw   %cx
820         pushw   %ax
821 1:      /* Empty the keyboard buffer before waiting for input */
822         movb    $0x01, %ah
823         int     $0x16
824         jz      2f
825         xorw    %ax, %ax
826         int     $0x16
827         jmp     1b
828 2:      /* Wait for a key press */
829         movw    $ROM_BANNER_TIMEOUT_TICKS, %cx
830 3:      decw    %cx
831         js      99f             /* Exit with ZF clear */
832         /* Wait for timer tick to be updated */
833         call    wait_for_tick
834         /* Check to see if a key was pressed */
835         movb    $0x01, %ah
836         int     $0x16
837         jz      3b
838         /* Check to see if key was the specified key */
839         andb    %bh, %al
840         cmpb    %al, %bl
841         je      99f             /* Exit with ZF set */
842         /* Not the specified key: remove from buffer and stop waiting */
843         pushfw
844         xorw    %ax, %ax
845         int     $0x16
846         popfw                   /* Exit with ZF clear */
847 99:     /* Restore registers and return */
848         popw    %ax
849         popw    %cx
850         ret
851         .size wait_for_key, . - wait_for_key
852
853 /* Wait for timer tick
854  *
855  * Used by wait_for_key
856  */
857 wait_for_tick:
858         pushl   %eax
859         pushw   %fs
860         movw    $0x40, %ax
861         movw    %ax, %fs
862         movl    %fs:(0x6c), %eax
863 1:      pushf
864         sti
865         hlt
866         popf
867         cmpl    %fs:(0x6c), %eax
868         je      1b
869         popw    %fs
870         popl    %eax
871         ret
872         .size wait_for_tick, . - wait_for_tick