summaryrefslogtreecommitdiff
path: root/gpxe/src/arch/i386/prefix/romprefix.S
diff options
context:
space:
mode:
Diffstat (limited to 'gpxe/src/arch/i386/prefix/romprefix.S')
-rw-r--r--gpxe/src/arch/i386/prefix/romprefix.S1079
1 files changed, 0 insertions, 1079 deletions
diff --git a/gpxe/src/arch/i386/prefix/romprefix.S b/gpxe/src/arch/i386/prefix/romprefix.S
deleted file mode 100644
index 02e54976..00000000
--- a/gpxe/src/arch/i386/prefix/romprefix.S
+++ /dev/null
@@ -1,1079 +0,0 @@
-/* At entry, the processor is in 16 bit real mode and the code is being
- * executed from an address it was not linked to. Code must be pic and
- * 32 bit sensitive until things are fixed up.
- *
- * Also be very careful as the stack is at the rear end of the interrupt
- * table so using a noticeable amount of stack space is a no-no.
- */
-
-FILE_LICENCE ( GPL2_OR_LATER )
-
-#include <config/general.h>
-
-#define PNP_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'n' << 16 ) + ( 'P' << 24 ) )
-#define PMM_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'M' << 16 ) + ( 'M' << 24 ) )
-#define PCI_SIGNATURE ( 'P' + ( 'C' << 8 ) + ( 'I' << 16 ) + ( ' ' << 24 ) )
-#define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) )
-#define PNP_GET_BBS_VERSION 0x60
-#define PMM_ALLOCATE 0x0000
-#define PMM_DEALLOCATE 0x0002
-
-/* ROM banner timeout. Based on the configurable BANNER_TIMEOUT in
- * config.h, but converted to a number of (18Hz) timer ticks, and
- * doubled to allow for BIOSes that switch video modes immediately
- * beforehand, so rendering the message almost invisible to the user.
- */
-#define ROM_BANNER_TIMEOUT ( 2 * ( 18 * BANNER_TIMEOUT ) / 10 )
-
-/* We can load a ROM in two ways: have the BIOS load all of it (.rom prefix)
- * or have the BIOS load a stub that loads the rest using PCI (.xrom prefix).
- * The latter is not as widely supported, but allows the use of large ROMs
- * on some systems with crowded option ROM space.
- */
-
-#ifdef LOAD_ROM_FROM_PCI
-#define ROM_SIZE_VALUE _prefix_filesz_sect /* Amount to load in BIOS */
-#else
-#define ROM_SIZE_VALUE 0 /* Load amount (before compr. fixup) */
-#endif
-
-
- .text
- .code16
- .arch i386
- .section ".prefix", "ax", @progbits
-
- .org 0x00
-romheader:
- .word 0xAA55 /* BIOS extension signature */
-romheader_size: .byte ROM_SIZE_VALUE /* Size in 512-byte blocks */
- jmp init /* Initialisation vector */
-checksum:
- .byte 0, 0
-real_size:
- .word 0
- .org 0x16
- .word undiheader
- .org 0x18
- .word pciheader
- .org 0x1a
- .word pnpheader
- .size romheader, . - romheader
-
- .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
-#ifndef LOAD_ROM_FROM_PCI
- .ascii "ADDB"
- .long romheader_size
- .long 512
- .long 0
-#endif
- .ascii "ADDB"
- .long real_size
- .long 512
- .long 0
- .previous
-
-pciheader:
- .ascii "PCIR" /* Signature */
- .word pci_vendor_id /* Vendor identification */
- .word pci_device_id /* Device identification */
- .word 0x0000 /* Device list pointer */
- .word pciheader_len /* PCI data structure length */
- .byte 0x03 /* PCI data structure revision */
- .byte 0x02, 0x00, 0x00 /* Class code */
-pciheader_image_length:
- .word ROM_SIZE_VALUE /* Image length */
- .word 0x0001 /* Revision level */
- .byte 0x00 /* Code type */
- .byte 0x80 /* Last image indicator */
-pciheader_runtime_length:
- .word ROM_SIZE_VALUE /* Maximum run-time image length */
- .word 0x0000 /* Configuration utility code header */
- .word 0x0000 /* DMTF CLP entry point */
- .equ pciheader_len, . - pciheader
- .size pciheader, . - pciheader
-
-#ifndef LOAD_ROM_FROM_PCI
- .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
- .ascii "ADDW"
- .long pciheader_image_length
- .long 512
- .long 0
- .ascii "ADDW"
- .long pciheader_runtime_length
- .long 512
- .long 0
- .previous
-#endif
-
-pnpheader:
- .ascii "$PnP" /* Signature */
- .byte 0x01 /* Structure revision */
- .byte ( pnpheader_len / 16 ) /* Length (in 16 byte increments) */
- .word 0x0000 /* Offset of next header */
- .byte 0x00 /* Reserved */
- .byte 0x00 /* Checksum */
- .long 0x00000000 /* Device identifier */
- .word mfgstr /* Manufacturer string */
- .word prodstr /* Product name */
- .byte 0x02 /* Device base type code */
- .byte 0x00 /* Device sub-type code */
- .byte 0x00 /* Device interface type code */
- .byte 0xf4 /* Device indicator */
- .word 0x0000 /* Boot connection vector */
- .word 0x0000 /* Disconnect vector */
- .word bev_entry /* Boot execution vector */
- .word 0x0000 /* Reserved */
- .word 0x0000 /* Static resource information vector*/
- .equ pnpheader_len, . - pnpheader
- .size pnpheader, . - pnpheader
-
-/* Manufacturer string */
-mfgstr:
- .asciz "http://etherboot.org"
- .size mfgstr, . - mfgstr
-
-/* Product string
- *
- * Defaults to PRODUCT_SHORT_NAME. If the ROM image is writable at
- * initialisation time, it will be filled in to include the PCI
- * bus:dev.fn number of the card as well.
- */
-prodstr:
- .ascii PRODUCT_SHORT_NAME
-prodstr_separator:
- .byte 0
- .ascii "(PCI "
-prodstr_pci_id:
- .asciz "xx:xx.x)" /* Filled in by init code */
- .size prodstr, . - prodstr
-
- .globl undiheader
- .weak undiloader
-undiheader:
- .ascii "UNDI" /* Signature */
- .byte undiheader_len /* Length of structure */
- .byte 0 /* Checksum */
- .byte 0 /* Structure revision */
- .byte 0,1,2 /* PXE version: 2.1.0 */
- .word undiloader /* Offset to loader routine */
- .word _data16_memsz /* Stack segment size */
- .word _data16_memsz /* Data segment size */
- .word _text16_memsz /* Code segment size */
- .ascii "PCIR" /* Bus type */
- .equ undiheader_len, . - undiheader
- .size undiheader, . - undiheader
-
-/* Initialisation (called once during POST)
- *
- * Determine whether or not this is a PnP system via a signature
- * check. If it is PnP, return to the PnP BIOS indicating that we are
- * a boot-capable device; the BIOS will call our boot execution vector
- * if it wants to boot us. If it is not PnP, hook INT 19.
- */
-init:
- /* Preserve registers, clear direction flag, set %ds=%cs */
- pushaw
- pushw %ds
- pushw %es
- pushw %fs
- pushw %gs
- cld
- pushw %cs
- popw %ds
-
- /* Shuffle some registers around. We need %di available for
- * the print_xxx functions, and in a register that's
- * addressable from %es, so shuffle as follows:
- *
- * %di (pointer to PnP structure) => %bx
- * %bx (runtime segment address, for PCI 3.0) => %gs
- */
- movw %bx, %gs
- movw %di, %bx
-
- /* Print message as early as possible */
- movw $init_message, %si
- xorw %di, %di
- call print_message
- call print_pci_busdevfn
-
-#ifdef LOAD_ROM_FROM_PCI
- /* Save PCI bus:dev.fn for later use */
- movw %ax, pci_busdevfn
-#endif
-
- /* Fill in product name string, if possible */
- movw $prodstr_pci_id, %di
- call print_pci_busdevfn
- movb $( ' ' ), prodstr_separator
-
- /* Print segment address */
- movb $( ' ' ), %al
- xorw %di, %di
- call print_character
- movw %cs, %ax
- call print_hex_word
-
- /* Check for PCI BIOS version */
- pushl %ebx
- pushl %edx
- pushl %edi
- stc
- movw $0xb101, %ax
- int $0x1a
- jc no_pci3
- cmpl $PCI_SIGNATURE, %edx
- jne no_pci3
- testb %ah, %ah
- jnz no_pci3
-#ifdef LOAD_ROM_FROM_PCI
- incb pcibios_present
-#endif
- movw $init_message_pci, %si
- xorw %di, %di
- call print_message
- movb %bh, %al
- call print_hex_nibble
- movb $( '.' ), %al
- call print_character
- movb %bl, %al
- call print_hex_byte
- cmpb $3, %bh
- jb no_pci3
- /* PCI >=3.0: leave %gs as-is if sane */
- movw %gs, %ax
- cmpw $0xa000, %ax /* Insane if %gs < 0xa000 */
- jb pci3_insane
- movw %cs, %bx /* Sane if %cs == %gs */
- cmpw %bx, %ax
- je 1f
- movzbw romheader_size, %cx /* Sane if %cs+len <= %gs */
- shlw $5, %cx
- addw %cx, %bx
- cmpw %bx, %ax
- jae 1f
- movw %cs, %bx /* Sane if %gs+len <= %cs */
- addw %cx, %ax
- cmpw %bx, %ax
- jbe 1f
-pci3_insane: /* PCI 3.0 with insane %gs value: print error and ignore %gs */
- movb $( '!' ), %al
- call print_character
- movw %gs, %ax
- call print_hex_word
-no_pci3:
- /* PCI <3.0: set %gs (runtime segment) = %cs (init-time segment) */
- pushw %cs
- popw %gs
-1: popl %edi
- popl %edx
- popl %ebx
-
- /* Check for PnP BIOS. Although %es:di should point to the
- * PnP BIOS signature on entry, some BIOSes fail to do this.
- */
- movw $( 0xf000 - 1 ), %bx
-pnp_scan:
- incw %bx
- jz no_pnp
- movw %bx, %es
- cmpl $PNP_SIGNATURE, %es:0
- jne pnp_scan
- xorw %dx, %dx
- xorw %si, %si
- movzbw %es:5, %cx
-1: es lodsb
- addb %al, %dl
- loop 1b
- jnz pnp_scan
- /* Is PnP: print PnP message */
- movw $init_message_pnp, %si
- xorw %di, %di
- call print_message
- /* Check for BBS */
- pushw %es:0x1b /* Real-mode data segment */
- pushw %ds /* &(bbs_version) */
- pushw $bbs_version
- pushw $PNP_GET_BBS_VERSION
- lcall *%es:0xd
- addw $8, %sp
- testw %ax, %ax
- je got_bbs
-no_pnp: /* Not PnP-compliant - therefore cannot be BBS-compliant */
-no_bbs: /* Not BBS-compliant - must hook INT 19 */
- movw $init_message_int19, %si
- xorw %di, %di
- call print_message
- xorw %ax, %ax
- movw %ax, %es
- pushl %es:( 0x19 * 4 )
- popl orig_int19
- pushw %gs /* %gs contains runtime %cs */
- pushw $int19_entry
- popl %es:( 0x19 * 4 )
- jmp bbs_done
-got_bbs: /* BBS compliant - no need to hook INT 19 */
- movw $init_message_bbs, %si
- xorw %di, %di
- call print_message
-bbs_done:
-
- /* Check for PMM */
- movw $( 0xe000 - 1 ), %bx
-pmm_scan:
- incw %bx
- jz no_pmm
- movw %bx, %es
- cmpl $PMM_SIGNATURE, %es:0
- jne pmm_scan
- xorw %dx, %dx
- xorw %si, %si
- movzbw %es:5, %cx
-1: es lodsb
- addb %al, %dl
- loop 1b
- jnz pmm_scan
- /* PMM found: print PMM message */
- movw $init_message_pmm, %si
- xorw %di, %di
- call print_message
- /* We have PMM and so a 1kB stack: preserve upper register halves */
- pushal
- /* Calculate required allocation size in %esi */
- movzwl real_size, %eax
- shll $9, %eax
- addl $_textdata_memsz, %eax
- orw $0xffff, %ax /* Ensure allocation size is at least 64kB */
- bsrl %eax, %ecx
- subw $15, %cx /* Round up and convert to 64kB count */
- movw $1, %si
- shlw %cl, %si
-pmm_loop:
- /* Try to allocate block via PMM */
- pushw $0x0006 /* Aligned, extended memory */
- pushl $0xffffffff /* No handle */
- movzwl %si, %eax
- shll $12, %eax
- pushl %eax /* Allocation size in paragraphs */
- pushw $PMM_ALLOCATE
- lcall *%es:7
- addw $12, %sp
- /* Abort if allocation fails */
- testw %dx, %dx /* %ax==0 even on success, since align>=64kB */
- jz pmm_fail
- /* If block has A20==1, free block and try again with twice
- * the allocation size (and hence alignment).
- */
- testw $0x0010, %dx
- jz got_pmm
- pushw %dx
- pushw $0
- pushw $PMM_DEALLOCATE
- lcall *%es:7
- addw $6, %sp
- addw %si, %si
- jmp pmm_loop
-got_pmm: /* PMM allocation succeeded */
- movw %dx, ( image_source + 2 )
- movw %dx, %ax
- xorw %di, %di
- call print_hex_word
- movb $( '@' ), %al
- call print_character
- movw %si, %ax
- call print_hex_byte
-pmm_copy:
- /* Copy ROM to PMM block */
- xorw %ax, %ax
- movw %ax, %es
- movl image_source, %edi
- xorl %esi, %esi
- movzbl romheader_size, %ecx
- shll $9, %ecx
- addr32 rep movsb /* PMM presence implies flat real mode */
- movl %edi, decompress_to
- /* Shrink ROM */
- movb $_prefix_memsz_sect, romheader_size
-#if defined(SHRINK_WITHOUT_PMM) || defined(LOAD_ROM_FROM_PCI)
- jmp pmm_done
-pmm_fail:
- /* Print marker and copy ourselves to high memory */
- movl $HIGHMEM_LOADPOINT, image_source
- xorw %di, %di
- movb $( '!' ), %al
- call print_character
- jmp pmm_copy
-pmm_done:
-#else
-pmm_fail:
-#endif
- /* Restore upper register halves */
- popal
-#if defined(LOAD_ROM_FROM_PCI)
- call load_from_pci
- jc load_err
- jmp load_ok
-no_pmm:
- /* Cannot continue without PMM - print error message */
- xorw %di, %di
- movw $init_message_no_pmm, %si
- call print_message
-load_err:
- /* Wait for five seconds to let user see message */
- movw $90, %cx
-1: call wait_for_tick
- loop 1b
- /* Mark environment as invalid and return */
- movl $0, decompress_to
- jmp out
-
-load_ok:
-#else
-no_pmm:
-#endif
- /* Update checksum */
- xorw %bx, %bx
- xorw %si, %si
- movzbw romheader_size, %cx
- shlw $9, %cx
-1: lodsb
- addb %al, %bl
- loop 1b
- subb %bl, checksum
-
- /* Copy self to option ROM space. Required for PCI3.0, which
- * loads us to a temporary location in low memory. Will be a
- * no-op for lower PCI versions.
- */
- movb $( ' ' ), %al
- xorw %di, %di
- call print_character
- movw %gs, %ax
- call print_hex_word
- movzbw romheader_size, %cx
- shlw $9, %cx
- movw %ax, %es
- xorw %si, %si
- xorw %di, %di
- cs rep movsb
-
- /* Prompt for POST-time shell */
- movw $init_message_prompt, %si
- xorw %di, %di
- call print_message
- movw $prodstr, %si
- call print_message
- movw $init_message_dots, %si
- call print_message
- /* Wait for Ctrl-B */
- movw $0xff02, %bx
- call wait_for_key
- /* Clear prompt */
- pushf
- xorw %di, %di
- call print_kill_line
- movw $init_message_done, %si
- call print_message
- popf
- jnz out
- /* Ctrl-B was pressed: invoke gPXE. The keypress will be
- * picked up by the initial shell prompt, and we will drop
- * into a shell.
- */
- pushw %cs
- call exec
-out:
- /* Restore registers */
- popw %gs
- popw %fs
- popw %es
- popw %ds
- popaw
-
- /* Indicate boot capability to PnP BIOS, if present */
- movw $0x20, %ax
- lret
- .size init, . - init
-
-/*
- * Note to hardware vendors:
- *
- * If you wish to brand this boot ROM, please do so by defining the
- * strings PRODUCT_NAME and PRODUCT_SHORT_NAME in config/general.h.
- *
- * While nothing in the GPL prevents you from removing all references
- * to gPXE or http://etherboot.org, we prefer you not to do so.
- *
- * If you have an OEM-mandated branding requirement that cannot be
- * satisfied simply by defining PRODUCT_NAME and PRODUCT_SHORT_NAME,
- * please contact us.
- *
- * [ Including an ASCII NUL in PRODUCT_NAME is considered to be
- * bypassing the spirit of this request! ]
- */
-init_message:
- .ascii "\n"
- .ascii PRODUCT_NAME
- .ascii "\n"
- .asciz "gPXE (http://etherboot.org) - "
- .size init_message, . - init_message
-init_message_pci:
- .asciz " PCI"
- .size init_message_pci, . - init_message_pci
-init_message_pnp:
- .asciz " PnP"
- .size init_message_pnp, . - init_message_pnp
-init_message_bbs:
- .asciz " BBS"
- .size init_message_bbs, . - init_message_bbs
-init_message_pmm:
- .asciz " PMM"
- .size init_message_pmm, . - init_message_pmm
-#ifdef LOAD_ROM_FROM_PCI
-init_message_no_pmm:
- .asciz "\nPMM required but not present!\n"
- .size init_message_no_pmm, . - init_message_no_pmm
-#endif
-init_message_int19:
- .asciz " INT19"
- .size init_message_int19, . - init_message_int19
-init_message_prompt:
- .asciz "\nPress Ctrl-B to configure "
- .size init_message_prompt, . - init_message_prompt
-init_message_dots:
- .asciz "..."
- .size init_message_dots, . - init_message_dots
-init_message_done:
- .asciz "\n\n"
- .size init_message_done, . - init_message_done
-
-/* ROM image location
- *
- * May be either within option ROM space, or within PMM-allocated block.
- */
- .globl image_source
-image_source:
- .long 0
- .size image_source, . - image_source
-
-/* Temporary decompression area
- *
- * May be either at HIGHMEM_LOADPOINT, or within PMM-allocated block.
- * If a PCI ROM load fails, this will be set to zero.
- */
- .globl decompress_to
-decompress_to:
- .long HIGHMEM_LOADPOINT
- .size decompress_to, . - decompress_to
-
-#ifdef LOAD_ROM_FROM_PCI
-
-/* Set if the PCI BIOS is present, even <3.0 */
-pcibios_present:
- .byte 0
- .byte 0 /* for alignment */
- .size pcibios_present, . - pcibios_present
-
-/* PCI bus:device.function word
- *
- * Filled in by init in the .xrom case, so the remainder of the ROM
- * can be located.
- */
-pci_busdevfn:
- .word 0
- .size pci_busdevfn, . - pci_busdevfn
-
-#endif
-
-/* BBS version
- *
- * Filled in by BBS BIOS. We ignore the value.
- */
-bbs_version:
- .word 0
- .size bbs_version, . - bbs_version
-
-/* Boot Execution Vector entry point
- *
- * Called by the PnP BIOS when it wants to boot us.
- */
-bev_entry:
- pushw %cs
- call exec
- lret
- .size bev_entry, . - bev_entry
-
-
-#ifdef LOAD_ROM_FROM_PCI
-
-#define PCI_ROM_ADDRESS 0x30 /* Bits 31:11 address, 10:1 reserved */
-#define PCI_ROM_ADDRESS_ENABLE 0x00000001
-#define PCI_ROM_ADDRESS_MASK 0xfffff800
-
-#define PCIBIOS_READ_WORD 0xb109
-#define PCIBIOS_READ_DWORD 0xb10a
-#define PCIBIOS_WRITE_WORD 0xb10c
-#define PCIBIOS_WRITE_DWORD 0xb10d
-
-/* Determine size of PCI BAR
- *
- * %bx : PCI bus:dev.fn to probe
- * %di : Address of BAR to find size of
- * %edx : Mask of address bits within BAR
- *
- * %ecx : Size for a memory resource,
- * 1 for an I/O resource (bit 0 set).
- * CF : Set on error or nonexistent device (all-ones read)
- *
- * All other registers saved.
- */
-pci_bar_size:
- /* Save registers */
- pushw %ax
- pushl %esi
- pushl %edx
-
- /* Read current BAR value */
- movw $PCIBIOS_READ_DWORD, %ax
- int $0x1a
-
- /* Check for device existence and save it */
- testb $1, %cl /* I/O bit? */
- jz 1f
- andl $1, %ecx /* If so, exit with %ecx = 1 */
- jmp 99f
-1: notl %ecx
- testl %ecx, %ecx /* Set ZF iff %ecx was all-ones */
- notl %ecx
- jnz 1f
- stc /* All ones - exit with CF set */
- jmp 99f
-1: movl %ecx, %esi /* Save in %esi */
-
- /* Write all ones to BAR */
- movl %edx, %ecx
- movw $PCIBIOS_WRITE_DWORD, %ax
- int $0x1a
-
- /* Read back BAR */
- movw $PCIBIOS_READ_DWORD, %ax
- int $0x1a
-
- /* Find decode size from least set bit in mask BAR */
- bsfl %ecx, %ecx /* Find least set bit, log2(decode size) */
- jz 1f /* Mask BAR should not be zero */
- xorl %edx, %edx
- incl %edx
- shll %cl, %edx /* %edx = decode size */
- jmp 2f
-1: xorl %edx, %edx /* Return zero size for mask BAR zero */
-
- /* Restore old BAR value */
-2: movl %esi, %ecx
- movw $PCIBIOS_WRITE_DWORD, %ax
- int $0x1a
-
- movl %edx, %ecx /* Return size in %ecx */
-
- /* Restore registers and return */
-99: popl %edx
- popl %esi
- popw %ax
- ret
-
- .size pci_bar_size, . - pci_bar_size
-
-/* PCI ROM loader
- *
- * Called from init in the .xrom case to load the non-prefix code
- * using the PCI ROM BAR.
- *
- * Returns with carry flag set on error. All registers saved.
- */
-load_from_pci:
- /*
- * Use PCI BIOS access to config space. The calls take
- *
- * %ah : 0xb1 %al : function
- * %bx : bus/dev/fn
- * %di : config space address
- * %ecx : value to write (for writes)
- *
- * %ecx : value read (for reads)
- * %ah : return code
- * CF : error indication
- *
- * All registers not used for return are preserved.
- */
-
- /* Save registers and set up %es for big real mode */
- pushal
- pushw %es
- xorw %ax, %ax
- movw %ax, %es
-
- /* Check PCI BIOS presence */
- cmpb $0, pcibios_present
- jz err_pcibios
-
- /* Load existing PCI ROM BAR */
- movw $PCIBIOS_READ_DWORD, %ax
- movw pci_busdevfn, %bx
- movw $PCI_ROM_ADDRESS, %di
- int $0x1a
-
- /* Maybe it's already enabled? */
- testb $PCI_ROM_ADDRESS_ENABLE, %cl
- jz 1f
- movb $1, %dl /* Flag indicating no deinit required */
- movl %ecx, %ebp
- jmp check_rom
-
- /* Determine PCI BAR decode size */
-1: movl $PCI_ROM_ADDRESS_MASK, %edx
- call pci_bar_size /* Returns decode size in %ecx */
- jc err_size_insane /* CF => no ROM BAR, %ecx == ffffffff */
-
- /* Check sanity of decode size */
- xorl %eax, %eax
- movw real_size, %ax
- shll $9, %eax /* %eax = ROM size */
- cmpl %ecx, %eax
- ja err_size_insane /* Insane if decode size < ROM size */
- cmpl $0x100000, %ecx
- jae err_size_insane /* Insane if decode size >= 1MB */
-
- /* Find a place to map the BAR
- * In theory we should examine e820 and all PCI BARs to find a
- * free region. However, we run at POST when e820 may not be
- * available, and memory reads of an unmapped location are
- * de facto standardized to return all-ones. Thus, we can get
- * away with searching high memory (0xf0000000 and up) on
- * multiples of the ROM BAR decode size for a sufficiently
- * large all-ones region.
- */
- movl %ecx, %edx /* Save ROM BAR size in %edx */
- movl $0xf0000000, %ebp
- xorl %eax, %eax
- notl %eax /* %eax = all ones */
-bar_search:
- movl %ebp, %edi
- movl %edx, %ecx
- shrl $2, %ecx
- addr32 repe scasl /* Scan %es:edi for anything not all-ones */
- jz bar_found
- addl %edx, %ebp
- testl $0x80000000, %ebp
- jz err_no_bar
- jmp bar_search
-
-bar_found:
- movl %edi, %ebp
- /* Save current BAR value on stack to restore later */
- movw $PCIBIOS_READ_DWORD, %ax
- movw $PCI_ROM_ADDRESS, %di
- int $0x1a
- pushl %ecx
-
- /* Map the ROM */
- movw $PCIBIOS_WRITE_DWORD, %ax
- movl %ebp, %ecx
- orb $PCI_ROM_ADDRESS_ENABLE, %cl
- int $0x1a
-
- xorb %dl, %dl /* %dl = 0 : ROM was not already mapped */
-check_rom:
- /* Check and copy ROM - enter with %dl set to skip unmapping,
- * %ebp set to mapped ROM BAR address.
- * We check up to prodstr_separator for equality, since anything past
- * that may have been modified. Since our check includes the checksum
- * byte over the whole ROM stub, that should be sufficient.
- */
- xorb %dh, %dh /* %dh = 0 : ROM did not fail integrity check */
-
- /* Verify ROM integrity */
- xorl %esi, %esi
- movl %ebp, %edi
- movl $prodstr_separator, %ecx
- addr32 repe cmpsb
- jz copy_rom
- incb %dh /* ROM failed integrity check */
- movl %ecx, %ebp /* Save number of bytes left */
- jmp skip_load
-
-copy_rom:
- /* Print BAR address and indicate whether we mapped it ourselves */
- movb $( ' ' ), %al
- xorw %di, %di
- call print_character
- movl %ebp, %eax
- call print_hex_dword
- movb $( '-' ), %al /* '-' for self-mapped */
- subb %dl, %al
- subb %dl, %al /* '+' = '-' - 2 for BIOS-mapped */
- call print_character
-
- /* Copy ROM at %ebp to PMM or highmem block */
- movl %ebp, %esi
- movl image_source, %edi
- movzwl real_size, %ecx
- shll $9, %ecx
- addr32 es rep movsb
- movl %edi, decompress_to
-skip_load:
- testb %dl, %dl /* Was ROM already mapped? */
- jnz skip_unmap
-
- /* Unmap the ROM by restoring old ROM BAR */
- movw $PCIBIOS_WRITE_DWORD, %ax
- movw $PCI_ROM_ADDRESS, %di
- popl %ecx
- int $0x1a
-
-skip_unmap:
- /* Error handling */
- testb %dh, %dh
- jnz err_rom_invalid
- clc
- jmp 99f
-
-err_pcibios: /* No PCI BIOS available */
- movw $load_message_no_pcibios, %si
- xorl %eax, %eax /* "error code" is zero */
- jmp 1f
-err_size_insane: /* BAR has size (%ecx) that is insane */
- movw $load_message_size_insane, %si
- movl %ecx, %eax
- jmp 1f
-err_no_bar: /* No space of sufficient size (%edx) found */
- movw $load_message_no_bar, %si
- movl %edx, %eax
- jmp 1f
-err_rom_invalid: /* Loaded ROM does not match (%ebp bytes left) */
- movw $load_message_rom_invalid, %si
- movzbl romheader_size, %eax
- shll $9, %eax
- subl %ebp, %eax
- decl %eax /* %eax is now byte index of failure */
-
-1: /* Error handler - print message at %si and dword in %eax */
- xorw %di, %di
- call print_message
- call print_hex_dword
- stc
-99: popw %es
- popal
- ret
-
- .size load_from_pci, . - load_from_pci
-
-load_message_no_pcibios:
- .asciz "\nNo PCI BIOS found! "
- .size load_message_no_pcibios, . - load_message_no_pcibios
-
-load_message_size_insane:
- .asciz "\nROM resource has invalid size "
- .size load_message_size_insane, . - load_message_size_insane
-
-load_message_no_bar:
- .asciz "\nNo memory hole of sufficient size "
- .size load_message_no_bar, . - load_message_no_bar
-
-load_message_rom_invalid:
- .asciz "\nLoaded ROM is invalid at "
- .size load_message_rom_invalid, . - load_message_rom_invalid
-
-#endif /* LOAD_ROM_FROM_PCI */
-
-
-/* INT19 entry point
- *
- * Called via the hooked INT 19 if we detected a non-PnP BIOS. We
- * attempt to return via the original INT 19 vector (if we were able
- * to store it).
- */
-int19_entry:
- pushw %cs
- popw %ds
- /* Prompt user to press B to boot */
- movw $int19_message_prompt, %si
- xorw %di, %di
- call print_message
- movw $prodstr, %si
- call print_message
- movw $int19_message_dots, %si
- call print_message
- movw $0xdf4e, %bx
- call wait_for_key
- pushf
- xorw %di, %di
- call print_kill_line
- movw $int19_message_done, %si
- call print_message
- popf
- jz 1f
- /* Leave keypress in buffer and start gPXE. The keypress will
- * cause the usual initial Ctrl-B prompt to be skipped.
- */
- pushw %cs
- call exec
-1: /* Try to call original INT 19 vector */
- movl %cs:orig_int19, %eax
- testl %eax, %eax
- je 2f
- ljmp *%cs:orig_int19
-2: /* No chained vector: issue INT 18 as a last resort */
- int $0x18
- .size int19_entry, . - int19_entry
-orig_int19:
- .long 0
- .size orig_int19, . - orig_int19
-
-int19_message_prompt:
- .asciz "Press N to skip booting from "
- .size int19_message_prompt, . - int19_message_prompt
-int19_message_dots:
- .asciz "..."
- .size int19_message_dots, . - int19_message_dots
-int19_message_done:
- .asciz "\n\n"
- .size int19_message_done, . - int19_message_done
-
-/* Execute as a boot device
- *
- */
-exec: /* Set %ds = %cs */
- pushw %cs
- popw %ds
-
-#ifdef LOAD_ROM_FROM_PCI
- /* Don't execute if load was invalid */
- cmpl $0, decompress_to
- jne 1f
- lret
-1:
-#endif
-
- /* Print message as soon as possible */
- movw $prodstr, %si
- xorw %di, %di
- call print_message
- movw $exec_message, %si
- call print_message
-
- /* Store magic word on BIOS stack and remember BIOS %ss:sp */
- pushl $STACK_MAGIC
- movw %ss, %dx
- movw %sp, %bp
-
- /* Obtain a reasonably-sized temporary stack */
- xorw %ax, %ax
- movw %ax, %ss
- movw $0x7c00, %sp
-
- /* Install gPXE */
- movl image_source, %esi
- movl decompress_to, %edi
- call alloc_basemem
- call install_prealloc
-
- /* Set up real-mode stack */
- movw %bx, %ss
- movw $_estack16, %sp
-
- /* Jump to .text16 segment */
- pushw %ax
- pushw $1f
- lret
- .section ".text16", "awx", @progbits
-1: /* Call main() */
- pushl $main
- pushw %cs
- call prot_call
- popl %ecx /* discard */
-
- /* Uninstall gPXE */
- call uninstall
-
- /* Restore BIOS stack */
- movw %dx, %ss
- movw %bp, %sp
-
- /* Check magic word on BIOS stack */
- popl %eax
- cmpl $STACK_MAGIC, %eax
- jne 1f
- /* BIOS stack OK: return to caller */
- lret
-1: /* BIOS stack corrupt: use INT 18 */
- int $0x18
- .previous
-
-exec_message:
- .asciz " starting execution\n"
- .size exec_message, . - exec_message
-
-/* Wait for key press specified by %bl (masked by %bh)
- *
- * Used by init and INT19 code when prompting user. If the specified
- * key is pressed, it is left in the keyboard buffer.
- *
- * Returns with ZF set iff specified key is pressed.
- */
-wait_for_key:
- /* Preserve registers */
- pushw %cx
- pushw %ax
-1: /* Empty the keyboard buffer before waiting for input */
- movb $0x01, %ah
- int $0x16
- jz 2f
- xorw %ax, %ax
- int $0x16
- jmp 1b
-2: /* Wait for a key press */
- movw $ROM_BANNER_TIMEOUT, %cx
-3: decw %cx
- js 99f /* Exit with ZF clear */
- /* Wait for timer tick to be updated */
- call wait_for_tick
- /* Check to see if a key was pressed */
- movb $0x01, %ah
- int $0x16
- jz 3b
- /* Check to see if key was the specified key */
- andb %bh, %al
- cmpb %al, %bl
- je 99f /* Exit with ZF set */
- /* Not the specified key: remove from buffer and stop waiting */
- pushfw
- xorw %ax, %ax
- int $0x16
- popfw /* Exit with ZF clear */
-99: /* Restore registers and return */
- popw %ax
- popw %cx
- ret
- .size wait_for_key, . - wait_for_key
-
-/* Wait for timer tick
- *
- * Used by wait_for_key
- */
-wait_for_tick:
- pushl %eax
- pushw %fs
- movw $0x40, %ax
- movw %ax, %fs
- movl %fs:(0x6c), %eax
-1: pushf
- sti
- hlt
- popf
- cmpl %fs:(0x6c), %eax
- je 1b
- popw %fs
- popl %eax
- ret
- .size wait_for_tick, . - wait_for_tick