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.
|
|
|
|
*/
|
|
|
|
|
2009-05-18 10:33:36 +02:00
|
|
|
FILE_LICENCE ( GPL2_OR_LATER )
|
|
|
|
|
2008-09-25 02:53:42 +02:00
|
|
|
#include <config/general.h>
|
|
|
|
|
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-03-11 13:02:12 +01:00
|
|
|
#define PNP_GET_BBS_VERSION 0x60
|
2008-08-26 00:36:24 +02:00
|
|
|
#define PMM_ALLOCATE 0x0000
|
2008-11-11 21:00:13 +01:00
|
|
|
#define PMM_DEALLOCATE 0x0002
|
2008-03-09 23:13:07 +01:00
|
|
|
|
2008-09-25 02:53:42 +02:00
|
|
|
/* 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 )
|
|
|
|
|
[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
|
|
|
/* 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
|
|
|
|
|
|
|
|
|
2005-03-08 19:53:11 +01:00
|
|
|
.text
|
|
|
|
.code16
|
|
|
|
.arch i386
|
|
|
|
.section ".prefix", "ax", @progbits
|
|
|
|
|
2006-06-06 17:33:39 +02:00
|
|
|
.org 0x00
|
|
|
|
romheader:
|
|
|
|
.word 0xAA55 /* BIOS extension signature */
|
[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
|
|
|
romheader_size: .byte ROM_SIZE_VALUE /* Size in 512-byte blocks */
|
2008-03-09 23:13:07 +01:00
|
|
|
jmp init /* Initialisation vector */
|
|
|
|
checksum:
|
[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
|
|
|
.byte 0, 0
|
|
|
|
real_size:
|
|
|
|
.word 0
|
2005-03-08 19:53:11 +01:00
|
|
|
.org 0x16
|
2006-06-06 17:33:39 +02:00
|
|
|
.word undiheader
|
2005-03-08 19:53:11 +01:00
|
|
|
.org 0x18
|
2006-06-06 17:33:39 +02:00
|
|
|
.word pciheader
|
|
|
|
.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 */
|
[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
|
|
|
#ifndef LOAD_ROM_FROM_PCI
|
2009-08-10 07:12:21 +02:00
|
|
|
.ascii "ADDB"
|
2007-07-16 18:17:26 +02:00
|
|
|
.long romheader_size
|
|
|
|
.long 512
|
|
|
|
.long 0
|
[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
|
|
|
#endif
|
|
|
|
.ascii "ADDB"
|
|
|
|
.long real_size
|
|
|
|
.long 512
|
|
|
|
.long 0
|
2007-07-16 18:17:26 +02:00
|
|
|
.previous
|
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 */
|
|
|
|
.word 0x0000 /* 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:
|
[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
|
|
|
.word ROM_SIZE_VALUE /* Image length */
|
2008-07-30 20:57:46 +02:00
|
|
|
.word 0x0001 /* Revision level */
|
|
|
|
.byte 0x00 /* Code type */
|
|
|
|
.byte 0x80 /* Last image indicator */
|
|
|
|
pciheader_runtime_length:
|
[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
|
|
|
.word ROM_SIZE_VALUE /* 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
|
|
|
|
|
|
|
#ifndef LOAD_ROM_FROM_PCI
|
2008-10-17 02:39:48 +02:00
|
|
|
.section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
|
2009-08-10 07:12:21 +02:00
|
|
|
.ascii "ADDW"
|
2008-07-30 20:57:46 +02:00
|
|
|
.long pciheader_image_length
|
|
|
|
.long 512
|
|
|
|
.long 0
|
2009-08-10 07:12:21 +02:00
|
|
|
.ascii "ADDW"
|
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
|
[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
|
|
|
#endif
|
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:
|
|
|
|
.asciz "http://etherboot.org"
|
|
|
|
.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
|
2008-05-21 19:43:58 +02:00
|
|
|
prodstr_separator:
|
|
|
|
.byte 0
|
|
|
|
.ascii "(PCI "
|
|
|
|
prodstr_pci_id:
|
|
|
|
.asciz "xx:xx.x)" /* Filled in by init code */
|
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
|
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 */
|
2008-08-27 23:08:57 +02:00
|
|
|
.ascii "PCIR" /* Bus type */
|
2006-06-06 17:33:39 +02:00
|
|
|
.equ undiheader_len, . - undiheader
|
|
|
|
.size undiheader, . - undiheader
|
|
|
|
|
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-07-30 20:57:46 +02:00
|
|
|
/* 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
|
2008-05-21 19:43:58 +02:00
|
|
|
movw %di, %bx
|
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-05-21 19:43:58 +02:00
|
|
|
call print_pci_busdevfn
|
2008-08-22 04:01:46 +02:00
|
|
|
|
[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
|
|
|
#ifdef LOAD_ROM_FROM_PCI
|
|
|
|
/* Save PCI bus:dev.fn for later use */
|
|
|
|
movw %ax, pci_busdevfn
|
|
|
|
#endif
|
|
|
|
|
2008-05-21 19:43:58 +02:00
|
|
|
/* Fill in product name string, if possible */
|
|
|
|
movw $prodstr_pci_id, %di
|
|
|
|
call print_pci_busdevfn
|
2009-02-16 04:53:25 +01:00
|
|
|
movb $( ' ' ), prodstr_separator
|
2008-08-22 04:01:46 +02:00
|
|
|
|
2008-07-30 20:57:46 +02:00
|
|
|
/* Print segment address */
|
2009-02-16 04:53:25 +01:00
|
|
|
movb $( ' ' ), %al
|
2008-05-21 19:43:58 +02:00
|
|
|
xorw %di, %di
|
2008-07-30 20:57:46 +02:00
|
|
|
call print_character
|
|
|
|
movw %cs, %ax
|
|
|
|
call print_hex_word
|
2008-08-22 04:01:46 +02:00
|
|
|
|
|
|
|
/* Check for PCI BIOS version */
|
|
|
|
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
|
[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
|
|
|
#ifdef LOAD_ROM_FROM_PCI
|
|
|
|
incb pcibios_present
|
|
|
|
#endif
|
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
|
|
|
|
|
2009-08-08 15:36:10 +02:00
|
|
|
/* 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
|
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
|
|
|
|
/* Check for BBS */
|
2009-08-08 15:36:10 +02:00
|
|
|
pushw %es:0x1b /* Real-mode data segment */
|
2008-03-11 13:02:12 +01:00
|
|
|
pushw %ds /* &(bbs_version) */
|
|
|
|
pushw $bbs_version
|
|
|
|
pushw $PNP_GET_BBS_VERSION
|
2009-08-08 15:36:10 +02:00
|
|
|
lcall *%es:0xd
|
2008-03-11 17:08:04 +01:00
|
|
|
addw $8, %sp
|
2008-03-11 13:02:12 +01:00
|
|
|
testw %ax, %ax
|
2008-08-26 00:36:24 +02:00
|
|
|
je got_bbs
|
2009-08-08 15:36:10 +02:00
|
|
|
no_pnp: /* Not PnP-compliant - therefore cannot be BBS-compliant */
|
2008-08-26 00:36:24 +02:00
|
|
|
no_bbs: /* Not BBS-compliant - must hook INT 19 */
|
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 )
|
2008-08-26 00:36:24 +02:00
|
|
|
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:
|
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
|
2008-11-11 21:00:13 +01:00
|
|
|
/* We have PMM and so a 1kB stack: preserve upper register halves */
|
|
|
|
pushal
|
|
|
|
/* Calculate required allocation size in %esi */
|
[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
|
|
|
movzwl real_size, %eax
|
2008-11-11 21:00:13 +01:00
|
|
|
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 */
|
2008-03-09 23:13:07 +01:00
|
|
|
pushw $0x0006 /* Aligned, extended memory */
|
|
|
|
pushl $0xffffffff /* No handle */
|
2008-11-11 21:00:13 +01:00
|
|
|
movzwl %si, %eax
|
|
|
|
shll $12, %eax
|
|
|
|
pushl %eax /* Allocation size in paragraphs */
|
2008-08-26 00:36:24 +02:00
|
|
|
pushw $PMM_ALLOCATE
|
2008-03-11 13:02:12 +01:00
|
|
|
lcall *%es:7
|
2008-03-09 23:13:07 +01:00
|
|
|
addw $12, %sp
|
2008-11-11 21:00:13 +01:00
|
|
|
/* 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 )
|
2008-08-26 00:36:24 +02:00
|
|
|
movw %dx, %ax
|
2008-07-30 20:57:46 +02:00
|
|
|
xorw %di, %di
|
2008-08-26 00:36:24 +02:00
|
|
|
call print_hex_word
|
2009-02-16 04:53:25 +01:00
|
|
|
movb $( '@' ), %al
|
2008-11-11 21:00:13 +01:00
|
|
|
call print_character
|
|
|
|
movw %si, %ax
|
|
|
|
call print_hex_byte
|
[prefix] Add .hrom prefix for a ROM that loads high under PCI3 without PMM
gPXE currently takes advantage of the feature of PCI3.0 that allows
option ROMs to relocate the bulk of their code to high memory and so
take up only a small amount of space in the option ROM area. Currently,
the relocation can only take place if the BIOS's implementation of PMM
can be made to return blocks aligned to an even megabyte, because of
the A20 gate. AMI BIOSes, in particular, will not return allocations
that gPXE can use.
Ameliorate the situation somewhat by adding a prefix, .hrom, that works
identically to .rom except in the case that PMM allocation fails. Where
.rom would give up and place itself entirely in option ROM space, .hrom
moves to a block (assumed free) at HIGHMEM_LOADPOINT = 4MB. This allows
for the use of larger gPXE ROMs than would otherwise be possible.
Because there is no way to check that the area at HIGHMEM_LOADPOINT is
really free, other devices using that memory during the boot process
will cause failure for gPXE, the other device, or both. In practice
such conflicts will likely not occur, but this prefix should still be
considered EXPERIMENTAL.
Signed-off-by: Marty Connor <mdc@etherboot.org>
2009-10-06 22:12:22 +02:00
|
|
|
pmm_copy:
|
2008-11-11 21:00:13 +01:00
|
|
|
/* Copy ROM to PMM block */
|
2008-08-26 00:36:24 +02:00
|
|
|
xorw %ax, %ax
|
|
|
|
movw %ax, %es
|
|
|
|
movl image_source, %edi
|
2008-03-09 23:13:07 +01:00
|
|
|
xorl %esi, %esi
|
|
|
|
movzbl romheader_size, %ecx
|
|
|
|
shll $9, %ecx
|
|
|
|
addr32 rep movsb /* PMM presence implies flat real mode */
|
|
|
|
movl %edi, decompress_to
|
2009-02-15 12:42:15 +01:00
|
|
|
/* Shrink ROM */
|
|
|
|
movb $_prefix_memsz_sect, romheader_size
|
[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
|
|
|
#if defined(SHRINK_WITHOUT_PMM) || defined(LOAD_ROM_FROM_PCI)
|
[prefix] Add .hrom prefix for a ROM that loads high under PCI3 without PMM
gPXE currently takes advantage of the feature of PCI3.0 that allows
option ROMs to relocate the bulk of their code to high memory and so
take up only a small amount of space in the option ROM area. Currently,
the relocation can only take place if the BIOS's implementation of PMM
can be made to return blocks aligned to an even megabyte, because of
the A20 gate. AMI BIOSes, in particular, will not return allocations
that gPXE can use.
Ameliorate the situation somewhat by adding a prefix, .hrom, that works
identically to .rom except in the case that PMM allocation fails. Where
.rom would give up and place itself entirely in option ROM space, .hrom
moves to a block (assumed free) at HIGHMEM_LOADPOINT = 4MB. This allows
for the use of larger gPXE ROMs than would otherwise be possible.
Because there is no way to check that the area at HIGHMEM_LOADPOINT is
really free, other devices using that memory during the boot process
will cause failure for gPXE, the other device, or both. In practice
such conflicts will likely not occur, but this prefix should still be
considered EXPERIMENTAL.
Signed-off-by: Marty Connor <mdc@etherboot.org>
2009-10-06 22:12:22 +02:00
|
|
|
jmp pmm_done
|
2009-02-15 12:42:15 +01:00
|
|
|
pmm_fail:
|
[prefix] Add .hrom prefix for a ROM that loads high under PCI3 without PMM
gPXE currently takes advantage of the feature of PCI3.0 that allows
option ROMs to relocate the bulk of their code to high memory and so
take up only a small amount of space in the option ROM area. Currently,
the relocation can only take place if the BIOS's implementation of PMM
can be made to return blocks aligned to an even megabyte, because of
the A20 gate. AMI BIOSes, in particular, will not return allocations
that gPXE can use.
Ameliorate the situation somewhat by adding a prefix, .hrom, that works
identically to .rom except in the case that PMM allocation fails. Where
.rom would give up and place itself entirely in option ROM space, .hrom
moves to a block (assumed free) at HIGHMEM_LOADPOINT = 4MB. This allows
for the use of larger gPXE ROMs than would otherwise be possible.
Because there is no way to check that the area at HIGHMEM_LOADPOINT is
really free, other devices using that memory during the boot process
will cause failure for gPXE, the other device, or both. In practice
such conflicts will likely not occur, but this prefix should still be
considered EXPERIMENTAL.
Signed-off-by: Marty Connor <mdc@etherboot.org>
2009-10-06 22:12:22 +02:00
|
|
|
/* 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
|
2009-02-15 12:42:15 +01:00
|
|
|
/* Restore upper register halves */
|
|
|
|
popal
|
[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
|
|
|
#if defined(LOAD_ROM_FROM_PCI)
|
|
|
|
call load_from_pci
|
|
|
|
jc load_err
|
|
|
|
jmp load_ok
|
2009-02-15 12:42:15 +01:00
|
|
|
no_pmm:
|
[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
|
|
|
/* 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
|
2009-02-15 12:42:15 +01:00
|
|
|
|
[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
|
|
|
load_ok:
|
|
|
|
#else
|
|
|
|
no_pmm:
|
|
|
|
#endif
|
2009-02-15 12:42:15 +01:00
|
|
|
/* 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
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
2009-02-16 04:53:25 +01:00
|
|
|
movb $( ' ' ), %al
|
2008-07-30 20:57:46 +02:00
|
|
|
xorw %di, %di
|
|
|
|
call print_character
|
|
|
|
movw %gs, %ax
|
|
|
|
call print_hex_word
|
|
|
|
movzbw romheader_size, %cx
|
|
|
|
shlw $9, %cx
|
|
|
|
movw %ax, %es
|
2008-08-06 00:18:07 +02:00
|
|
|
xorw %si, %si
|
|
|
|
xorw %di, %di
|
|
|
|
cs rep movsb
|
2008-08-22 04:01:46 +02:00
|
|
|
|
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
|
[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
|
|
|
jnz out
|
2008-09-24 01:53:40 +02:00
|
|
|
/* Ctrl-B was pressed: invoke gPXE. The keypress will be
|
|
|
|
* picked up by the initial shell prompt, and we will drop
|
|
|
|
* into a shell.
|
2008-05-22 16:14:33 +02:00
|
|
|
*/
|
|
|
|
pushw %cs
|
|
|
|
call exec
|
[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
|
|
|
out:
|
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
|
|
|
|
|
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
|
|
|
|
* 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! ]
|
|
|
|
*/
|
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"
|
2008-08-26 00:36:24 +02:00
|
|
|
.asciz "gPXE (http://etherboot.org) - "
|
2008-03-09 23:13:07 +01:00
|
|
|
.size init_message, . - init_message
|
2008-07-30 20:57:46 +02:00
|
|
|
init_message_pci:
|
|
|
|
.asciz " PCI"
|
|
|
|
.size init_message_pci, . - init_message_pci
|
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-11 13:02:12 +01:00
|
|
|
init_message_bbs:
|
|
|
|
.asciz " BBS"
|
2008-05-22 16:14:33 +02:00
|
|
|
.size init_message_bbs, . - init_message_bbs
|
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
|
[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
|
|
|
#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
|
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
|
|
|
|
|
|
|
/* ROM image location
|
|
|
|
*
|
|
|
|
* May be either within option ROM space, or within PMM-allocated block.
|
|
|
|
*/
|
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
|
|
|
|
2008-03-09 23:13:07 +01:00
|
|
|
/* Temporary decompression area
|
|
|
|
*
|
|
|
|
* May be either at HIGHMEM_LOADPOINT, or within PMM-allocated block.
|
[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
|
|
|
* If a PCI ROM load fails, this will be set to zero.
|
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:
|
|
|
|
.long HIGHMEM_LOADPOINT
|
|
|
|
.size decompress_to, . - decompress_to
|
|
|
|
|
[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
|
|
|
#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
|
|
|
|
|
2008-03-11 13:02:12 +01:00
|
|
|
/* BBS version
|
|
|
|
*
|
|
|
|
* Filled in by BBS BIOS. We ignore the value.
|
|
|
|
*/
|
|
|
|
bbs_version:
|
|
|
|
.word 0
|
2008-08-26 00:36:24 +02:00
|
|
|
.size bbs_version, . - bbs_version
|
2008-03-11 13:02:12 +01:00
|
|
|
|
2008-03-09 23:13:07 +01:00
|
|
|
/* 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
|
|
|
|
|
[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
|
|
|
|
|
|
|
#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 */
|
|
|
|
|
|
|
|
|
2008-03-09 23:13:07 +01:00
|
|
|
/* 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
|
2008-09-24 01:53:40 +02:00
|
|
|
/* Leave keypress in buffer and start gPXE. The keypress will
|
|
|
|
* cause the usual initial Ctrl-B prompt to be skipped.
|
|
|
|
*/
|
|
|
|
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
|
|
|
|
|
[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
|
|
|
#ifdef LOAD_ROM_FROM_PCI
|
|
|
|
/* Don't execute if load was invalid */
|
|
|
|
cmpl $0, decompress_to
|
|
|
|
jne 1f
|
|
|
|
lret
|
|
|
|
1:
|
|
|
|
#endif
|
|
|
|
|
2008-03-09 23:13:07 +01:00
|
|
|
/* 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
|
2008-08-26 00:36:24 +02:00
|
|
|
movw $exec_message, %si
|
|
|
|
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
|
|
|
|
movw %ss, %dx
|
|
|
|
movw %sp, %bp
|
|
|
|
|
|
|
|
/* Obtain a reasonably-sized temporary stack */
|
2006-06-06 17:33:39 +02:00
|
|
|
xorw %ax, %ax
|
|
|
|
movw %ax, %ss
|
|
|
|
movw $0x7c00, %sp
|
2005-03-08 19:53:11 +01:00
|
|
|
|
2008-03-09 23:13:07 +01:00
|
|
|
/* Install gPXE */
|
|
|
|
movl image_source, %esi
|
|
|
|
movl decompress_to, %edi
|
|
|
|
call alloc_basemem
|
|
|
|
call install_prealloc
|
2005-03-08 19:53:11 +01:00
|
|
|
|
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
|
2008-03-09 23:13:07 +01:00
|
|
|
1: /* Call main() */
|
2006-06-06 17:33:39 +02:00
|
|
|
pushl $main
|
2005-03-08 19:53:11 +01:00
|
|
|
pushw %cs
|
2006-06-06 17:33:39 +02:00
|
|
|
call prot_call
|
2008-11-18 20:43:13 +01:00
|
|
|
popl %ecx /* discard */
|
|
|
|
|
|
|
|
/* Uninstall gPXE */
|
|
|
|
call uninstall
|
|
|
|
|
2008-03-09 23:13:07 +01:00
|
|
|
/* Restore BIOS stack */
|
|
|
|
movw %dx, %ss
|
|
|
|
movw %bp, %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
|
|
|
|
|
2006-06-06 17:33:39 +02:00
|
|
|
exec_message:
|
2008-08-26 00:36:24 +02:00
|
|
|
.asciz " starting execution\n"
|
2006-06-06 17:33:39 +02:00
|
|
|
.size exec_message, . - exec_message
|
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 */
|
|
|
|
movw $ROM_BANNER_TIMEOUT, %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
|