Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[pxeprefix] Add .kkpxe image type and ability to return via PXE stack
Certain combinations of PXE stack and BIOS result in a broken INT 18
call, which will leave the system displaying a "PRESS ANY KEY TO
REBOOT" message instead of proceeding to the next boot device.  On
these systems, returning via the PXE stack is the only way to continue
to the next boot device.  Returning via the PXE stack works only if we
haven't already blown away the PXE base code in pxeprefix.S.

In most circumstances, we do want to blow away the PXE base code.
Base memory is a limited resource, and it is desirable to reclaim as
much as possible.  When we perform an iSCSI boot, we need to place the
iBFT above the 512kB mark, because otherwise it may not be detected by
the loaded OS; this may not be possible if the PXE base code is still
occupying that memory.

Introduce a new prefix type .kkpxe which will preserve both the PXE
base code and the UNDI driver (as compared to .kpxe, which preserves
the UNDI driver but uninstalls the PXE base code).  This prefix type
can be used on systems that are known to experience the specific
problem of INT 18 being broken, or in builds (such as gpxelinux.0) for
which it is particularly important to know that returning to the BIOS
will work.

Written by H. Peter Anvin <hpa@zytor.com> and Stefan Hajnoczi
<stefanha@gmail.com>, minor structural alterations by Michael Brown
<mcb30@etherboot.org>.
  • Loading branch information
Michael Brown committed Feb 18, 2009
1 parent dd44a7c commit b557755
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 39 deletions.
1 change: 1 addition & 0 deletions src/arch/i386/Makefile.pcbios
Expand Up @@ -13,6 +13,7 @@ LDFLAGS += -N --no-check-sections
MEDIA += rom
MEDIA += pxe
MEDIA += kpxe
MEDIA += kkpxe
MEDIA += elf
MEDIA += elfd
MEDIA += lmelf
Expand Down
57 changes: 35 additions & 22 deletions src/arch/i386/drivers/net/undinet.c
Expand Up @@ -669,15 +669,19 @@ int undinet_probe ( struct undi_device *undi ) {
undi->flags |= UNDI_FL_STARTED;

/* Bring up UNDI stack */
memset ( &undi_startup, 0, sizeof ( undi_startup ) );
if ( ( rc = undinet_call ( undinic, PXENV_UNDI_STARTUP, &undi_startup,
sizeof ( undi_startup ) ) ) != 0 )
goto err_undi_startup;
memset ( &undi_initialize, 0, sizeof ( undi_initialize ) );
if ( ( rc = undinet_call ( undinic, PXENV_UNDI_INITIALIZE,
&undi_initialize,
sizeof ( undi_initialize ) ) ) != 0 )
goto err_undi_initialize;
if ( ! ( undi->flags & UNDI_FL_INITIALIZED ) ) {
memset ( &undi_startup, 0, sizeof ( undi_startup ) );
if ( ( rc = undinet_call ( undinic, PXENV_UNDI_STARTUP,
&undi_startup,
sizeof ( undi_startup ) ) ) != 0 )
goto err_undi_startup;
memset ( &undi_initialize, 0, sizeof ( undi_initialize ) );
if ( ( rc = undinet_call ( undinic, PXENV_UNDI_INITIALIZE,
&undi_initialize,
sizeof ( undi_initialize ))) != 0 )
goto err_undi_initialize;
}
undi->flags |= UNDI_FL_INITIALIZED;

/* Get device information */
memset ( &undi_info, 0, sizeof ( undi_info ) );
Expand Down Expand Up @@ -731,11 +735,13 @@ int undinet_probe ( struct undi_device *undi ) {
memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) );
undinet_call ( undinic, PXENV_UNDI_CLEANUP, &undi_cleanup,
sizeof ( undi_cleanup ) );
undi->flags &= ~UNDI_FL_INITIALIZED;
err_undi_startup:
/* Unhook UNDI stack */
memset ( &stop_undi, 0, sizeof ( stop_undi ) );
undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi,
sizeof ( stop_undi ) );
undi->flags &= ~UNDI_FL_STARTED;
err_start_undi:
netdev_nullify ( netdev );
netdev_put ( netdev );
Expand All @@ -758,19 +764,26 @@ void undinet_remove ( struct undi_device *undi ) {
/* Unregister net device */
unregister_netdev ( netdev );

/* Shut down UNDI stack */
memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) );
undinet_call ( undinic, PXENV_UNDI_SHUTDOWN, &undi_shutdown,
sizeof ( undi_shutdown ) );
memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) );
undinet_call ( undinic, PXENV_UNDI_CLEANUP, &undi_cleanup,
sizeof ( undi_cleanup ) );

/* Unhook UNDI stack */
memset ( &stop_undi, 0, sizeof ( stop_undi ) );
undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi,
sizeof ( stop_undi ) );
undi->flags &= ~UNDI_FL_STARTED;
/* If we are preparing for an OS boot, or if we cannot exit
* via the PXE stack, then shut down the PXE stack.
*/
if ( ! ( undi->flags & UNDI_FL_KEEP_ALL ) ) {

/* Shut down UNDI stack */
memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) );
undinet_call ( undinic, PXENV_UNDI_SHUTDOWN, &undi_shutdown,
sizeof ( undi_shutdown ) );
memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) );
undinet_call ( undinic, PXENV_UNDI_CLEANUP, &undi_cleanup,
sizeof ( undi_cleanup ) );
undi->flags &= ~UNDI_FL_INITIALIZED;

/* Unhook UNDI stack */
memset ( &stop_undi, 0, sizeof ( stop_undi ) );
undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi,
sizeof ( stop_undi ) );
undi->flags &= ~UNDI_FL_STARTED;
}

/* Clear entry point */
memset ( &undinet_entry_point, 0, sizeof ( undinet_entry_point ) );
Expand Down
18 changes: 18 additions & 0 deletions src/arch/i386/drivers/net/undionly.c
Expand Up @@ -20,6 +20,7 @@
#include <stdlib.h>
#include <string.h>
#include <gpxe/device.h>
#include <gpxe/init.h>
#include <undi.h>
#include <undinet.h>
#include <undipreload.h>
Expand Down Expand Up @@ -107,3 +108,20 @@ struct root_device undi_root_device __root_device = {
.dev = { .name = "UNDI" },
.driver = &undi_root_driver,
};

/**
* Prepare for exit
*
* @v flags Shutdown flags
*/
static void undionly_shutdown ( int flags ) {
/* If we are shutting down to boot an OS, clear the "keep PXE
* stack" flag.
*/
if ( flags & SHUTDOWN_BOOT )
preloaded_undi.flags &= ~UNDI_FL_KEEP_ALL;
}

struct startup_fn startup_undionly __startup_fn ( STARTUP_LATE ) = {
.shutdown = undionly_shutdown,
};
6 changes: 6 additions & 0 deletions src/arch/i386/include/undi.h
Expand Up @@ -95,4 +95,10 @@ static inline void * undi_get_drvdata ( struct undi_device *undi ) {
/** UNDI flag: START_UNDI has been called */
#define UNDI_FL_STARTED 0x0001

/** UNDI flag: UNDI_STARTUP and UNDI_INITIALIZE have been called */
#define UNDI_FL_INITIALIZED 0x0002

/** UNDI flag: keep stack resident */
#define UNDI_FL_KEEP_ALL 0x0004

#endif /* _UNDI_H */
8 changes: 8 additions & 0 deletions src/arch/i386/prefix/kkpxeprefix.S
@@ -0,0 +1,8 @@
/*****************************************************************************
* PXE prefix that keeps the whole PXE stack present
*****************************************************************************
*/

#define PXELOADER_KEEP_UNDI
#define PXELOADER_KEEP_PXE
#include "pxeprefix.S"
79 changes: 62 additions & 17 deletions src/arch/i386/prefix/pxeprefix.S
Expand Up @@ -10,27 +10,45 @@

#include <undi.h>

#define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) )

/*****************************************************************************
* Entry point: set operating context, print welcome message
*****************************************************************************
*/
.section ".prefix", "ax", @progbits
/* Set up our non-stack segment registers */
jmp $0x7c0, $1f
1: movw %cs, %ax
1:
/* Preserve registers for possible return to PXE */
pushfl
pushal
pushw %gs
pushw %fs
pushw %es
pushw %ds

/* Store magic word on PXE stack and remember PXE %ss:esp */
pushl $STACK_MAGIC
movw %ss, %cs:pxe_ss
movl %esp, %cs:pxe_esp
movw %sp, %bp
movl (10*4+4*2+4)(%bp),%ebp /* !PXE address */

/* Set up %ds */
movw %cs, %ax
movw %ax, %ds
movw $0x40, %ax /* BIOS data segment access */
movw %ax, %fs
/* Record PXENV+ and !PXE nominal addresses */
movw %es, %ax /* PXENV+ address */
movw %ax, pxenv_segment
movw %es, pxenv_segment /* PXENV+ address */
movw %bx, pxenv_offset
popl %eax /* Discard return address */
popl ppxe_segoff /* !PXE address */
movl %ebp, ppxe_segoff /* !PXE address */
/* Set up %es and %fs */
movw %ax, %es
movw $0x40, %ax /* BIOS data segment access */
movw %ax, %fs
/* Set up stack just below 0x7c00 */
xorw %ax, %ax
movw %ax, %ss
movw $0x7c00, %sp
movl $0x7c00, %esp
/* Clear direction flag, for the sake of sanity */
cld
/* Print welcome message */
Expand Down Expand Up @@ -249,18 +267,14 @@ no_physical_device:
* Leave NIC in a safe state
*****************************************************************************
*/
#ifndef PXELOADER_KEEP_PXE
shutdown_nic:
/* Issue PXENV_UNDI_SHUTDOWN */
movw $PXENV_UNDI_SHUTDOWN, %bx
call pxe_call
jnc 1f
call print_pxe_error
1:

/*****************************************************************************
* Unload PXE base code
*****************************************************************************
*/
unload_base_code:
/* Issue PXENV_UNLOAD_STACK */
movw $PXENV_UNLOAD_STACK, %bx
Expand All @@ -273,6 +287,8 @@ unload_base_code:
movw %fs:(0x13), %bx
call free_basemem
99:
andw $~( UNDI_FL_INITIALIZED | UNDI_FL_KEEP_ALL ), flags
#endif /* PXELOADER_KEEP_PXE */

/*****************************************************************************
* Unload UNDI driver
Expand Down Expand Up @@ -511,6 +527,10 @@ print_pxe_error:
* PXE data structures
*****************************************************************************
*/
.section ".prefix.data"

pxe_ss: .word 0
pxe_esp: .long 0

pxe_parameter_structure: .fill 20

Expand Down Expand Up @@ -547,14 +567,16 @@ isapnp_read_port: .word UNDI_NO_ISAPNP_READ_PORT

pci_vendor: .word 0
pci_device: .word 0
flags: .word UNDI_FL_STARTED
flags:
.word ( UNDI_FL_INITIALIZED | UNDI_FL_STARTED | UNDI_FL_KEEP_ALL )

.equ undi_device_size, ( . - undi_device )

/*****************************************************************************
* Run gPXE main code
*****************************************************************************
*/
*/
.section ".prefix"
run_gpxe:
/* Install gPXE */
call install
Expand All @@ -572,6 +594,10 @@ run_gpxe:
rep movsb
#endif

/* Retrieve PXE %ss:esp */
movw pxe_ss, %di
movl pxe_esp, %ebp

/* Jump to .text16 segment with %ds pointing to .data16 */
movw %bx, %ds
pushw %ax
Expand All @@ -588,6 +614,25 @@ run_gpxe:
/* Uninstall gPXE */
call uninstall

/* Boot next device */
/* Restore PXE stack */
movw %di, %ss
movl %ebp, %esp

/* Check PXE stack magic */
popl %eax
cmpl $STACK_MAGIC, %eax
jne 1f

/* PXE stack OK: return to caller */
popw %ds
popw %es
popw %fs
popw %gs
popal
popfl
xorw %ax, %ax /* Return success */
lret

1: /* PXE stack corrupt or removed: use INT 18 */
int $0x18
.previous
1 change: 1 addition & 0 deletions src/include/gpxe/init.h
Expand Up @@ -63,6 +63,7 @@ struct startup_fn {

#define STARTUP_EARLY 01 /**< Early startup */
#define STARTUP_NORMAL 02 /**< Normal startup */
#define STARTUP_LATE 03 /**< Late startup */

/** @} */

Expand Down

0 comments on commit b557755

Please sign in to comment.