summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/arch/i386/firmware/pcbios/hidemem.c2
-rw-r--r--src/arch/i386/image/bzimage.c2
-rw-r--r--src/arch/i386/image/elfboot.c2
-rw-r--r--src/arch/i386/image/multiboot.c2
-rw-r--r--src/arch/i386/image/nbi.c2
-rw-r--r--src/core/config.c7
-rw-r--r--src/core/device.c18
-rw-r--r--src/core/init.c14
-rw-r--r--src/core/main.c2
-rw-r--r--src/core/serial.c4
-rw-r--r--src/include/gpxe/device.h3
-rw-r--r--src/include/gpxe/dhcp.h15
-rw-r--r--src/include/gpxe/errfile.h1
-rw-r--r--src/include/gpxe/init.h14
-rw-r--r--src/include/usr/autoboot.h2
-rw-r--r--src/interface/pxe/pxe_preboot.c2
-rw-r--r--src/usr/autoboot.c3
-rw-r--r--src/usr/iscsiboot.c71
18 files changed, 115 insertions, 51 deletions
diff --git a/src/arch/i386/firmware/pcbios/hidemem.c b/src/arch/i386/firmware/pcbios/hidemem.c
index eba94007..11ca3128 100644
--- a/src/arch/i386/firmware/pcbios/hidemem.c
+++ b/src/arch/i386/firmware/pcbios/hidemem.c
@@ -128,7 +128,7 @@ static void hide_etherboot ( void ) {
* Uninstalls the INT 15 handler installed by hide_etherboot(), if
* possible.
*/
-static void unhide_etherboot ( void ) {
+static void unhide_etherboot ( int flags __unused ) {
/* If we have more than one hooked interrupt at this point, it
* means that some other vector is still hooked, in which case
diff --git a/src/arch/i386/image/bzimage.c b/src/arch/i386/image/bzimage.c
index d9c05453..e6fd854f 100644
--- a/src/arch/i386/image/bzimage.c
+++ b/src/arch/i386/image/bzimage.c
@@ -348,7 +348,7 @@ static int bzimage_exec ( struct image *image ) {
sizeof ( bzhdr ) );
/* Prepare for exiting */
- shutdown();
+ shutdown ( SHUTDOWN_BOOT );
DBGC ( image, "bzImage %p jumping to RM kernel at %04x:0000 "
"(stack %04x:%04zx)\n", image,
diff --git a/src/arch/i386/image/elfboot.c b/src/arch/i386/image/elfboot.c
index 52510aa9..60c54992 100644
--- a/src/arch/i386/image/elfboot.c
+++ b/src/arch/i386/image/elfboot.c
@@ -46,7 +46,7 @@ static int elfboot_exec ( struct image *image ) {
/* An ELF image has no callback interface, so we need to shut
* down before invoking it.
*/
- shutdown();
+ shutdown ( SHUTDOWN_BOOT );
/* Jump to OS with flat physical addressing */
__asm__ __volatile__ ( PHYS_CODE ( "call *%%edi\n\t" )
diff --git a/src/arch/i386/image/multiboot.c b/src/arch/i386/image/multiboot.c
index fbaebd5c..d7c2b8da 100644
--- a/src/arch/i386/image/multiboot.c
+++ b/src/arch/i386/image/multiboot.c
@@ -277,7 +277,7 @@ static int multiboot_exec ( struct image *image ) {
/* Multiboot images may not return and have no callback
* interface, so shut everything down prior to booting the OS.
*/
- shutdown();
+ shutdown ( SHUTDOWN_BOOT );
/* Jump to OS with flat physical addressing */
__asm__ __volatile__ ( PHYS_CODE ( "call *%%edi\n\t" )
diff --git a/src/arch/i386/image/nbi.c b/src/arch/i386/image/nbi.c
index 73791be9..e6a0ab0f 100644
--- a/src/arch/i386/image/nbi.c
+++ b/src/arch/i386/image/nbi.c
@@ -429,7 +429,7 @@ static int nbi_exec ( struct image *image ) {
/* Shut down now if NBI image will not return */
may_return = NBI_PROGRAM_RETURNS ( imgheader.flags );
if ( ! may_return )
- shutdown();
+ shutdown ( SHUTDOWN_BOOT );
/* Execute NBI image */
if ( NBI_LINEAR_EXEC_ADDR ( imgheader.flags ) ) {
diff --git a/src/core/config.c b/src/core/config.c
index 42026827..220b7cdb 100644
--- a/src/core/config.c
+++ b/src/core/config.c
@@ -205,3 +205,10 @@ REQUIRE_OBJECT ( gdbidt );
REQUIRE_OBJECT ( gdbudp );
REQUIRE_OBJECT ( gdbstub_cmd );
#endif
+
+/*
+ * Drag in objects that are always required, but not dragged in via
+ * symbol dependencies.
+ *
+ */
+REQUIRE_OBJECT ( device );
diff --git a/src/core/device.c b/src/core/device.c
index b1b148e8..84915c2d 100644
--- a/src/core/device.c
+++ b/src/core/device.c
@@ -20,6 +20,7 @@
#include <gpxe/list.h>
#include <gpxe/tables.h>
#include <gpxe/device.h>
+#include <gpxe/init.h>
/**
* @file
@@ -68,13 +69,11 @@ static void rootdev_remove ( struct root_device *rootdev ) {
/**
* Probe all devices
*
- * @ret rc Return status code
- *
* This initiates probing for all devices in the system. After this
* call, the device hierarchy will be populated, and all hardware
* should be ready to use.
*/
-int probe_devices ( void ) {
+static void probe_devices ( void ) {
struct root_device *rootdev;
int rc;
@@ -84,19 +83,28 @@ int probe_devices ( void ) {
if ( ( rc = rootdev_probe ( rootdev ) ) != 0 )
list_del ( &rootdev->dev.siblings );
}
- return 0;
}
/**
* Remove all devices
*
*/
-void remove_devices ( void ) {
+static void remove_devices ( int flags ) {
struct root_device *rootdev;
struct root_device *tmp;
+ if ( flags & SHUTDOWN_KEEP_DEVICES ) {
+ DBG ( "Refusing to remove devices on shutdown\n" );
+ return;
+ }
+
list_for_each_entry_safe ( rootdev, tmp, &devices, dev.siblings ) {
rootdev_remove ( rootdev );
list_del ( &rootdev->dev.siblings );
}
}
+
+struct startup_fn startup_devices __startup_fn ( STARTUP_NORMAL ) = {
+ .startup = probe_devices,
+ .shutdown = remove_devices,
+};
diff --git a/src/core/init.c b/src/core/init.c
index ed91bf36..50e199ce 100644
--- a/src/core/init.c
+++ b/src/core/init.c
@@ -79,17 +79,14 @@ void startup ( void ) {
startup_fn->startup();
}
- /* Probe for all devices. Treated separately because nothing
- * else will drag in device.o
- */
- probe_devices();
-
started = 1;
}
/**
* Shut down gPXE
*
+ * @v flags Shutdown behaviour flags
+ *
* This function reverses the actions of startup(), and leaves gPXE in
* a state ready to be removed from memory. You may call startup()
* again after calling shutdown().
@@ -97,20 +94,17 @@ void startup ( void ) {
* Call this function only once, before either exiting main() or
* starting up a non-returnable image.
*/
-void shutdown ( void ) {
+void shutdown ( int flags ) {
struct startup_fn *startup_fn;
if ( ! started )
return;
- /* Remove all devices */
- remove_devices();
-
/* Call registered shutdown functions (in reverse order) */
for ( startup_fn = startup_fns_end - 1 ; startup_fn >= startup_fns ;
startup_fn-- ) {
if ( startup_fn->shutdown )
- startup_fn->shutdown();
+ startup_fn->shutdown ( flags );
}
started = 0;
diff --git a/src/core/main.c b/src/core/main.c
index ca62db25..d5892261 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -62,7 +62,7 @@ __cdecl int main ( void ) {
shell();
}
- shutdown();
+ shutdown ( SHUTDOWN_EXIT | shutdown_exit_flags );
return 0;
}
diff --git a/src/core/serial.c b/src/core/serial.c
index 54c22954..97640f93 100644
--- a/src/core/serial.c
+++ b/src/core/serial.c
@@ -224,7 +224,7 @@ static void serial_init ( void ) {
* Cleanup our use of the serial port, in particular flush the
* output buffer so we don't accidentially lose characters.
*/
-static void serial_fini ( void ) {
+static void serial_fini ( int flags __unused ) {
int i, status;
/* Flush the output buffer to avoid dropping characters,
* if we are reinitializing the serial port.
@@ -247,6 +247,6 @@ struct init_fn serial_init_fn __init_fn ( INIT_SERIAL ) = {
};
/** Serial driver startup function */
-struct startup_fn serial_startup_fn __startup_fn ( STARTUP_NORMAL ) = {
+struct startup_fn serial_startup_fn __startup_fn ( STARTUP_EARLY ) = {
.shutdown = serial_fini,
};
diff --git a/src/include/gpxe/device.h b/src/include/gpxe/device.h
index caabdae5..f40cc95a 100644
--- a/src/include/gpxe/device.h
+++ b/src/include/gpxe/device.h
@@ -105,7 +105,4 @@ struct root_driver {
/** Declare a root device */
#define __root_device __table ( struct root_device, root_devices, 01 )
-extern int probe_devices ( void );
-extern void remove_devices ( void );
-
#endif /* _GPXE_DEVICE_H */
diff --git a/src/include/gpxe/dhcp.h b/src/include/gpxe/dhcp.h
index 61445977..1c9c49fa 100644
--- a/src/include/gpxe/dhcp.h
+++ b/src/include/gpxe/dhcp.h
@@ -164,7 +164,7 @@ struct dhcp_packet;
* priority of multiple option blocks (e.g. options from non-volatile
* storage versus options from a DHCP server).
*/
-#define DHCP_EB_PRIORITY DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 1 )
+#define DHCP_EB_PRIORITY DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x01 )
/** "Your" IP address
*
@@ -172,7 +172,7 @@ struct dhcp_packet;
* field, in order to provide a consistent approach to storing and
* processing options. It should never be present in a DHCP packet.
*/
-#define DHCP_EB_YIADDR DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 2 )
+#define DHCP_EB_YIADDR DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x02 )
/** "Server" IP address
*
@@ -180,7 +180,16 @@ struct dhcp_packet;
* field, in order to provide a consistent approach to storing and
* processing options. It should never be present in a DHCP packet.
*/
-#define DHCP_EB_SIADDR DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 3 )
+#define DHCP_EB_SIADDR DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x03 )
+
+/** Keep SAN drive registered
+ *
+ * If set to a non-zero value, gPXE will not detach any SAN drive
+ * after failing to boot from it. (This option is required in order
+ * to perform a Windows Server 2008 installation direct to an iSCSI
+ * target.)
+ */
+#define DHCP_EB_KEEP_SAN DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x08 )
/*
* Tags in the range 0x10-0x7f are reserved for feature markers
diff --git a/src/include/gpxe/errfile.h b/src/include/gpxe/errfile.h
index 5717bc71..ca0abebf 100644
--- a/src/include/gpxe/errfile.h
+++ b/src/include/gpxe/errfile.h
@@ -155,6 +155,7 @@
#define ERRFILE_ibft ( ERRFILE_OTHER | 0x000c0000 )
#define ERRFILE_tls ( ERRFILE_OTHER | 0x000d0000 )
#define ERRFILE_ifmgmt ( ERRFILE_OTHER | 0x000e0000 )
+#define ERRFILE_iscsiboot ( ERRFILE_OTHER | 0x000f0000 )
/** @} */
diff --git a/src/include/gpxe/init.h b/src/include/gpxe/init.h
index c468213e..d2b450d7 100644
--- a/src/include/gpxe/init.h
+++ b/src/include/gpxe/init.h
@@ -28,6 +28,16 @@ struct init_fn {
/** @} */
+/** Shutdown flags */
+enum shutdown_flags {
+ /** Shutdown is in order to exit (return to gPXE's caller) */
+ SHUTDOWN_EXIT = 0x0001,
+ /** Shutdown is in order to boot an OS */
+ SHUTDOWN_BOOT = 0x0002,
+ /** Do not remove devices */
+ SHUTDOWN_KEEP_DEVICES = 0x0004,
+};
+
/**
* A startup/shutdown function
*
@@ -36,7 +46,7 @@ struct init_fn {
*/
struct startup_fn {
void ( * startup ) ( void );
- void ( * shutdown ) ( void );
+ void ( * shutdown ) ( int flags );
};
/** Declare a startup/shutdown function */
@@ -58,6 +68,6 @@ struct startup_fn {
extern void initialise ( void );
extern void startup ( void );
-extern void shutdown ( void );
+extern void shutdown ( int flags );
#endif /* _GPXE_INIT_H */
diff --git a/src/include/usr/autoboot.h b/src/include/usr/autoboot.h
index b451a8c1..b64cbb8e 100644
--- a/src/include/usr/autoboot.h
+++ b/src/include/usr/autoboot.h
@@ -7,6 +7,8 @@
*
*/
+extern int shutdown_exit_flags;
+
extern void autoboot ( void );
extern int boot_root_path ( const char *root_path );
diff --git a/src/interface/pxe/pxe_preboot.c b/src/interface/pxe/pxe_preboot.c
index b2914d36..8220d1f2 100644
--- a/src/interface/pxe/pxe_preboot.c
+++ b/src/interface/pxe/pxe_preboot.c
@@ -318,7 +318,7 @@ PXENV_EXIT_t pxenv_stop_undi ( struct s_PXENV_STOP_UNDI *stop_undi ) {
pxe_set_netdev ( NULL );
/* Prepare for unload */
- shutdown();
+ shutdown ( SHUTDOWN_BOOT );
stop_undi->Status = PXENV_STATUS_SUCCESS;
return PXENV_EXIT_SUCCESS;
diff --git a/src/usr/autoboot.c b/src/usr/autoboot.c
index cff6e95d..fdd502da 100644
--- a/src/usr/autoboot.c
+++ b/src/usr/autoboot.c
@@ -41,6 +41,9 @@
/** Time to wait for link-up */
#define LINK_WAIT_MS 15000
+/** Shutdown flags for exit */
+int shutdown_exit_flags = 0;
+
/**
* Identify the boot network device
*
diff --git a/src/usr/iscsiboot.c b/src/usr/iscsiboot.c
index 99edc879..84d77c45 100644
--- a/src/usr/iscsiboot.c
+++ b/src/usr/iscsiboot.c
@@ -1,13 +1,25 @@
#include <stdint.h>
#include <string.h>
+#include <stdlib.h>
#include <stdio.h>
+#include <errno.h>
#include <gpxe/iscsi.h>
#include <gpxe/settings.h>
+#include <gpxe/dhcp.h>
#include <gpxe/netdevice.h>
#include <gpxe/ibft.h>
+#include <gpxe/init.h>
#include <int13.h>
+#include <usr/autoboot.h>
#include <usr/iscsiboot.h>
+struct setting keep_san_setting __setting = {
+ .name = "keep-san",
+ .description = "Preserve SAN connection",
+ .tag = DHCP_EB_KEEP_SAN,
+ .type = &setting_type_int8,
+};
+
/**
* Guess boot network device
*
@@ -25,45 +37,66 @@ static struct net_device * guess_boot_netdev ( void ) {
}
int iscsiboot ( const char *root_path ) {
- struct scsi_device scsi;
- struct int13_drive drive;
+ struct scsi_device *scsi;
+ struct int13_drive *drive;
+ int keep_san;
int rc;
- memset ( &scsi, 0, sizeof ( scsi ) );
- memset ( &drive, 0, sizeof ( drive ) );
+ scsi = zalloc ( sizeof ( *scsi ) );
+ if ( ! scsi ) {
+ rc = -ENOMEM;
+ goto err_alloc_scsi;
+ }
+ drive = zalloc ( sizeof ( *drive ) );
+ if ( ! drive ) {
+ rc = -ENOMEM;
+ goto err_alloc_drive;
+ }
printf ( "iSCSI booting from %s\n", root_path );
- if ( ( rc = iscsi_attach ( &scsi, root_path ) ) != 0 ) {
+ if ( ( rc = iscsi_attach ( scsi, root_path ) ) != 0 ) {
printf ( "Could not attach iSCSI device: %s\n",
strerror ( rc ) );
- goto error_attach;
+ goto err_attach;
}
- if ( ( rc = init_scsidev ( &scsi ) ) != 0 ) {
+ if ( ( rc = init_scsidev ( scsi ) ) != 0 ) {
printf ( "Could not initialise iSCSI device: %s\n",
strerror ( rc ) );
- goto error_init;
+ goto err_init;
}
- drive.blockdev = &scsi.blockdev;
+ drive->blockdev = &scsi->blockdev;
/* FIXME: ugly, ugly hack */
struct net_device *netdev = guess_boot_netdev();
struct iscsi_session *iscsi =
- container_of ( scsi.backend, struct iscsi_session, refcnt );
+ container_of ( scsi->backend, struct iscsi_session, refcnt );
ibft_fill_data ( netdev, iscsi );
- register_int13_drive ( &drive );
- printf ( "Registered as BIOS drive %#02x\n", drive.drive );
- printf ( "Booting from BIOS drive %#02x\n", drive.drive );
- rc = int13_boot ( drive.drive );
+ register_int13_drive ( drive );
+ printf ( "Registered as BIOS drive %#02x\n", drive->drive );
+ printf ( "Booting from BIOS drive %#02x\n", drive->drive );
+ rc = int13_boot ( drive->drive );
printf ( "Boot failed\n" );
- printf ( "Unregistering BIOS drive %#02x\n", drive.drive );
- unregister_int13_drive ( &drive );
+ /* Leave drive registered, if instructed to do so */
+ keep_san = fetch_intz_setting ( NULL, &keep_san_setting );
+ if ( keep_san ) {
+ printf ( "Preserving connection to SAN disk\n" );
+ shutdown_exit_flags |= SHUTDOWN_KEEP_DEVICES;
+ return rc;
+ }
+
+ printf ( "Unregistering BIOS drive %#02x\n", drive->drive );
+ unregister_int13_drive ( drive );
- error_init:
- iscsi_detach ( &scsi );
- error_attach:
+ err_init:
+ iscsi_detach ( scsi );
+ err_attach:
+ free ( drive );
+ err_alloc_drive:
+ free ( scsi );
+ err_alloc_scsi:
return rc;
}