aboutsummaryrefslogtreecommitdiffstats
path: root/gpxe/src/arch/i386/prefix/pxeprefix.S
diff options
context:
space:
mode:
Diffstat (limited to 'gpxe/src/arch/i386/prefix/pxeprefix.S')
-rw-r--r--gpxe/src/arch/i386/prefix/pxeprefix.S100
1 files changed, 80 insertions, 20 deletions
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