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 )
11 #include <config/general.h>
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
28 /* ROM banner timeout, converted to a number of (18Hz) timer ticks. */
29 #define ROM_BANNER_TIMEOUT_TICKS ( ( 18 * ROM_BANNER_TIMEOUT ) / 10 )
31 /* Allow payload to be excluded from ROM size
33 #if ROMPREFIX_EXCLUDE_PAYLOAD
34 #define ZINFO_TYPE_ADxB "ADHB"
35 #define ZINFO_TYPE_ADxW "ADHW"
37 #define ZINFO_TYPE_ADxB "ADDB"
38 #define ZINFO_TYPE_ADxW "ADDW"
41 /* Allow ROM to be marked as containing multiple images
43 #if ROMPREFIX_MORE_IMAGES
44 #define INDICATOR 0x00
46 #define INDICATOR 0x80
49 /* Default to building a PCI ROM if no bus type is specified
52 #define BUSTYPE "PCIR"
58 .section ".prefix", "ax", @progbits
64 .word 0xAA55 /* BIOS extension signature */
65 romheader_size: .byte 0 /* Size in 512-byte blocks */
66 jmp init /* Initialisation vector */
73 .ifeqs BUSTYPE, "PCIR"
79 .size romheader, . - romheader
81 .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
82 .ascii ZINFO_TYPE_ADxB
88 .ifeqs BUSTYPE, "PCIR"
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
109 .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
110 .ascii ZINFO_TYPE_ADxW
111 .long pciheader_image_length
114 .ascii ZINFO_TYPE_ADxW
115 .long pciheader_runtime_length
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
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
148 /* Manufacturer string */
150 .asciz "http://ipxe.org"
151 .size mfgstr, . - mfgstr
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.
160 .ascii PRODUCT_SHORT_NAME
161 .ifeqs BUSTYPE, "PCIR"
166 .ascii "xx:xx.x)" /* Filled in by init code */
169 .size prodstr, . - prodstr
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
188 .ascii "iPXE" /* Signature */
189 .byte ipxeheader_len /* Length of structure */
190 .byte 0 /* Checksum */
192 .byte 0 /* Shrunk size (in 512-byte blocks) */
193 .byte 0 /* Reserved */
195 .long _build_id /* Randomly-generated build ID */
196 .equ ipxeheader_len, . - ipxeheader
197 .size ipxeheader, . - ipxeheader
199 .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
201 .long shrunk_rom_size
206 /* Initialisation (called once during POST)
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.
214 /* Preserve registers, clear direction flag, set %ds=%cs */
224 /* Print message as early as possible */
225 movw $init_message, %si
229 /* Store PCI 3.0 runtime segment address for later use, if
232 .ifeqs BUSTYPE, "PCIR"
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.
239 .ifeqs BUSTYPE, "PCIR"
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
249 /* Print segment address */
255 /* Check for PCI BIOS version, if applicable */
256 .ifeqs BUSTYPE, "PCIR"
264 cmpl $PCI_SIGNATURE, %edx
268 movw $init_message_pci, %si
272 call print_hex_nibble
279 /* PCI >=3.0: leave %gs as-is if sane */
281 cmpw $0xa000, %ax /* Insane if %gs < 0xa000 */
283 movw %cs, %bx /* Sane if %cs == %gs */
286 movzbw romheader_size, %cx /* Sane if %cs+len <= %gs */
291 movw %cs, %bx /* Sane if %gs+len <= %cs */
295 pci3_insane: /* PCI 3.0 with insane %gs value: print error and ignore %gs */
301 /* PCI <3.0: set %gs (runtime segment) = %cs (init-time segment) */
309 /* Check for PnP BIOS. Although %es:di should point to the
310 * PnP BIOS signature on entry, some BIOSes fail to do this.
312 movw $( 0xf000 - 1 ), %bx
317 cmpl $PNP_SIGNATURE, %es:0
326 /* Is PnP: print PnP message */
327 movw $init_message_pnp, %si
331 no_pnp: /* Not PnP-compliant - hook INT 19 */
332 #ifdef NONPNP_HOOK_INT19
333 movw $init_message_int19, %si
338 pushl %es:( 0x19 * 4 )
340 pushw %gs /* %gs contains runtime %cs */
342 popl %es:( 0x19 * 4 )
343 #endif /* NONPNP_HOOK_INT19 */
347 movw $( 0xe000 - 1 ), %bx
352 cmpl $PMM_SIGNATURE, %es:0
361 /* PMM found: print PMM message */
362 movw $init_message_pmm, %si
365 /* We have PMM and so a 1kB stack: preserve whole registers */
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.
370 movzbl romheader_size, %ecx
372 addw $0x0007, %cx /* Round up to multiple of 8 512-byte sectors */
375 movl $PMM_HANDLE_BASE_IMAGE_SOURCE, %ebx
376 movw $get_pmm_image_source, %bp
378 movl %esi, image_source
380 /* Copy ROM to image source PMM block */
386 movzbl romheader_size, %ecx
388 addr32 rep movsl /* PMM presence implies flat real mode */
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
398 movl $_textdata_memsz_pgh, %ecx
399 addl $0x00001fff, %ecx
400 andl $0xffffe000, %ecx
403 orl $PMM_HANDLE_BASE_DECOMPRESS_TO, %ebx
404 movw $get_pmm_decompress_to, %bp
406 movl %esi, decompress_to
407 /* Restore registers */
411 /* Update checksum */
414 movzbw romheader_size, %cx
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.
425 .ifeqs BUSTYPE, "PCIR"
430 movzbw romheader_size, %cx
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
443 /* Prompt for POST-time shell */
444 movw $init_message_prompt, %si
449 movw $init_message_dots, %si
451 /* Wait for Ctrl-B */
458 movw $init_message_done, %si
462 /* Ctrl-B was pressed: invoke iPXE. The keypress will be
463 * picked up by the initial shell prompt, and we will drop
466 xorl %ebp, %ebp /* Inhibit use of INT 15,e820 and INT 15,e801 */
474 /* Restore registers */
481 /* Indicate boot capability to PnP BIOS, if present */
486 /* Attempt to find or allocate PMM block
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
495 * %esi : allocated block address, or zero (with ZF set) if allocation failed
498 /* Preserve registers */
503 /* Try to find existing block */
504 pushl %ebx /* PMM handle */
511 /* Treat 0xffffffff (not supported) as 0x00000000 (not found) */
516 /* Block found - check acceptability */
519 /* Block not acceptable - increment handle and retry */
523 /* Block not found - try to allocate new block */
524 pushw $0x0002 /* Extended memory */
525 pushl %ebx /* PMM handle */
526 pushl %ecx /* Length */
533 movw $( '+' ), %di /* Indicate allocation attempt */
535 /* Print block address */
541 /* Treat 0xffffffff (not supported) as 0x00000000 (allocation
542 * failed), and set ZF to indicate a zero result.
547 1: /* Restore registers and return */
551 .size get_pmm, . - get_pmm
553 /* Check acceptability of image source block */
554 get_pmm_image_source:
559 addr32 cmpl %es:build_id(%esi), %eax
564 .size get_pmm_image_source, . - get_pmm_image_source
566 /* Check acceptability of decompression block */
567 get_pmm_decompress_to:
570 .size get_pmm_decompress_to, . - get_pmm_decompress_to
573 * Note to hardware vendors:
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.
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.
581 * If you have an OEM-mandated branding requirement that cannot be
582 * satisfied simply by defining PRODUCT_NAME and PRODUCT_SHORT_NAME,
585 * [ Including an ASCII NUL in PRODUCT_NAME is considered to be
586 * bypassing the spirit of this request! ]
592 .asciz "iPXE (http://ipxe.org)"
593 .size init_message, . - init_message
594 .ifeqs BUSTYPE, "PCIR"
597 .size init_message_pci, . - init_message_pci
601 .size init_message_pnp, . - init_message_pnp
604 .size init_message_pmm, . - init_message_pmm
607 .size init_message_int19, . - init_message_int19
609 .asciz "\nPress Ctrl-B to configure "
610 .size init_message_prompt, . - init_message_prompt
613 .size init_message_dots, . - init_message_dots
616 .size init_message_done, . - init_message_done
621 .ifeqs BUSTYPE, "PCIR"
624 .size init_pci_busdevfn, . - init_pci_busdevfn
629 * May be either zero (indicating to use option ROM space as source),
630 * or within a PMM-allocated block.
635 .size image_source, . - image_source
637 /* Additional image source size (in 512-byte sectors)
642 .size extra_size, . - extra_size
644 /* Temporary decompression area
646 * May be either zero (indicating to use default decompression area in
647 * high memory), or within a PMM-allocated block.
652 .size decompress_to, . - decompress_to
654 /* Boot Execution Vector entry point
656 * Called by the PnP BIOS when it wants to boot us.
659 orl $0xffffffff, %ebp /* Allow arbitrary relocation */
663 .size bev_entry, . - bev_entry
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
674 /* Prompt user to press B to boot */
675 movw $int19_message_prompt, %si
680 movw $int19_message_dots, %si
687 movw $int19_message_done, %si
691 /* Leave keypress in buffer and start iPXE. The keypress will
692 * cause the usual initial Ctrl-B prompt to be skipped.
694 orl $0xffffffff, %ebp /* Allow arbitrary relocation */
697 1: /* Try to call original INT 19 vector */
698 movl %cs:orig_int19, %eax
702 2: /* No chained vector: issue INT 18 as a last resort */
704 .size int19_entry, . - int19_entry
707 .size orig_int19, . - orig_int19
709 int19_message_prompt:
710 .asciz "Press N to skip booting from "
711 .size int19_message_prompt, . - int19_message_prompt
714 .size int19_message_dots, . - int19_message_dots
717 .size int19_message_done, . - int19_message_done
719 /* Execute as a boot device
722 exec: /* Set %ds = %cs */
726 /* Print message as soon as possible */
730 movw $exec_message_pre_install, %si
733 /* Store magic word on BIOS stack and remember BIOS %ss:sp */
738 /* Obtain a reasonably-sized temporary stack */
745 movl image_source, %esi
746 movl decompress_to, %edi
747 call install_prealloc
749 /* Print message indicating successful installation */
750 movw $exec_message_post_install, %si
754 /* Set up real-mode stack */
758 /* Jump to .text16 segment */
762 .section ".text16", "awx", @progbits
764 /* Retrieve PCI bus:dev.fn, if applicable */
765 .ifeqs BUSTYPE, "PCIR"
766 movw init_pci_busdevfn, %ax
769 /* Set up %ds for access to .data16 */
772 /* Store PCI bus:dev.fn, if applicable */
773 .ifeqs BUSTYPE, "PCIR"
774 movw %ax, autoboot_busdevfn
781 popl %eax /* discard */
783 /* Set up flat real mode for return to BIOS */
784 call flatten_real_mode
789 /* Restore BIOS stack */
793 /* Check magic word on BIOS stack */
795 cmpl $STACK_MAGIC, %eax
797 /* BIOS stack OK: return to caller */
799 1: /* BIOS stack corrupt: use INT 18 */
803 exec_message_pre_install:
804 .asciz " starting execution..."
805 .size exec_message_pre_install, . - exec_message_pre_install
806 exec_message_post_install:
808 .size exec_message_post_install, . - exec_message_post_install
810 /* Wait for key press specified by %bl (masked by %bh)
812 * Used by init and INT19 code when prompting user. If the specified
813 * key is pressed, it is left in the keyboard buffer.
815 * Returns with ZF set iff specified key is pressed.
818 /* Preserve registers */
821 1: /* Empty the keyboard buffer before waiting for input */
828 2: /* Wait for a key press */
829 movw $ROM_BANNER_TIMEOUT_TICKS, %cx
831 js 99f /* Exit with ZF clear */
832 /* Wait for timer tick to be updated */
834 /* Check to see if a key was pressed */
838 /* Check to see if key was the specified key */
841 je 99f /* Exit with ZF set */
842 /* Not the specified key: remove from buffer and stop waiting */
846 popfw /* Exit with ZF clear */
847 99: /* Restore registers and return */
851 .size wait_for_key, . - wait_for_key
853 /* Wait for timer tick
855 * Used by wait_for_key
862 movl %fs:(0x6c), %eax
867 cmpl %fs:(0x6c), %eax
872 .size wait_for_tick, . - wait_for_tick