david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

[PXE] Add PMM support to romprefix.S (untested)

ROM initialisation vector now attempts to allocate a 2MB block using
PMM.  If successful, it copies the ROM image to this block, then
shrinks the ROM image to allow for more option ROMs.  If unsuccessful,
it leaves the ROM as-is.

ROM BEV now attempts to return to the BIOS, resorting to INT 18 only
if the BIOS stack has been corrupted.
This commit is contained in:
Michael Brown 2008-03-09 22:13:07 +00:00
parent fad35829eb
commit 12f203c606
3 changed files with 246 additions and 76 deletions

View File

@ -17,6 +17,10 @@
*
*/
.arch i386
.section ".prefix.lib", "awx", @progbits
.section ".data16", "aw", @progbits
/**
* High memory temporary load address
*
@ -27,25 +31,18 @@
* We use the start of an even megabyte so that we don't have to worry
* about the current state of the A20 line.
*
* We use 4MB rather than 2MB because there is at least one commercial
* PXE ROM ("Broadcom UNDI, PXE-2.1 (build 082) v2.0.4") which stores
* data required by the UNDI ROM loader (yes, the ROM loader; that's
* the component which should be impossible to damage short of
* screwing with the MMU) around the 2MB mark. Sadly, this is not a
* joke.
*
* We use 4MB rather than 2MB because some PXE stack / PMM BIOS
* combinations are known to place data required by other UNDI ROMs
* loader around the 2MB mark.
*/
#define HIGHMEM_LOADPOINT ( 4 << 20 )
.globl HIGHMEM_LOADPOINT
.equ HIGHMEM_LOADPOINT, ( 4 << 20 )
/* Image compression enabled */
#define COMPRESS 1
#define CR0_PE 1
.arch i386
.section ".prefix.lib", "awx", @progbits
.section ".data16", "aw", @progbits
/****************************************************************************
* pm_call (real-mode near call)
*
@ -223,12 +220,15 @@ copy_bytes:
* Returns:
* %ds:esi : next source address (will be a multiple of 16)
* Corrupts:
* %edi, %ecx, %edx
* %ecx, %edx
****************************************************************************
*/
.section ".prefix.lib"
.code16
install_block:
/* Preserve registers */
pushl %edi
#if COMPRESS
/* Decompress source to destination */
call decompress16
@ -249,6 +249,8 @@ install_block:
addl $0xf, %esi
andl $~0xf, %esi
/* Restore registers and return */
popl %edi
ret
.size install_block, . - install_block
@ -270,6 +272,7 @@ install_block:
*/
.section ".prefix.lib"
.code16
.globl alloc_basemem
alloc_basemem:
/* FBMS => %ax as segment address */
movw $0x40, %ax
@ -308,13 +311,14 @@ alloc_basemem:
* Returns:
* %esi : next source physical address (will be a multiple of 16)
* Corrupts:
* %edi, %ecx, %edx
* %ecx, %edx
****************************************************************************
*/
.section ".prefix.lib"
.code16
install_basemem:
/* Preserve registers */
pushl %edi
pushw %ds
/* Preserve original %esi */
@ -335,6 +339,7 @@ install_basemem:
/* Restore registers */
popw %ds
popl %edi
ret
.size install_basemem, . - install_basemem
@ -351,7 +356,7 @@ install_basemem:
* Returns:
* %esi : next source physical address (will be a multiple of 16)
* Corrupts:
* %edi, %ecx, %edx
* %ecx, %edx
****************************************************************************
*/
@ -376,17 +381,14 @@ install_highmem:
/****************************************************************************
* install (real-mode near call)
* install_prealloc (real-mode near call)
*
* Install all text and data segments.
*
* Parameters:
* %ax : .text16 segment address (install_prealloc only)
* %bx : .data16 segment address (install_prealloc only)
* none
* Returns:
* %ax : .text16 segment address
* %bx : .data16 segment address
* %edi : .text physical address (if applicable)
* %ax : .text16 segment address
* %bx : .data16 segment address
* Corrupts:
* none
****************************************************************************
@ -395,26 +397,55 @@ install_highmem:
.code16
.globl install
install:
/* Preserve registers */
pushl %esi
pushl %edi
/* Allocate space for .text16 and .data16 */
call alloc_basemem
/* Image source = %cs:0000 */
xorl %esi, %esi
/* Image destination = HIGHMEM_LOADPOINT */
movl $HIGHMEM_LOADPOINT, %edi
/* Install text and data segments */
call install_prealloc
/* Restore registers and return */
popl %edi
popl %esi
ret
.size install, . - install
/****************************************************************************
* install_prealloc (real-mode near call)
*
* Install all text and data segments.
*
* Parameters:
* %ax : .text16 segment address
* %bx : .data16 segment address
* %esi : Image source physical address (or zero for %cs:0000)
* %edi : Decompression temporary area physical address
* Corrupts:
* none
****************************************************************************
*/
.section ".prefix.lib"
.code16
.globl install_prealloc
install_prealloc:
/* Save registers */
pushal
pushw %ds
pushw %es
pushl %esi
pushl %ecx
pushl %edx
/* Sanity: clear the direction flag asap */
cld
/* Calculate physical address of payload (i.e. first source) */
xorl %esi, %esi
testl %esi, %esi
jnz 1f
movw %cs, %si
shll $4, %esi
addl $_payload_offset, %esi
1: addl $_payload_offset, %esi
/* Install .text16 */
movw %ax, %es
@ -440,7 +471,6 @@ install_prealloc:
* prior to reading the E820 memory map and relocating
* properly.
*/
movl $HIGHMEM_LOADPOINT, %edi
movl $_textdata_progbits_size, %ecx
movl $_textdata_size, %edx
pushl %edi
@ -473,11 +503,9 @@ install_prealloc:
#endif
/* Restore registers */
popl %edx
popl %ecx
popl %esi
popw %es
popw %ds
popal
ret
.size install_prealloc, . - install_prealloc

View File

@ -6,6 +6,10 @@
* table so using a noticeable amount of stack space is a no-no.
*/
#define PNP_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'n' << 16 ) + ( 'P' << 24 ) )
#define PMM_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'M' << 16 ) + ( 'M' << 24 ) )
#define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) )
.text
.code16
.arch i386
@ -15,7 +19,9 @@
romheader:
.word 0xAA55 /* BIOS extension signature */
romheader_size: .byte _load_size_sect /* Size in 512-byte blocks */
jmp init_vector /* Initialisation vector */
jmp init /* Initialisation vector */
checksum:
.byte 0
.org 0x16
.word undiheader
.org 0x18
@ -72,7 +78,7 @@ pnpheader:
.byte 0x54 /* Device indicator */
.word 0x0000 /* Boot connection vector */
.word 0x0000 /* Disconnect vector */
.word exec_vector /* Boot execution vector */
.word bev_entry /* Boot execution vector */
.word 0x0000 /* Reserved */
.word 0x0000 /* Static resource information vector*/
.equ pnpheader_len, . - pnpheader
@ -98,60 +104,180 @@ undiheader:
.equ undiheader_len, . - undiheader
.size undiheader, . - undiheader
/* Initialisation vector
/* Initialisation (called once during POST)
*
* Determine whether or not this is a PnP system via a signature
* check. If it is PnP, return to the PnP BIOS indicating that we are
* a boot-capable device; the BIOS will call our boot execution vector
* if it wants to boot us. If it is not PnP, hook INT 19.
*/
init_vector:
pushw %si
cmpw $'$'+'P'*256, %es:0(%di)
jne notpnp
cmpw $'n'+'P'*256, %es:2(%di)
jne notpnp
ispnp:
movw $ispnp_message, %si
jmp 99f
notpnp:
init:
/* Preserve registers, clear direction flag, set %ds=%cs */
pushaw
pushw %ds
pushw $0
popw %ds
pushw %es
cld
pushw %cs
pushw $exec_vector
popl ( 0x19 * 4 )
popw %ds
movw $notpnp_message, %si
99:
/* Print message as early as possible */
movw $init_message, %si
call print_message
movw $0x20, %ax
popw %si
lret
.size init_vector, . - init_vector
ispnp_message:
.asciz "gPXE detected PnP BIOS\r\n"
.size ispnp_message, . - ispnp_message
notpnp_message:
.asciz "gPXE detected non-PnP BIOS\r\n"
.size notpnp_message, . - notpnp_message
/* Boot execution vector
*pciheader_size
* Called by the PnP BIOS when it wants to boot us, or via the hooked
* INT 19 if we detected a non-PnP BIOS.
*/
exec_vector:
/* Obtain a reasonably-sized stack */
/* Check for PnP BIOS */
cmpl $PNP_SIGNATURE, %es:0(%di)
je ispnp
notpnp: /* Not PnP: hook INT19 */
xorw %ax, %ax
movw %ax, %ss
movw $0x7c00, %sp
movw %ax, %es
pushw %cs
pushw $int19_entry
popl %es:( 0x19 * 4 )
jmp 99f
ispnp: /* Is PnP: print PnP message */
movw $init_message_pnp, %si
call print_message
/* Check for PMM */
movw $( 0xe000 - 1 ), %di
pmm_scan:
incw %di
jz 99f
movw %di, %es
cmpl $PMM_SIGNATURE, %es:0
jne pmm_scan
xorw %bx, %bx
xorw %si, %si
movzbw %es:5, %cx
1: es lodsb
addb %al, %bl
loop 1b
jnz pmm_scan
/* PMM found: print PMM message */
movw $init_message_pmm, %si
call print_message
/* Try to allocate 2MB block via PMM */
pushw $0x0006 /* Aligned, extended memory */
pushl $0xffffffff /* No handle */
pushl $( 0x00200000 / 16 ) /* 2MB in paragraphs */
pushw $0x0000 /* pmmAllocate */
lcall %es:*(7)
addw $12, %sp
testw %dx, %dx /* %ax==0 even on success, since align=2MB */
jnz gotpmm
movw $init_message_pmm_failed, %si
call print_message
jmp 99f
gotpmm: /* PMM allocation succeeded: copy ROM to PMM block */
pushal /* PMM presence implies 1kB stack */
movw %ax, %es /* %ax=0 already - see above */
pushw %dx
pushw %ax
popl %edi
movl %edi, image_source
xorl %esi, %esi
movzbl romheader_size, %ecx
shll $9, %ecx
addr32 rep movsb /* PMM presence implies flat real mode */
movl %edi, decompress_to
/* Shrink ROM and update checksum */
xorw %bx, %bx
xorw %si, %si
movb $_prefix_size_sect, romheader_size
shlw $9, %cx
1: lodsb
addb %al, %bl
loop 1b
subb %bl, checksum
popal
99:
/* Print CRLF to terminate messages */
movw $init_message_crlf, %si
call print_message
/* Restore registers */
popw %es
popw %ds
popaw
/* Indicate boot capability to PnP BIOS, if present */
movw $0x20, %ax
lret
.size init, . - init
init_message:
.asciz "gPXE (http://etherboot.org)"
.size init_message, . - init_message
init_message_pnp:
.asciz " - PnP BIOS detected"
.size init_message_pnp, . - init_message_pnp
init_message_pmm:
.asciz ", using PMM"
.size init_message_pmm, . - init_message_pmm
init_message_pmm_failed:
.asciz " (failed)"
.size init_message_pmm_failed, . - init_message_pmm_failed
init_message_crlf:
.asciz "\r\n"
.size init_message_crlf, . - init_message_crlf
/* ROM image location
*
* May be either within option ROM space, or within PMM-allocated block.
*/
image_source:
.long 0
.size image_source, . - image_source
/* Temporary decompression area
*
* May be either at HIGHMEM_LOADPOINT, or within PMM-allocated block.
*/
decompress_to:
.long HIGHMEM_LOADPOINT
.size decompress_to, . - decompress_to
/* 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
/* INT19 entry point
*
* Called via the hooked INT 19 if we detected a non-PnP BIOS.
*/
int19_entry:
pushw %cs
call exec
/* No real way to return from INT19 */
int $0x18
.size int19_entry, . - int19_entry
/* Execute as a boot device
*
*/
exec: /* Set %ds = %cs */
pushw %cs
popw %ds
/* Print message as soon as possible */
movw $exec_message, %si
call print_message
call install
/* Store magic word on BIOS stack and remember BIOS %ss:sp */
pushl $STACK_MAGIC
movw %ss, %dx
movw %sp, %bp
/* Obtain a reasonably-sized temporary stack */
xorw %ax, %ax
movw %ax, %ss
movw $0x7c00, %sp
/* Install gPXE */
movl image_source, %esi
movl decompress_to, %edi
call alloc_basemem
call install_prealloc
/* Set up real-mode stack */
movw %bx, %ss
@ -162,13 +288,23 @@ exec_vector:
pushw $1f
lret
.section ".text16", "awx", @progbits
1:
1: /* Call main() */
pushl $main
pushw %cs
call prot_call
popl %eax /* discard */
/* No need to clean up stack; we are about to reload %ss:sp */
/* Restore BIOS stack */
movw %dx, %ss
movw %bp, %sp
/* Boot next device */
/* Check magic word on BIOS stack */
popl %eax
cmpl $STACK_MAGIC, %eax
jne 1f
/* BIOS stack OK: return to caller */
lret
1: /* BIOS stack corrupt: use INT 18 */
int $0x18
.previous
@ -182,6 +318,7 @@ exec_message:
*/
undiloader:
/* Save registers */
pushl %esi
pushl %edi
pushw %es
pushw %bx
@ -193,6 +330,8 @@ undiloader:
pushw %di
movw %es:12(%di), %bx
movw %es:14(%di), %ax
movl %cs:image_source, %esi
movl %cs:decompress_to, %edi
call install_prealloc
popw %di
/* Call UNDI loader C code */
@ -208,6 +347,7 @@ undiloader:
popw %bx
popw %es
popl %edi
popl %esi
lret
.size undiloader, . - undiloader
@ -218,7 +358,7 @@ print_message:
pushw %bx
pushw %bp
movw $0x0007, %bx
1: cs lodsb
1: lodsb
testb %al, %al
je 2f
movb $0x0e, %ah /* write char, tty mode */

View File

@ -257,6 +257,8 @@ SECTIONS {
/*
* Values calculated to save code from doing it
*/
_prefix_size_pgh = ( ( _prefix_size + 15 ) / 16 );
_prefix_size_sect = ( ( _prefix_size + 511 ) / 512 );
_text16_size_pgh = ( ( _text16_size + 15 ) / 16 );
_data16_size_pgh = ( ( _data16_size + 15 ) / 16 );