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.
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.
9 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
11 #include <config/general.h>
12 #include <config/branding.h>
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
29 /* ROM banner timeout, converted to a number of (18Hz) timer ticks. */
30 #define ROM_BANNER_TIMEOUT_TICKS ( ( 18 * ROM_BANNER_TIMEOUT ) / 10 )
32 /* Allow payload to be excluded from ROM size
34 #if ROMPREFIX_EXCLUDE_PAYLOAD
35 #define ZINFO_TYPE_ADxB "ADHB"
36 #define ZINFO_TYPE_ADxW "ADHW"
38 #define ZINFO_TYPE_ADxB "ADDB"
39 #define ZINFO_TYPE_ADxW "ADDW"
42 /* Allow ROM to be marked as containing multiple images
44 #if ROMPREFIX_MORE_IMAGES
45 #define INDICATOR 0x00
47 #define INDICATOR 0x80
50 /* Default to building a PCI ROM if no bus type is specified
53 #define BUSTYPE "PCIR"
59 .section ".prefix", "ax", @progbits
65 .word 0xAA55 /* BIOS extension signature */
66 romheader_size: .byte 0 /* Size in 512-byte blocks */
67 jmp init /* Initialisation vector */
74 .ifeqs BUSTYPE, "PCIR"
80 .size romheader, . - romheader
82 .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
83 .ascii ZINFO_TYPE_ADxB
89 .ifeqs BUSTYPE, "PCIR"
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
110 /* PCI additional device list (filled in by linker) */
111 .section ".pci_devlist.00000000", "a", @progbits
114 .section ".pci_devlist.ffffffff", "a", @progbits
116 .short 0x0000 /* List terminator */
118 /* Ensure that terminator is always present */
119 .reloc pciheader, RELOC_TYPE_NONE, pci_devlist_end
121 .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
122 .ascii ZINFO_TYPE_ADxW
123 .long pciheader_image_length
126 .ascii ZINFO_TYPE_ADxW
127 .long pciheader_runtime_length
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
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
160 /* Manufacturer string */
162 .asciz "http://ipxe.org"
163 .size mfgstr, . - mfgstr
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.
172 .ascii PRODUCT_SHORT_NAME
173 .ifeqs BUSTYPE, "PCIR"
178 .ascii "xx:xx.x)" /* Filled in by init code */
181 .size prodstr, . - prodstr
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
200 .ascii "iPXE" /* Signature */
201 .byte ipxeheader_len /* Length of structure */
202 .byte 0 /* Checksum */
204 .byte 0 /* Shrunk size (in 512-byte blocks) */
205 .byte 0 /* Reserved */
207 .long _build_id /* Randomly-generated build ID */
208 .equ ipxeheader_len, . - ipxeheader
209 .size ipxeheader, . - ipxeheader
211 .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
213 .long shrunk_rom_size
218 /* Initialisation (called once during POST)
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.
226 /* Preserve registers, clear direction flag, set %ds=%cs */
236 /* Print message as early as possible */
237 movw $init_message, %si
241 /* Store PCI 3.0 runtime segment address for later use, if
244 .ifeqs BUSTYPE, "PCIR"
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.
251 .ifeqs BUSTYPE, "PCIR"
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
261 /* Print segment address */
267 /* Check for PCI BIOS version, if applicable */
268 .ifeqs BUSTYPE, "PCIR"
276 cmpl $PCI_SIGNATURE, %edx
280 movw $init_message_pci, %si
284 call print_hex_nibble
291 /* PCI >=3.0: leave %gs as-is if sane */
293 cmpw $0xa000, %ax /* Insane if %gs < 0xa000 */
295 movw %cs, %bx /* Sane if %cs == %gs */
298 movzbw romheader_size, %cx /* Sane if %cs+len <= %gs */
303 movw %cs, %bx /* Sane if %gs+len <= %cs */
307 pci3_insane: /* PCI 3.0 with insane %gs value: print error and ignore %gs */
313 /* PCI <3.0: set %gs (runtime segment) = %cs (init-time segment) */
321 /* Check for PnP BIOS. Although %es:di should point to the
322 * PnP BIOS signature on entry, some BIOSes fail to do this.
324 movw $( 0xf000 - 1 ), %bx
329 cmpl $PNP_SIGNATURE, %es:0
338 /* Is PnP: print PnP message */
339 movw $init_message_pnp, %si
343 no_pnp: /* Not PnP-compliant - hook INT 19 */
344 #ifdef NONPNP_HOOK_INT19
345 movw $init_message_int19, %si
350 pushl %es:( 0x19 * 4 )
352 pushw %gs /* %gs contains runtime %cs */
354 popl %es:( 0x19 * 4 )
355 #endif /* NONPNP_HOOK_INT19 */
359 movw $( 0xe000 - 1 ), %bx
364 cmpl $PMM_SIGNATURE, %es:0
373 /* PMM found: print PMM message */
374 movw $init_message_pmm, %si
377 /* We have PMM and so a 1kB stack: preserve whole registers */
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.
382 movzbl romheader_size, %ecx
384 addw $0x0007, %cx /* Round up to multiple of 8 512-byte sectors */
387 movl $PMM_HANDLE_BASE_IMAGE_SOURCE, %ebx
388 movw $get_pmm_image_source, %bp
390 movl %esi, image_source
392 /* Copy ROM to image source PMM block */
398 movzbl romheader_size, %ecx
400 addr32 rep movsl /* PMM presence implies flat real mode */
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
410 movl $_textdata_memsz_pgh, %ecx
411 addl $0x00001fff, %ecx
412 andl $0xffffe000, %ecx
415 orl $PMM_HANDLE_BASE_DECOMPRESS_TO, %ebx
416 movw $get_pmm_decompress_to, %bp
418 movl %esi, decompress_to
419 /* Restore registers */
423 /* Update checksum */
426 movzbw romheader_size, %cx
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.
437 .ifeqs BUSTYPE, "PCIR"
442 movzbw romheader_size, %cx
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
455 /* Prompt for POST-time shell */
456 movw $init_message_prompt, %si
461 movw $init_message_dots, %si
463 /* Wait for Ctrl-B */
470 movw $init_message_done, %si
474 /* Ctrl-B was pressed: invoke iPXE. The keypress will be
475 * picked up by the initial shell prompt, and we will drop
478 xorl %ebp, %ebp /* Inhibit use of INT 15,e820 and INT 15,e801 */
486 /* Restore registers */
493 /* Indicate boot capability to PnP BIOS, if present */
498 /* Attempt to find or allocate PMM block
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
507 * %esi : allocated block address, or zero (with ZF set) if allocation failed
510 /* Preserve registers */
515 /* Try to find existing block */
516 pushl %ebx /* PMM handle */
523 /* Treat 0xffffffff (not supported) as 0x00000000 (not found) */
528 /* Block found - check acceptability */
531 /* Block not acceptable - increment handle and retry */
535 /* Block not found - try to allocate new block */
536 pushw $0x0002 /* Extended memory */
537 pushl %ebx /* PMM handle */
538 pushl %ecx /* Length */
545 movw $( '+' ), %di /* Indicate allocation attempt */
547 /* Print block address */
553 /* Treat 0xffffffff (not supported) as 0x00000000 (allocation
554 * failed), and set ZF to indicate a zero result.
559 1: /* Restore registers and return */
563 .size get_pmm, . - get_pmm
565 /* Check acceptability of image source block */
566 get_pmm_image_source:
571 addr32 cmpl %es:build_id(%esi), %eax
576 .size get_pmm_image_source, . - get_pmm_image_source
578 /* Check acceptability of decompression block */
579 get_pmm_decompress_to:
582 .size get_pmm_decompress_to, . - get_pmm_decompress_to
585 * Note to hardware vendors:
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.
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.
593 * If you have an OEM-mandated branding requirement that cannot be
594 * satisfied simply by defining PRODUCT_NAME and PRODUCT_SHORT_NAME,
597 * [ Including an ASCII NUL in PRODUCT_NAME is considered to be
598 * bypassing the spirit of this request! ]
604 .ascii PRODUCT_SHORT_NAME
608 .size init_message, . - init_message
609 .ifeqs BUSTYPE, "PCIR"
612 .size init_message_pci, . - init_message_pci
616 .size init_message_pnp, . - init_message_pnp
619 .size init_message_pmm, . - init_message_pmm
622 .size init_message_int19, . - init_message_int19
624 .asciz "\nPress Ctrl-B to configure "
625 .size init_message_prompt, . - init_message_prompt
628 .size init_message_dots, . - init_message_dots
631 .size init_message_done, . - init_message_done
636 .ifeqs BUSTYPE, "PCIR"
639 .size init_pci_busdevfn, . - init_pci_busdevfn
644 * May be either zero (indicating to use option ROM space as source),
645 * or within a PMM-allocated block.
650 .size image_source, . - image_source
652 /* Additional image source size (in 512-byte sectors)
657 .size extra_size, . - extra_size
659 /* Temporary decompression area
661 * May be either zero (indicating to use default decompression area in
662 * high memory), or within a PMM-allocated block.
667 .size decompress_to, . - decompress_to
669 /* Boot Execution Vector entry point
671 * Called by the PnP BIOS when it wants to boot us.
674 orl $0xffffffff, %ebp /* Allow arbitrary relocation */
678 .size bev_entry, . - bev_entry
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
689 /* Prompt user to press B to boot */
690 movw $int19_message_prompt, %si
695 movw $int19_message_dots, %si
702 movw $int19_message_done, %si
706 /* Leave keypress in buffer and start iPXE. The keypress will
707 * cause the usual initial Ctrl-B prompt to be skipped.
709 orl $0xffffffff, %ebp /* Allow arbitrary relocation */
712 1: /* Try to call original INT 19 vector */
713 movl %cs:orig_int19, %eax
717 2: /* No chained vector: issue INT 18 as a last resort */
719 .size int19_entry, . - int19_entry
722 .size orig_int19, . - orig_int19
724 int19_message_prompt:
725 .asciz "Press N to skip booting from "
726 .size int19_message_prompt, . - int19_message_prompt
729 .size int19_message_dots, . - int19_message_dots
732 .size int19_message_done, . - int19_message_done
734 /* Execute as a boot device
737 exec: /* Set %ds = %cs */
741 /* Print message as soon as possible */
745 movw $exec_message_pre_install, %si
748 /* Store magic word on BIOS stack and remember BIOS %ss:sp */
753 /* Obtain a reasonably-sized temporary stack */
760 movl image_source, %esi
761 movl decompress_to, %edi
762 call install_prealloc
764 /* Print message indicating successful installation */
765 movw $exec_message_post_install, %si
769 /* Set up real-mode stack */
773 /* Jump to .text16 segment */
777 .section ".text16", "awx", @progbits
779 /* Retrieve PCI bus:dev.fn, if applicable */
780 .ifeqs BUSTYPE, "PCIR"
781 movw init_pci_busdevfn, %ax
784 /* Set up %ds for access to .data16 */
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 */
798 popl %eax /* discard */
800 /* Set up flat real mode for return to BIOS */
801 call flatten_real_mode
806 /* Restore BIOS stack */
810 /* Check magic word on BIOS stack */
812 cmpl $STACK_MAGIC, %eax
814 /* BIOS stack OK: return to caller */
816 1: /* BIOS stack corrupt: use INT 18 */
820 exec_message_pre_install:
821 .asciz " starting execution..."
822 .size exec_message_pre_install, . - exec_message_pre_install
823 exec_message_post_install:
825 .size exec_message_post_install, . - exec_message_post_install
827 /* Wait for key press specified by %bl (masked by %bh)
829 * Used by init and INT19 code when prompting user. If the specified
830 * key is pressed, it is left in the keyboard buffer.
832 * Returns with ZF set iff specified key is pressed.
835 /* Preserve registers */
838 1: /* Empty the keyboard buffer before waiting for input */
845 2: /* Wait for a key press */
846 movw $ROM_BANNER_TIMEOUT_TICKS, %cx
848 js 99f /* Exit with ZF clear */
849 /* Wait for timer tick to be updated */
851 /* Check to see if a key was pressed */
855 /* Check to see if key was the specified key */
858 je 99f /* Exit with ZF set */
859 /* Not the specified key: remove from buffer and stop waiting */
863 popfw /* Exit with ZF clear */
864 99: /* Restore registers and return */
868 .size wait_for_key, . - wait_for_key
870 /* Wait for timer tick
872 * Used by wait_for_key
879 movl %fs:(0x6c), %eax
884 cmpl %fs:(0x6c), %eax
889 .size wait_for_tick, . - wait_for_tick
891 /* Drag in objects via _rom_start */
892 REQUIRING_SYMBOL ( _rom_start )
894 /* Drag in ROM configuration */
895 REQUIRE_OBJECT ( config_romprefix )