2005-03-08 19:53:11 +01:00
|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
|
2015-03-02 14:29:46 +01:00
|
|
|
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
2009-05-18 10:33:36 +02:00
|
|
|
|
2016-02-19 00:23:38 +01:00
|
|
|
#include <librm.h>
|
2008-09-25 02:53:42 +02:00
|
|
|
#include <config/general.h>
|
2015-02-11 13:51:58 +01:00
|
|
|
#include <config/branding.h>
|
2008-09-25 02:53:42 +02:00
|
|
|
|
2008-03-09 23:13:07 +01:00
|
|
|
#define PNP_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'n' << 16 ) + ( 'P' << 24 ) )
|
|
|
|
#define PMM_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'M' << 16 ) + ( 'M' << 24 ) )
|
2008-07-30 20:57:46 +02:00
|
|
|
#define PCI_SIGNATURE ( 'P' + ( 'C' << 8 ) + ( 'I' << 16 ) + ( ' ' << 24 ) )
|
2008-03-09 23:13:07 +01:00
|
|
|
#define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) )
|
2008-08-26 00:36:24 +02:00
|
|
|
#define PMM_ALLOCATE 0x0000
|
2010-04-24 23:34:28 +02:00
|
|
|
#define PMM_FIND 0x0001
|
|
|
|
#define PMM_HANDLE_BASE ( ( ( 'F' - 'A' + 1 ) << 26 ) + \
|
|
|
|
( ( 'E' - 'A' + 1 ) << 21 ) + \
|
|
|
|
( ( 'N' - 'A' + 1 ) << 16 ) )
|
|
|
|
#define PMM_HANDLE_BASE_IMAGE_SOURCE \
|
|
|
|
( PMM_HANDLE_BASE | 0x00001000 )
|
|
|
|
#define PMM_HANDLE_BASE_DECOMPRESS_TO \
|
|
|
|
( PMM_HANDLE_BASE | 0x00002000 )
|
2013-03-11 02:43:12 +01:00
|
|
|
#define PCI_FUNC_MASK 0x07
|
2008-03-09 23:13:07 +01:00
|
|
|
|
2014-02-26 00:33:08 +01:00
|
|
|
/* ROM banner timeout, converted to a number of (18Hz) timer ticks. */
|
|
|
|
#define ROM_BANNER_TIMEOUT_TICKS ( ( 18 * ROM_BANNER_TIMEOUT ) / 10 )
|
2008-09-25 02:53:42 +02:00
|
|
|
|
2010-04-25 16:57:00 +02:00
|
|
|
/* Allow payload to be excluded from ROM size
|
|
|
|
*/
|
|
|
|
#if ROMPREFIX_EXCLUDE_PAYLOAD
|
|
|
|
#define ZINFO_TYPE_ADxB "ADHB"
|
|
|
|
#define ZINFO_TYPE_ADxW "ADHW"
|
|
|
|
#else
|
|
|
|
#define ZINFO_TYPE_ADxB "ADDB"
|
|
|
|
#define ZINFO_TYPE_ADxW "ADDW"
|
2012-06-10 19:25:26 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Allow ROM to be marked as containing multiple images
|
|
|
|
*/
|
|
|
|
#if ROMPREFIX_MORE_IMAGES
|
|
|
|
#define INDICATOR 0x00
|
|
|
|
#else
|
|
|
|
#define INDICATOR 0x80
|
2014-08-21 17:34:26 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Default to building a PCI ROM if no bus type is specified
|
|
|
|
*/
|
|
|
|
#ifndef BUSTYPE
|
|
|
|
#define BUSTYPE "PCIR"
|
2010-04-25 16:57:00 +02:00
|
|
|
#endif
|
|
|
|
|
2005-03-08 19:53:11 +01:00
|
|
|
.text
|
|
|
|
.code16
|
|
|
|
.arch i386
|
|
|
|
.section ".prefix", "ax", @progbits
|
2011-02-23 22:12:56 +01:00
|
|
|
.globl _rom_start
|
|
|
|
_rom_start:
|
2005-03-08 19:53:11 +01:00
|
|
|
|
2006-06-06 17:33:39 +02:00
|
|
|
.org 0x00
|
|
|
|
romheader:
|
|
|
|
.word 0xAA55 /* BIOS extension signature */
|
2010-04-19 21:32:25 +02:00
|
|
|
romheader_size: .byte 0 /* Size in 512-byte blocks */
|
2008-03-09 23:13:07 +01:00
|
|
|
jmp init /* Initialisation vector */
|
|
|
|
checksum:
|
2010-04-19 21:32:25 +02:00
|
|
|
.byte 0
|
2012-07-23 18:41:38 +02:00
|
|
|
.org 0x10
|
|
|
|
.word ipxeheader
|
2005-03-08 19:53:11 +01:00
|
|
|
.org 0x16
|
2006-06-06 17:33:39 +02:00
|
|
|
.word undiheader
|
2014-08-21 17:34:26 +02:00
|
|
|
.ifeqs BUSTYPE, "PCIR"
|
2005-03-08 19:53:11 +01:00
|
|
|
.org 0x18
|
2006-06-06 17:33:39 +02:00
|
|
|
.word pciheader
|
2014-08-21 17:34:26 +02:00
|
|
|
.endif
|
2006-06-06 17:33:39 +02:00
|
|
|
.org 0x1a
|
|
|
|
.word pnpheader
|
|
|
|
.size romheader, . - romheader
|
[prefix] Add .xrom prefix for a ROM that loads itself by PCI accesses
The standard option ROM format provides a header indicating the size
of the entire ROM, which the BIOS will reserve space for, load, and
call as necessary. However, this space is strictly limited to 128k for
all ROMs. gPXE ameliorates this somewhat by reserving space for itself
in high memory and relocating the majority of its code there, but on
systems prior to PCI3 enough space must still be present to load the
ROM in the first place. Even on PCI3 systems, the BIOS often limits the
size of ROM it will load to a bit over 64kB.
These space problems can be solved by providing an artificially small
size in the ROM header: just enough to let the prefix code (at the
beginning of the ROM image) be loaded by the BIOS. To the BIOS, the
gPXE ROM will appear to be only a few kilobytes; it can then load
the rest of itself by accessing the ROM directly using the PCI
interface reserved for that task.
There are a few problems with this approach. First, gPXE needs to find
an unmapped region in memory to map the ROM so it can read from it;
this is done using the crude but effective approach of scanning high
memory (over 0xF0000000) for a sufficiently large region of all-ones
(0xFF) reads. (In x86 architecture, all-ones is returned for accesses
to memory regions that no mapped device can satisfy.) This is not
provably valid in all situations, but has worked well in practice.
More importantly, this type of ROM access can only work if the PCI ROM
BAR exists at all. NICs on physical add-in PCI cards generally must
have the BAR in order for the BIOS to be able to load their ROM, but
ISA cards and LAN-on-Motherboard cards will both fail to load gPXE
using this scheme.
Due to these uncertainties, it is recommended that .xrom only be used
when a regular .rom image is infeasible due to crowded option ROM
space. However, when it works it could allow loading gPXE images
as large as a flash chip one could find - 128kB or even higher.
Signed-off-by: Marty Connor <mdc@etherboot.org>
2009-10-18 22:12:51 +02:00
|
|
|
|
2008-10-17 02:39:48 +02:00
|
|
|
.section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
|
2010-04-25 16:57:00 +02:00
|
|
|
.ascii ZINFO_TYPE_ADxB
|
2007-07-16 18:17:26 +02:00
|
|
|
.long romheader_size
|
|
|
|
.long 512
|
|
|
|
.long 0
|
|
|
|
.previous
|
2006-06-06 17:33:39 +02:00
|
|
|
|
2014-08-21 17:34:26 +02:00
|
|
|
.ifeqs BUSTYPE, "PCIR"
|
2017-08-30 11:15:25 +02:00
|
|
|
.align 4
|
2006-06-06 17:33:39 +02:00
|
|
|
pciheader:
|
|
|
|
.ascii "PCIR" /* Signature */
|
2008-07-30 20:57:46 +02:00
|
|
|
.word pci_vendor_id /* Vendor identification */
|
|
|
|
.word pci_device_id /* Device identification */
|
2015-04-14 10:59:59 +02:00
|
|
|
.word ( pci_devlist - pciheader ) /* Device list pointer */
|
2006-06-06 17:33:39 +02:00
|
|
|
.word pciheader_len /* PCI data structure length */
|
2008-07-30 20:57:46 +02:00
|
|
|
.byte 0x03 /* PCI data structure revision */
|
|
|
|
.byte 0x02, 0x00, 0x00 /* Class code */
|
|
|
|
pciheader_image_length:
|
2010-04-19 21:32:25 +02:00
|
|
|
.word 0 /* Image length */
|
2008-07-30 20:57:46 +02:00
|
|
|
.word 0x0001 /* Revision level */
|
|
|
|
.byte 0x00 /* Code type */
|
2012-06-10 19:25:26 +02:00
|
|
|
.byte INDICATOR /* Last image indicator */
|
2008-07-30 20:57:46 +02:00
|
|
|
pciheader_runtime_length:
|
2010-04-19 21:32:25 +02:00
|
|
|
.word 0 /* Maximum run-time image length */
|
2008-07-30 20:57:46 +02:00
|
|
|
.word 0x0000 /* Configuration utility code header */
|
|
|
|
.word 0x0000 /* DMTF CLP entry point */
|
2006-06-06 17:33:39 +02:00
|
|
|
.equ pciheader_len, . - pciheader
|
|
|
|
.size pciheader, . - pciheader
|
[prefix] Add .xrom prefix for a ROM that loads itself by PCI accesses
The standard option ROM format provides a header indicating the size
of the entire ROM, which the BIOS will reserve space for, load, and
call as necessary. However, this space is strictly limited to 128k for
all ROMs. gPXE ameliorates this somewhat by reserving space for itself
in high memory and relocating the majority of its code there, but on
systems prior to PCI3 enough space must still be present to load the
ROM in the first place. Even on PCI3 systems, the BIOS often limits the
size of ROM it will load to a bit over 64kB.
These space problems can be solved by providing an artificially small
size in the ROM header: just enough to let the prefix code (at the
beginning of the ROM image) be loaded by the BIOS. To the BIOS, the
gPXE ROM will appear to be only a few kilobytes; it can then load
the rest of itself by accessing the ROM directly using the PCI
interface reserved for that task.
There are a few problems with this approach. First, gPXE needs to find
an unmapped region in memory to map the ROM so it can read from it;
this is done using the crude but effective approach of scanning high
memory (over 0xF0000000) for a sufficiently large region of all-ones
(0xFF) reads. (In x86 architecture, all-ones is returned for accesses
to memory regions that no mapped device can satisfy.) This is not
provably valid in all situations, but has worked well in practice.
More importantly, this type of ROM access can only work if the PCI ROM
BAR exists at all. NICs on physical add-in PCI cards generally must
have the BAR in order for the BIOS to be able to load their ROM, but
ISA cards and LAN-on-Motherboard cards will both fail to load gPXE
using this scheme.
Due to these uncertainties, it is recommended that .xrom only be used
when a regular .rom image is infeasible due to crowded option ROM
space. However, when it works it could allow loading gPXE images
as large as a flash chip one could find - 128kB or even higher.
Signed-off-by: Marty Connor <mdc@etherboot.org>
2009-10-18 22:12:51 +02:00
|
|
|
|
2015-04-14 10:59:59 +02:00
|
|
|
/* PCI additional device list (filled in by linker) */
|
|
|
|
.section ".pci_devlist.00000000", "a", @progbits
|
|
|
|
pci_devlist:
|
|
|
|
.previous
|
|
|
|
.section ".pci_devlist.ffffffff", "a", @progbits
|
|
|
|
pci_devlist_end:
|
|
|
|
.short 0x0000 /* List terminator */
|
|
|
|
.previous
|
|
|
|
/* Ensure that terminator is always present */
|
|
|
|
.reloc pciheader, RELOC_TYPE_NONE, pci_devlist_end
|
|
|
|
|
2008-10-17 02:39:48 +02:00
|
|
|
.section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
|
2010-04-25 16:57:00 +02:00
|
|
|
.ascii ZINFO_TYPE_ADxW
|
2008-07-30 20:57:46 +02:00
|
|
|
.long pciheader_image_length
|
|
|
|
.long 512
|
|
|
|
.long 0
|
2016-01-06 00:40:18 +01:00
|
|
|
.ascii "ADHW"
|
2008-07-30 20:57:46 +02:00
|
|
|
.long pciheader_runtime_length
|
2007-07-16 18:17:26 +02:00
|
|
|
.long 512
|
|
|
|
.long 0
|
|
|
|
.previous
|
2014-08-21 17:34:26 +02:00
|
|
|
.endif /* PCIR */
|
2006-06-06 17:33:39 +02:00
|
|
|
|
2011-05-17 23:48:52 +02:00
|
|
|
/* PnP doesn't require any particular alignment, but IBM
|
|
|
|
* BIOSes will scan on 16-byte boundaries rather than using
|
|
|
|
* the offset stored at 0x1a
|
|
|
|
*/
|
|
|
|
.align 16
|
2006-06-06 17:33:39 +02:00
|
|
|
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 */
|
2008-08-26 00:36:24 +02:00
|
|
|
.byte 0xf4 /* Device indicator */
|
2006-06-06 17:33:39 +02:00
|
|
|
.word 0x0000 /* Boot connection vector */
|
|
|
|
.word 0x0000 /* Disconnect vector */
|
2008-03-09 23:13:07 +01:00
|
|
|
.word bev_entry /* Boot execution vector */
|
2006-06-06 17:33:39 +02:00
|
|
|
.word 0x0000 /* Reserved */
|
|
|
|
.word 0x0000 /* Static resource information vector*/
|
|
|
|
.equ pnpheader_len, . - pnpheader
|
|
|
|
.size pnpheader, . - pnpheader
|
2005-03-08 19:53:11 +01:00
|
|
|
|
2008-05-21 19:43:58 +02:00
|
|
|
/* Manufacturer string */
|
2006-06-06 17:33:39 +02:00
|
|
|
mfgstr:
|
2010-04-19 21:16:01 +02:00
|
|
|
.asciz "http://ipxe.org"
|
2006-06-06 17:33:39 +02:00
|
|
|
.size mfgstr, . - mfgstr
|
2008-05-21 19:43:58 +02:00
|
|
|
|
|
|
|
/* Product string
|
|
|
|
*
|
2008-10-31 20:10:28 +01:00
|
|
|
* 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.
|
2008-05-21 19:43:58 +02:00
|
|
|
*/
|
2006-06-06 17:33:39 +02:00
|
|
|
prodstr:
|
2008-10-31 20:10:28 +01:00
|
|
|
.ascii PRODUCT_SHORT_NAME
|
2014-08-21 17:34:26 +02:00
|
|
|
.ifeqs BUSTYPE, "PCIR"
|
2008-05-21 19:43:58 +02:00
|
|
|
prodstr_separator:
|
|
|
|
.byte 0
|
|
|
|
.ascii "(PCI "
|
|
|
|
prodstr_pci_id:
|
2014-08-21 17:34:26 +02:00
|
|
|
.ascii "xx:xx.x)" /* Filled in by init code */
|
|
|
|
.endif /* PCIR */
|
|
|
|
.byte 0
|
2006-06-06 17:33:39 +02:00
|
|
|
.size prodstr, . - prodstr
|
2008-08-28 00:45:59 +02:00
|
|
|
|
|
|
|
.globl undiheader
|
2009-10-07 01:15:06 +02:00
|
|
|
.weak undiloader
|
2017-08-30 11:15:25 +02:00
|
|
|
.align 4
|
2006-06-06 17:33:39 +02:00
|
|
|
undiheader:
|
|
|
|
.ascii "UNDI" /* Signature */
|
|
|
|
.byte undiheader_len /* Length of structure */
|
2005-03-08 19:53:11 +01:00
|
|
|
.byte 0 /* Checksum */
|
|
|
|
.byte 0 /* Structure revision */
|
2006-06-06 17:33:39 +02:00
|
|
|
.byte 0,1,2 /* PXE version: 2.1.0 */
|
|
|
|
.word undiloader /* Offset to loader routine */
|
2008-10-09 23:22:01 +02:00
|
|
|
.word _data16_memsz /* Stack segment size */
|
|
|
|
.word _data16_memsz /* Data segment size */
|
|
|
|
.word _text16_memsz /* Code segment size */
|
2014-08-21 17:34:26 +02:00
|
|
|
.ascii BUSTYPE /* Bus type */
|
2006-06-06 17:33:39 +02:00
|
|
|
.equ undiheader_len, . - undiheader
|
|
|
|
.size undiheader, . - undiheader
|
|
|
|
|
2017-08-30 11:15:25 +02:00
|
|
|
.align 4
|
2012-07-23 18:41:38 +02:00
|
|
|
ipxeheader:
|
|
|
|
.ascii "iPXE" /* Signature */
|
|
|
|
.byte ipxeheader_len /* Length of structure */
|
|
|
|
.byte 0 /* Checksum */
|
|
|
|
shrunk_rom_size:
|
|
|
|
.byte 0 /* Shrunk size (in 512-byte blocks) */
|
|
|
|
.byte 0 /* Reserved */
|
|
|
|
build_id:
|
|
|
|
.long _build_id /* Randomly-generated build ID */
|
|
|
|
.equ ipxeheader_len, . - ipxeheader
|
|
|
|
.size ipxeheader, . - ipxeheader
|
|
|
|
|
|
|
|
.section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
|
|
|
|
.ascii "ADHB"
|
|
|
|
.long shrunk_rom_size
|
|
|
|
.long 512
|
|
|
|
.long 0
|
|
|
|
.previous
|
|
|
|
|
2008-03-09 23:13:07 +01:00
|
|
|
/* Initialisation (called once during POST)
|
2006-06-06 17:33:39 +02:00
|
|
|
*
|
|
|
|
* 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.
|
2005-03-08 19:53:11 +01:00
|
|
|
*/
|
2008-03-09 23:13:07 +01:00
|
|
|
init:
|
|
|
|
/* Preserve registers, clear direction flag, set %ds=%cs */
|
|
|
|
pushaw
|
2005-03-08 19:53:11 +01:00
|
|
|
pushw %ds
|
2008-03-09 23:13:07 +01:00
|
|
|
pushw %es
|
2008-05-22 16:14:33 +02:00
|
|
|
pushw %fs
|
2008-07-30 20:57:46 +02:00
|
|
|
pushw %gs
|
2008-03-09 23:13:07 +01:00
|
|
|
cld
|
2006-06-06 17:33:39 +02:00
|
|
|
pushw %cs
|
|
|
|
popw %ds
|
2008-08-22 04:01:46 +02:00
|
|
|
|
2008-03-09 23:13:07 +01:00
|
|
|
/* Print message as early as possible */
|
|
|
|
movw $init_message, %si
|
2008-07-30 20:57:46 +02:00
|
|
|
xorw %di, %di
|
2008-03-09 23:13:07 +01:00
|
|
|
call print_message
|
2008-08-22 04:01:46 +02:00
|
|
|
|
2014-08-21 17:34:26 +02:00
|
|
|
/* Store PCI 3.0 runtime segment address for later use, if
|
|
|
|
* applicable.
|
|
|
|
*/
|
|
|
|
.ifeqs BUSTYPE, "PCIR"
|
|
|
|
movw %bx, %gs
|
|
|
|
.endif
|
|
|
|
|
|
|
|
/* Store PCI bus:dev.fn address, print PCI bus:dev.fn, and add
|
|
|
|
* PCI bus:dev.fn to product name string, if applicable.
|
|
|
|
*/
|
|
|
|
.ifeqs BUSTYPE, "PCIR"
|
|
|
|
xorw %di, %di
|
|
|
|
call print_space
|
|
|
|
movw %ax, init_pci_busdevfn
|
|
|
|
call print_pci_busdevfn
|
2008-05-21 19:43:58 +02:00
|
|
|
movw $prodstr_pci_id, %di
|
|
|
|
call print_pci_busdevfn
|
2009-02-16 04:53:25 +01:00
|
|
|
movb $( ' ' ), prodstr_separator
|
2014-08-21 17:34:26 +02:00
|
|
|
.endif
|
2008-08-22 04:01:46 +02:00
|
|
|
|
2008-07-30 20:57:46 +02:00
|
|
|
/* Print segment address */
|
2008-05-21 19:43:58 +02:00
|
|
|
xorw %di, %di
|
2014-08-21 17:34:26 +02:00
|
|
|
call print_space
|
2008-07-30 20:57:46 +02:00
|
|
|
movw %cs, %ax
|
|
|
|
call print_hex_word
|
2008-08-22 04:01:46 +02:00
|
|
|
|
2014-08-21 17:34:26 +02:00
|
|
|
/* Check for PCI BIOS version, if applicable */
|
|
|
|
.ifeqs BUSTYPE, "PCIR"
|
2008-08-22 04:01:46 +02:00
|
|
|
pushl %ebx
|
|
|
|
pushl %edx
|
2008-08-26 06:03:19 +02:00
|
|
|
pushl %edi
|
2008-08-22 04:01:46 +02:00
|
|
|
stc
|
|
|
|
movw $0xb101, %ax
|
|
|
|
int $0x1a
|
2008-10-29 02:10:33 +01:00
|
|
|
jc no_pci3
|
2008-08-22 04:01:46 +02:00
|
|
|
cmpl $PCI_SIGNATURE, %edx
|
2008-10-29 02:10:33 +01:00
|
|
|
jne no_pci3
|
2008-08-22 04:01:46 +02:00
|
|
|
testb %ah, %ah
|
2008-10-29 02:10:33 +01:00
|
|
|
jnz no_pci3
|
2008-08-22 04:01:46 +02:00
|
|
|
movw $init_message_pci, %si
|
|
|
|
xorw %di, %di
|
|
|
|
call print_message
|
|
|
|
movb %bh, %al
|
|
|
|
call print_hex_nibble
|
2009-02-16 04:53:25 +01:00
|
|
|
movb $( '.' ), %al
|
2008-08-22 04:01:46 +02:00
|
|
|
call print_character
|
|
|
|
movb %bl, %al
|
|
|
|
call print_hex_byte
|
|
|
|
cmpb $3, %bh
|
2008-10-29 02:10:33 +01:00
|
|
|
jb no_pci3
|
2008-10-17 19:12:24 +02:00
|
|
|
/* PCI >=3.0: leave %gs as-is if sane */
|
|
|
|
movw %gs, %ax
|
2008-10-29 02:10:33 +01:00
|
|
|
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 */
|
2009-02-16 04:53:25 +01:00
|
|
|
movb $( '!' ), %al
|
2008-10-17 19:12:24 +02:00
|
|
|
call print_character
|
|
|
|
movw %gs, %ax
|
|
|
|
call print_hex_word
|
2008-10-29 02:10:33 +01:00
|
|
|
no_pci3:
|
|
|
|
/* PCI <3.0: set %gs (runtime segment) = %cs (init-time segment) */
|
2008-08-22 04:01:46 +02:00
|
|
|
pushw %cs
|
|
|
|
popw %gs
|
2008-10-29 02:10:33 +01:00
|
|
|
1: popl %edi
|
2008-08-26 06:03:19 +02:00
|
|
|
popl %edx
|
2008-08-22 04:01:46 +02:00
|
|
|
popl %ebx
|
2014-08-21 17:34:26 +02:00
|
|
|
.endif /* PCIR */
|
2008-08-22 04:01:46 +02:00
|
|
|
|
2011-05-17 16:27:47 +02:00
|
|
|
/* Check for PnP BIOS. Although %es:di should point to the
|
2009-08-08 15:36:10 +02:00
|
|
|
* 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
|
2008-03-11 13:02:12 +01:00
|
|
|
/* Is PnP: print PnP message */
|
|
|
|
movw $init_message_pnp, %si
|
2008-07-30 20:57:46 +02:00
|
|
|
xorw %di, %di
|
2008-03-11 13:02:12 +01:00
|
|
|
call print_message
|
2010-06-24 20:03:04 +02:00
|
|
|
jmp pnp_done
|
|
|
|
no_pnp: /* Not PnP-compliant - hook INT 19 */
|
2011-05-17 16:35:23 +02:00
|
|
|
#ifdef NONPNP_HOOK_INT19
|
2008-03-11 13:02:12 +01:00
|
|
|
movw $init_message_int19, %si
|
2008-07-30 20:57:46 +02:00
|
|
|
xorw %di, %di
|
2008-03-11 13:02:12 +01:00
|
|
|
call print_message
|
2008-03-09 23:13:07 +01:00
|
|
|
xorw %ax, %ax
|
|
|
|
movw %ax, %es
|
2008-06-14 14:49:26 +02:00
|
|
|
pushl %es:( 0x19 * 4 )
|
|
|
|
popl orig_int19
|
2008-08-22 04:01:46 +02:00
|
|
|
pushw %gs /* %gs contains runtime %cs */
|
2008-03-09 23:13:07 +01:00
|
|
|
pushw $int19_entry
|
|
|
|
popl %es:( 0x19 * 4 )
|
2011-05-17 16:35:23 +02:00
|
|
|
#endif /* NONPNP_HOOK_INT19 */
|
2010-06-24 20:03:04 +02:00
|
|
|
pnp_done:
|
2008-08-22 04:01:46 +02:00
|
|
|
|
2008-03-09 23:13:07 +01:00
|
|
|
/* Check for PMM */
|
2008-06-29 00:18:11 +02:00
|
|
|
movw $( 0xe000 - 1 ), %bx
|
2008-03-09 23:13:07 +01:00
|
|
|
pmm_scan:
|
2008-05-21 19:43:58 +02:00
|
|
|
incw %bx
|
2008-03-11 13:02:12 +01:00
|
|
|
jz no_pmm
|
2008-05-21 19:43:58 +02:00
|
|
|
movw %bx, %es
|
2008-03-09 23:13:07 +01:00
|
|
|
cmpl $PMM_SIGNATURE, %es:0
|
|
|
|
jne pmm_scan
|
2008-05-21 19:43:58 +02:00
|
|
|
xorw %dx, %dx
|
2008-03-09 23:13:07 +01:00
|
|
|
xorw %si, %si
|
|
|
|
movzbw %es:5, %cx
|
|
|
|
1: es lodsb
|
2008-05-21 19:43:58 +02:00
|
|
|
addb %al, %dl
|
2008-03-09 23:13:07 +01:00
|
|
|
loop 1b
|
|
|
|
jnz pmm_scan
|
|
|
|
/* PMM found: print PMM message */
|
|
|
|
movw $init_message_pmm, %si
|
2008-07-30 20:57:46 +02:00
|
|
|
xorw %di, %di
|
2008-03-09 23:13:07 +01:00
|
|
|
call print_message
|
2010-04-24 23:34:28 +02:00
|
|
|
/* We have PMM and so a 1kB stack: preserve whole registers */
|
2008-11-11 21:00:13 +01:00
|
|
|
pushal
|
2012-07-25 15:32:37 +02:00
|
|
|
/* Allocate image source PMM block. Round up the size to the
|
|
|
|
* nearest 4kB (8 512-byte sectors) to work around AMI BIOS bugs.
|
|
|
|
*/
|
2012-06-10 19:25:26 +02:00
|
|
|
movzbl romheader_size, %ecx
|
|
|
|
addw extra_size, %cx
|
2012-07-25 15:32:37 +02:00
|
|
|
addw $0x0007, %cx /* Round up to multiple of 8 512-byte sectors */
|
|
|
|
andw $0xfff8, %cx
|
2011-03-15 02:52:58 +01:00
|
|
|
shll $5, %ecx
|
2010-04-24 23:34:28 +02:00
|
|
|
movl $PMM_HANDLE_BASE_IMAGE_SOURCE, %ebx
|
|
|
|
movw $get_pmm_image_source, %bp
|
|
|
|
call get_pmm
|
|
|
|
movl %esi, image_source
|
2012-06-19 19:54:22 +02:00
|
|
|
jz 1f
|
2010-04-24 23:34:28 +02:00
|
|
|
/* Copy ROM to image source PMM block */
|
|
|
|
pushw %es
|
2008-08-26 00:36:24 +02:00
|
|
|
xorw %ax, %ax
|
|
|
|
movw %ax, %es
|
2010-04-24 23:34:28 +02:00
|
|
|
movl %esi, %edi
|
2008-03-09 23:13:07 +01:00
|
|
|
xorl %esi, %esi
|
|
|
|
movzbl romheader_size, %ecx
|
2012-06-10 19:25:26 +02:00
|
|
|
shll $7, %ecx
|
|
|
|
addr32 rep movsl /* PMM presence implies flat real mode */
|
2010-04-24 23:34:28 +02:00
|
|
|
popw %es
|
2009-02-15 12:42:15 +01:00
|
|
|
/* Shrink ROM */
|
2012-07-23 18:41:38 +02:00
|
|
|
movb shrunk_rom_size, %al
|
2010-04-20 12:05:53 +02:00
|
|
|
movb %al, romheader_size
|
2016-02-18 03:58:03 +01:00
|
|
|
1: /* Allocate decompression PMM block. Allow 4kB for page
|
|
|
|
* alignment and round up the size to the nearest 128kB, then
|
|
|
|
* use the size within the PMM handle; this allows the same
|
|
|
|
* decompression area to be shared between multiple iPXE ROMs
|
|
|
|
* even with differing build IDs
|
2010-04-24 23:34:28 +02:00
|
|
|
*/
|
|
|
|
movl $_textdata_memsz_pgh, %ecx
|
2016-02-18 03:58:03 +01:00
|
|
|
addl $( 0x00000100 /* 4kB */ + 0x00001fff /* 128kB - 1 */ ), %ecx
|
|
|
|
andl $( 0xffffe000 /* ~( 128kB - 1 ) */ ), %ecx
|
2010-04-24 23:34:28 +02:00
|
|
|
movl %ecx, %ebx
|
|
|
|
shrw $12, %bx
|
|
|
|
orl $PMM_HANDLE_BASE_DECOMPRESS_TO, %ebx
|
|
|
|
movw $get_pmm_decompress_to, %bp
|
|
|
|
call get_pmm
|
2016-02-18 03:58:03 +01:00
|
|
|
addl $( 0x00000fff /* 4kB - 1 */ ), %esi
|
|
|
|
andl $( 0xfffff000 /* ~( 4kB - 1 ) */ ), %esi
|
2010-04-24 23:34:28 +02:00
|
|
|
movl %esi, decompress_to
|
|
|
|
/* Restore registers */
|
2009-02-15 12:42:15 +01:00
|
|
|
popal
|
|
|
|
no_pmm:
|
|
|
|
|
|
|
|
/* Update checksum */
|
2008-03-09 23:13:07 +01:00
|
|
|
xorw %bx, %bx
|
|
|
|
xorw %si, %si
|
2009-02-15 12:42:15 +01:00
|
|
|
movzbw romheader_size, %cx
|
2008-03-09 23:13:07 +01:00
|
|
|
shlw $9, %cx
|
|
|
|
1: lodsb
|
|
|
|
addb %al, %bl
|
|
|
|
loop 1b
|
|
|
|
subb %bl, checksum
|
2008-08-22 04:01:46 +02:00
|
|
|
|
2014-08-21 17:34:26 +02:00
|
|
|
/* Copy self to option ROM space, if applicable. Required for
|
|
|
|
* PCI3.0, which loads us to a temporary location in low
|
|
|
|
* memory. Will be a no-op for lower PCI versions.
|
2008-08-22 04:01:46 +02:00
|
|
|
*/
|
2014-08-21 17:34:26 +02:00
|
|
|
.ifeqs BUSTYPE, "PCIR"
|
2016-01-06 00:40:18 +01:00
|
|
|
/* Get runtime segment address and length */
|
|
|
|
movw %gs, %ax
|
|
|
|
movw %ax, %es
|
|
|
|
movzbw romheader_size, %cx
|
|
|
|
/* Print runtime segment address */
|
2008-07-30 20:57:46 +02:00
|
|
|
xorw %di, %di
|
2014-08-21 17:34:26 +02:00
|
|
|
call print_space
|
2008-07-30 20:57:46 +02:00
|
|
|
call print_hex_word
|
2016-01-06 00:40:18 +01:00
|
|
|
/* Fail if we have insufficient space in final location */
|
|
|
|
movw %cs, %si
|
|
|
|
cmpw %si, %ax
|
|
|
|
je 1f
|
|
|
|
cmpw pciheader_runtime_length, %cx
|
|
|
|
jbe 1f
|
|
|
|
movb $( '!' ), %al
|
|
|
|
call print_character
|
|
|
|
xorw %cx, %cx
|
|
|
|
1: /* Copy to final location */
|
2008-07-30 20:57:46 +02:00
|
|
|
shlw $9, %cx
|
2008-08-06 00:18:07 +02:00
|
|
|
xorw %si, %si
|
|
|
|
xorw %di, %di
|
|
|
|
cs rep movsb
|
2014-08-21 17:34:26 +02:00
|
|
|
.endif
|
2008-08-22 04:01:46 +02:00
|
|
|
|
2014-08-21 17:34:26 +02:00
|
|
|
/* Skip prompt if this is not the first PCI function, if applicable */
|
|
|
|
.ifeqs BUSTYPE, "PCIR"
|
2013-03-11 02:43:12 +01:00
|
|
|
testb $PCI_FUNC_MASK, init_pci_busdevfn
|
|
|
|
jnz no_shell
|
2014-08-21 17:34:26 +02:00
|
|
|
.endif
|
2008-07-30 20:57:46 +02:00
|
|
|
/* Prompt for POST-time shell */
|
2008-05-22 16:14:33 +02:00
|
|
|
movw $init_message_prompt, %si
|
2008-07-30 20:57:46 +02:00
|
|
|
xorw %di, %di
|
2008-05-22 16:14:33 +02:00
|
|
|
call print_message
|
2008-10-31 20:10:28 +01:00
|
|
|
movw $prodstr, %si
|
|
|
|
call print_message
|
|
|
|
movw $init_message_dots, %si
|
|
|
|
call print_message
|
2008-09-24 01:53:40 +02:00
|
|
|
/* Wait for Ctrl-B */
|
|
|
|
movw $0xff02, %bx
|
|
|
|
call wait_for_key
|
2008-09-25 02:53:42 +02:00
|
|
|
/* Clear prompt */
|
|
|
|
pushf
|
|
|
|
xorw %di, %di
|
2008-10-31 20:10:28 +01:00
|
|
|
call print_kill_line
|
|
|
|
movw $init_message_done, %si
|
2008-09-25 02:53:42 +02:00
|
|
|
call print_message
|
|
|
|
popf
|
2013-03-11 02:43:12 +01:00
|
|
|
jnz no_shell
|
2010-04-19 21:16:01 +02:00
|
|
|
/* Ctrl-B was pressed: invoke iPXE. The keypress will be
|
2008-09-24 01:53:40 +02:00
|
|
|
* picked up by the initial shell prompt, and we will drop
|
|
|
|
* into a shell.
|
2008-05-22 16:14:33 +02:00
|
|
|
*/
|
[pcbios] Inhibit all calls to INT 15,e820 and INT 15,e801 during POST
Many BIOSes do not construct the full system memory map until after
calling the option ROM initialisation entry points. For several
years, we have added sanity checks and workarounds to accommodate
charming quirks such as BIOSes which report the entire 32-bit address
space (including all memory-mapped PCI BARs) as being usable RAM.
The IBM x3650 takes quirky behaviour to a new extreme. Calling either
INT 15,e820 or INT 15,e801 during POST doesn't just get you invalid
data. We could cope with invalid data. Instead, these nominally
read-only API calls manage to trash some internal BIOS state, with the
result that the system memory map is _never_ constructed. This tends
to confuse subsequent bootloaders and operating systems.
[ GRUB 0.97 fails in a particularly amusing way. Someone thought it
would be a good idea for memcpy() to check that the destination memory
region is a valid part of the system memory map; if not, then memcpy()
will sulk, fail, and return NULL. This breaks pretty much every use
of memcpy() including, for example, those inserted implicitly by gcc
to copy non-const initialisers. Debugging is _fun_ when a simple call
to printf() manages to create an infinite recursion, exhaust the
available stack space, and shut down the CPU. ]
Fix by completely inhibiting calls to INT 15,e820 and INT 15,e801
during POST.
We do now allow relocation during POST up to the maximum address
returned by INT 15,88 (which seems so far to always be safe). This
allows us to continue to have a reasonable size of external heap, even
if the PMM allocation is close to the 1MB mark.
The downside of allowing relocation during POST is that we may
overwrite PMM-allocated memory in use by other option ROMs. However,
the downside of inhibiting relocation, when combined with also
inhibiting calls to INT 15,e820 and INT 15,e801, would be that we
might have no external heap available: this would make booting an OS
impossible and could prevent some devices from even completing
initialisation.
On balance, the lesser evil is probably to allow relocation during
POST (up to the limit provided by INT 15,88). Entering iPXE during
POST is a rare operation; on the even rarer systems where doing so
happens to overwrite a PMM-allocated region, then there exists a
fairly simple workaround: if the user enters iPXE during POST and
wishes to exit iPXE, then the user must reboot. This is an acceptable
cost, given the rarity of the situation and the simplicity of the
workaround.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2013-03-11 01:50:52 +01:00
|
|
|
xorl %ebp, %ebp /* Inhibit use of INT 15,e820 and INT 15,e801 */
|
2008-05-22 16:14:33 +02:00
|
|
|
pushw %cs
|
|
|
|
call exec
|
2013-03-11 02:43:12 +01:00
|
|
|
no_shell:
|
|
|
|
movb $( '\n' ), %al
|
|
|
|
xorw %di, %di
|
|
|
|
call print_character
|
|
|
|
|
2008-03-09 23:13:07 +01:00
|
|
|
/* Restore registers */
|
2008-07-30 20:57:46 +02:00
|
|
|
popw %gs
|
2008-05-22 16:14:33 +02:00
|
|
|
popw %fs
|
2008-03-09 23:13:07 +01:00
|
|
|
popw %es
|
|
|
|
popw %ds
|
|
|
|
popaw
|
2008-08-22 04:01:46 +02:00
|
|
|
|
2008-03-09 23:13:07 +01:00
|
|
|
/* Indicate boot capability to PnP BIOS, if present */
|
2006-06-06 17:33:39 +02:00
|
|
|
movw $0x20, %ax
|
2005-03-08 19:53:11 +01:00
|
|
|
lret
|
2008-03-09 23:13:07 +01:00
|
|
|
.size init, . - init
|
|
|
|
|
2010-04-24 23:34:28 +02:00
|
|
|
/* Attempt to find or allocate PMM block
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* %ecx : size of block to allocate, in paragraphs
|
|
|
|
* %ebx : PMM handle base
|
|
|
|
* %bp : routine to check acceptability of found blocks
|
|
|
|
* %es:0000 : PMM structure
|
|
|
|
* Returns:
|
|
|
|
* %ebx : PMM handle
|
2012-06-19 19:54:22 +02:00
|
|
|
* %esi : allocated block address, or zero (with ZF set) if allocation failed
|
2010-04-24 23:34:28 +02:00
|
|
|
*/
|
|
|
|
get_pmm:
|
|
|
|
/* Preserve registers */
|
|
|
|
pushl %eax
|
|
|
|
pushw %di
|
2011-08-06 21:40:04 +02:00
|
|
|
movw $( ' ' ), %di
|
2010-04-24 23:34:28 +02:00
|
|
|
get_pmm_find:
|
|
|
|
/* Try to find existing block */
|
|
|
|
pushl %ebx /* PMM handle */
|
|
|
|
pushw $PMM_FIND
|
|
|
|
lcall *%es:7
|
|
|
|
addw $6, %sp
|
|
|
|
pushw %dx
|
|
|
|
pushw %ax
|
|
|
|
popl %esi
|
2012-06-19 19:54:22 +02:00
|
|
|
/* Treat 0xffffffff (not supported) as 0x00000000 (not found) */
|
|
|
|
incl %esi
|
|
|
|
jz get_pmm_allocate
|
|
|
|
decl %esi
|
2010-04-24 23:34:28 +02:00
|
|
|
jz get_pmm_allocate
|
|
|
|
/* Block found - check acceptability */
|
|
|
|
call *%bp
|
|
|
|
jnc get_pmm_done
|
|
|
|
/* Block not acceptable - increment handle and retry */
|
|
|
|
incl %ebx
|
|
|
|
jmp get_pmm_find
|
|
|
|
get_pmm_allocate:
|
|
|
|
/* Block not found - try to allocate new block */
|
|
|
|
pushw $0x0002 /* Extended memory */
|
|
|
|
pushl %ebx /* PMM handle */
|
|
|
|
pushl %ecx /* Length */
|
|
|
|
pushw $PMM_ALLOCATE
|
|
|
|
lcall *%es:7
|
|
|
|
addw $12, %sp
|
|
|
|
pushw %dx
|
|
|
|
pushw %ax
|
|
|
|
popl %esi
|
2011-08-06 21:40:04 +02:00
|
|
|
movw $( '+' ), %di /* Indicate allocation attempt */
|
2010-04-24 23:34:28 +02:00
|
|
|
get_pmm_done:
|
|
|
|
/* Print block address */
|
|
|
|
movw %di, %ax
|
|
|
|
xorw %di, %di
|
|
|
|
call print_character
|
|
|
|
movl %esi, %eax
|
|
|
|
call print_hex_dword
|
2012-06-19 19:54:22 +02:00
|
|
|
/* Treat 0xffffffff (not supported) as 0x00000000 (allocation
|
|
|
|
* failed), and set ZF to indicate a zero result.
|
|
|
|
*/
|
|
|
|
incl %esi
|
|
|
|
jz 1f
|
|
|
|
decl %esi
|
|
|
|
1: /* Restore registers and return */
|
2010-04-24 23:34:28 +02:00
|
|
|
popw %di
|
|
|
|
popl %eax
|
|
|
|
ret
|
|
|
|
.size get_pmm, . - get_pmm
|
|
|
|
|
|
|
|
/* Check acceptability of image source block */
|
|
|
|
get_pmm_image_source:
|
|
|
|
pushw %es
|
|
|
|
xorw %ax, %ax
|
|
|
|
movw %ax, %es
|
|
|
|
movl build_id, %eax
|
2010-10-29 02:45:21 +02:00
|
|
|
addr32 cmpl %es:build_id(%esi), %eax
|
2010-04-24 23:34:28 +02:00
|
|
|
je 1f
|
|
|
|
stc
|
|
|
|
1: popw %es
|
|
|
|
ret
|
|
|
|
.size get_pmm_image_source, . - get_pmm_image_source
|
|
|
|
|
|
|
|
/* Check acceptability of decompression block */
|
|
|
|
get_pmm_decompress_to:
|
|
|
|
clc
|
|
|
|
ret
|
|
|
|
.size get_pmm_decompress_to, . - get_pmm_decompress_to
|
|
|
|
|
2008-10-31 20:10:28 +01:00
|
|
|
/*
|
|
|
|
* Note to hardware vendors:
|
|
|
|
*
|
|
|
|
* If you wish to brand this boot ROM, please do so by defining the
|
2015-02-11 13:51:58 +01:00
|
|
|
* strings PRODUCT_NAME and PRODUCT_SHORT_NAME in config/branding.h.
|
2008-10-31 20:10:28 +01:00
|
|
|
*
|
|
|
|
* While nothing in the GPL prevents you from removing all references
|
2010-04-19 21:16:01 +02:00
|
|
|
* to iPXE or http://ipxe.org, we prefer you not to do so.
|
2008-10-31 20:10:28 +01:00
|
|
|
*
|
|
|
|
* 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! ]
|
|
|
|
*/
|
2008-03-09 23:13:07 +01:00
|
|
|
init_message:
|
2008-10-31 20:10:28 +01:00
|
|
|
.ascii "\n"
|
|
|
|
.ascii PRODUCT_NAME
|
|
|
|
.ascii "\n"
|
2015-02-11 14:02:52 +01:00
|
|
|
.ascii PRODUCT_SHORT_NAME
|
2015-02-11 14:08:36 +01:00
|
|
|
.ascii " ("
|
|
|
|
.ascii PRODUCT_URI
|
|
|
|
.asciz ")"
|
2008-03-09 23:13:07 +01:00
|
|
|
.size init_message, . - init_message
|
2014-08-21 17:34:26 +02:00
|
|
|
.ifeqs BUSTYPE, "PCIR"
|
2008-07-30 20:57:46 +02:00
|
|
|
init_message_pci:
|
|
|
|
.asciz " PCI"
|
|
|
|
.size init_message_pci, . - init_message_pci
|
2014-08-21 17:34:26 +02:00
|
|
|
.endif /* PCIR */
|
2008-03-09 23:13:07 +01:00
|
|
|
init_message_pnp:
|
2008-03-11 13:02:12 +01:00
|
|
|
.asciz " PnP"
|
2008-05-22 16:14:33 +02:00
|
|
|
.size init_message_pnp, . - init_message_pnp
|
2008-03-09 23:13:07 +01:00
|
|
|
init_message_pmm:
|
2008-03-11 13:02:12 +01:00
|
|
|
.asciz " PMM"
|
2008-05-22 16:14:33 +02:00
|
|
|
.size init_message_pmm, . - init_message_pmm
|
2008-03-11 13:02:12 +01:00
|
|
|
init_message_int19:
|
|
|
|
.asciz " INT19"
|
2008-05-22 16:14:33 +02:00
|
|
|
.size init_message_int19, . - init_message_int19
|
|
|
|
init_message_prompt:
|
2008-10-31 20:10:28 +01:00
|
|
|
.asciz "\nPress Ctrl-B to configure "
|
2008-05-22 16:14:33 +02:00
|
|
|
.size init_message_prompt, . - init_message_prompt
|
2008-10-31 20:10:28 +01:00
|
|
|
init_message_dots:
|
|
|
|
.asciz "..."
|
|
|
|
.size init_message_dots, . - init_message_dots
|
|
|
|
init_message_done:
|
|
|
|
.asciz "\n\n"
|
|
|
|
.size init_message_done, . - init_message_done
|
2008-03-09 23:13:07 +01:00
|
|
|
|
2010-04-25 16:57:00 +02:00
|
|
|
/* PCI bus:dev.fn
|
|
|
|
*
|
|
|
|
*/
|
2014-08-21 17:34:26 +02:00
|
|
|
.ifeqs BUSTYPE, "PCIR"
|
2010-04-25 16:57:00 +02:00
|
|
|
init_pci_busdevfn:
|
2013-03-11 02:43:12 +01:00
|
|
|
.word 0
|
2010-04-25 16:57:00 +02:00
|
|
|
.size init_pci_busdevfn, . - init_pci_busdevfn
|
2014-08-21 17:34:26 +02:00
|
|
|
.endif /* PCIR */
|
2010-04-25 16:57:00 +02:00
|
|
|
|
2010-04-24 23:22:54 +02:00
|
|
|
/* Image source area
|
2008-03-09 23:13:07 +01:00
|
|
|
*
|
2010-04-24 23:22:54 +02:00
|
|
|
* May be either zero (indicating to use option ROM space as source),
|
|
|
|
* or within a PMM-allocated block.
|
2008-03-09 23:13:07 +01:00
|
|
|
*/
|
2009-10-07 01:15:06 +02:00
|
|
|
.globl image_source
|
2008-03-09 23:13:07 +01:00
|
|
|
image_source:
|
|
|
|
.long 0
|
|
|
|
.size image_source, . - image_source
|
2008-03-11 13:02:12 +01:00
|
|
|
|
2012-06-10 19:25:26 +02:00
|
|
|
/* Additional image source size (in 512-byte sectors)
|
2010-04-25 16:57:00 +02:00
|
|
|
*
|
|
|
|
*/
|
2012-06-10 19:25:26 +02:00
|
|
|
extra_size:
|
2010-04-25 16:57:00 +02:00
|
|
|
.word 0
|
2012-06-10 19:25:26 +02:00
|
|
|
.size extra_size, . - extra_size
|
2010-04-20 12:05:53 +02:00
|
|
|
|
2008-03-09 23:13:07 +01:00
|
|
|
/* Temporary decompression area
|
|
|
|
*
|
2010-04-24 23:22:54 +02:00
|
|
|
* May be either zero (indicating to use default decompression area in
|
|
|
|
* high memory), or within a PMM-allocated block.
|
2008-03-09 23:13:07 +01:00
|
|
|
*/
|
2009-10-07 01:15:06 +02:00
|
|
|
.globl decompress_to
|
2008-03-09 23:13:07 +01:00
|
|
|
decompress_to:
|
2010-04-24 23:22:54 +02:00
|
|
|
.long 0
|
2008-03-09 23:13:07 +01:00
|
|
|
.size decompress_to, . - decompress_to
|
|
|
|
|
|
|
|
/* Boot Execution Vector entry point
|
|
|
|
*
|
|
|
|
* Called by the PnP BIOS when it wants to boot us.
|
|
|
|
*/
|
|
|
|
bev_entry:
|
[pcbios] Inhibit all calls to INT 15,e820 and INT 15,e801 during POST
Many BIOSes do not construct the full system memory map until after
calling the option ROM initialisation entry points. For several
years, we have added sanity checks and workarounds to accommodate
charming quirks such as BIOSes which report the entire 32-bit address
space (including all memory-mapped PCI BARs) as being usable RAM.
The IBM x3650 takes quirky behaviour to a new extreme. Calling either
INT 15,e820 or INT 15,e801 during POST doesn't just get you invalid
data. We could cope with invalid data. Instead, these nominally
read-only API calls manage to trash some internal BIOS state, with the
result that the system memory map is _never_ constructed. This tends
to confuse subsequent bootloaders and operating systems.
[ GRUB 0.97 fails in a particularly amusing way. Someone thought it
would be a good idea for memcpy() to check that the destination memory
region is a valid part of the system memory map; if not, then memcpy()
will sulk, fail, and return NULL. This breaks pretty much every use
of memcpy() including, for example, those inserted implicitly by gcc
to copy non-const initialisers. Debugging is _fun_ when a simple call
to printf() manages to create an infinite recursion, exhaust the
available stack space, and shut down the CPU. ]
Fix by completely inhibiting calls to INT 15,e820 and INT 15,e801
during POST.
We do now allow relocation during POST up to the maximum address
returned by INT 15,88 (which seems so far to always be safe). This
allows us to continue to have a reasonable size of external heap, even
if the PMM allocation is close to the 1MB mark.
The downside of allowing relocation during POST is that we may
overwrite PMM-allocated memory in use by other option ROMs. However,
the downside of inhibiting relocation, when combined with also
inhibiting calls to INT 15,e820 and INT 15,e801, would be that we
might have no external heap available: this would make booting an OS
impossible and could prevent some devices from even completing
initialisation.
On balance, the lesser evil is probably to allow relocation during
POST (up to the limit provided by INT 15,88). Entering iPXE during
POST is a rare operation; on the even rarer systems where doing so
happens to overwrite a PMM-allocated region, then there exists a
fairly simple workaround: if the user enters iPXE during POST and
wishes to exit iPXE, then the user must reboot. This is an acceptable
cost, given the rarity of the situation and the simplicity of the
workaround.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2013-03-11 01:50:52 +01:00
|
|
|
orl $0xffffffff, %ebp /* Allow arbitrary relocation */
|
2008-03-09 23:13:07 +01:00
|
|
|
pushw %cs
|
|
|
|
call exec
|
|
|
|
lret
|
|
|
|
.size bev_entry, . - bev_entry
|
|
|
|
|
|
|
|
/* INT19 entry point
|
|
|
|
*
|
2008-06-14 14:49:26 +02:00
|
|
|
* Called via the hooked INT 19 if we detected a non-PnP BIOS. We
|
2008-09-24 01:53:40 +02:00
|
|
|
* attempt to return via the original INT 19 vector (if we were able
|
|
|
|
* to store it).
|
2008-03-09 23:13:07 +01:00
|
|
|
*/
|
|
|
|
int19_entry:
|
|
|
|
pushw %cs
|
2008-09-24 01:53:40 +02:00
|
|
|
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
|
2008-12-04 17:46:16 +01:00
|
|
|
movw $0xdf4e, %bx
|
2008-09-24 01:53:40 +02:00
|
|
|
call wait_for_key
|
2008-09-25 02:53:42 +02:00
|
|
|
pushf
|
|
|
|
xorw %di, %di
|
2008-10-31 20:10:28 +01:00
|
|
|
call print_kill_line
|
|
|
|
movw $int19_message_done, %si
|
2008-09-25 02:53:42 +02:00
|
|
|
call print_message
|
|
|
|
popf
|
2008-12-04 17:46:16 +01:00
|
|
|
jz 1f
|
2010-04-19 21:16:01 +02:00
|
|
|
/* Leave keypress in buffer and start iPXE. The keypress will
|
2008-09-24 01:53:40 +02:00
|
|
|
* cause the usual initial Ctrl-B prompt to be skipped.
|
|
|
|
*/
|
[pcbios] Inhibit all calls to INT 15,e820 and INT 15,e801 during POST
Many BIOSes do not construct the full system memory map until after
calling the option ROM initialisation entry points. For several
years, we have added sanity checks and workarounds to accommodate
charming quirks such as BIOSes which report the entire 32-bit address
space (including all memory-mapped PCI BARs) as being usable RAM.
The IBM x3650 takes quirky behaviour to a new extreme. Calling either
INT 15,e820 or INT 15,e801 during POST doesn't just get you invalid
data. We could cope with invalid data. Instead, these nominally
read-only API calls manage to trash some internal BIOS state, with the
result that the system memory map is _never_ constructed. This tends
to confuse subsequent bootloaders and operating systems.
[ GRUB 0.97 fails in a particularly amusing way. Someone thought it
would be a good idea for memcpy() to check that the destination memory
region is a valid part of the system memory map; if not, then memcpy()
will sulk, fail, and return NULL. This breaks pretty much every use
of memcpy() including, for example, those inserted implicitly by gcc
to copy non-const initialisers. Debugging is _fun_ when a simple call
to printf() manages to create an infinite recursion, exhaust the
available stack space, and shut down the CPU. ]
Fix by completely inhibiting calls to INT 15,e820 and INT 15,e801
during POST.
We do now allow relocation during POST up to the maximum address
returned by INT 15,88 (which seems so far to always be safe). This
allows us to continue to have a reasonable size of external heap, even
if the PMM allocation is close to the 1MB mark.
The downside of allowing relocation during POST is that we may
overwrite PMM-allocated memory in use by other option ROMs. However,
the downside of inhibiting relocation, when combined with also
inhibiting calls to INT 15,e820 and INT 15,e801, would be that we
might have no external heap available: this would make booting an OS
impossible and could prevent some devices from even completing
initialisation.
On balance, the lesser evil is probably to allow relocation during
POST (up to the limit provided by INT 15,88). Entering iPXE during
POST is a rare operation; on the even rarer systems where doing so
happens to overwrite a PMM-allocated region, then there exists a
fairly simple workaround: if the user enters iPXE during POST and
wishes to exit iPXE, then the user must reboot. This is an acceptable
cost, given the rarity of the situation and the simplicity of the
workaround.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2013-03-11 01:50:52 +01:00
|
|
|
orl $0xffffffff, %ebp /* Allow arbitrary relocation */
|
2008-09-24 01:53:40 +02:00
|
|
|
pushw %cs
|
2008-03-09 23:13:07 +01:00
|
|
|
call exec
|
2008-09-25 02:53:42 +02:00
|
|
|
1: /* Try to call original INT 19 vector */
|
2008-06-14 14:49:26 +02:00
|
|
|
movl %cs:orig_int19, %eax
|
|
|
|
testl %eax, %eax
|
2008-09-24 01:53:40 +02:00
|
|
|
je 2f
|
2008-06-14 14:49:26 +02:00
|
|
|
ljmp *%cs:orig_int19
|
2008-09-24 01:53:40 +02:00
|
|
|
2: /* No chained vector: issue INT 18 as a last resort */
|
2008-03-09 23:13:07 +01:00
|
|
|
int $0x18
|
|
|
|
.size int19_entry, . - int19_entry
|
2008-06-14 14:49:26 +02:00
|
|
|
orig_int19:
|
|
|
|
.long 0
|
|
|
|
.size orig_int19, . - orig_int19
|
2008-03-09 23:13:07 +01:00
|
|
|
|
2008-09-24 01:53:40 +02:00
|
|
|
int19_message_prompt:
|
2008-12-04 17:46:16 +01:00
|
|
|
.asciz "Press N to skip booting from "
|
2008-09-24 01:53:40 +02:00
|
|
|
.size int19_message_prompt, . - int19_message_prompt
|
|
|
|
int19_message_dots:
|
|
|
|
.asciz "..."
|
|
|
|
.size int19_message_dots, . - int19_message_dots
|
2008-10-31 20:10:28 +01:00
|
|
|
int19_message_done:
|
|
|
|
.asciz "\n\n"
|
|
|
|
.size int19_message_done, . - int19_message_done
|
2008-09-24 01:53:40 +02:00
|
|
|
|
2008-03-09 23:13:07 +01:00
|
|
|
/* Execute as a boot device
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
exec: /* Set %ds = %cs */
|
|
|
|
pushw %cs
|
|
|
|
popw %ds
|
|
|
|
|
|
|
|
/* Print message as soon as possible */
|
2008-08-26 00:36:24 +02:00
|
|
|
movw $prodstr, %si
|
2008-05-21 19:43:58 +02:00
|
|
|
xorw %di, %di
|
2008-03-09 23:13:07 +01:00
|
|
|
call print_message
|
2010-04-21 14:35:31 +02:00
|
|
|
movw $exec_message_pre_install, %si
|
2008-08-26 00:36:24 +02:00
|
|
|
call print_message
|
2008-03-09 23:13:07 +01:00
|
|
|
|
|
|
|
/* Store magic word on BIOS stack and remember BIOS %ss:sp */
|
|
|
|
pushl $STACK_MAGIC
|
2011-11-12 00:20:28 +01:00
|
|
|
movw %ss, %cx
|
|
|
|
movw %sp, %dx
|
2008-03-09 23:13:07 +01:00
|
|
|
|
|
|
|
/* Obtain a reasonably-sized temporary stack */
|
2010-04-25 02:37:25 +02:00
|
|
|
xorw %bx, %bx
|
|
|
|
movw %bx, %ss
|
2006-06-06 17:33:39 +02:00
|
|
|
movw $0x7c00, %sp
|
2005-03-08 19:53:11 +01:00
|
|
|
|
2010-04-19 21:16:01 +02:00
|
|
|
/* Install iPXE */
|
2010-04-25 02:37:25 +02:00
|
|
|
call alloc_basemem
|
2008-03-09 23:13:07 +01:00
|
|
|
movl image_source, %esi
|
|
|
|
movl decompress_to, %edi
|
|
|
|
call install_prealloc
|
2005-03-08 19:53:11 +01:00
|
|
|
|
2010-04-21 14:35:31 +02:00
|
|
|
/* Print message indicating successful installation */
|
|
|
|
movw $exec_message_post_install, %si
|
|
|
|
xorw %di, %di
|
|
|
|
call print_message
|
|
|
|
|
2007-06-28 22:56:14 +02:00
|
|
|
/* Set up real-mode stack */
|
|
|
|
movw %bx, %ss
|
|
|
|
movw $_estack16, %sp
|
|
|
|
|
2006-06-06 17:33:39 +02:00
|
|
|
/* Jump to .text16 segment */
|
2005-03-08 19:53:11 +01:00
|
|
|
pushw %ax
|
2006-06-06 17:33:39 +02:00
|
|
|
pushw $1f
|
|
|
|
lret
|
|
|
|
.section ".text16", "awx", @progbits
|
2014-02-26 00:00:44 +01:00
|
|
|
1:
|
2014-08-21 17:34:26 +02:00
|
|
|
/* Retrieve PCI bus:dev.fn, if applicable */
|
|
|
|
.ifeqs BUSTYPE, "PCIR"
|
2014-03-05 13:25:21 +01:00
|
|
|
movw init_pci_busdevfn, %ax
|
2014-08-21 17:34:26 +02:00
|
|
|
.endif
|
2014-02-26 00:00:44 +01:00
|
|
|
|
|
|
|
/* Set up %ds for access to .data16 */
|
|
|
|
movw %bx, %ds
|
|
|
|
|
2014-08-21 17:34:26 +02:00
|
|
|
/* Store PCI bus:dev.fn, if applicable */
|
|
|
|
.ifeqs BUSTYPE, "PCIR"
|
2015-04-13 15:49:02 +02:00
|
|
|
#ifdef AUTOBOOT_ROM_FILTER
|
2014-03-05 13:25:21 +01:00
|
|
|
movw %ax, autoboot_busdevfn
|
2015-04-13 15:49:02 +02:00
|
|
|
#endif /* AUTOBOOT_ROM_FILTER */
|
2014-08-21 17:34:26 +02:00
|
|
|
.endif
|
2014-02-26 00:00:44 +01:00
|
|
|
|
2016-02-19 00:23:38 +01:00
|
|
|
/* Run iPXE */
|
|
|
|
virtcall main
|
2008-11-18 20:43:13 +01:00
|
|
|
|
2014-04-28 02:21:08 +02:00
|
|
|
/* Set up flat real mode for return to BIOS */
|
|
|
|
call flatten_real_mode
|
|
|
|
|
2010-04-19 21:16:01 +02:00
|
|
|
/* Uninstall iPXE */
|
2008-11-18 20:43:13 +01:00
|
|
|
call uninstall
|
|
|
|
|
2008-03-09 23:13:07 +01:00
|
|
|
/* Restore BIOS stack */
|
2011-11-12 00:20:28 +01:00
|
|
|
movw %cx, %ss
|
|
|
|
movw %dx, %sp
|
2005-03-08 19:53:11 +01:00
|
|
|
|
2008-03-09 23:13:07 +01:00
|
|
|
/* 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 */
|
2006-06-06 17:33:39 +02:00
|
|
|
int $0x18
|
2005-03-08 19:53:11 +01:00
|
|
|
.previous
|
|
|
|
|
2010-04-21 14:35:31 +02:00
|
|
|
exec_message_pre_install:
|
|
|
|
.asciz " starting execution..."
|
|
|
|
.size exec_message_pre_install, . - exec_message_pre_install
|
|
|
|
exec_message_post_install:
|
|
|
|
.asciz "ok\n"
|
|
|
|
.size exec_message_post_install, . - exec_message_post_install
|
2005-03-08 19:53:11 +01:00
|
|
|
|
2008-09-24 01:53:40 +02:00
|
|
|
/* 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
|
2008-09-25 02:53:42 +02:00
|
|
|
2: /* Wait for a key press */
|
2014-02-26 00:33:08 +01:00
|
|
|
movw $ROM_BANNER_TIMEOUT_TICKS, %cx
|
2008-09-24 01:53:40 +02:00
|
|
|
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
|
2015-03-04 18:22:07 +01:00
|
|
|
|
2015-03-04 19:48:19 +01:00
|
|
|
/* Drag in objects via _rom_start */
|
|
|
|
REQUIRING_SYMBOL ( _rom_start )
|
|
|
|
|
2015-03-04 18:22:07 +01:00
|
|
|
/* Drag in ROM configuration */
|
|
|
|
REQUIRE_OBJECT ( config_romprefix )
|