david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

Merge branch 'pxerom-pmm'

This commit is contained in:
Michael Brown 2008-03-11 16:11:51 +00:00
commit 08b19abf94
4 changed files with 492 additions and 315 deletions

View File

@ -17,6 +17,10 @@
* *
*/ */
.arch i386
.section ".prefix.lib", "awx", @progbits
.section ".data16", "aw", @progbits
/** /**
* High memory temporary load address * High memory temporary load address
* *
@ -27,24 +31,125 @@
* We use the start of an even megabyte so that we don't have to worry * We use the start of an even megabyte so that we don't have to worry
* about the current state of the A20 line. * about the current state of the A20 line.
* *
* We use 4MB rather than 2MB because there is at least one commercial * We use 4MB rather than 2MB because some PXE stack / PMM BIOS
* PXE ROM ("Broadcom UNDI, PXE-2.1 (build 082) v2.0.4") which stores * combinations are known to place data required by other UNDI ROMs
* data required by the UNDI ROM loader (yes, the ROM loader; that's * loader around the 2MB mark.
* the component which should be impossible to damage short of
* screwing with the MMU) around the 2MB mark. Sadly, this is not a
* joke.
*
*/ */
#define HIGHMEM_LOADPOINT ( 4 << 20 ) .globl HIGHMEM_LOADPOINT
.equ HIGHMEM_LOADPOINT, ( 4 << 20 )
/* Image compression enabled */ /* Image compression enabled */
#define COMPRESS 1 #define COMPRESS 1
#define CR0_PE 1 #define CR0_PE 1
.arch i386 /*****************************************************************************
.section ".prefix.lib", "awx", @progbits * Utility function: print character (with LF -> LF,CR translation)
.section ".data16", "aw", @progbits *
* Parameters:
* %al : character to print
* Returns:
* Nothing
* Corrupts:
* %ax
*****************************************************************************
*/
.section ".prefix.lib"
.code16
.globl print_character
print_character:
/* Preserve registers */
pushw %bx
pushw %bp
/* Print character */
movw $0x0007, %bx /* page 0, attribute 7 (normal) */
movb $0x0e, %ah /* write char, tty mode */
cmpb $0x0a, %al /* '\n'? */
jne 1f
int $0x10
movb $0x0d, %al
1: int $0x10
/* Restore registers and return */
popw %bp
popw %bx
ret
.size print_character, . - print_character
/*****************************************************************************
* Utility function: print a NUL-terminated string
*
* Parameters:
* %ds:si : string to print
* Returns:
* %ds:si : character after terminating NUL
*****************************************************************************
*/
.section ".prefix.lib"
.code16
.globl print_message
print_message:
/* Preserve registers */
pushw %ax
/* Print string */
1: lodsb
testb %al, %al
je 2f
call print_character
jmp 1b
2: /* Restore registers and return */
popw %ax
ret
.size print_message, . - print_message
/*****************************************************************************
* Utility functions: print hex digit/byte/word/dword
*
* Parameters:
* %al (low nibble) : digit to print
* %al : byte to print
* %ax : word to print
* %eax : dword to print
* Returns:
* Nothing
*****************************************************************************
*/
.section ".prefix.lib"
.code16
.globl print_hex_dword
print_hex_dword:
rorl $16, %eax
call print_hex_word
rorl $16, %eax
/* Fall through */
.size print_hex_dword, . - print_hex_dword
.globl print_hex_word
print_hex_word:
xchgb %al, %ah
call print_hex_byte
xchgb %al, %ah
/* Fall through */
.size print_hex_word, . - print_hex_word
.globl print_hex_byte
print_hex_byte:
rorb $4, %al
call print_hex_nibble
rorb $4, %al
/* Fall through */
.size print_hex_byte, . - print_hex_byte
.globl print_hex_nibble
print_hex_nibble:
/* Preserve registers */
pushw %ax
/* Print digit (technique by Norbert Juffa <norbert.juffa@amd.com> */
andb $0x0f, %al
cmpb $10, %al
sbbb $0x69, %al
das
call print_character
/* Restore registers and return */
popw %ax
ret
.size print_hex_nibble, . - print_hex_nibble
/**************************************************************************** /****************************************************************************
* pm_call (real-mode near call) * pm_call (real-mode near call)
@ -70,13 +175,14 @@
#ifndef KEEP_IT_REAL #ifndef KEEP_IT_REAL
/* GDT for protected-mode calls */ /* GDT for protected-mode calls */
.section ".data16" .section ".prefix.lib"
.align 16 .align 16
pm_call_vars:
gdt: gdt:
gdt_limit: .word gdt_length - 1 gdt_limit: .word gdt_length - 1
gdt_base: .long 0 gdt_base: .long 0
.word 0 /* padding */ .word 0 /* padding */
pm_cs: /* 16-bit protected-mode code segment */ pm_cs: /* 16-bit protected-mode code segment */
.equ PM_CS, pm_cs - gdt .equ PM_CS, pm_cs - gdt
.word 0xffff, 0 .word 0xffff, 0
.byte 0, 0x9b, 0x00, 0 .byte 0, 0x9b, 0x00, 0
@ -92,18 +198,24 @@ gdt_end:
.equ gdt_length, . - gdt .equ gdt_length, . - gdt
.size gdt, . - gdt .size gdt, . - gdt
.section ".data16" .section ".prefix.lib"
.align 16 .align 16
pm_saved_gdt: pm_saved_gdt:
.long 0, 0 .long 0, 0
.size pm_saved_gdt, . - pm_saved_gdt .size pm_saved_gdt, . - pm_saved_gdt
.equ pm_call_vars_size, . - pm_call_vars
#define PM_CALL_VAR(x) ( -pm_call_vars_size + ( (x) - pm_call_vars ) )
.section ".prefix.lib" .section ".prefix.lib"
.code16 .code16
pm_call: pm_call:
/* Preserve registers, flags, GDT, and RM return point */ /* Preserve registers, flags, and RM return point */
pushw %bp
movw %sp, %bp
subw $pm_call_vars_size, %sp
andw $0xfff0, %sp
pushfl pushfl
sgdt pm_saved_gdt
pushw %gs pushw %gs
pushw %fs pushw %fs
pushw %es pushw %es
@ -112,27 +224,43 @@ pm_call:
pushw %cs pushw %cs
pushw $99f pushw $99f
/* Set up local variable block, and preserve GDT */
pushw %cx
pushw %si
pushw %di
pushw %ss
popw %es
movw $pm_call_vars, %si
leaw PM_CALL_VAR(pm_call_vars)(%bp), %di
movw $pm_call_vars_size, %cx
cs rep movsb
popw %di
popw %si
popw %cx
sgdt PM_CALL_VAR(pm_saved_gdt)(%bp)
/* Set up GDT bases */ /* Set up GDT bases */
pushl %eax pushl %eax
pushw %bx pushl %edi
xorl %eax, %eax xorl %eax, %eax
movw %ds, %ax movw %ss, %ax
shll $4, %eax shll $4, %eax
addl $gdt, %eax movzwl %bp, %edi
movl %eax, gdt_base leal PM_CALL_VAR(gdt)(%eax, %edi), %eax
movl %eax, PM_CALL_VAR(gdt_base)(%bp)
movw %cs, %ax movw %cs, %ax
movw $pm_cs, %bx movw $PM_CALL_VAR(pm_cs), %di
call set_seg_base call set_seg_base
movw %ss, %ax movw %ss, %ax
movw $pm_ss, %bx movw $PM_CALL_VAR(pm_ss), %di
call set_seg_base call set_seg_base
popw %bx popl %edi
popl %eax popl %eax
/* Switch CPU to protected mode and load up segment registers */ /* Switch CPU to protected mode and load up segment registers */
pushl %eax pushl %eax
cli cli
lgdt gdt lgdt PM_CALL_VAR(gdt)(%bp)
movl %cr0, %eax movl %cr0, %eax
orb $CR0_PE, %al orb $CR0_PE, %al
movl %eax, %cr0 movl %eax, %cr0
@ -168,18 +296,19 @@ pm_call:
popw %es popw %es
popw %fs popw %fs
popw %gs popw %gs
lgdt pm_saved_gdt lgdt PM_CALL_VAR(pm_saved_gdt)(%bp)
popfl popfl
movw %bp, %sp
popw %bp
ret ret
.size pm_call, . - pm_call .size pm_call, . - pm_call
set_seg_base: set_seg_base:
rolw $4, %ax rolw $4, %ax
movw %ax, 2(%bx) movw %ax, 2(%bp,%di)
andw $0xfff0, 2(%bx) andw $0xfff0, 2(%bp,%di)
movb %al, 4(%bx) movb %al, 4(%bp,%di)
andb $0x0f, 4(%bx) andb $0x0f, 4(%bp,%di)
ret ret
.size set_seg_base, . - set_seg_base .size set_seg_base, . - set_seg_base
@ -196,7 +325,7 @@ set_seg_base:
* %ecx : length * %ecx : length
* Returns: * Returns:
* %ds:esi : next source address * %ds:esi : next source address
* %ds:esi : next destination address * %es:edi : next destination address
* Corrupts: * Corrupts:
* None * None
**************************************************************************** ****************************************************************************
@ -211,24 +340,57 @@ copy_bytes:
.size copy_bytes, . - copy_bytes .size copy_bytes, . - copy_bytes
/**************************************************************************** /****************************************************************************
* install_block (real-mode or 16-bit protected-mode near call) * install_block (real-mode near call)
* *
* Install block to specified address * Install block to specified address
* *
* Parameters: * Parameters:
* %ds:esi : source address (must be a multiple of 16) * %esi : source physical address (must be a multiple of 16)
* %es:edi : destination address * %edi : destination physical address (must be a multiple of 16)
* %ecx : length of (decompressed) data * %ecx : length of (decompressed) data
* %edx : total length of block (including any uninitialised data portion) * %edx : total length of block (including any uninitialised data portion)
* Returns: * Returns:
* %ds:esi : next source address (will be a multiple of 16) * %esi : next source physical address (will be a multiple of 16)
* Corrupts: * Corrupts:
* %edi, %ecx, %edx * none
**************************************************************************** ****************************************************************************
*/ */
.section ".prefix.lib" .section ".prefix.lib"
.code16 .code16
install_block: install_block:
#ifdef KEEP_IT_REAL
/* Preserve registers */
pushw %ds
pushw %es
pushl %ecx
pushl %edi
/* Convert %esi and %edi to segment registers */
shrl $4, %esi
movw %si, %ds
xorw %si, %si
shrl $4, %edi
movw %di, %es
xorw %di, %di
#else /* KEEP_IT_REAL */
/* Call self in protected mode */
pushw %ax
movw $1f, %ax
call pm_call
popw %ax
ret
1:
/* Preserve registers */
pushl %ecx
pushl %edi
#endif /* KEEP_IT_REAL */
#if COMPRESS #if COMPRESS
/* Decompress source to destination */ /* Decompress source to destination */
call decompress16 call decompress16
@ -249,6 +411,28 @@ install_block:
addl $0xf, %esi addl $0xf, %esi
andl $~0xf, %esi andl $~0xf, %esi
#ifdef KEEP_IT_REAL
/* Convert %ds:esi back to a physical address */
movzwl %ds, %cx
shll $4, %ecx
addl %ecx, %esi
/* Restore registers */
popl %edi
popl %ecx
popw %es
popw %ds
#else /* KEEP_IT_REAL */
/* Restore registers */
popl %edi
popl %ecx
#endif
ret ret
.size install_block, . - install_block .size install_block, . - install_block
@ -270,6 +454,7 @@ install_block:
*/ */
.section ".prefix.lib" .section ".prefix.lib"
.code16 .code16
.globl alloc_basemem
alloc_basemem: alloc_basemem:
/* FBMS => %ax as segment address */ /* FBMS => %ax as segment address */
movw $0x40, %ax movw $0x40, %ax
@ -295,98 +480,16 @@ alloc_basemem:
ret ret
.size alloc_basemem, . - alloc_basemem .size alloc_basemem, . - alloc_basemem
/****************************************************************************
* install_basemem (real-mode near call)
*
* Install source block into base memory
*
* Parameters:
* %esi : source physical address (must be a multiple of 16)
* %es : destination segment address
* %cx : length of (decompressed) data
* %dx : total length of block (including any uninitialised data portion)
* Returns:
* %esi : next source physical address (will be a multiple of 16)
* Corrupts:
* %edi, %ecx, %edx
****************************************************************************
*/
.section ".prefix.lib"
.code16
install_basemem:
/* Preserve registers */
pushw %ds
/* Preserve original %esi */
pushl %esi
/* Install to specified address */
shrl $4, %esi
movw %si, %ds
xorw %si, %si
xorl %edi, %edi
movzwl %cx, %ecx
movzwl %dx, %edx
call install_block
/* Fix up %esi for return */
popl %ecx
addl %ecx, %esi
/* Restore registers */
popw %ds
ret
.size install_basemem, . - install_basemem
/****************************************************************************
* install_highmem (real-mode near call)
*
* Install source block into high memory
*
* Parameters:
* %esi : source physical address (must be a multiple of 16)
* %edi : destination physical address
* %ecx : length of (decompressed) data
* %edx : total length of block (including any uninitialised data portion)
* Returns:
* %esi : next source physical address (will be a multiple of 16)
* Corrupts:
* %edi, %ecx, %edx
****************************************************************************
*/
#ifndef KEEP_IT_REAL
.section ".prefix.lib"
.code16
install_highmem:
/* Preserve registers */
pushw %ax
/* Install to specified address */
movw $install_block, %ax
call pm_call
/* Restore registers */
popw %ax
ret
.size install_highmem, . - install_highmem
#endif /* KEEP_IT_REAL */
/**************************************************************************** /****************************************************************************
* install (real-mode near call) * install (real-mode near call)
* install_prealloc (real-mode near call)
* *
* Install all text and data segments. * Install all text and data segments.
* *
* Parameters: * Parameters:
* %ax : .text16 segment address (install_prealloc only) * none
* %bx : .data16 segment address (install_prealloc only)
* Returns: * Returns:
* %ax : .text16 segment address * %ax : .text16 segment address
* %bx : .data16 segment address * %bx : .data16 segment address
* %edi : .text physical address (if applicable)
* Corrupts: * Corrupts:
* none * none
**************************************************************************** ****************************************************************************
@ -395,38 +498,69 @@ install_highmem:
.code16 .code16
.globl install .globl install
install: install:
/* Preserve registers */
pushl %esi
pushl %edi
/* Allocate space for .text16 and .data16 */ /* Allocate space for .text16 and .data16 */
call alloc_basemem 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 .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 .globl install_prealloc
install_prealloc: install_prealloc:
/* Save registers */ /* Save registers */
pushal
pushw %ds pushw %ds
pushw %es pushw %es
pushl %esi
pushl %ecx
pushl %edx
/* Sanity: clear the direction flag asap */ /* Sanity: clear the direction flag asap */
cld cld
/* Calculate physical address of payload (i.e. first source) */ /* Calculate physical address of payload (i.e. first source) */
xorl %esi, %esi testl %esi, %esi
jnz 1f
movw %cs, %si movw %cs, %si
shll $4, %esi shll $4, %esi
addl $_payload_offset, %esi 1: addl $_payload_offset, %esi
/* Install .text16 */ /* Install .text16 and .data16 */
movw %ax, %es pushl %edi
movw $_text16_size, %cx movzwl %ax, %edi
movw %cx, %dx shll $4, %edi
call install_basemem movl $_text16_size, %ecx
movl %ecx, %edx
/* Install .data16 */ call install_block /* .text16 */
movw %bx, %es movzwl %bx, %edi
movw $_data16_progbits_size, %cx shll $4, %edi
movw $_data16_size, %dx movl $_data16_progbits_size, %ecx
call install_basemem movl $_data16_size, %edx
call install_block /* .data16 */
popl %edi
/* Set up %ds for access to .data16 */ /* Set up %ds for access to .data16 */
movw %bx, %ds movw %bx, %ds
@ -440,12 +574,9 @@ install_prealloc:
* prior to reading the E820 memory map and relocating * prior to reading the E820 memory map and relocating
* properly. * properly.
*/ */
movl $HIGHMEM_LOADPOINT, %edi
movl $_textdata_progbits_size, %ecx movl $_textdata_progbits_size, %ecx
movl $_textdata_size, %edx movl $_textdata_size, %edx
pushl %edi call install_block
call install_highmem
popl %edi
/* Initialise librm at current location */ /* Initialise librm at current location */
movw %ax, (init_librm_vector+2) movw %ax, (init_librm_vector+2)
@ -473,11 +604,9 @@ install_prealloc:
#endif #endif
/* Restore registers */ /* Restore registers */
popl %edx
popl %ecx
popl %esi
popw %es popw %es
popw %ds popw %ds
popal
ret ret
.size install_prealloc, . - install_prealloc .size install_prealloc, . - install_prealloc

View File

@ -320,112 +320,6 @@ print_free_basemem:
finished: finished:
jmp run_etherboot jmp run_etherboot
/*****************************************************************************
* Subroutine: print character (with LF -> LF,CR translation)
*
* Parameters:
* %al : character to print
* Returns:
* Nothing
*****************************************************************************
*/
print_character:
/* Preserve registers */
pushw %ax
pushw %bx
pushw %bp
/* Print character */
movw $0x0007, %bx /* page 0, attribute 7 (normal) */
movb $0x0e, %ah /* write char, tty mode */
cmpb $0x0a, %al /* '\n'? */
jne 1f
int $0x10
movb $0x0d, %al
1: int $0x10
/* Restore registers and return */
popw %bp
popw %bx
popw %ax
ret
/*****************************************************************************
* Subroutine: print a NUL-terminated string
*
* Parameters:
* %ds:%si : string to print
* Returns:
* Nothing
*****************************************************************************
*/
print_message:
/* Preserve registers */
pushw %ax
pushw %si
/* Print string */
1: lodsb
testb %al, %al
je 2f
call print_character
jmp 1b
2: /* Restore registers and return */
popw %si
popw %ax
ret
/*****************************************************************************
* Subroutine: print hex digit
*
* Parameters:
* %al (low nibble) : digit to print
* Returns:
* Nothing
*****************************************************************************
*/
print_hex_nibble:
/* Preserve registers */
pushw %ax
/* Print digit (technique by Norbert Juffa <norbert.juffa@amd.com> */
andb $0x0f, %al
cmpb $10, %al
sbbb $0x69, %al
das
call print_character
/* Restore registers and return */
popw %ax
ret
/*****************************************************************************
* Subroutine: print hex byte
*
* Parameters:
* %al : byte to print
* Returns:
* Nothing
*****************************************************************************
*/
print_hex_byte:
rorb $4, %al
call print_hex_nibble
rorb $4, %al
call print_hex_nibble
ret
/*****************************************************************************
* Subroutine: print hex word
*
* Parameters:
* %ax : word to print
* Returns:
* Nothing
*****************************************************************************
*/
print_hex_word:
xchgb %al, %ah
call print_hex_byte
xchgb %al, %ah
call print_hex_byte
ret
/***************************************************************************** /*****************************************************************************
* Subroutine: print segment:offset address * Subroutine: print segment:offset address
* *

View File

@ -6,6 +6,11 @@
* table so using a noticeable amount of stack space is a no-no. * 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 ) )
#define PNP_GET_BBS_VERSION 0x60
.text .text
.code16 .code16
.arch i386 .arch i386
@ -15,7 +20,9 @@
romheader: romheader:
.word 0xAA55 /* BIOS extension signature */ .word 0xAA55 /* BIOS extension signature */
romheader_size: .byte _load_size_sect /* Size in 512-byte blocks */ 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 .org 0x16
.word undiheader .word undiheader
.org 0x18 .org 0x18
@ -72,7 +79,7 @@ pnpheader:
.byte 0x54 /* Device indicator */ .byte 0x54 /* Device indicator */
.word 0x0000 /* Boot connection vector */ .word 0x0000 /* Boot connection vector */
.word 0x0000 /* Disconnect vector */ .word 0x0000 /* Disconnect vector */
.word exec_vector /* Boot execution vector */ .word bev_entry /* Boot execution vector */
.word 0x0000 /* Reserved */ .word 0x0000 /* Reserved */
.word 0x0000 /* Static resource information vector*/ .word 0x0000 /* Static resource information vector*/
.equ pnpheader_len, . - pnpheader .equ pnpheader_len, . - pnpheader
@ -98,60 +105,210 @@ undiheader:
.equ undiheader_len, . - undiheader .equ undiheader_len, . - undiheader
.size undiheader, . - undiheader .size undiheader, . - undiheader
/* Initialisation vector /* Initialisation (called once during POST)
* *
* Determine whether or not this is a PnP system via a signature * 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 * 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 * 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. * if it wants to boot us. If it is not PnP, hook INT 19.
*/ */
init_vector: init:
pushw %si /* Preserve registers, clear direction flag, set %ds=%cs */
cmpw $'$'+'P'*256, %es:0(%di) pushaw
jne notpnp
cmpw $'n'+'P'*256, %es:2(%di)
jne notpnp
ispnp:
movw $ispnp_message, %si
jmp 99f
notpnp:
pushw %ds pushw %ds
pushw $0 pushw %es
popw %ds cld
pushw %cs pushw %cs
pushw $exec_vector
popl ( 0x19 * 4 )
popw %ds popw %ds
movw $notpnp_message, %si /* Print message as early as possible */
99: movw $init_message, %si
call print_message
/* Check for PnP BIOS */
testw $0x0f, %di /* PnP signature must be aligned - bochs */
jnz hook_int19 /* uses unalignment to indicate 'fake' PnP. */
cmpl $PNP_SIGNATURE, %es:0(%di)
jne hook_int19
/* Is PnP: print PnP message */
movw $init_message_pnp, %si
call print_message
xchgw %bx, %bx
/* Check for BBS */
pushw %es:0x1b(%di) /* Real-mode data segment */
pushw %ds /* &(bbs_version) */
pushw $bbs_version
pushw $PNP_GET_BBS_VERSION
lcall *%es:0xd(%di)
addw $8, %sp
testw %ax, %ax
jne hook_int19
movw $init_message_bbs, %si
call print_message
jmp hook_bbs
/* Not BBS-compliant - must hook INT 19 */
hook_int19:
movw $init_message_int19, %si
call print_message 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 */
xorw %ax, %ax xorw %ax, %ax
movw %ax, %ss movw %ax, %es
movw $0x7c00, %sp pushw %cs
pushw $int19_entry
popl %es:( 0x19 * 4 )
hook_bbs:
/* Check for PMM */
movw $( 0xe000 - 1 ), %di
pmm_scan:
incw %di
jz no_pmm
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 no_pmm
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
movw $_prefix_size_sect, %cx
movb %cl, romheader_size
shlw $9, %cx
1: lodsb
addb %al, %bl
loop 1b
subb %bl, checksum
popal
no_pmm:
/* Print CRLF to terminate messages */
movw $'\n', %ax
call print_character
/* 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"
.size init_message_pnp, . - init_message_pnp
init_message_bbs:
.asciz " BBS"
.size init_message_bbs, . - init_message_bbs
init_message_pmm:
.asciz " PMM"
.size init_message_pmm, . - init_message_pmm
init_message_pmm_failed:
.asciz "(failed)"
.size init_message_pmm_failed, . - init_message_pmm_failed
init_message_int19:
.asciz " INT19"
.size init_message_int19, . - init_message_int19
/* 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
/* BBS version
*
* Filled in by BBS BIOS. We ignore the value.
*/
bbs_version:
.word 0
/* 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 movw $exec_message, %si
call print_message 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 */ /* Set up real-mode stack */
movw %bx, %ss movw %bx, %ss
@ -162,18 +319,28 @@ exec_vector:
pushw $1f pushw $1f
lret lret
.section ".text16", "awx", @progbits .section ".text16", "awx", @progbits
1: 1: /* Call main() */
pushl $main pushl $main
pushw %cs pushw %cs
call prot_call 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 int $0x18
.previous .previous
exec_message: exec_message:
.asciz "gPXE starting boot\r\n" .asciz "gPXE starting boot\n"
.size exec_message, . - exec_message .size exec_message, . - exec_message
/* UNDI loader /* UNDI loader
@ -182,6 +349,7 @@ exec_message:
*/ */
undiloader: undiloader:
/* Save registers */ /* Save registers */
pushl %esi
pushl %edi pushl %edi
pushw %es pushw %es
pushw %bx pushw %bx
@ -193,6 +361,8 @@ undiloader:
pushw %di pushw %di
movw %es:12(%di), %bx movw %es:12(%di), %bx
movw %es:14(%di), %ax movw %es:14(%di), %ax
movl %cs:image_source, %esi
movl %cs:decompress_to, %edi
call install_prealloc call install_prealloc
popw %di popw %di
/* Call UNDI loader C code */ /* Call UNDI loader C code */
@ -208,24 +378,6 @@ undiloader:
popw %bx popw %bx
popw %es popw %es
popl %edi popl %edi
popl %esi
lret lret
.size undiloader, . - undiloader .size undiloader, . - undiloader
/* Utility function: print string
*/
print_message:
pushw %ax
pushw %bx
pushw %bp
movw $0x0007, %bx
1: cs lodsb
testb %al, %al
je 2f
movb $0x0e, %ah /* write char, tty mode */
int $0x10
jmp 1b
2: popw %bp
popw %bx
popw %ax
ret
.size print_message, . - print_message

View File

@ -257,6 +257,8 @@ SECTIONS {
/* /*
* Values calculated to save code from doing it * 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 ); _text16_size_pgh = ( ( _text16_size + 15 ) / 16 );
_data16_size_pgh = ( ( _data16_size + 15 ) / 16 ); _data16_size_pgh = ( ( _data16_size + 15 ) / 16 );