aboutsummaryrefslogtreecommitdiffstats
path: root/gpxe/src/arch/i386/prefix
diff options
context:
space:
mode:
Diffstat (limited to 'gpxe/src/arch/i386/prefix')
-rw-r--r--gpxe/src/arch/i386/prefix/bImageprefix.S611
-rw-r--r--gpxe/src/arch/i386/prefix/bootpart.S2
-rw-r--r--gpxe/src/arch/i386/prefix/comprefix.S46
-rw-r--r--gpxe/src/arch/i386/prefix/dskprefix.S6
-rw-r--r--gpxe/src/arch/i386/prefix/elf_dprefix.S94
-rw-r--r--gpxe/src/arch/i386/prefix/elfprefix.S94
-rwxr-xr-xgpxe/src/arch/i386/prefix/exeprefix.S41
-rw-r--r--gpxe/src/arch/i386/prefix/hdprefix.S6
-rw-r--r--gpxe/src/arch/i386/prefix/hromprefix.S12
-rw-r--r--gpxe/src/arch/i386/prefix/kkpxeprefix.S5
-rw-r--r--gpxe/src/arch/i386/prefix/kpxeprefix.S2
-rw-r--r--gpxe/src/arch/i386/prefix/libprefix.S2
-rw-r--r--gpxe/src/arch/i386/prefix/lkrnprefix.S6
-rw-r--r--gpxe/src/arch/i386/prefix/lmelf_dprefix.S161
-rw-r--r--gpxe/src/arch/i386/prefix/lmelf_prefix.S161
-rw-r--r--gpxe/src/arch/i386/prefix/nbiprefix.S8
-rw-r--r--gpxe/src/arch/i386/prefix/pxeprefix.S100
-rw-r--r--gpxe/src/arch/i386/prefix/romprefix.S480
-rw-r--r--gpxe/src/arch/i386/prefix/undiloader.S49
-rw-r--r--gpxe/src/arch/i386/prefix/unnrv2b.S2
-rw-r--r--gpxe/src/arch/i386/prefix/unnrv2b16.S9
-rw-r--r--gpxe/src/arch/i386/prefix/xromprefix.S9
22 files changed, 605 insertions, 1301 deletions
diff --git a/gpxe/src/arch/i386/prefix/bImageprefix.S b/gpxe/src/arch/i386/prefix/bImageprefix.S
deleted file mode 100644
index 30020f73..00000000
--- a/gpxe/src/arch/i386/prefix/bImageprefix.S
+++ /dev/null
@@ -1,611 +0,0 @@
-/*
- Copyright (C) 2000, Entity Cyber, Inc.
-
- Authors: Gary Byers (gb@thinguin.org)
- Marty Connor (mdc@thinguin.org)
- Eric Biederman (ebiederman@lnxi.com)
-
- This code also derives a lot from arch/i386/boot/setup.S in
- the linux kernel.
-
- This software may be used and distributed according to the terms
- of the GNU Public License (GPL), incorporated herein by reference.
-
- Description:
-
- This is just a little bit of code and data that can get prepended
- to an Etherboot ROM image in order to allow LILO to load the
- result as if it were a Linux kernel image.
-
- A real Linux kernel image consists of a one-sector boot loader
- (to load the image from a floppy disk), followed a few sectors
- of setup code, followed by the kernel code itself. There's
- a table in the first sector (starting at offset 497) that indicates
- how many sectors of setup code follow the first sector and which
- contains some other parameters that aren't interesting in this
- case.
-
- When LILO loads the sectors that comprise a kernel image, it doesn't
- execute the code in the first sector (since that code would try to
- load the image from a floppy disk.) The code in the first sector
- below doesn't expect to get executed (and prints an error message
- if it ever -is- executed.) LILO's only interested in knowing the
- number of setup sectors advertised in the table (at offset 497 in
- the first sector.)
-
- Etherboot doesn't require much in the way of setup code.
- Historically, the Linux kernel required at least 4 sectors of
- setup code. Current versions of LILO look at the byte at
- offset 497 in the first sector to indicate how many sectors
- of setup code are contained in the image.
-
- The setup code that is present here does a lot of things
- exactly the way the linux kernel does them instead of in
- ways more typical of etherboot. Generally this is so
- the code can be strongly compatible with the linux kernel.
- In addition the general etherboot technique of enabling the a20
- after we switch into protected mode does not work if etherboot
- is being loaded at 1MB.
-*/
-
- .equ CR0_PE,1
-
-#ifdef GAS291
-#define DATA32 data32;
-#define ADDR32 addr32;
-#define LJMPI(x) ljmp x
-#else
-#define DATA32 data32
-#define ADDR32 addr32
-/* newer GAS295 require #define LJMPI(x) ljmp *x */
-#define LJMPI(x) ljmp x
-#endif
-
-/* Simple and small GDT entries for booting only */
-#define GDT_ENTRY_BOOT_CS 2
-#define GDT_ENTRY_BOOT_DS (GDT_ENTRY_BOOT_CS + 1)
-#define __BOOT_CS (GDT_ENTRY_BOOT_CS * 8)
-#define __BOOT_DS (GDT_ENTRY_BOOT_DS * 8)
-
-
-#define SETUPSECS 4 /* Minimal nr of setup-sectors */
-#define PREFIXSIZE ((SETUPSECS+1)*512)
-#define PREFIXPGH (PREFIXSIZE / 16 )
-#define BOOTSEG 0x07C0 /* original address of boot-sector */
-#define INITSEG 0x9000 /* we move boot here - out of the way */
-#define SETUPSEG 0x9020 /* setup starts here */
-#define SYSSEG 0x1000 /* system loaded at 0x10000 (65536). */
-
-#define DELTA_INITSEG (SETUPSEG - INITSEG) /* 0x0020 */
-
-/* Signature words to ensure LILO loaded us right */
-#define SIG1 0xAA55
-#define SIG2 0x5A5A
-
- .text
- .code16
- .arch i386
- .org 0
- .section ".prefix", "ax", @progbits
-_prefix:
-
-/*
- This is a minimal boot sector. If anyone tries to execute it (e.g., if
- a .lkrn file is dd'ed to a floppy), print an error message.
-*/
-
-bootsector:
- jmp $BOOTSEG, $go - _prefix /* reload cs:ip to match relocation addr */
-go:
- movw $0x2000, %di /* 0x2000 is arbitrary value >= length
- of bootsect + room for stack */
-
- movw $BOOTSEG, %ax
- movw %ax,%ds
- movw %ax,%es
-
- cli
- movw %ax, %ss /* put stack at BOOTSEG:0x2000. */
- movw %di,%sp
- sti
-
- movw $why_end-why, %cx
- movw $why - _prefix, %si
-
- movw $0x0007, %bx /* page 0, attribute 7 (normal) */
- movb $0x0e, %ah /* write char, tty mode */
-prloop:
- lodsb
- int $0x10
- loop prloop
-freeze: jmp freeze
-
-why: .ascii "This image cannot be loaded from a floppy disk.\r\n"
-why_end:
-
-
- .org 497
-setup_sects:
- .byte SETUPSECS
-root_flags:
- .word 0
-syssize:
- .word _verbatim_size_pgh - PREFIXPGH
-swap_dev:
- .word 0
-ram_size:
- .word 0
-vid_mode:
- .word 0
-root_dev:
- .word 0
-boot_flag:
- .word 0xAA55
-
-/*
- We're now at the beginning of the second sector of the image -
- where the setup code goes.
-
- We don't need to do too much setup for Etherboot.
-
- This code gets loaded at SETUPSEG:0. It wants to start
- executing the Etherboot image that's loaded at SYSSEG:0 and
- whose entry point is SYSSEG:0.
-*/
-setup_code:
- jmp trampoline
-# This is the setup header, and it must start at %cs:2 (old 0x9020:2)
-
- .ascii "HdrS" # header signature
- .word 0x0203 # header version number (>= 0x0105)
- # or else old loadlin-1.5 will fail)
-realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
-start_sys_seg: .word SYSSEG # low load segment (obsolete)
- .word kernel_version - setup_code
- # pointing to kernel version string
- # above section of header is compatible
- # with loadlin-1.5 (header v1.5). Don't
- # change it.
-
-type_of_loader: .byte 0 # = 0, old one (LILO, Loadlin,
- # Bootlin, SYSLX, bootsect...)
- # See Documentation/i386/boot.txt for
- # assigned ids
-
-# flags, unused bits must be zero (RFU) bit within loadflags
-loadflags:
-LOADED_HIGH = 1 # If set, the kernel is loaded high
-CAN_USE_HEAP = 0x80 # If set, the loader also has set
- # heap_end_ptr to tell how much
- # space behind setup.S can be used for
- # heap purposes.
- # Only the loader knows what is free
- .byte LOADED_HIGH
-
-setup_move_size: .word 0x8000 # size to move, when setup is not
- # loaded at 0x90000. We will move setup
- # to 0x90000 then just before jumping
- # into the kernel. However, only the
- # loader knows how much data behind
- # us also needs to be loaded.
-
-code32_start: # here loaders can put a different
- # start address for 32-bit code.
- .long 0x100000 # 0x100000 = default for big kernel
-
-ramdisk_image: .long 0 # address of loaded ramdisk image
- # Here the loader puts the 32-bit
- # address where it loaded the image.
- # This only will be read by the kernel.
-
-ramdisk_size: .long 0 # its size in bytes
-
-bootsect_kludge:
- .long 0 # obsolete
-
-heap_end_ptr: .word 0 # (Header version 0x0201 or later)
- # space from here (exclusive) down to
- # end of setup code can be used by setup
- # for local heap purposes.
-
-pad1: .word 0
-cmd_line_ptr: .long 0 # (Header version 0x0202 or later)
- # If nonzero, a 32-bit pointer
- # to the kernel command line.
- # The command line should be
- # located between the start of
- # setup and the end of low
- # memory (0xa0000), or it may
- # get overwritten before it
- # gets read. If this field is
- # used, there is no longer
- # anything magical about the
- # 0x90000 segment; the setup
- # can be located anywhere in
- # low memory 0x10000 or higher.
-
-ramdisk_max: .long 0 # (Header version 0x0203 or later)
- # The highest safe address for
- # the contents of an initrd
-
-trampoline: call start_of_setup
-trampoline_end:
- .space 1024
-# End of setup header #####################################################
-
-start_of_setup:
-# Set %ds = %cs, we know that SETUPSEG = %cs at this point
- movw %cs, %ax # aka SETUPSEG
- movw %ax, %ds
-# Check signature at end of setup
- cmpw $SIG1, (setup_sig1 - setup_code)
- jne bad_sig
-
- cmpw $SIG2, (setup_sig2 - setup_code)
- jne bad_sig
-
- jmp good_sig1
-
-# Routine to print asciiz string at ds:si
-prtstr:
- lodsb
- andb %al, %al
- jz fin
-
- call prtchr
- jmp prtstr
-
-fin: ret
-
-# Part of above routine, this one just prints ascii al
-prtchr: pushw %ax
- pushw %cx
- movw $7,%bx
- movw $0x01, %cx
- movb $0x0e, %ah
- int $0x10
- popw %cx
- popw %ax
- ret
-
-no_sig_mess: .string "No setup signature found ..."
-
-good_sig1:
- jmp good_sig
-
-# We now have to find the rest of the setup code/data
-bad_sig:
- movw %cs, %ax # SETUPSEG
- subw $DELTA_INITSEG, %ax # INITSEG
- movw %ax, %ds
- xorb %bh, %bh
- movb (497), %bl # get setup sect from bootsect
- subw $4, %bx # LILO loads 4 sectors of setup
- shlw $8, %bx # convert to words (1sect=2^8 words)
- movw %bx, %cx
- shrw $3, %bx # convert to segment
- addw $SYSSEG, %bx
- movw %bx, %cs:(start_sys_seg - setup_code)
-# Move rest of setup code/data to here
- movw $2048, %di # four sectors loaded by LILO
- subw %si, %si
- pushw %cs
- popw %es
- movw $SYSSEG, %ax
- movw %ax, %ds
- rep
- movsw
- movw %cs, %ax # aka SETUPSEG
- movw %ax, %ds
- cmpw $SIG1, (setup_sig1 - setup_code)
- jne no_sig
-
- cmpw $SIG2, (setup_sig2 - setup_code)
- jne no_sig
-
- jmp good_sig
-
-no_sig:
- lea (no_sig_mess - setup_code), %si
- call prtstr
-
-no_sig_loop:
- hlt
- jmp no_sig_loop
-
-good_sig:
- cmpw $0, %cs:(realmode_swtch - setup_code)
- jz rmodeswtch_normal
-
- lcall *%cs:(realmode_swtch - setup_code)
- jmp rmodeswtch_end
-
-rmodeswtch_normal:
- pushw %cs
- call default_switch
-
-rmodeswtch_end:
-# we get the code32 start address and modify the below 'jmpi'
-# (loader may have changed it)
- movl %cs:(code32_start - setup_code), %eax
- movl %eax, %cs:(code32 - setup_code)
-
-# then we load the segment descriptors
- movw %cs, %ax # aka SETUPSEG
- movw %ax, %ds
-
-#
-# Enable A20. This is at the very best an annoying procedure.
-# A20 code ported from SYSLINUX 1.52-1.63 by H. Peter Anvin.
-#
-
-A20_TEST_LOOPS = 32 # Iterations per wait
-A20_ENABLE_LOOPS = 255 # Total loops to try
-
-a20_try_loop:
-
- # First, see if we are on a system with no A20 gate.
-a20_none:
- call a20_test
- jnz a20_done
-
- # Next, try the BIOS (INT 0x15, AX=0x2401)
-a20_bios:
- movw $0x2401, %ax
- pushfl # Be paranoid about flags
- int $0x15
- popfl
-
- call a20_test
- jnz a20_done
-
- # Try enabling A20 through the keyboard controller
-a20_kbc:
- call empty_8042
-
- call a20_test # Just in case the BIOS worked
- jnz a20_done # but had a delayed reaction.
-
- movb $0xD1, %al # command write
- outb %al, $0x64
- call empty_8042
-
- movb $0xDF, %al # A20 on
- outb %al, $0x60
- call empty_8042
-
- # Wait until a20 really *is* enabled; it can take a fair amount of
- # time on certain systems; Toshiba Tecras are known to have this
- # problem.
-a20_kbc_wait:
- xorw %cx, %cx
-a20_kbc_wait_loop:
- call a20_test
- jnz a20_done
- loop a20_kbc_wait_loop
-
- # Final attempt: use "configuration port A"
-a20_fast:
- inb $0x92, %al # Configuration Port A
- orb $0x02, %al # "fast A20" version
- andb $0xFE, %al # don't accidentally reset
- outb %al, $0x92
-
- # Wait for configuration port A to take effect
-a20_fast_wait:
- xorw %cx, %cx
-a20_fast_wait_loop:
- call a20_test
- jnz a20_done
- loop a20_fast_wait_loop
-
- # A20 is still not responding. Try frobbing it again.
- #
- decb (a20_tries - setup_code)
- jnz a20_try_loop
-
- movw $(a20_err_msg - setup_code), %si
- call prtstr
-
-a20_die:
- hlt
- jmp a20_die
-
-a20_tries:
- .byte A20_ENABLE_LOOPS
-
-a20_err_msg:
- .ascii "linux: fatal error: A20 gate not responding!"
- .byte 13, 10, 0
-
- # If we get here, all is good
-a20_done:
- # Leave the idt alone
-
- # set up gdt
- xorl %eax, %eax # Compute gdt_base
- movw %ds, %ax # (Convert %ds:gdt to a linear ptr)
- shll $4, %eax
- addl $(bImage_gdt - setup_code), %eax
- movl %eax, (bImage_gdt_48+2 - setup_code)
- DATA32 lgdt %ds:(bImage_gdt_48 - setup_code) # load gdt with whatever is
- # appropriate
-
- # Switch to protected mode
- movl %cr0, %eax
- orb $CR0_PE, %al
- movl %eax, %cr0
-
- DATA32 ljmp *%ds:(code32 - setup_code)
-code32:
- .long 0x100000
- .word __BOOT_CS, 0
-
-# Here's a bunch of information about your current kernel..
-kernel_version: .ascii "Etherboot "
- .ascii VERSION
- .byte 0
-
-# This is the default real mode switch routine.
-# to be called just before protected mode transition
-default_switch:
- cli # no interrupts allowed !
- movb $0x80, %al # disable NMI for bootup
- # sequence
- outb %al, $0x70
- lret
-
-# This routine tests whether or not A20 is enabled. If so, it
-# exits with zf = 0.
-#
-# The memory address used, 0x200, is the int $0x80 vector, which
-# should be safe.
-
-A20_TEST_ADDR = 4*0x80
-
-a20_test:
- pushw %cx
- pushw %ax
- xorw %cx, %cx
- movw %cx, %fs # Low memory
- decw %cx
- movw %cx, %gs # High memory area
- movw $A20_TEST_LOOPS, %cx
- movw %fs:(A20_TEST_ADDR), %ax
- pushw %ax
-a20_test_wait:
- incw %ax
- movw %ax, %fs:(A20_TEST_ADDR)
- call delay # Serialize and make delay constant
- cmpw %gs:(A20_TEST_ADDR+0x10), %ax
- loope a20_test_wait
-
- popw %fs:(A20_TEST_ADDR)
- popw %ax
- popw %cx
- ret
-
-
-# This routine checks that the keyboard command queue is empty
-# (after emptying the output buffers)
-#
-# Some machines have delusions that the keyboard buffer is always full
-# with no keyboard attached...
-#
-# If there is no keyboard controller, we will usually get 0xff
-# to all the reads. With each IO taking a microsecond and
-# a timeout of 100,000 iterations, this can take about half a
-# second ("delay" == outb to port 0x80). That should be ok,
-# and should also be plenty of time for a real keyboard controller
-# to empty.
-#
-
-empty_8042:
- pushl %ecx
- movl $100000, %ecx
-
-empty_8042_loop:
- decl %ecx
- jz empty_8042_end_loop
-
- call delay
-
- inb $0x64, %al # 8042 status port
- testb $1, %al # output buffer?
- jz no_output
-
- call delay
- inb $0x60, %al # read it
- jmp empty_8042_loop
-
-no_output:
- testb $2, %al # is input buffer full?
- jnz empty_8042_loop # yes - loop
-empty_8042_end_loop:
- popl %ecx
-
-
-# Delay is needed after doing I/O
-delay:
- outb %al,$0x80
- ret
-
-# Descriptor tables
-#
-# NOTE: The intel manual says gdt should be sixteen bytes aligned for
-# efficiency reasons. However, there are machines which are known not
-# to boot with misaligned GDTs, so alter this at your peril! If you alter
-# GDT_ENTRY_BOOT_CS (in asm/segment.h) remember to leave at least two
-# empty GDT entries (one for NULL and one reserved).
-#
-# NOTE: On some CPUs, the GDT must be 8 byte aligned. This is
-# true for the Voyager Quad CPU card which will not boot without
-# This directive. 16 byte aligment is recommended by intel.
-#
- .balign 16
-bImage_gdt:
- .fill GDT_ENTRY_BOOT_CS,8,0
-
- .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
- .word 0 # base address = 0
- .word 0x9A00 # code read/exec
- .word 0x00CF # granularity = 4096, 386
- # (+5th nibble of limit)
-
- .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
- .word 0 # base address = 0
- .word 0x9200 # data read/write
- .word 0x00CF # granularity = 4096, 386
- # (+5th nibble of limit)
-bImage_gdt_end:
- .balign 4
-
- .word 0 # alignment byte
-bImage_idt_48:
- .word 0 # idt limit = 0
- .long 0 # idt base = 0L
-
- .word 0 # alignment byte
-bImage_gdt_48:
- .word bImage_gdt_end - bImage_gdt - 1 # gdt limit
- .long bImage_gdt_48 - setup_code # gdt base (filled in later)
-
- .section ".text16", "ax", @progbits
-prefix_exit:
- int $0x19 /* should try to boot machine */
-prefix_exit_end:
- .previous
-
-
- .org (PREFIXSIZE - 4)
-# Setup signature -- must be last
-setup_sig1: .word SIG1
-setup_sig2: .word SIG2
- /* Etherboot expects to be contiguous in memory once loaded.
- * The linux bImage protocol does not do this, but since we
- * don't need any information that's left in the prefix, it
- * doesn't matter: we just have to ensure that we make it to _start
- *
- * protected_start will live at 0x100000 and it will be the
- * the first code called as we enter protected mode.
- */
- .code32
-protected_start:
- /* Load segment registers */
- movw $__BOOT_DS, %ax
- movw %ax, %ss
- movw %ax, %ds
- movw %ax, %es
- movw %ax, %fs
- movw %ax, %gs
-
- /* Use the internal etherboot stack */
- movl $(_prefix_stack_end - protected_start + 0x100000), %esp
-
- pushl $0 /* No parameters to preserve for exit path */
- pushl $0 /* Use prefix exit path mechanism */
-
- jmp _start
-/*
- That's about it.
-*/
diff --git a/gpxe/src/arch/i386/prefix/bootpart.S b/gpxe/src/arch/i386/prefix/bootpart.S
index d60fe9bc..968da1a3 100644
--- a/gpxe/src/arch/i386/prefix/bootpart.S
+++ b/gpxe/src/arch/i386/prefix/bootpart.S
@@ -1,3 +1,5 @@
+FILE_LICENCE ( GPL2_OR_LATER )
+
#define BOOT_SEG 0x07c0
#define EXEC_SEG 0x0100
#define STACK_SEG 0x0200
diff --git a/gpxe/src/arch/i386/prefix/comprefix.S b/gpxe/src/arch/i386/prefix/comprefix.S
deleted file mode 100644
index 2cbbca50..00000000
--- a/gpxe/src/arch/i386/prefix/comprefix.S
+++ /dev/null
@@ -1,46 +0,0 @@
-/* We need a real mode stack that won't be stomped on by Etherboot
- which starts at 0x20000. Choose something that's sufficiently high,
- but not in DOC territory. Note that we couldn't do this in a real
- .com program since stack variables are in the same segment as the
- code and data, but this isn't really a .com program, it just looks
- like one to make DOS load it into memory. It still has the 64kB
- limitation of .com files though. */
-#define STACK_SEG 0x7000
-#define STACK_SIZE 0x4000
-
- .text
- .code16
- .arch i386
- .section ".prefix", "ax", @progbits
-
-/* Cheat a little with the relocations: .COM files are loaded at 0x100 */
-_prefix:
- /* Set up temporary stack */
- movw $STACK_SEG, %ax
- movw %ax, %ss
- movw $STACK_SIZE, %sp
-
- pushl $0 /* No parameters to preserve for exit path */
- pushw $0 /* Dummy return address - use prefix_exit */
-
- /* Calculate segment address of image start */
- pushw %cs
- popw %ax
- addw $(0x100/16), %ax
- pushw %ax
- pushw $_start
- /* Calculated lcall to _start with %cs:0000 = image start */
- lret
-
- .section ".text16", "ax", @progbits
-prefix_exit:
- movw $0x4c00,%ax /* return to DOS */
- int $0x21 /* reach this on Quit */
-prefix_exit_end:
- .previous
-
-/* The body of etherboot is attached here at build time.
- * Force 16 byte alignment
- */
- .align 16,0
-_body:
diff --git a/gpxe/src/arch/i386/prefix/dskprefix.S b/gpxe/src/arch/i386/prefix/dskprefix.S
index 0156812a..60d351f7 100644
--- a/gpxe/src/arch/i386/prefix/dskprefix.S
+++ b/gpxe/src/arch/i386/prefix/dskprefix.S
@@ -16,6 +16,8 @@
* getting whole tracks at a time whenever possible.
*/
+FILE_LICENCE ( GPL2_ONLY )
+
.equ BOOTSEG, 0x07C0 /* original address of boot-sector */
.equ SYSSEG, 0x1000 /* system loaded at SYSSEG<<4 */
@@ -144,9 +146,9 @@ got_sectors:
/* Jump to loaded copy */
ljmp $SYSSEG, $start_runtime
-endseg: .word SYSSEG + _filesz_pgh
+endseg: .word SYSSEG
.section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
- .ascii "SUBW"
+ .ascii "ADDW"
.long endseg
.long 16
.long 0
diff --git a/gpxe/src/arch/i386/prefix/elf_dprefix.S b/gpxe/src/arch/i386/prefix/elf_dprefix.S
deleted file mode 100644
index 0eac77e0..00000000
--- a/gpxe/src/arch/i386/prefix/elf_dprefix.S
+++ /dev/null
@@ -1,94 +0,0 @@
-#include "elf.h"
-
- .arch i386
- .section ".prefix", "a", @progbits
-
-#define LOAD_ADDR 0x10000
-
- /* ELF Header */
- .globl elf_header
-elf_header:
-e_ident: .byte 0x7f, 'E', 'L', 'F', 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
-e_type: .short ET_DYN
-e_machine: .short EM_386
-e_version: .long 1
-e_entry: .long LOAD_ADDR + _start - elf_header
-e_phoff: .long elf_program_header - elf_header
-e_shoff: .long 0
-e_flags: .long 0
-e_ehsize: .short elf_header_end - elf_header
-e_phentsize: .short ELF32_PHDR_SIZE
-e_phnum: .short (elf_program_header_end - elf_program_header)/ELF32_PHDR_SIZE
-e_shentsize: .short 0
-e_shnum: .short 0
-e_shstrndx: .short 0
-elf_header_end:
-
-elf_program_header:
-phdr1_p_type: .long PT_NOTE
-phdr1_p_offset: .long elf_note - elf_header
-phdr1_p_vaddr: .long elf_note
-phdr1_p_paddr: .long elf_note
-phdr1_p_filesz: .long elf_note_end - elf_note
-phdr1_p_memsz: .long elf_note_end - elf_note
-phdr1_p_flags: .long PF_R | PF_W | PF_X
-phdr1_p_align: .long 0
-
-/* The decompressor */
-phdr2_p_type: .long PT_LOAD
-phdr2_p_offset: .long 0
-phdr2_p_vaddr: .long elf_header
-phdr2_p_paddr: .long LOAD_ADDR
-phdr2_p_filesz: .long _verbatim_size
-phdr2_p_memsz: .long _image_size
-phdr2_p_flags: .long PF_R | PF_W | PF_X
-phdr2_p_align: .long 16
-
-elf_program_header_end:
-
- .globl elf_note
-elf_note:
- .balign 4
- .int 2f - 1f
- .int 4f - 3f
- .int EIN_PROGRAM_NAME
-1: .asciz "ELFBoot"
-2:
- .balign 4
-3:
- .asciz "Etherboot"
-4:
-
-
- .balign 4
- .int 2f - 1f
- .int 4f - 3f
- .int EIN_PROGRAM_VERSION
-1: .asciz "ELFBoot"
-2:
- .balign 4
-3:
- .asciz VERSION
-4:
-
-#if 0
- .balign 4
- .int 2f - 1f
- .int 4f - 3f
- .int EIN_PROGRAM_CHECKSUM
-1: .asciz "ELFBoot"
-2:
- .balign 4
-3:
- .word 0
-4:
-#endif
- .balign 4
-elf_note_end:
-
- /* Dummy routines to satisfy the build */
- .section ".text16", "ax", @progbits
-prefix_exit:
-
-prefix_exit_end:
- .previous
diff --git a/gpxe/src/arch/i386/prefix/elfprefix.S b/gpxe/src/arch/i386/prefix/elfprefix.S
deleted file mode 100644
index d712753a..00000000
--- a/gpxe/src/arch/i386/prefix/elfprefix.S
+++ /dev/null
@@ -1,94 +0,0 @@
-#include "elf.h"
-
- .arch i386
- .section ".prefix", "a", @progbits
-
-#define LOAD_ADDR 0x10000
-
- /* ELF Header */
- .globl elf_header
-elf_header:
-e_ident: .byte 0x7f, 'E', 'L', 'F', 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
-e_type: .short ET_EXEC
-e_machine: .short EM_386
-e_version: .long 1
-e_entry: .long LOAD_ADDR + _start - elf_header
-e_phoff: .long elf_program_header - elf_header
-e_shoff: .long 0
-e_flags: .long 0
-e_ehsize: .short elf_header_end - elf_header
-e_phentsize: .short ELF32_PHDR_SIZE
-e_phnum: .short (elf_program_header_end - elf_program_header)/ELF32_PHDR_SIZE
-e_shentsize: .short 0
-e_shnum: .short 0
-e_shstrndx: .short 0
-elf_header_end:
-
-elf_program_header:
-phdr1_p_type: .long PT_NOTE
-phdr1_p_offset: .long elf_note - elf_header
-phdr1_p_vaddr: .long elf_note
-phdr1_p_paddr: .long elf_note
-phdr1_p_filesz: .long elf_note_end - elf_note
-phdr1_p_memsz: .long elf_note_end - elf_note
-phdr1_p_flags: .long PF_R | PF_W | PF_X
-phdr1_p_align: .long 0
-
-/* The decompressor */
-phdr2_p_type: .long PT_LOAD
-phdr2_p_offset: .long 0
-phdr2_p_vaddr: .long elf_header
-phdr2_p_paddr: .long LOAD_ADDR
-phdr2_p_filesz: .long _verbatim_size
-phdr2_p_memsz: .long _image_size
-phdr2_p_flags: .long PF_R | PF_W | PF_X
-phdr2_p_align: .long 16
-
-elf_program_header_end:
-
- .globl elf_note
-elf_note:
- .balign 4
- .int 2f - 1f
- .int 4f - 3f
- .int EIN_PROGRAM_NAME
-1: .asciz "ELFBoot"
-2:
- .balign 4
-3:
- .asciz "Etherboot"
-4:
-
-
- .balign 4
- .int 2f - 1f
- .int 4f - 3f
- .int EIN_PROGRAM_VERSION
-1: .asciz "ELFBoot"
-2:
- .balign 4
-3:
- .asciz VERSION
-4:
-
-#if 0
- .balign 4
- .int 2f - 1f
- .int 4f - 3f
- .int EIN_PROGRAM_CHECKSUM
-1: .asciz "ELFBoot"
-2:
- .balign 4
-3:
- .word 0
-4:
-#endif
- .balign 4
-elf_note_end:
-
- /* Dummy routines to satisfy the build */
- .section ".text16", "ax", @progbits
-prefix_exit:
-
-prefix_exit_end:
- .previous
diff --git a/gpxe/src/arch/i386/prefix/exeprefix.S b/gpxe/src/arch/i386/prefix/exeprefix.S
deleted file mode 100755
index f1b402b7..00000000
--- a/gpxe/src/arch/i386/prefix/exeprefix.S
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- Prefix for .exe images
- Doesn't work yet, even though it starts off the same as a .com
- image as shown by DOS debug.
-*/
-
- .text
- .code16
- .arch i386
- .section ".prefix", "ax", @progbits
-
-_prefix:
- .byte 'M', 'Z'
- .short _exe_size_tail /* tail */
- .short _exe_size_pages /* pages */
- .short 0 /* relocations */
- .short 2 /* header paras */
- .short _exe_bss_size /* min */
- .short 0xFFFF /* max paras */
- .short _exe_ss_offset /* SS */
- .short _stack_size /* SP */
- .short 0 /* checksum */
- .short 0 /* IP */
- .short 0 /* CS */
- .short 0x1C /* reloc offset */
- .short 0 /* overlay number */
- .short 0 /* fill */
- .short 0 /* fill */
-
- .section ".text16", "ax", @progbits
-prefix_exit:
- movw $0x4c00,%ax /* return to DOS */
- int $0x21 /* reach this on Quit */
-prefix_exit_end:
- .previous
-
-/* The body of etherboot is attached here at build time.
- * Force 16 byte alignment
- */
- .align 16,0
-_body:
diff --git a/gpxe/src/arch/i386/prefix/hdprefix.S b/gpxe/src/arch/i386/prefix/hdprefix.S
index 086d7f45..05767567 100644
--- a/gpxe/src/arch/i386/prefix/hdprefix.S
+++ b/gpxe/src/arch/i386/prefix/hdprefix.S
@@ -1,3 +1,5 @@
+FILE_LICENCE ( GPL2_OR_LATER )
+
.text
.arch i386
.section ".prefix", "awx", @progbits
@@ -63,10 +65,10 @@ max_sector:
max_head:
.byte 0
load_length:
- .long _filesz_sect
+ .long 0
.section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
- .ascii "SUBL"
+ .ascii "ADDL"
.long load_length
.long 512
.long 0
diff --git a/gpxe/src/arch/i386/prefix/hromprefix.S b/gpxe/src/arch/i386/prefix/hromprefix.S
new file mode 100644
index 00000000..03acf1e2
--- /dev/null
+++ b/gpxe/src/arch/i386/prefix/hromprefix.S
@@ -0,0 +1,12 @@
+/*****************************************************************************
+ * ROM prefix that relocates to HIGHMEM_LOADPOINT during POST if PMM allocation
+ * fails. Intended to be used, with caution, on BIOSes that support PCI3.00 but
+ * have limited PMM support, such as most AMI BIOSes.
+ *****************************************************************************
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER )
+
+#define SHRINK_WITHOUT_PMM
+
+#include "romprefix.S"
diff --git a/gpxe/src/arch/i386/prefix/kkpxeprefix.S b/gpxe/src/arch/i386/prefix/kkpxeprefix.S
index e0bea0cd..02cc6fee 100644
--- a/gpxe/src/arch/i386/prefix/kkpxeprefix.S
+++ b/gpxe/src/arch/i386/prefix/kkpxeprefix.S
@@ -3,6 +3,11 @@
*****************************************************************************
*/
+FILE_LICENCE ( GPL2_OR_LATER )
+
+/* Since we have the whole stack, we can use cached DHCP information */
+REQUEST_OBJECT ( pxeparent_dhcp )
+
#define PXELOADER_KEEP_UNDI
#define PXELOADER_KEEP_PXE
#include "pxeprefix.S"
diff --git a/gpxe/src/arch/i386/prefix/kpxeprefix.S b/gpxe/src/arch/i386/prefix/kpxeprefix.S
index d708604b..923faccc 100644
--- a/gpxe/src/arch/i386/prefix/kpxeprefix.S
+++ b/gpxe/src/arch/i386/prefix/kpxeprefix.S
@@ -3,5 +3,7 @@
*****************************************************************************
*/
+FILE_LICENCE ( GPL2_OR_LATER )
+
#define PXELOADER_KEEP_UNDI
#include "pxeprefix.S"
diff --git a/gpxe/src/arch/i386/prefix/libprefix.S b/gpxe/src/arch/i386/prefix/libprefix.S
index 42189135..9e6ba6f0 100644
--- a/gpxe/src/arch/i386/prefix/libprefix.S
+++ b/gpxe/src/arch/i386/prefix/libprefix.S
@@ -17,6 +17,8 @@
*
*/
+FILE_LICENCE ( GPL2_OR_LATER )
+
.arch i386
/**
diff --git a/gpxe/src/arch/i386/prefix/lkrnprefix.S b/gpxe/src/arch/i386/prefix/lkrnprefix.S
index 094263d2..101d0388 100644
--- a/gpxe/src/arch/i386/prefix/lkrnprefix.S
+++ b/gpxe/src/arch/i386/prefix/lkrnprefix.S
@@ -34,6 +34,8 @@
*/
+FILE_LICENCE ( GPL_ANY )
+
#define SETUPSECS 4 /* Minimal nr of setup-sectors */
#define PREFIXSIZE ((SETUPSECS+1)*512)
#define PREFIXPGH (PREFIXSIZE / 16 )
@@ -92,10 +94,10 @@ setup_sects:
root_flags:
.word 0
syssize:
- .long _filesz_pgh - PREFIXPGH
+ .long -PREFIXPGH
.section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
- .ascii "SUBL"
+ .ascii "ADDL"
.long syssize
.long 16
.long 0
diff --git a/gpxe/src/arch/i386/prefix/lmelf_dprefix.S b/gpxe/src/arch/i386/prefix/lmelf_dprefix.S
deleted file mode 100644
index 93534df5..00000000
--- a/gpxe/src/arch/i386/prefix/lmelf_dprefix.S
+++ /dev/null
@@ -1,161 +0,0 @@
-#include "elf.h"
- .arch sledgehammer
- .code32
- .equ FLAT_CODE_SEG,_pmcs-_gdt
- .equ FLAT_DATA_SEG,_pmds-_gdt
- .equ MSR_K6_EFER, 0xC0000080
- .equ EFER_LME, 0x00000100
- .equ X86_CR4_PAE, 0x00000020
- .equ CR0_PG, 0x80000000
-
- .section ".prefix", "ax", @progbits
-
-#define LOAD_ADDR 0x10000
-
- /* ELF Header */
- .globl elf_header
-elf_header:
-e_ident: .byte 0x7f, 'E', 'L', 'F', 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
-e_type: .short ET_DYN
-e_machine: .short EM_X86_64
-e_version: .long 1
-e_entry: .long LOAD_ADDR + elf_start - elf_header
-e_phoff: .long elf_program_header - elf_header
-e_shoff: .long 0
-e_flags: .long 0
-e_ehsize: .short elf_header_end - elf_header
-e_phentsize: .short ELF32_PHDR_SIZE
-e_phnum: .short (elf_program_header_end - elf_program_header)/ELF32_PHDR_SIZE
-e_shentsize: .short 0
-e_shnum: .short 0
-e_shstrndx: .short 0
-elf_header_end:
-
-elf_program_header:
-phdr1_p_type: .long PT_NOTE
-phdr1_p_offset: .long elf_note - elf_header
-phdr1_p_vaddr: .long elf_note
-phdr1_p_paddr: .long elf_note
-phdr1_p_filesz: .long elf_note_end - elf_note
-phdr1_p_memsz: .long elf_note_end - elf_note
-phdr1_p_flags: .long PF_R | PF_W | PF_X
-phdr1_p_align: .long 0
-
-/* The decompressor */
-phdr2_p_type: .long PT_LOAD
-phdr2_p_offset: .long 0
-phdr2_p_vaddr: .long elf_header
-phdr2_p_paddr: .long LOAD_ADDR
-phdr2_p_filesz: .long _verbatim_size
-phdr2_p_memsz: .long _image_size
-phdr2_p_flags: .long PF_R | PF_W | PF_X
-phdr2_p_align: .long 16
-
-elf_program_header_end:
-
- .globl elf_note
-elf_note:
- .balign 4
- .int 2f - 1f
- .int 4f - 3f
- .int EIN_PROGRAM_NAME
-1: .asciz "ELFBoot"
-2:
- .balign 4
-3:
- .asciz "Etherboot"
-4:
-
-
- .balign 4
- .int 2f - 1f
- .int 4f - 3f
- .int EIN_PROGRAM_VERSION
-1: .asciz "ELFBoot"
-2:
- .balign 4
-3:
- .asciz VERSION
-4:
-
-#if 0
- .balign 4
- .int 2f - 1f
- .int 4f - 3f
- .int EIN_PROGRAM_CHECKSUM
-1: .asciz "ELFBoot"
-2:
- .balign 4
-3:
- .word 0
-4:
-#endif
- .balign 4
-elf_note_end:
-
-elf_start:
- .code64
- /* Reload the gdt to something I know */
- leaq _gdt(%rip), %rax
- movq %rax, 0x02 + gdtptr(%rip)
- lgdt gdtptr(%rip)
-
- /* Enter 32bit compatibility mode */
- leaq elf_start32(%rip), %rax
- movl %eax, 0x00 + elf_start32_addr(%rip)
- ljmp *elf_start32_addr(%rip)
-
-elf_start32:
- .code32
- /* Reload the data segments */
- movl $FLAT_DATA_SEG, %eax
- movl %eax, %ds
- movl %eax, %es
- movl %eax, %ss
-
- /* Disable paging */
- movl %cr0, %eax
- andl $~CR0_PG, %eax
- movl %eax, %cr0
-
- /* Disable long mode */
- movl $MSR_K6_EFER, %ecx
- rdmsr
- andl $~EFER_LME, %eax
- wrmsr
-
- /* Disable PAE */
- movl %cr4, %eax
- andl $~X86_CR4_PAE, %eax
- movl %eax, %cr4
-
- /* Save the first argument */
- pushl %ebx
- jmp _start
-
-gdtptr:
- .word _gdt_end - _gdt -1
- .long _gdt
- .long 0
-_gdt:
-elf_start32_addr:
- .long elf_start32
- .long FLAT_CODE_SEG
-_pmcs:
- /* 32 bit protected mode code segment, base 0 */
- .word 0xffff,0
- .byte 0,0x9f,0xcf,0
-
-_pmds:
- /* 32 bit protected mode data segment, base 0 */
- .word 0xffff,0
- .byte 0,0x93,0xcf,0
-_gdt_end:
-
-
- /* Dummy routines to satisfy the build */
- .section ".text16", "ax", @progbits
-prefix_exit:
-
-prefix_exit_end:
- .previous
diff --git a/gpxe/src/arch/i386/prefix/lmelf_prefix.S b/gpxe/src/arch/i386/prefix/lmelf_prefix.S
deleted file mode 100644
index 3c1e7251..00000000
--- a/gpxe/src/arch/i386/prefix/lmelf_prefix.S
+++ /dev/null
@@ -1,161 +0,0 @@
-#include "elf.h"
- .arch sledgehammer
- .code32
- .equ FLAT_CODE_SEG,_pmcs-_gdt
- .equ FLAT_DATA_SEG,_pmds-_gdt
- .equ MSR_K6_EFER, 0xC0000080
- .equ EFER_LME, 0x00000100
- .equ X86_CR4_PAE, 0x00000020
- .equ CR0_PG, 0x80000000
-
- .section ".prefix", "ax", @progbits
-
-#define LOAD_ADDR 0x10000
-
- /* ELF Header */
- .globl elf_header
-elf_header:
-e_ident: .byte 0x7f, 'E', 'L', 'F', 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
-e_type: .short ET_EXEC
-e_machine: .short EM_X86_64
-e_version: .long 1
-e_entry: .long LOAD_ADDR + elf_start - elf_header
-e_phoff: .long elf_program_header - elf_header
-e_shoff: .long 0
-e_flags: .long 0
-e_ehsize: .short elf_header_end - elf_header
-e_phentsize: .short ELF32_PHDR_SIZE
-e_phnum: .short (elf_program_header_end - elf_program_header)/ELF32_PHDR_SIZE
-e_shentsize: .short 0
-e_shnum: .short 0
-e_shstrndx: .short 0
-elf_header_end:
-
-elf_program_header:
-phdr1_p_type: .long PT_NOTE
-phdr1_p_offset: .long elf_note - elf_header
-phdr1_p_vaddr: .long elf_note
-phdr1_p_paddr: .long elf_note
-phdr1_p_filesz: .long elf_note_end - elf_note
-phdr1_p_memsz: .long elf_note_end - elf_note
-phdr1_p_flags: .long PF_R | PF_W | PF_X
-phdr1_p_align: .long 0
-
-/* The decompressor */
-phdr2_p_type: .long PT_LOAD
-phdr2_p_offset: .long 0
-phdr2_p_vaddr: .long elf_header
-phdr2_p_paddr: .long LOAD_ADDR
-phdr2_p_filesz: .long _verbatim_size
-phdr2_p_memsz: .long _image_size
-phdr2_p_flags: .long PF_R | PF_W | PF_X
-phdr2_p_align: .long 16
-
-elf_program_header_end:
-
- .globl elf_note
-elf_note:
- .balign 4
- .int 2f - 1f
- .int 4f - 3f
- .int EIN_PROGRAM_NAME
-1: .asciz "ELFBoot"
-2:
- .balign 4
-3:
- .asciz "Etherboot"
-4:
-
-
- .balign 4
- .int 2f - 1f
- .int 4f - 3f
- .int EIN_PROGRAM_VERSION
-1: .asciz "ELFBoot"
-2:
- .balign 4
-3:
- .asciz VERSION
-4:
-
-#if 0
- .balign 4
- .int 2f - 1f
- .int 4f - 3f
- .int EIN_PROGRAM_CHECKSUM
-1: .asciz "ELFBoot"
-2:
- .balign 4
-3:
- .word 0
-4:
-#endif
- .balign 4
-elf_note_end:
-
-elf_start:
- .code64
- /* Reload the gdt to something I know */
- leaq _gdt(%rip), %rax
- movq %rax, 0x02 + gdtptr(%rip)
- lgdt gdtptr(%rip)
-
- /* Enter 32bit compatibility mode */
- leaq elf_start32(%rip), %rax
- movl %eax, 0x00 + elf_start32_addr(%rip)
- ljmp *elf_start32_addr(%rip)
-
-elf_start32:
- .code32
- /* Reload the data segments */
- movl $FLAT_DATA_SEG, %eax
- movl %eax, %ds
- movl %eax, %es
- movl %eax, %ss
-
- /* Disable paging */
- movl %cr0, %eax
- andl $~CR0_PG, %eax
- movl %eax, %cr0
-
- /* Disable long mode */
- movl $MSR_K6_EFER, %ecx
- rdmsr
- andl $~EFER_LME, %eax
- wrmsr
-
- /* Disable PAE */
- movl %cr4, %eax
- andl $~X86_CR4_PAE, %eax
- movl %eax, %cr4
-
- /* Save the first argument */
- pushl %ebx
- jmp _start
-
-gdtptr:
- .word _gdt_end - _gdt -1
- .long _gdt
- .long 0
-_gdt:
-elf_start32_addr:
- .long elf_start32
- .long FLAT_CODE_SEG
-_pmcs:
- /* 32 bit protected mode code segment, base 0 */
- .word 0xffff,0
- .byte 0,0x9f,0xcf,0
-
-_pmds:
- /* 32 bit protected mode data segment, base 0 */
- .word 0xffff,0
- .byte 0,0x93,0xcf,0
-_gdt_end:
-
-
- /* Dummy routines to satisfy the build */
- .section ".text16", "ax", @progbits
-prefix_exit:
-
-prefix_exit_end:
- .previous
diff --git a/gpxe/src/arch/i386/prefix/nbiprefix.S b/gpxe/src/arch/i386/prefix/nbiprefix.S
index 4fb4acb1..607d80fb 100644
--- a/gpxe/src/arch/i386/prefix/nbiprefix.S
+++ b/gpxe/src/arch/i386/prefix/nbiprefix.S
@@ -30,16 +30,16 @@ segment_header:
.byte 0
.byte 0x04 /* Last segment */
.long 0x00007e00
-imglen: .long _filesz - 512
-memlen: .long _filesz - 512
+imglen: .long -512
+memlen: .long -512
.size segment_header, . - segment_header
.section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
- .ascii "SUBL"
+ .ascii "ADDL"
.long imglen
.long 1
.long 0
- .ascii "SUBL"
+ .ascii "ADDL"
.long memlen
.long 1
.long 0
diff --git a/gpxe/src/arch/i386/prefix/pxeprefix.S b/gpxe/src/arch/i386/prefix/pxeprefix.S
index b3b7947f..e728c482 100644
--- a/gpxe/src/arch/i386/prefix/pxeprefix.S
+++ b/gpxe/src/arch/i386/prefix/pxeprefix.S
@@ -1,8 +1,13 @@
+FILE_LICENCE ( GPL2_OR_LATER )
+
#define PXENV_UNDI_SHUTDOWN 0x0005
#define PXENV_UNDI_GET_NIC_TYPE 0x0012
+#define PXENV_UNDI_GET_IFACE_INFO 0x0013
#define PXENV_STOP_UNDI 0x0015
#define PXENV_UNLOAD_STACK 0x0070
+#define PXE_HACK_EB54 0x0001
+
.text
.arch i386
.org 0
@@ -11,6 +16,8 @@
#include <undi.h>
#define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) )
+#define EB_MAGIC_1 ( 'E' + ( 't' << 8 ) + ( 'h' << 16 ) + ( 'e' << 24 ) )
+#define EB_MAGIC_2 ( 'r' + ( 'b' << 8 ) + ( 'o' << 16 ) + ( 'o' << 24 ) )
/*****************************************************************************
* Entry point: set operating context, print welcome message
@@ -105,20 +112,13 @@ have_pxenv:
/* Record entry point and UNDI segments */
pushl %es:0x0a(%bx) /* Entry point */
- popl entry_segoff
pushw %es:0x24(%bx) /* UNDI code segment */
pushw %es:0x26(%bx) /* UNDI code size */
- popl undi_code_segoff
pushw %es:0x20(%bx) /* UNDI data segment */
pushw %es:0x22(%bx) /* UNDI data size */
- popl undi_data_segoff
/* Print "PXENV+ at <address>" */
movw $10f, %si
- call print_message
- call print_segoff
- movb $( ',' ), %al
- call print_character
jmp check_have_stack
.section ".prefix.data", "aw", @progbits
10: .asciz " PXENV+ at "
@@ -129,19 +129,13 @@ have_ppxe:
movw %es, ppxe_segment
pushl %es:0x10(%bx) /* Entry point */
- popl entry_segoff
pushw %es:0x30(%bx) /* UNDI code segment */
pushw %es:0x36(%bx) /* UNDI code size */
- popl undi_code_segoff
pushw %es:0x28(%bx) /* UNDI data segment */
pushw %es:0x2e(%bx) /* UNDI data size */
- popl undi_data_segoff
+
/* Print "!PXE at <address>" */
movw $10f, %si
- call print_message
- call print_segoff
- movb $( ',' ), %al
- call print_character
jmp check_have_stack
.section ".prefix.data", "aw", @progbits
10: .asciz " !PXE at "
@@ -201,6 +195,17 @@ memory_scan_common:
*****************************************************************************
*/
check_have_stack:
+ /* Save common values pushed onto the stack */
+ popl undi_data_segoff
+ popl undi_code_segoff
+ popl entry_segoff
+
+ /* Print have !PXE/PXENV+ message; structure pointer in %es:%bx */
+ call print_message
+ call print_segoff
+ movb $( ',' ), %al
+ call print_character
+
/* Check for entry point */
movl entry_segoff, %eax
testl %eax, %eax
@@ -309,8 +314,6 @@ pci_physical_device:
movw $10f, %si
call print_message
call print_pci_busdevfn
- movb $0x0a, %al
- call print_character
jmp 99f
.section ".prefix.data", "aw", @progbits
10: .asciz " UNDI device is PCI "
@@ -321,12 +324,47 @@ no_physical_device:
movw $10f, %si
call print_message
.section ".prefix.data", "aw", @progbits
-10: .asciz " Unable to determine UNDI physical device\n"
+10: .asciz " Unable to determine UNDI physical device"
.previous
99:
/*****************************************************************************
+ * Determine interface type
+ *****************************************************************************
+ */
+get_iface_type:
+ /* Issue PXENV_UNDI_GET_IFACE_INFO */
+ movw $PXENV_UNDI_GET_IFACE_INFO, %bx
+ call pxe_call
+ jnc 1f
+ call print_pxe_error
+ jmp 99f
+1: /* Print interface type */
+ movw $10f, %si
+ call print_message
+ leaw ( pxe_parameter_structure + 0x02 ), %si
+ call print_message
+ .section ".prefix.data", "aw", @progbits
+10: .asciz ", type "
+ .previous
+ /* Check for "Etherboot" interface type */
+ cmpl $EB_MAGIC_1, ( pxe_parameter_structure + 0x02 )
+ jne 99f
+ cmpl $EB_MAGIC_2, ( pxe_parameter_structure + 0x06 )
+ jne 99f
+ movw $10f, %si
+ call print_message
+ .section ".prefix.data", "aw", @progbits
+10: .asciz " (workaround enabled)"
+ .previous
+ /* Flag Etherboot workarounds as required */
+ orw $PXE_HACK_EB54, pxe_hacks
+
+99: movb $0x0a, %al
+ call print_character
+
+/*****************************************************************************
* Leave NIC in a safe state
*****************************************************************************
*/
@@ -339,6 +377,14 @@ shutdown_nic:
call print_pxe_error
1:
unload_base_code:
+ /* Etherboot treats PXENV_UNLOAD_STACK as PXENV_STOP_UNDI, so
+ * we must not issue this call if the underlying stack is
+ * Etherboot and we were not intending to issue a PXENV_STOP_UNDI.
+ */
+#ifdef PXELOADER_KEEP_UNDI
+ testw $PXE_HACK_EB54, pxe_hacks
+ jnz 99f
+#endif /* PXELOADER_KEEP_UNDI */
/* Issue PXENV_UNLOAD_STACK */
movw $PXENV_UNLOAD_STACK, %bx
call pxe_call
@@ -551,7 +597,9 @@ pxe_call:
testw %ax, %ax
jz 1f
stc
-1: /* Restore registers and return */
+1: /* Clear direction flag, for the sake of sanity */
+ cld
+ /* Restore registers and return */
popw %es
popw %di
ret
@@ -595,7 +643,7 @@ print_pxe_error:
pxe_esp: .long 0
pxe_ss: .word 0
-pxe_parameter_structure: .fill 20
+pxe_parameter_structure: .fill 64
undi_code_segoff:
undi_code_size: .word 0
@@ -605,6 +653,8 @@ undi_data_segoff:
undi_data_size: .word 0
undi_data_segment: .word 0
+pxe_hacks: .word 0
+
/* The following fields are part of a struct undi_device */
undi_device:
@@ -668,6 +718,13 @@ run_gpxe:
lret
.section ".text16", "ax", @progbits
1:
+ /* Update the exit hook */
+ movw %cs,pxe_exit_hook+2
+ push %ax
+ mov $2f,%ax
+ mov %ax,pxe_exit_hook
+ pop %ax
+
/* Run main program */
pushl $main
pushw %cs
@@ -681,7 +738,10 @@ run_gpxe:
movw %di, %ss
movl %ebp, %esp
- /* Check PXE stack magic */
+ /* Jump to hook if applicable */
+ ljmpw *pxe_exit_hook
+
+2: /* Check PXE stack magic */
popl %eax
cmpl $STACK_MAGIC, %eax
jne 1f
diff --git a/gpxe/src/arch/i386/prefix/romprefix.S b/gpxe/src/arch/i386/prefix/romprefix.S
index 7d532375..02e54976 100644
--- a/gpxe/src/arch/i386/prefix/romprefix.S
+++ b/gpxe/src/arch/i386/prefix/romprefix.S
@@ -6,6 +6,8 @@
* table so using a noticeable amount of stack space is a no-no.
*/
+FILE_LICENCE ( GPL2_OR_LATER )
+
#include <config/general.h>
#define PNP_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'n' << 16 ) + ( 'P' << 24 ) )
@@ -23,6 +25,19 @@
*/
#define ROM_BANNER_TIMEOUT ( 2 * ( 18 * BANNER_TIMEOUT ) / 10 )
+/* We can load a ROM in two ways: have the BIOS load all of it (.rom prefix)
+ * or have the BIOS load a stub that loads the rest using PCI (.xrom prefix).
+ * The latter is not as widely supported, but allows the use of large ROMs
+ * on some systems with crowded option ROM space.
+ */
+
+#ifdef LOAD_ROM_FROM_PCI
+#define ROM_SIZE_VALUE _prefix_filesz_sect /* Amount to load in BIOS */
+#else
+#define ROM_SIZE_VALUE 0 /* Load amount (before compr. fixup) */
+#endif
+
+
.text
.code16
.arch i386
@@ -31,10 +46,12 @@
.org 0x00
romheader:
.word 0xAA55 /* BIOS extension signature */
-romheader_size: .byte _filesz_sect /* Size in 512-byte blocks */
+romheader_size: .byte ROM_SIZE_VALUE /* Size in 512-byte blocks */
jmp init /* Initialisation vector */
checksum:
- .byte 0
+ .byte 0, 0
+real_size:
+ .word 0
.org 0x16
.word undiheader
.org 0x18
@@ -42,12 +59,18 @@ checksum:
.org 0x1a
.word pnpheader
.size romheader, . - romheader
-
+
.section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
- .ascii "SUBB"
+#ifndef LOAD_ROM_FROM_PCI
+ .ascii "ADDB"
.long romheader_size
.long 512
.long 0
+#endif
+ .ascii "ADDB"
+ .long real_size
+ .long 512
+ .long 0
.previous
pciheader:
@@ -59,27 +82,29 @@ pciheader:
.byte 0x03 /* PCI data structure revision */
.byte 0x02, 0x00, 0x00 /* Class code */
pciheader_image_length:
- .word _filesz_sect /* Image length */
+ .word ROM_SIZE_VALUE /* Image length */
.word 0x0001 /* Revision level */
.byte 0x00 /* Code type */
.byte 0x80 /* Last image indicator */
pciheader_runtime_length:
- .word _filesz_sect /* Maximum run-time image length */
+ .word ROM_SIZE_VALUE /* Maximum run-time image length */
.word 0x0000 /* Configuration utility code header */
.word 0x0000 /* DMTF CLP entry point */
.equ pciheader_len, . - pciheader
.size pciheader, . - pciheader
-
+
+#ifndef LOAD_ROM_FROM_PCI
.section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
- .ascii "SUBW"
+ .ascii "ADDW"
.long pciheader_image_length
.long 512
.long 0
- .ascii "SUBW"
+ .ascii "ADDW"
.long pciheader_runtime_length
.long 512
.long 0
.previous
+#endif
pnpheader:
.ascii "$PnP" /* Signature */
@@ -124,6 +149,7 @@ prodstr_pci_id:
.size prodstr, . - prodstr
.globl undiheader
+ .weak undiloader
undiheader:
.ascii "UNDI" /* Signature */
.byte undiheader_len /* Length of structure */
@@ -172,6 +198,11 @@ init:
call print_message
call print_pci_busdevfn
+#ifdef LOAD_ROM_FROM_PCI
+ /* Save PCI bus:dev.fn for later use */
+ movw %ax, pci_busdevfn
+#endif
+
/* Fill in product name string, if possible */
movw $prodstr_pci_id, %di
call print_pci_busdevfn
@@ -196,6 +227,9 @@ init:
jne no_pci3
testb %ah, %ah
jnz no_pci3
+#ifdef LOAD_ROM_FROM_PCI
+ incb pcibios_present
+#endif
movw $init_message_pci, %si
xorw %di, %di
call print_message
@@ -236,24 +270,37 @@ no_pci3:
popl %edx
popl %ebx
- /* Check for PnP BIOS */
- testw $0x0f, %bx /* PnP signature must be aligned - bochs */
- jnz no_bbs /* uses unalignment to indicate 'fake' PnP. */
- cmpl $PNP_SIGNATURE, %es:0(%bx)
- jne no_bbs
+ /* Check for PnP BIOS. Although %es:di should point to the
+ * PnP BIOS signature on entry, some BIOSes fail to do this.
+ */
+ movw $( 0xf000 - 1 ), %bx
+pnp_scan:
+ incw %bx
+ jz no_pnp
+ movw %bx, %es
+ cmpl $PNP_SIGNATURE, %es:0
+ jne pnp_scan
+ xorw %dx, %dx
+ xorw %si, %si
+ movzbw %es:5, %cx
+1: es lodsb
+ addb %al, %dl
+ loop 1b
+ jnz pnp_scan
/* Is PnP: print PnP message */
movw $init_message_pnp, %si
xorw %di, %di
call print_message
/* Check for BBS */
- pushw %es:0x1b(%bx) /* Real-mode data segment */
+ pushw %es:0x1b /* Real-mode data segment */
pushw %ds /* &(bbs_version) */
pushw $bbs_version
pushw $PNP_GET_BBS_VERSION
- lcall *%es:0xd(%bx)
+ lcall *%es:0xd
addw $8, %sp
testw %ax, %ax
je got_bbs
+no_pnp: /* Not PnP-compliant - therefore cannot be BBS-compliant */
no_bbs: /* Not BBS-compliant - must hook INT 19 */
movw $init_message_int19, %si
xorw %di, %di
@@ -294,7 +341,7 @@ pmm_scan:
/* We have PMM and so a 1kB stack: preserve upper register halves */
pushal
/* Calculate required allocation size in %esi */
- movzbl romheader_size, %eax
+ movzwl real_size, %eax
shll $9, %eax
addl $_textdata_memsz, %eax
orw $0xffff, %ax /* Ensure allocation size is at least 64kB */
@@ -336,6 +383,7 @@ got_pmm: /* PMM allocation succeeded */
call print_character
movw %si, %ax
call print_hex_byte
+pmm_copy:
/* Copy ROM to PMM block */
xorw %ax, %ax
movw %ax, %es
@@ -347,11 +395,43 @@ got_pmm: /* PMM allocation succeeded */
movl %edi, decompress_to
/* Shrink ROM */
movb $_prefix_memsz_sect, romheader_size
+#if defined(SHRINK_WITHOUT_PMM) || defined(LOAD_ROM_FROM_PCI)
+ jmp pmm_done
+pmm_fail:
+ /* Print marker and copy ourselves to high memory */
+ movl $HIGHMEM_LOADPOINT, image_source
+ xorw %di, %di
+ movb $( '!' ), %al
+ call print_character
+ jmp pmm_copy
+pmm_done:
+#else
pmm_fail:
+#endif
/* Restore upper register halves */
popal
+#if defined(LOAD_ROM_FROM_PCI)
+ call load_from_pci
+ jc load_err
+ jmp load_ok
no_pmm:
+ /* Cannot continue without PMM - print error message */
+ xorw %di, %di
+ movw $init_message_no_pmm, %si
+ call print_message
+load_err:
+ /* Wait for five seconds to let user see message */
+ movw $90, %cx
+1: call wait_for_tick
+ loop 1b
+ /* Mark environment as invalid and return */
+ movl $0, decompress_to
+ jmp out
+load_ok:
+#else
+no_pmm:
+#endif
/* Update checksum */
xorw %bx, %bx
xorw %si, %si
@@ -396,14 +476,14 @@ no_pmm:
movw $init_message_done, %si
call print_message
popf
- jnz 2f
+ jnz out
/* Ctrl-B was pressed: invoke gPXE. The keypress will be
* picked up by the initial shell prompt, and we will drop
* into a shell.
*/
pushw %cs
call exec
-2:
+out:
/* Restore registers */
popw %gs
popw %fs
@@ -450,6 +530,11 @@ init_message_bbs:
init_message_pmm:
.asciz " PMM"
.size init_message_pmm, . - init_message_pmm
+#ifdef LOAD_ROM_FROM_PCI
+init_message_no_pmm:
+ .asciz "\nPMM required but not present!\n"
+ .size init_message_no_pmm, . - init_message_no_pmm
+#endif
init_message_int19:
.asciz " INT19"
.size init_message_int19, . - init_message_int19
@@ -467,6 +552,7 @@ init_message_done:
*
* May be either within option ROM space, or within PMM-allocated block.
*/
+ .globl image_source
image_source:
.long 0
.size image_source, . - image_source
@@ -474,11 +560,32 @@ image_source:
/* Temporary decompression area
*
* May be either at HIGHMEM_LOADPOINT, or within PMM-allocated block.
+ * If a PCI ROM load fails, this will be set to zero.
*/
+ .globl decompress_to
decompress_to:
.long HIGHMEM_LOADPOINT
.size decompress_to, . - decompress_to
+#ifdef LOAD_ROM_FROM_PCI
+
+/* Set if the PCI BIOS is present, even <3.0 */
+pcibios_present:
+ .byte 0
+ .byte 0 /* for alignment */
+ .size pcibios_present, . - pcibios_present
+
+/* PCI bus:device.function word
+ *
+ * Filled in by init in the .xrom case, so the remainder of the ROM
+ * can be located.
+ */
+pci_busdevfn:
+ .word 0
+ .size pci_busdevfn, . - pci_busdevfn
+
+#endif
+
/* BBS version
*
* Filled in by BBS BIOS. We ignore the value.
@@ -497,6 +604,289 @@ bev_entry:
lret
.size bev_entry, . - bev_entry
+
+#ifdef LOAD_ROM_FROM_PCI
+
+#define PCI_ROM_ADDRESS 0x30 /* Bits 31:11 address, 10:1 reserved */
+#define PCI_ROM_ADDRESS_ENABLE 0x00000001
+#define PCI_ROM_ADDRESS_MASK 0xfffff800
+
+#define PCIBIOS_READ_WORD 0xb109
+#define PCIBIOS_READ_DWORD 0xb10a
+#define PCIBIOS_WRITE_WORD 0xb10c
+#define PCIBIOS_WRITE_DWORD 0xb10d
+
+/* Determine size of PCI BAR
+ *
+ * %bx : PCI bus:dev.fn to probe
+ * %di : Address of BAR to find size of
+ * %edx : Mask of address bits within BAR
+ *
+ * %ecx : Size for a memory resource,
+ * 1 for an I/O resource (bit 0 set).
+ * CF : Set on error or nonexistent device (all-ones read)
+ *
+ * All other registers saved.
+ */
+pci_bar_size:
+ /* Save registers */
+ pushw %ax
+ pushl %esi
+ pushl %edx
+
+ /* Read current BAR value */
+ movw $PCIBIOS_READ_DWORD, %ax
+ int $0x1a
+
+ /* Check for device existence and save it */
+ testb $1, %cl /* I/O bit? */
+ jz 1f
+ andl $1, %ecx /* If so, exit with %ecx = 1 */
+ jmp 99f
+1: notl %ecx
+ testl %ecx, %ecx /* Set ZF iff %ecx was all-ones */
+ notl %ecx
+ jnz 1f
+ stc /* All ones - exit with CF set */
+ jmp 99f
+1: movl %ecx, %esi /* Save in %esi */
+
+ /* Write all ones to BAR */
+ movl %edx, %ecx
+ movw $PCIBIOS_WRITE_DWORD, %ax
+ int $0x1a
+
+ /* Read back BAR */
+ movw $PCIBIOS_READ_DWORD, %ax
+ int $0x1a
+
+ /* Find decode size from least set bit in mask BAR */
+ bsfl %ecx, %ecx /* Find least set bit, log2(decode size) */
+ jz 1f /* Mask BAR should not be zero */
+ xorl %edx, %edx
+ incl %edx
+ shll %cl, %edx /* %edx = decode size */
+ jmp 2f
+1: xorl %edx, %edx /* Return zero size for mask BAR zero */
+
+ /* Restore old BAR value */
+2: movl %esi, %ecx
+ movw $PCIBIOS_WRITE_DWORD, %ax
+ int $0x1a
+
+ movl %edx, %ecx /* Return size in %ecx */
+
+ /* Restore registers and return */
+99: popl %edx
+ popl %esi
+ popw %ax
+ ret
+
+ .size pci_bar_size, . - pci_bar_size
+
+/* PCI ROM loader
+ *
+ * Called from init in the .xrom case to load the non-prefix code
+ * using the PCI ROM BAR.
+ *
+ * Returns with carry flag set on error. All registers saved.
+ */
+load_from_pci:
+ /*
+ * Use PCI BIOS access to config space. The calls take
+ *
+ * %ah : 0xb1 %al : function
+ * %bx : bus/dev/fn
+ * %di : config space address
+ * %ecx : value to write (for writes)
+ *
+ * %ecx : value read (for reads)
+ * %ah : return code
+ * CF : error indication
+ *
+ * All registers not used for return are preserved.
+ */
+
+ /* Save registers and set up %es for big real mode */
+ pushal
+ pushw %es
+ xorw %ax, %ax
+ movw %ax, %es
+
+ /* Check PCI BIOS presence */
+ cmpb $0, pcibios_present
+ jz err_pcibios
+
+ /* Load existing PCI ROM BAR */
+ movw $PCIBIOS_READ_DWORD, %ax
+ movw pci_busdevfn, %bx
+ movw $PCI_ROM_ADDRESS, %di
+ int $0x1a
+
+ /* Maybe it's already enabled? */
+ testb $PCI_ROM_ADDRESS_ENABLE, %cl
+ jz 1f
+ movb $1, %dl /* Flag indicating no deinit required */
+ movl %ecx, %ebp
+ jmp check_rom
+
+ /* Determine PCI BAR decode size */
+1: movl $PCI_ROM_ADDRESS_MASK, %edx
+ call pci_bar_size /* Returns decode size in %ecx */
+ jc err_size_insane /* CF => no ROM BAR, %ecx == ffffffff */
+
+ /* Check sanity of decode size */
+ xorl %eax, %eax
+ movw real_size, %ax
+ shll $9, %eax /* %eax = ROM size */
+ cmpl %ecx, %eax
+ ja err_size_insane /* Insane if decode size < ROM size */
+ cmpl $0x100000, %ecx
+ jae err_size_insane /* Insane if decode size >= 1MB */
+
+ /* Find a place to map the BAR
+ * In theory we should examine e820 and all PCI BARs to find a
+ * free region. However, we run at POST when e820 may not be
+ * available, and memory reads of an unmapped location are
+ * de facto standardized to return all-ones. Thus, we can get
+ * away with searching high memory (0xf0000000 and up) on
+ * multiples of the ROM BAR decode size for a sufficiently
+ * large all-ones region.
+ */
+ movl %ecx, %edx /* Save ROM BAR size in %edx */
+ movl $0xf0000000, %ebp
+ xorl %eax, %eax
+ notl %eax /* %eax = all ones */
+bar_search:
+ movl %ebp, %edi
+ movl %edx, %ecx
+ shrl $2, %ecx
+ addr32 repe scasl /* Scan %es:edi for anything not all-ones */
+ jz bar_found
+ addl %edx, %ebp
+ testl $0x80000000, %ebp
+ jz err_no_bar
+ jmp bar_search
+
+bar_found:
+ movl %edi, %ebp
+ /* Save current BAR value on stack to restore later */
+ movw $PCIBIOS_READ_DWORD, %ax
+ movw $PCI_ROM_ADDRESS, %di
+ int $0x1a
+ pushl %ecx
+
+ /* Map the ROM */
+ movw $PCIBIOS_WRITE_DWORD, %ax
+ movl %ebp, %ecx
+ orb $PCI_ROM_ADDRESS_ENABLE, %cl
+ int $0x1a
+
+ xorb %dl, %dl /* %dl = 0 : ROM was not already mapped */
+check_rom:
+ /* Check and copy ROM - enter with %dl set to skip unmapping,
+ * %ebp set to mapped ROM BAR address.
+ * We check up to prodstr_separator for equality, since anything past
+ * that may have been modified. Since our check includes the checksum
+ * byte over the whole ROM stub, that should be sufficient.
+ */
+ xorb %dh, %dh /* %dh = 0 : ROM did not fail integrity check */
+
+ /* Verify ROM integrity */
+ xorl %esi, %esi
+ movl %ebp, %edi
+ movl $prodstr_separator, %ecx
+ addr32 repe cmpsb
+ jz copy_rom
+ incb %dh /* ROM failed integrity check */
+ movl %ecx, %ebp /* Save number of bytes left */
+ jmp skip_load
+
+copy_rom:
+ /* Print BAR address and indicate whether we mapped it ourselves */
+ movb $( ' ' ), %al
+ xorw %di, %di
+ call print_character
+ movl %ebp, %eax
+ call print_hex_dword
+ movb $( '-' ), %al /* '-' for self-mapped */
+ subb %dl, %al
+ subb %dl, %al /* '+' = '-' - 2 for BIOS-mapped */
+ call print_character
+
+ /* Copy ROM at %ebp to PMM or highmem block */
+ movl %ebp, %esi
+ movl image_source, %edi
+ movzwl real_size, %ecx
+ shll $9, %ecx
+ addr32 es rep movsb
+ movl %edi, decompress_to
+skip_load:
+ testb %dl, %dl /* Was ROM already mapped? */
+ jnz skip_unmap
+
+ /* Unmap the ROM by restoring old ROM BAR */
+ movw $PCIBIOS_WRITE_DWORD, %ax
+ movw $PCI_ROM_ADDRESS, %di
+ popl %ecx
+ int $0x1a
+
+skip_unmap:
+ /* Error handling */
+ testb %dh, %dh
+ jnz err_rom_invalid
+ clc
+ jmp 99f
+
+err_pcibios: /* No PCI BIOS available */
+ movw $load_message_no_pcibios, %si
+ xorl %eax, %eax /* "error code" is zero */
+ jmp 1f
+err_size_insane: /* BAR has size (%ecx) that is insane */
+ movw $load_message_size_insane, %si
+ movl %ecx, %eax
+ jmp 1f
+err_no_bar: /* No space of sufficient size (%edx) found */
+ movw $load_message_no_bar, %si
+ movl %edx, %eax
+ jmp 1f
+err_rom_invalid: /* Loaded ROM does not match (%ebp bytes left) */
+ movw $load_message_rom_invalid, %si
+ movzbl romheader_size, %eax
+ shll $9, %eax
+ subl %ebp, %eax
+ decl %eax /* %eax is now byte index of failure */
+
+1: /* Error handler - print message at %si and dword in %eax */
+ xorw %di, %di
+ call print_message
+ call print_hex_dword
+ stc
+99: popw %es
+ popal
+ ret
+
+ .size load_from_pci, . - load_from_pci
+
+load_message_no_pcibios:
+ .asciz "\nNo PCI BIOS found! "
+ .size load_message_no_pcibios, . - load_message_no_pcibios
+
+load_message_size_insane:
+ .asciz "\nROM resource has invalid size "
+ .size load_message_size_insane, . - load_message_size_insane
+
+load_message_no_bar:
+ .asciz "\nNo memory hole of sufficient size "
+ .size load_message_no_bar, . - load_message_no_bar
+
+load_message_rom_invalid:
+ .asciz "\nLoaded ROM is invalid at "
+ .size load_message_rom_invalid, . - load_message_rom_invalid
+
+#endif /* LOAD_ROM_FROM_PCI */
+
+
/* INT19 entry point
*
* Called via the hooked INT 19 if we detected a non-PnP BIOS. We
@@ -557,6 +947,14 @@ exec: /* Set %ds = %cs */
pushw %cs
popw %ds
+#ifdef LOAD_ROM_FROM_PCI
+ /* Don't execute if load was invalid */
+ cmpl $0, decompress_to
+ jne 1f
+ lret
+1:
+#endif
+
/* Print message as soon as possible */
movw $prodstr, %si
xorw %di, %di
@@ -616,50 +1014,6 @@ exec_message:
.asciz " starting execution\n"
.size exec_message, . - exec_message
-/* UNDI loader
- *
- * Called by an external program to load our PXE stack.
- */
-undiloader:
- /* Save registers */
- pushl %esi
- pushl %edi
- pushw %ds
- pushw %es
- pushw %bx
- /* ROM segment address to %ds */
- pushw %cs
- popw %ds
- /* UNDI loader parameter structure address into %es:%di */
- movw %sp, %bx
- movw %ss:18(%bx), %di
- movw %ss:20(%bx), %es
- /* Install to specified real-mode addresses */
- pushw %di
- movw %es:12(%di), %bx
- movw %es:14(%di), %ax
- movl image_source, %esi
- movl decompress_to, %edi
- call install_prealloc
- popw %di
- /* Call UNDI loader C code */
- pushl $pxe_loader_call
- pushw %cs
- pushw $1f
- pushw %ax
- pushw $prot_call
- lret
-1: popw %bx /* discard */
- popw %bx /* discard */
- /* Restore registers and return */
- popw %bx
- popw %es
- popw %ds
- popl %edi
- popl %esi
- lret
- .size undiloader, . - undiloader
-
/* Wait for key press specified by %bl (masked by %bh)
*
* Used by init and INT19 code when prompting user. If the specified
diff --git a/gpxe/src/arch/i386/prefix/undiloader.S b/gpxe/src/arch/i386/prefix/undiloader.S
new file mode 100644
index 00000000..36c1bef3
--- /dev/null
+++ b/gpxe/src/arch/i386/prefix/undiloader.S
@@ -0,0 +1,49 @@
+ .text
+ .code16
+ .arch i386
+ .section ".prefix", "ax", @progbits
+
+/* UNDI loader
+ *
+ * Called by an external program to load our PXE stack.
+ */
+ .globl undiloader
+undiloader:
+ /* Save registers */
+ pushl %esi
+ pushl %edi
+ pushw %ds
+ pushw %es
+ pushw %bx
+ /* ROM segment address to %ds */
+ pushw %cs
+ popw %ds
+ /* UNDI loader parameter structure address into %es:%di */
+ movw %sp, %bx
+ movw %ss:18(%bx), %di
+ movw %ss:20(%bx), %es
+ /* Install to specified real-mode addresses */
+ pushw %di
+ movw %es:12(%di), %bx
+ movw %es:14(%di), %ax
+ movl image_source, %esi
+ movl decompress_to, %edi
+ call install_prealloc
+ popw %di
+ /* Call UNDI loader C code */
+ pushl $pxe_loader_call
+ pushw %cs
+ pushw $1f
+ pushw %ax
+ pushw $prot_call
+ lret
+1: popw %bx /* discard */
+ popw %bx /* discard */
+ /* Restore registers and return */
+ popw %bx
+ popw %es
+ popw %ds
+ popl %edi
+ popl %esi
+ lret
+ .size undiloader, . - undiloader
diff --git a/gpxe/src/arch/i386/prefix/unnrv2b.S b/gpxe/src/arch/i386/prefix/unnrv2b.S
index 70167a14..f5724c13 100644
--- a/gpxe/src/arch/i386/prefix/unnrv2b.S
+++ b/gpxe/src/arch/i386/prefix/unnrv2b.S
@@ -20,6 +20,8 @@
* Michael Brown 9 Mar 2005
*/
+FILE_LICENCE ( GPL2_OR_LATER )
+
/****************************************************************************
* This file provides the decompress() and decompress16() functions
* which can be called in order to decompress an image compressed with
diff --git a/gpxe/src/arch/i386/prefix/unnrv2b16.S b/gpxe/src/arch/i386/prefix/unnrv2b16.S
new file mode 100644
index 00000000..b24c2846
--- /dev/null
+++ b/gpxe/src/arch/i386/prefix/unnrv2b16.S
@@ -0,0 +1,9 @@
+/*
+ * 16-bit version of the decompressor
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER )
+
+#define CODE16
+#include "unnrv2b.S"
diff --git a/gpxe/src/arch/i386/prefix/xromprefix.S b/gpxe/src/arch/i386/prefix/xromprefix.S
new file mode 100644
index 00000000..d7c861f5
--- /dev/null
+++ b/gpxe/src/arch/i386/prefix/xromprefix.S
@@ -0,0 +1,9 @@
+/*
+ * ROM prefix that loads the bulk of the ROM using direct PCI accesses,
+ * so as not to take up much option ROM space on PCI <3.0 systems.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER )
+
+#define LOAD_ROM_FROM_PCI
+#include "romprefix.S"