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