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