Home | History | Annotate | Download | only in prefix
      1 /* At entry, the processor is in 16 bit real mode and the code is being
      2  * executed from an address it was not linked to. Code must be pic and
      3  * 32 bit sensitive until things are fixed up.
      4  *
      5  * Also be very careful as the stack is at the rear end of the interrupt
      6  * table so using a noticeable amount of stack space is a no-no.
      7  */
      8 
      9 FILE_LICENCE ( GPL2_OR_LATER )
     10 
     11 #include <config/general.h>
     12 
     13 #define PNP_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'n' << 16 ) + ( 'P' << 24 ) )
     14 #define PMM_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'M' << 16 ) + ( 'M' << 24 ) )
     15 #define PCI_SIGNATURE ( 'P' + ( 'C' << 8 ) + ( 'I' << 16 ) + ( ' ' << 24 ) )
     16 #define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) )
     17 #define PNP_GET_BBS_VERSION 0x60
     18 #define PMM_ALLOCATE 0x0000
     19 #define PMM_DEALLOCATE 0x0002
     20 
     21 /* ROM banner timeout.  Based on the configurable BANNER_TIMEOUT in
     22  * config.h, but converted to a number of (18Hz) timer ticks, and
     23  * doubled to allow for BIOSes that switch video modes immediately
     24  * beforehand, so rendering the message almost invisible to the user.
     25  */
     26 #define ROM_BANNER_TIMEOUT ( 2 * ( 18 * BANNER_TIMEOUT ) / 10 )
     27 
     28 /* We can load a ROM in two ways: have the BIOS load all of it (.rom prefix)
     29  * or have the BIOS load a stub that loads the rest using PCI (.xrom prefix).
     30  * The latter is not as widely supported, but allows the use of large ROMs
     31  * on some systems with crowded option ROM space.
     32  */
     33 
     34 #ifdef LOAD_ROM_FROM_PCI
     35 #define ROM_SIZE_VALUE	_prefix_filesz_sect /* Amount to load in BIOS */
     36 #else
     37 #define ROM_SIZE_VALUE	0		/* Load amount (before compr. fixup) */
     38 #endif
     39 
     40 
     41 	.text
     42 	.code16
     43 	.arch i386
     44 	.section ".prefix", "ax", @progbits
     45 
     46 	.org	0x00
     47 romheader:
     48 	.word	0xAA55			/* BIOS extension signature */
     49 romheader_size:	.byte ROM_SIZE_VALUE	/* Size in 512-byte blocks */
     50 	jmp	init			/* Initialisation vector */
     51 checksum:
     52 	.byte	0, 0
     53 real_size:
     54 	.word	0
     55 	.org	0x16
     56 	.word	undiheader
     57 	.org	0x18
     58 	.word	pciheader
     59 	.org	0x1a
     60 	.word	pnpheader
     61 	.size romheader, . - romheader
     62 
     63 	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
     64 #ifndef LOAD_ROM_FROM_PCI
     65 	.ascii	"ADDB"
     66 	.long	romheader_size
     67 	.long	512
     68 	.long	0
     69 #endif
     70 	.ascii	"ADDB"
     71 	.long	real_size
     72 	.long	512
     73 	.long	0
     74 	.previous
     75 
     76 pciheader:
     77 	.ascii	"PCIR"			/* Signature */
     78 	.word	pci_vendor_id		/* Vendor identification */
     79 	.word	pci_device_id		/* Device identification */
     80 	.word	0x0000			/* Device list pointer */
     81 	.word	pciheader_len		/* PCI data structure length */
     82 	.byte	0x03			/* PCI data structure revision */
     83 	.byte	0x02, 0x00, 0x00	/* Class code */
     84 pciheader_image_length:
     85 	.word	ROM_SIZE_VALUE		/* Image length */
     86 	.word	0x0001			/* Revision level */
     87 	.byte	0x00			/* Code type */
     88 	.byte	0x80			/* Last image indicator */
     89 pciheader_runtime_length:
     90 	.word	ROM_SIZE_VALUE		/* Maximum run-time image length */
     91 	.word	0x0000			/* Configuration utility code header */
     92 	.word	0x0000			/* DMTF CLP entry point */
     93 	.equ pciheader_len, . - pciheader
     94 	.size pciheader, . - pciheader
     95 
     96 #ifndef LOAD_ROM_FROM_PCI
     97 	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
     98 	.ascii	"ADDW"
     99 	.long	pciheader_image_length
    100 	.long	512
    101 	.long	0
    102 	.ascii	"ADDW"
    103 	.long	pciheader_runtime_length
    104 	.long	512
    105 	.long	0
    106 	.previous
    107 #endif
    108 
    109 pnpheader:
    110 	.ascii	"$PnP"			/* Signature */
    111 	.byte	0x01			/* Structure revision */
    112 	.byte	( pnpheader_len	/ 16 )	/* Length (in 16 byte increments) */
    113 	.word	0x0000			/* Offset of next header */
    114 	.byte	0x00			/* Reserved */
    115 	.byte	0x00			/* Checksum */
    116 	.long	0x00000000		/* Device identifier */
    117 	.word	mfgstr			/* Manufacturer string */
    118 	.word	prodstr			/* Product name */
    119 	.byte	0x02			/* Device base type code */
    120 	.byte	0x00			/* Device sub-type code */
    121 	.byte	0x00			/* Device interface type code */
    122 	.byte	0xf4			/* Device indicator */
    123 	.word	0x0000			/* Boot connection vector */
    124 	.word	0x0000			/* Disconnect vector */
    125 	.word	bev_entry		/* Boot execution vector */
    126 	.word	0x0000			/* Reserved */
    127 	.word	0x0000			/* Static resource information vector*/
    128 	.equ pnpheader_len, . - pnpheader
    129 	.size pnpheader, . - pnpheader
    130 
    131 /* Manufacturer string */
    132 mfgstr:
    133 	.asciz	"http://etherboot.org"
    134 	.size mfgstr, . - mfgstr
    135 
    136 /* Product string
    137  *
    138  * Defaults to PRODUCT_SHORT_NAME.  If the ROM image is writable at
    139  * initialisation time, it will be filled in to include the PCI
    140  * bus:dev.fn number of the card as well.
    141  */
    142 prodstr:
    143 	.ascii	PRODUCT_SHORT_NAME
    144 prodstr_separator:
    145 	.byte	0
    146 	.ascii	"(PCI "
    147 prodstr_pci_id:
    148 	.asciz	"xx:xx.x)"		/* Filled in by init code */
    149 	.size prodstr, . - prodstr
    150 
    151 	.globl	undiheader
    152 	.weak	undiloader
    153 undiheader:
    154 	.ascii	"UNDI"			/* Signature */
    155 	.byte	undiheader_len		/* Length of structure */
    156 	.byte	0			/* Checksum */
    157 	.byte	0			/* Structure revision */
    158 	.byte	0,1,2			/* PXE version: 2.1.0 */
    159 	.word	undiloader		/* Offset to loader routine */
    160 	.word	_data16_memsz		/* Stack segment size */
    161 	.word	_data16_memsz		/* Data segment size */
    162 	.word	_text16_memsz		/* Code segment size */
    163 	.ascii	"PCIR"			/* Bus type */
    164 	.equ undiheader_len, . - undiheader
    165 	.size undiheader, . - undiheader
    166 
    167 /* Initialisation (called once during POST)
    168  *
    169  * Determine whether or not this is a PnP system via a signature
    170  * check.  If it is PnP, return to the PnP BIOS indicating that we are
    171  * a boot-capable device; the BIOS will call our boot execution vector
    172  * if it wants to boot us.  If it is not PnP, hook INT 19.
    173  */
    174 init:
    175 	/* Preserve registers, clear direction flag, set %ds=%cs */
    176 	pushaw
    177 	pushw	%ds
    178 	pushw	%es
    179 	pushw	%fs
    180 	pushw	%gs
    181 	cld
    182 	pushw	%cs
    183 	popw	%ds
    184 
    185 	/* Shuffle some registers around.  We need %di available for
    186 	 * the print_xxx functions, and in a register that's
    187 	 * addressable from %es, so shuffle as follows:
    188 	 *
    189 	 *    %di (pointer to PnP structure) => %bx
    190 	 *    %bx (runtime segment address, for PCI 3.0) => %gs
    191 	 */
    192 	movw	%bx, %gs
    193 	movw	%di, %bx
    194 
    195 	/* Print message as early as possible */
    196 	movw	$init_message, %si
    197 	xorw	%di, %di
    198 	call	print_message
    199 	call	print_pci_busdevfn
    200 
    201 #ifdef LOAD_ROM_FROM_PCI
    202 	/* Save PCI bus:dev.fn for later use */
    203 	movw	%ax, pci_busdevfn
    204 #endif
    205 
    206 	/* Fill in product name string, if possible */
    207 	movw	$prodstr_pci_id, %di
    208 	call	print_pci_busdevfn
    209 	movb	$( ' ' ), prodstr_separator
    210 
    211 	/* Print segment address */
    212 	movb	$( ' ' ), %al
    213 	xorw	%di, %di
    214 	call	print_character
    215 	movw	%cs, %ax
    216 	call	print_hex_word
    217 
    218 	/* Check for PCI BIOS version */
    219 	pushl	%ebx
    220 	pushl	%edx
    221 	pushl	%edi
    222 	stc
    223 	movw	$0xb101, %ax
    224 	int	$0x1a
    225 	jc	no_pci3
    226 	cmpl	$PCI_SIGNATURE, %edx
    227 	jne	no_pci3
    228 	testb	%ah, %ah
    229 	jnz	no_pci3
    230 #ifdef LOAD_ROM_FROM_PCI
    231 	incb	pcibios_present
    232 #endif
    233 	movw	$init_message_pci, %si
    234 	xorw	%di, %di
    235 	call	print_message
    236 	movb	%bh, %al
    237 	call	print_hex_nibble
    238 	movb	$( '.' ), %al
    239 	call	print_character
    240 	movb	%bl, %al
    241 	call	print_hex_byte
    242 	cmpb	$3, %bh
    243 	jb	no_pci3
    244 	/* PCI >=3.0: leave %gs as-is if sane */
    245 	movw	%gs, %ax
    246 	cmpw	$0xa000, %ax	/* Insane if %gs < 0xa000 */
    247 	jb	pci3_insane
    248 	movw	%cs, %bx	/* Sane if %cs == %gs */
    249 	cmpw	%bx, %ax
    250 	je	1f
    251 	movzbw	romheader_size, %cx /* Sane if %cs+len <= %gs */
    252 	shlw	$5, %cx
    253 	addw	%cx, %bx
    254 	cmpw	%bx, %ax
    255 	jae	1f
    256 	movw	%cs, %bx	/* Sane if %gs+len <= %cs */
    257 	addw	%cx, %ax
    258 	cmpw	%bx, %ax
    259 	jbe	1f
    260 pci3_insane: /* PCI 3.0 with insane %gs value: print error and ignore %gs */
    261 	movb	$( '!' ), %al
    262 	call	print_character
    263 	movw	%gs, %ax
    264 	call	print_hex_word
    265 no_pci3:
    266 	/* PCI <3.0: set %gs (runtime segment) = %cs (init-time segment) */
    267 	pushw	%cs
    268 	popw	%gs
    269 1:	popl	%edi
    270 	popl	%edx
    271 	popl	%ebx
    272 
    273 	/* Check for PnP BIOS.  Although %es:di should point to the
    274 	 * PnP BIOS signature on entry, some BIOSes fail to do this.
    275 	 */
    276 	movw	$( 0xf000 - 1 ), %bx
    277 pnp_scan:
    278 	incw	%bx
    279 	jz	no_pnp
    280 	movw	%bx, %es
    281 	cmpl	$PNP_SIGNATURE, %es:0
    282 	jne	pnp_scan
    283 	xorw	%dx, %dx
    284 	xorw	%si, %si
    285 	movzbw	%es:5, %cx
    286 1:	es lodsb
    287 	addb	%al, %dl
    288 	loop	1b
    289 	jnz	pnp_scan
    290 	/* Is PnP: print PnP message */
    291 	movw	$init_message_pnp, %si
    292 	xorw	%di, %di
    293 	call	print_message
    294 	/* Check for BBS */
    295 	pushw	%es:0x1b	/* Real-mode data segment */
    296 	pushw	%ds		/* &(bbs_version) */
    297 	pushw	$bbs_version
    298 	pushw	$PNP_GET_BBS_VERSION
    299 	lcall	*%es:0xd
    300 	addw	$8, %sp
    301 	testw	%ax, %ax
    302 	je	got_bbs
    303 no_pnp:	/* Not PnP-compliant - therefore cannot be BBS-compliant */
    304 no_bbs:	/* Not BBS-compliant - must hook INT 19 */
    305 	movw	$init_message_int19, %si
    306 	xorw	%di, %di
    307 	call	print_message
    308 	xorw	%ax, %ax
    309 	movw	%ax, %es
    310 	pushl	%es:( 0x19 * 4 )
    311 	popl	orig_int19
    312 	pushw	%gs /* %gs contains runtime %cs */
    313 	pushw	$int19_entry
    314 	popl	%es:( 0x19 * 4 )
    315 	jmp	bbs_done
    316 got_bbs: /* BBS compliant - no need to hook INT 19 */
    317 	movw	$init_message_bbs, %si
    318 	xorw	%di, %di
    319 	call	print_message
    320 bbs_done:
    321 
    322 	/* Check for PMM */
    323 	movw	$( 0xe000 - 1 ), %bx
    324 pmm_scan:
    325 	incw	%bx
    326 	jz	no_pmm
    327 	movw	%bx, %es
    328 	cmpl	$PMM_SIGNATURE, %es:0
    329 	jne	pmm_scan
    330 	xorw	%dx, %dx
    331 	xorw	%si, %si
    332 	movzbw	%es:5, %cx
    333 1:	es lodsb
    334 	addb	%al, %dl
    335 	loop	1b
    336 	jnz	pmm_scan
    337 	/* PMM found: print PMM message */
    338 	movw	$init_message_pmm, %si
    339 	xorw	%di, %di
    340 	call	print_message
    341 	/* We have PMM and so a 1kB stack: preserve upper register halves */
    342 	pushal
    343 	/* Calculate required allocation size in %esi */
    344 	movzwl	real_size, %eax
    345 	shll	$9, %eax
    346 	addl	$_textdata_memsz, %eax
    347 	orw	$0xffff, %ax	/* Ensure allocation size is at least 64kB */
    348 	bsrl	%eax, %ecx
    349 	subw	$15, %cx	/* Round up and convert to 64kB count */
    350 	movw	$1, %si
    351 	shlw	%cl, %si
    352 pmm_loop:
    353 	/* Try to allocate block via PMM */
    354 	pushw	$0x0006		/* Aligned, extended memory */
    355 	pushl	$0xffffffff	/* No handle */
    356 	movzwl	%si, %eax
    357 	shll	$12, %eax
    358 	pushl	%eax		/* Allocation size in paragraphs */
    359 	pushw	$PMM_ALLOCATE
    360 	lcall	*%es:7
    361 	addw	$12, %sp
    362 	/* Abort if allocation fails */
    363 	testw	%dx, %dx	/* %ax==0 even on success, since align>=64kB */
    364 	jz	pmm_fail
    365 	/* If block has A20==1, free block and try again with twice
    366 	 * the allocation size (and hence alignment).
    367 	 */
    368 	testw	$0x0010, %dx
    369 	jz	got_pmm
    370 	pushw	%dx
    371 	pushw	$0
    372 	pushw	$PMM_DEALLOCATE
    373 	lcall	*%es:7
    374 	addw	$6, %sp
    375 	addw	%si, %si
    376 	jmp	pmm_loop
    377 got_pmm: /* PMM allocation succeeded */
    378 	movw	%dx, ( image_source + 2 )
    379 	movw	%dx, %ax
    380 	xorw	%di, %di
    381 	call	print_hex_word
    382 	movb	$( '@' ), %al
    383 	call	print_character
    384 	movw	%si, %ax
    385 	call	print_hex_byte
    386 pmm_copy:
    387 	/* Copy ROM to PMM block */
    388 	xorw	%ax, %ax
    389 	movw	%ax, %es
    390 	movl	image_source, %edi
    391 	xorl	%esi, %esi
    392 	movzbl	romheader_size, %ecx
    393 	shll	$9, %ecx
    394 	addr32 rep movsb	/* PMM presence implies flat real mode */
    395 	movl	%edi, decompress_to
    396 	/* Shrink ROM */
    397 	movb	$_prefix_memsz_sect, romheader_size
    398 #if defined(SHRINK_WITHOUT_PMM) || defined(LOAD_ROM_FROM_PCI)
    399 	jmp	pmm_done
    400 pmm_fail:
    401 	/* Print marker and copy ourselves to high memory */
    402 	movl	$HIGHMEM_LOADPOINT, image_source
    403 	xorw	%di, %di
    404 	movb	$( '!' ), %al
    405 	call	print_character
    406 	jmp	pmm_copy
    407 pmm_done:
    408 #else
    409 pmm_fail:
    410 #endif
    411 	/* Restore upper register halves */
    412 	popal
    413 #if defined(LOAD_ROM_FROM_PCI)
    414 	call	load_from_pci
    415 	jc	load_err
    416 	jmp	load_ok
    417 no_pmm:
    418 	/* Cannot continue without PMM - print error message */
    419 	xorw	%di, %di
    420 	movw	$init_message_no_pmm, %si
    421 	call	print_message
    422 load_err:
    423 	/* Wait for five seconds to let user see message */
    424 	movw	$90, %cx
    425 1:	call	wait_for_tick
    426 	loop	1b
    427 	/* Mark environment as invalid and return */
    428 	movl	$0, decompress_to
    429 	jmp	out
    430 
    431 load_ok:
    432 #else
    433 no_pmm:
    434 #endif
    435 	/* Update checksum */
    436 	xorw	%bx, %bx
    437 	xorw	%si, %si
    438 	movzbw	romheader_size, %cx
    439 	shlw	$9, %cx
    440 1:	lodsb
    441 	addb	%al, %bl
    442 	loop	1b
    443 	subb	%bl, checksum
    444 
    445 	/* Copy self to option ROM space.  Required for PCI3.0, which
    446 	 * loads us to a temporary location in low memory.  Will be a
    447 	 * no-op for lower PCI versions.
    448 	 */
    449 	movb	$( ' ' ), %al
    450 	xorw	%di, %di
    451 	call	print_character
    452 	movw	%gs, %ax
    453 	call	print_hex_word
    454 	movzbw	romheader_size, %cx
    455 	shlw	$9, %cx
    456 	movw	%ax, %es
    457 	xorw	%si, %si
    458 	xorw	%di, %di
    459 	cs rep	movsb
    460 
    461 	/* Prompt for POST-time shell */
    462 	movw	$init_message_prompt, %si
    463 	xorw	%di, %di
    464 	call	print_message
    465 	movw	$prodstr, %si
    466 	call	print_message
    467 	movw	$init_message_dots, %si
    468 	call	print_message
    469 	/* Wait for Ctrl-B */
    470 	movw	$0xff02, %bx
    471 	call	wait_for_key
    472 	/* Clear prompt */
    473 	pushf
    474 	xorw	%di, %di
    475 	call	print_kill_line
    476 	movw	$init_message_done, %si
    477 	call	print_message
    478 	popf
    479 	jnz	out
    480 	/* Ctrl-B was pressed: invoke gPXE.  The keypress will be
    481 	 * picked up by the initial shell prompt, and we will drop
    482 	 * into a shell.
    483 	 */
    484 	pushw	%cs
    485 	call	exec
    486 out:
    487 	/* Restore registers */
    488 	popw	%gs
    489 	popw	%fs
    490 	popw	%es
    491 	popw	%ds
    492 	popaw
    493 
    494 	/* Indicate boot capability to PnP BIOS, if present */
    495 	movw	$0x20, %ax
    496 	lret
    497 	.size init, . - init
    498 
    499 /*
    500  * Note to hardware vendors:
    501  *
    502  * If you wish to brand this boot ROM, please do so by defining the
    503  * strings PRODUCT_NAME and PRODUCT_SHORT_NAME in config/general.h.
    504  *
    505  * While nothing in the GPL prevents you from removing all references
    506  * to gPXE or http://etherboot.org, we prefer you not to do so.
    507  *
    508  * If you have an OEM-mandated branding requirement that cannot be
    509  * satisfied simply by defining PRODUCT_NAME and PRODUCT_SHORT_NAME,
    510  * please contact us.
    511  *
    512  * [ Including an ASCII NUL in PRODUCT_NAME is considered to be
    513  *   bypassing the spirit of this request! ]
    514  */
    515 init_message:
    516 	.ascii	"\n"
    517 	.ascii	PRODUCT_NAME
    518 	.ascii	"\n"
    519 	.asciz	"gPXE (http://etherboot.org) - "
    520 	.size	init_message, . - init_message
    521 init_message_pci:
    522 	.asciz	" PCI"
    523 	.size	init_message_pci, . - init_message_pci
    524 init_message_pnp:
    525 	.asciz	" PnP"
    526 	.size	init_message_pnp, . - init_message_pnp
    527 init_message_bbs:
    528 	.asciz	" BBS"
    529 	.size	init_message_bbs, . - init_message_bbs
    530 init_message_pmm:
    531 	.asciz	" PMM"
    532 	.size	init_message_pmm, . - init_message_pmm
    533 #ifdef LOAD_ROM_FROM_PCI
    534 init_message_no_pmm:
    535 	.asciz	"\nPMM required but not present!\n"
    536 	.size	init_message_no_pmm, . - init_message_no_pmm
    537 #endif
    538 init_message_int19:
    539 	.asciz	" INT19"
    540 	.size	init_message_int19, . - init_message_int19
    541 init_message_prompt:
    542 	.asciz	"\nPress Ctrl-B to configure "
    543 	.size	init_message_prompt, . - init_message_prompt
    544 init_message_dots:
    545 	.asciz	"..."
    546 	.size	init_message_dots, . - init_message_dots
    547 init_message_done:
    548 	.asciz	"\n\n"
    549 	.size	init_message_done, . - init_message_done
    550 
    551 /* ROM image location
    552  *
    553  * May be either within option ROM space, or within PMM-allocated block.
    554  */
    555 	.globl	image_source
    556 image_source:
    557 	.long	0
    558 	.size	image_source, . - image_source
    559 
    560 /* Temporary decompression area
    561  *
    562  * May be either at HIGHMEM_LOADPOINT, or within PMM-allocated block.
    563  * If a PCI ROM load fails, this will be set to zero.
    564  */
    565 	.globl	decompress_to
    566 decompress_to:
    567 	.long	HIGHMEM_LOADPOINT
    568 	.size	decompress_to, . - decompress_to
    569 
    570 #ifdef LOAD_ROM_FROM_PCI
    571 
    572 /* Set if the PCI BIOS is present, even <3.0 */
    573 pcibios_present:
    574 	.byte	0
    575 	.byte	0		/* for alignment */
    576 	.size	pcibios_present, . - pcibios_present
    577 
    578 /* PCI bus:device.function word
    579  *
    580  * Filled in by init in the .xrom case, so the remainder of the ROM
    581  * can be located.
    582  */
    583 pci_busdevfn:
    584 	.word	0
    585 	.size	pci_busdevfn, . - pci_busdevfn
    586 
    587 #endif
    588 
    589 /* BBS version
    590  *
    591  * Filled in by BBS BIOS.  We ignore the value.
    592  */
    593 bbs_version:
    594 	.word	0
    595 	.size	bbs_version, . - bbs_version
    596 
    597 /* Boot Execution Vector entry point
    598  *
    599  * Called by the PnP BIOS when it wants to boot us.
    600  */
    601 bev_entry:
    602 	pushw	%cs
    603 	call	exec
    604 	lret
    605 	.size	bev_entry, . - bev_entry
    606 
    607 
    608 #ifdef LOAD_ROM_FROM_PCI
    609 
    610 #define PCI_ROM_ADDRESS		0x30	/* Bits 31:11 address, 10:1 reserved */
    611 #define PCI_ROM_ADDRESS_ENABLE	 0x00000001
    612 #define PCI_ROM_ADDRESS_MASK	 0xfffff800
    613 
    614 #define PCIBIOS_READ_WORD	0xb109
    615 #define PCIBIOS_READ_DWORD	0xb10a
    616 #define PCIBIOS_WRITE_WORD	0xb10c
    617 #define PCIBIOS_WRITE_DWORD	0xb10d
    618 
    619 /* Determine size of PCI BAR
    620  *
    621  *  %bx : PCI bus:dev.fn to probe
    622  *  %di : Address of BAR to find size of
    623  * %edx : Mask of address bits within BAR
    624  *
    625  * %ecx : Size for a memory resource,
    626  *	  1 for an I/O resource (bit 0 set).
    627  *   CF : Set on error or nonexistent device (all-ones read)
    628  *
    629  * All other registers saved.
    630  */
    631 pci_bar_size:
    632 	/* Save registers */
    633 	pushw	%ax
    634 	pushl	%esi
    635 	pushl	%edx
    636 
    637 	/* Read current BAR value */
    638 	movw	$PCIBIOS_READ_DWORD, %ax
    639 	int	$0x1a
    640 
    641 	/* Check for device existence and save it */
    642 	testb	$1, %cl		/* I/O bit? */
    643 	jz	1f
    644 	andl	$1, %ecx	/* If so, exit with %ecx = 1 */
    645 	jmp	99f
    646 1:	notl	%ecx
    647 	testl	%ecx, %ecx	/* Set ZF iff %ecx was all-ones */
    648 	notl	%ecx
    649 	jnz	1f
    650 	stc			/* All ones - exit with CF set */
    651 	jmp	99f
    652 1:	movl	%ecx, %esi	/* Save in %esi */
    653 
    654 	/* Write all ones to BAR */
    655 	movl	%edx, %ecx
    656 	movw	$PCIBIOS_WRITE_DWORD, %ax
    657 	int	$0x1a
    658 
    659 	/* Read back BAR */
    660 	movw	$PCIBIOS_READ_DWORD, %ax
    661 	int	$0x1a
    662 
    663 	/* Find decode size from least set bit in mask BAR */
    664 	bsfl	%ecx, %ecx	/* Find least set bit, log2(decode size) */
    665 	jz	1f		/* Mask BAR should not be zero */
    666 	xorl	%edx, %edx
    667 	incl	%edx
    668 	shll	%cl, %edx	/* %edx = decode size */
    669 	jmp	2f
    670 1:	xorl	%edx, %edx	/* Return zero size for mask BAR zero */
    671 
    672 	/* Restore old BAR value */
    673 2:	movl	%esi, %ecx
    674 	movw	$PCIBIOS_WRITE_DWORD, %ax
    675 	int	$0x1a
    676 
    677 	movl	%edx, %ecx	/* Return size in %ecx */
    678 
    679 	/* Restore registers and return */
    680 99:	popl	%edx
    681 	popl	%esi
    682 	popw	%ax
    683 	ret
    684 
    685 	.size	pci_bar_size, . - pci_bar_size
    686 
    687 /* PCI ROM loader
    688  *
    689  * Called from init in the .xrom case to load the non-prefix code
    690  * using the PCI ROM BAR.
    691  *
    692  * Returns with carry flag set on error. All registers saved.
    693  */
    694 load_from_pci:
    695 	/*
    696 	 * Use PCI BIOS access to config space. The calls take
    697 	 *
    698 	 *   %ah : 0xb1		%al : function
    699 	 *   %bx : bus/dev/fn
    700 	 *   %di : config space address
    701 	 *  %ecx : value to write (for writes)
    702 	 *
    703 	 *  %ecx : value read (for reads)
    704 	 *   %ah : return code
    705 	 *    CF : error indication
    706 	 *
    707 	 * All registers not used for return are preserved.
    708 	 */
    709 
    710 	/* Save registers and set up %es for big real mode */
    711 	pushal
    712 	pushw	%es
    713 	xorw	%ax, %ax
    714 	movw	%ax, %es
    715 
    716 	/* Check PCI BIOS presence */
    717 	cmpb	$0, pcibios_present
    718 	jz	err_pcibios
    719 
    720 	/* Load existing PCI ROM BAR */
    721 	movw	$PCIBIOS_READ_DWORD, %ax
    722 	movw	pci_busdevfn, %bx
    723 	movw	$PCI_ROM_ADDRESS, %di
    724 	int	$0x1a
    725 
    726 	/* Maybe it's already enabled? */
    727 	testb	$PCI_ROM_ADDRESS_ENABLE, %cl
    728 	jz	1f
    729 	movb	$1, %dl		/* Flag indicating no deinit required */
    730 	movl	%ecx, %ebp
    731 	jmp	check_rom
    732 
    733 	/* Determine PCI BAR decode size */
    734 1:	movl	$PCI_ROM_ADDRESS_MASK, %edx
    735 	call	pci_bar_size	/* Returns decode size in %ecx */
    736 	jc	err_size_insane	/* CF => no ROM BAR, %ecx == ffffffff */
    737 
    738 	/* Check sanity of decode size */
    739 	xorl	%eax, %eax
    740 	movw	real_size, %ax
    741 	shll	$9, %eax	/* %eax = ROM size */
    742 	cmpl	%ecx, %eax
    743 	ja	err_size_insane	/* Insane if decode size < ROM size */
    744 	cmpl	$0x100000, %ecx
    745 	jae	err_size_insane	/* Insane if decode size >= 1MB */
    746 
    747 	/* Find a place to map the BAR
    748 	 * In theory we should examine e820 and all PCI BARs to find a
    749 	 * free region. However, we run at POST when e820 may not be
    750 	 * available, and memory reads of an unmapped location are
    751 	 * de facto standardized to return all-ones. Thus, we can get
    752 	 * away with searching high memory (0xf0000000 and up) on
    753 	 * multiples of the ROM BAR decode size for a sufficiently
    754 	 * large all-ones region.
    755 	 */
    756 	movl	%ecx, %edx	/* Save ROM BAR size in %edx */
    757 	movl	$0xf0000000, %ebp
    758 	xorl	%eax, %eax
    759 	notl	%eax		/* %eax = all ones */
    760 bar_search:
    761 	movl	%ebp, %edi
    762 	movl	%edx, %ecx
    763 	shrl	$2, %ecx
    764 	addr32 repe scasl	/* Scan %es:edi for anything not all-ones */
    765 	jz	bar_found
    766 	addl	%edx, %ebp
    767 	testl	$0x80000000, %ebp
    768 	jz	err_no_bar
    769 	jmp	bar_search
    770 
    771 bar_found:
    772 	movl	%edi, %ebp
    773 	/* Save current BAR value on stack to restore later */
    774 	movw	$PCIBIOS_READ_DWORD, %ax
    775 	movw	$PCI_ROM_ADDRESS, %di
    776 	int	$0x1a
    777 	pushl	%ecx
    778 
    779 	/* Map the ROM */
    780 	movw	$PCIBIOS_WRITE_DWORD, %ax
    781 	movl	%ebp, %ecx
    782 	orb	$PCI_ROM_ADDRESS_ENABLE, %cl
    783 	int	$0x1a
    784 
    785 	xorb	%dl, %dl	/* %dl = 0 : ROM was not already mapped */
    786 check_rom:
    787 	/* Check and copy ROM - enter with %dl set to skip unmapping,
    788 	 * %ebp set to mapped ROM BAR address.
    789 	 * We check up to prodstr_separator for equality, since anything past
    790 	 * that may have been modified. Since our check includes the checksum
    791 	 * byte over the whole ROM stub, that should be sufficient.
    792 	 */
    793 	xorb	%dh, %dh	/* %dh = 0 : ROM did not fail integrity check */
    794 
    795 	/* Verify ROM integrity */
    796 	xorl	%esi, %esi
    797 	movl	%ebp, %edi
    798 	movl	$prodstr_separator, %ecx
    799 	addr32 repe cmpsb
    800 	jz	copy_rom
    801 	incb	%dh		/* ROM failed integrity check */
    802 	movl	%ecx, %ebp	/* Save number of bytes left */
    803 	jmp	skip_load
    804 
    805 copy_rom:
    806 	/* Print BAR address and indicate whether we mapped it ourselves */
    807 	movb	$( ' ' ), %al
    808 	xorw	%di, %di
    809 	call	print_character
    810 	movl	%ebp, %eax
    811 	call	print_hex_dword
    812 	movb	$( '-' ), %al	/* '-' for self-mapped */
    813 	subb	%dl, %al
    814 	subb	%dl, %al	/* '+' = '-' - 2 for BIOS-mapped */
    815 	call	print_character
    816 
    817 	/* Copy ROM at %ebp to PMM or highmem block */
    818 	movl	%ebp, %esi
    819 	movl	image_source, %edi
    820 	movzwl	real_size, %ecx
    821 	shll	$9, %ecx
    822 	addr32 es rep movsb
    823 	movl	%edi, decompress_to
    824 skip_load:
    825 	testb	%dl, %dl	/* Was ROM already mapped? */
    826 	jnz	skip_unmap
    827 
    828 	/* Unmap the ROM by restoring old ROM BAR */
    829 	movw	$PCIBIOS_WRITE_DWORD, %ax
    830 	movw	$PCI_ROM_ADDRESS, %di
    831 	popl	%ecx
    832 	int	$0x1a
    833 
    834 skip_unmap:
    835 	/* Error handling */
    836 	testb	%dh, %dh
    837 	jnz	err_rom_invalid
    838 	clc
    839 	jmp	99f
    840 
    841 err_pcibios:			/* No PCI BIOS available */
    842 	movw	$load_message_no_pcibios, %si
    843 	xorl	%eax, %eax	/* "error code" is zero */
    844 	jmp	1f
    845 err_size_insane:		/* BAR has size (%ecx) that is insane */
    846 	movw	$load_message_size_insane, %si
    847 	movl	%ecx, %eax
    848 	jmp	1f
    849 err_no_bar:			/* No space of sufficient size (%edx) found */
    850 	movw	$load_message_no_bar, %si
    851 	movl	%edx, %eax
    852 	jmp	1f
    853 err_rom_invalid:		/* Loaded ROM does not match (%ebp bytes left) */
    854 	movw	$load_message_rom_invalid, %si
    855 	movzbl	romheader_size, %eax
    856 	shll	$9, %eax
    857 	subl	%ebp, %eax
    858 	decl	%eax		/* %eax is now byte index of failure */
    859 
    860 1:	/* Error handler - print message at %si and dword in %eax */
    861 	xorw	%di, %di
    862 	call	print_message
    863 	call	print_hex_dword
    864 	stc
    865 99:	popw	%es
    866 	popal
    867 	ret
    868 
    869 	.size	load_from_pci, . - load_from_pci
    870 
    871 load_message_no_pcibios:
    872 	.asciz	"\nNo PCI BIOS found! "
    873 	.size	load_message_no_pcibios, . - load_message_no_pcibios
    874 
    875 load_message_size_insane:
    876 	.asciz	"\nROM resource has invalid size "
    877 	.size	load_message_size_insane, . - load_message_size_insane
    878 
    879 load_message_no_bar:
    880 	.asciz	"\nNo memory hole of sufficient size "
    881 	.size	load_message_no_bar, . - load_message_no_bar
    882 
    883 load_message_rom_invalid:
    884 	.asciz	"\nLoaded ROM is invalid at "
    885 	.size	load_message_rom_invalid, . - load_message_rom_invalid
    886 
    887 #endif /* LOAD_ROM_FROM_PCI */
    888 
    889 
    890 /* INT19 entry point
    891  *
    892  * Called via the hooked INT 19 if we detected a non-PnP BIOS.  We
    893  * attempt to return via the original INT 19 vector (if we were able
    894  * to store it).
    895  */
    896 int19_entry:
    897 	pushw	%cs
    898 	popw	%ds
    899 	/* Prompt user to press B to boot */
    900 	movw	$int19_message_prompt, %si
    901 	xorw	%di, %di
    902 	call	print_message
    903 	movw	$prodstr, %si
    904 	call	print_message
    905 	movw	$int19_message_dots, %si
    906 	call	print_message
    907 	movw	$0xdf4e, %bx
    908 	call	wait_for_key
    909 	pushf
    910 	xorw	%di, %di
    911 	call	print_kill_line
    912 	movw	$int19_message_done, %si
    913 	call	print_message
    914 	popf
    915 	jz	1f
    916 	/* Leave keypress in buffer and start gPXE.  The keypress will
    917 	 * cause the usual initial Ctrl-B prompt to be skipped.
    918 	 */
    919 	pushw	%cs
    920 	call	exec
    921 1:	/* Try to call original INT 19 vector */
    922 	movl	%cs:orig_int19, %eax
    923 	testl	%eax, %eax
    924 	je	2f
    925 	ljmp	*%cs:orig_int19
    926 2:	/* No chained vector: issue INT 18 as a last resort */
    927 	int	$0x18
    928 	.size	int19_entry, . - int19_entry
    929 orig_int19:
    930 	.long	0
    931 	.size	orig_int19, . - orig_int19
    932 
    933 int19_message_prompt:
    934 	.asciz	"Press N to skip booting from "
    935 	.size	int19_message_prompt, . - int19_message_prompt
    936 int19_message_dots:
    937 	.asciz	"..."
    938 	.size	int19_message_dots, . - int19_message_dots
    939 int19_message_done:
    940 	.asciz	"\n\n"
    941 	.size	int19_message_done, . - int19_message_done
    942 
    943 /* Execute as a boot device
    944  *
    945  */
    946 exec:	/* Set %ds = %cs */
    947 	pushw	%cs
    948 	popw	%ds
    949 
    950 #ifdef LOAD_ROM_FROM_PCI
    951 	/* Don't execute if load was invalid */
    952 	cmpl	$0, decompress_to
    953 	jne	1f
    954 	lret
    955 1:
    956 #endif
    957 
    958 	/* Print message as soon as possible */
    959 	movw	$prodstr, %si
    960 	xorw	%di, %di
    961 	call	print_message
    962 	movw	$exec_message, %si
    963 	call	print_message
    964 
    965 	/* Store magic word on BIOS stack and remember BIOS %ss:sp */
    966 	pushl	$STACK_MAGIC
    967 	movw	%ss, %dx
    968 	movw	%sp, %bp
    969 
    970 	/* Obtain a reasonably-sized temporary stack */
    971 	xorw	%ax, %ax
    972 	movw	%ax, %ss
    973 	movw	$0x7c00, %sp
    974 
    975 	/* Install gPXE */
    976 	movl	image_source, %esi
    977 	movl	decompress_to, %edi
    978 	call	alloc_basemem
    979 	call	install_prealloc
    980 
    981 	/* Set up real-mode stack */
    982 	movw	%bx, %ss
    983 	movw	$_estack16, %sp
    984 
    985 	/* Jump to .text16 segment */
    986 	pushw	%ax
    987 	pushw	$1f
    988 	lret
    989 	.section ".text16", "awx", @progbits
    990 1:	/* Call main() */
    991 	pushl	$main
    992 	pushw	%cs
    993 	call	prot_call
    994 	popl	%ecx /* discard */
    995 
    996 	/* Uninstall gPXE */
    997 	call	uninstall
    998 
    999 	/* Restore BIOS stack */
   1000 	movw	%dx, %ss
   1001 	movw	%bp, %sp
   1002 
   1003 	/* Check magic word on BIOS stack */
   1004 	popl	%eax
   1005 	cmpl	$STACK_MAGIC, %eax
   1006 	jne	1f
   1007 	/* BIOS stack OK: return to caller */
   1008 	lret
   1009 1:	/* BIOS stack corrupt: use INT 18 */
   1010 	int	$0x18
   1011 	.previous
   1012 
   1013 exec_message:
   1014 	.asciz	" starting execution\n"
   1015 	.size exec_message, . - exec_message
   1016 
   1017 /* Wait for key press specified by %bl (masked by %bh)
   1018  *
   1019  * Used by init and INT19 code when prompting user.  If the specified
   1020  * key is pressed, it is left in the keyboard buffer.
   1021  *
   1022  * Returns with ZF set iff specified key is pressed.
   1023  */
   1024 wait_for_key:
   1025 	/* Preserve registers */
   1026 	pushw	%cx
   1027 	pushw	%ax
   1028 1:	/* Empty the keyboard buffer before waiting for input */
   1029 	movb	$0x01, %ah
   1030 	int	$0x16
   1031 	jz	2f
   1032 	xorw	%ax, %ax
   1033 	int	$0x16
   1034 	jmp	1b
   1035 2:	/* Wait for a key press */
   1036 	movw	$ROM_BANNER_TIMEOUT, %cx
   1037 3:	decw	%cx
   1038 	js	99f		/* Exit with ZF clear */
   1039 	/* Wait for timer tick to be updated */
   1040 	call	wait_for_tick
   1041 	/* Check to see if a key was pressed */
   1042 	movb	$0x01, %ah
   1043 	int	$0x16
   1044 	jz	3b
   1045 	/* Check to see if key was the specified key */
   1046 	andb	%bh, %al
   1047 	cmpb	%al, %bl
   1048 	je	99f		/* Exit with ZF set */
   1049 	/* Not the specified key: remove from buffer and stop waiting */
   1050 	pushfw
   1051 	xorw	%ax, %ax
   1052 	int	$0x16
   1053 	popfw			/* Exit with ZF clear */
   1054 99:	/* Restore registers and return */
   1055 	popw	%ax
   1056 	popw	%cx
   1057 	ret
   1058 	.size wait_for_key, . - wait_for_key
   1059 
   1060 /* Wait for timer tick
   1061  *
   1062  * Used by wait_for_key
   1063  */
   1064 wait_for_tick:
   1065 	pushl	%eax
   1066 	pushw	%fs
   1067 	movw	$0x40, %ax
   1068 	movw	%ax, %fs
   1069 	movl	%fs:(0x6c), %eax
   1070 1:	pushf
   1071 	sti
   1072 	hlt
   1073 	popf
   1074 	cmpl	%fs:(0x6c), %eax
   1075 	je	1b
   1076 	popw	%fs
   1077 	popl	%eax
   1078 	ret
   1079 	.size wait_for_tick, . - wait_for_tick
   1080