Переглянути джерело

[iSCSI] Support Windows Server 2008 direct iSCSI installation

Add yet another ugly hack to iscsiboot.c, this time to allow the user to
inhibit the shutdown/removal of the iSCSI INT13 device (and the network
devices, since they are required for the iSCSI device to function).

On the plus side, the fact that shutdown() now takes flags to
differentiate between shutdown-for-exit and shutdown-for-boot means that
another ugly hack (to allow returning via the PXE stack on BIOSes that
have broken INT 18 calls) will be easier.

I feel dirty.
tags/v0.9.4
Michael Brown 16 роки тому
джерело
коміт
03c80c12b8

+ 1
- 1
src/arch/i386/firmware/pcbios/hidemem.c Переглянути файл

@@ -128,7 +128,7 @@ static void hide_etherboot ( void ) {
128 128
  * Uninstalls the INT 15 handler installed by hide_etherboot(), if
129 129
  * possible.
130 130
  */
131
-static void unhide_etherboot ( void ) {
131
+static void unhide_etherboot ( int flags __unused ) {
132 132
 
133 133
 	/* If we have more than one hooked interrupt at this point, it
134 134
 	 * means that some other vector is still hooked, in which case

+ 1
- 1
src/arch/i386/image/bzimage.c Переглянути файл

@@ -348,7 +348,7 @@ static int bzimage_exec ( struct image *image ) {
348 348
 		       sizeof ( bzhdr ) );
349 349
 
350 350
 	/* Prepare for exiting */
351
-	shutdown();
351
+	shutdown ( SHUTDOWN_BOOT );
352 352
 
353 353
 	DBGC ( image, "bzImage %p jumping to RM kernel at %04x:0000 "
354 354
 	       "(stack %04x:%04zx)\n", image,

+ 1
- 1
src/arch/i386/image/elfboot.c Переглянути файл

@@ -46,7 +46,7 @@ static int elfboot_exec ( struct image *image ) {
46 46
 	/* An ELF image has no callback interface, so we need to shut
47 47
 	 * down before invoking it.
48 48
 	 */
49
-	shutdown();
49
+	shutdown ( SHUTDOWN_BOOT );
50 50
 
51 51
 	/* Jump to OS with flat physical addressing */
52 52
 	__asm__ __volatile__ ( PHYS_CODE ( "call *%%edi\n\t" )

+ 1
- 1
src/arch/i386/image/multiboot.c Переглянути файл

@@ -277,7 +277,7 @@ static int multiboot_exec ( struct image *image ) {
277 277
 	/* Multiboot images may not return and have no callback
278 278
 	 * interface, so shut everything down prior to booting the OS.
279 279
 	 */
280
-	shutdown();
280
+	shutdown ( SHUTDOWN_BOOT );
281 281
 
282 282
 	/* Jump to OS with flat physical addressing */
283 283
 	__asm__ __volatile__ ( PHYS_CODE ( "call *%%edi\n\t" )

+ 1
- 1
src/arch/i386/image/nbi.c Переглянути файл

@@ -429,7 +429,7 @@ static int nbi_exec ( struct image *image ) {
429 429
 	/* Shut down now if NBI image will not return */
430 430
 	may_return = NBI_PROGRAM_RETURNS ( imgheader.flags );
431 431
 	if ( ! may_return )
432
-		shutdown();
432
+		shutdown ( SHUTDOWN_BOOT );
433 433
 
434 434
 	/* Execute NBI image */
435 435
 	if ( NBI_LINEAR_EXEC_ADDR ( imgheader.flags ) ) {

+ 7
- 0
src/core/config.c Переглянути файл

@@ -205,3 +205,10 @@ REQUIRE_OBJECT ( gdbidt );
205 205
 REQUIRE_OBJECT ( gdbudp );
206 206
 REQUIRE_OBJECT ( gdbstub_cmd );
207 207
 #endif
208
+
209
+/*
210
+ * Drag in objects that are always required, but not dragged in via
211
+ * symbol dependencies.
212
+ *
213
+ */
214
+REQUIRE_OBJECT ( device );

+ 13
- 5
src/core/device.c Переглянути файл

@@ -20,6 +20,7 @@
20 20
 #include <gpxe/list.h>
21 21
 #include <gpxe/tables.h>
22 22
 #include <gpxe/device.h>
23
+#include <gpxe/init.h>
23 24
 
24 25
 /**
25 26
  * @file
@@ -68,13 +69,11 @@ static void rootdev_remove ( struct root_device *rootdev ) {
68 69
 /**
69 70
  * Probe all devices
70 71
  *
71
- * @ret rc		Return status code
72
- *
73 72
  * This initiates probing for all devices in the system.  After this
74 73
  * call, the device hierarchy will be populated, and all hardware
75 74
  * should be ready to use.
76 75
  */
77
-int probe_devices ( void ) {
76
+static void probe_devices ( void ) {
78 77
 	struct root_device *rootdev;
79 78
 	int rc;
80 79
 
@@ -84,19 +83,28 @@ int probe_devices ( void ) {
84 83
 		if ( ( rc = rootdev_probe ( rootdev ) ) != 0 )
85 84
 			list_del ( &rootdev->dev.siblings );
86 85
 	}
87
-	return 0;
88 86
 }
89 87
 
90 88
 /**
91 89
  * Remove all devices
92 90
  *
93 91
  */
94
-void remove_devices ( void ) {
92
+static void remove_devices ( int flags ) {
95 93
 	struct root_device *rootdev;
96 94
 	struct root_device *tmp;
97 95
 
96
+	if ( flags & SHUTDOWN_KEEP_DEVICES ) {
97
+		DBG ( "Refusing to remove devices on shutdown\n" );
98
+		return;
99
+	}
100
+
98 101
 	list_for_each_entry_safe ( rootdev, tmp, &devices, dev.siblings ) {
99 102
 		rootdev_remove ( rootdev );
100 103
 		list_del ( &rootdev->dev.siblings );
101 104
 	}
102 105
 }
106
+
107
+struct startup_fn startup_devices __startup_fn ( STARTUP_NORMAL ) = {
108
+	.startup = probe_devices,
109
+	.shutdown = remove_devices,
110
+};

+ 4
- 10
src/core/init.c Переглянути файл

@@ -79,17 +79,14 @@ void startup ( void ) {
79 79
 			startup_fn->startup();
80 80
 	}
81 81
 
82
-	/* Probe for all devices.  Treated separately because nothing
83
-	 * else will drag in device.o
84
-	 */
85
-	probe_devices();
86
-
87 82
 	started = 1;
88 83
 }
89 84
 
90 85
 /**
91 86
  * Shut down gPXE
92 87
  *
88
+ * @v flags		Shutdown behaviour flags
89
+ *
93 90
  * This function reverses the actions of startup(), and leaves gPXE in
94 91
  * a state ready to be removed from memory.  You may call startup()
95 92
  * again after calling shutdown().
@@ -97,20 +94,17 @@ void startup ( void ) {
97 94
  * Call this function only once, before either exiting main() or
98 95
  * starting up a non-returnable image.
99 96
  */
100
-void shutdown ( void ) {
97
+void shutdown ( int flags ) {
101 98
 	struct startup_fn *startup_fn;
102 99
 
103 100
 	if ( ! started )
104 101
 		return;
105 102
 
106
-	/* Remove all devices */
107
-	remove_devices();
108
-
109 103
 	/* Call registered shutdown functions (in reverse order) */
110 104
 	for ( startup_fn = startup_fns_end - 1 ; startup_fn >= startup_fns ;
111 105
 	      startup_fn-- ) {
112 106
 		if ( startup_fn->shutdown )
113
-			startup_fn->shutdown();
107
+			startup_fn->shutdown ( flags );
114 108
 	}
115 109
 
116 110
 	started = 0;

+ 1
- 1
src/core/main.c Переглянути файл

@@ -62,7 +62,7 @@ __cdecl int main ( void ) {
62 62
 			shell();
63 63
 	}
64 64
 
65
-	shutdown();
65
+	shutdown ( SHUTDOWN_EXIT | shutdown_exit_flags );
66 66
 
67 67
 	return 0;
68 68
 }

+ 2
- 2
src/core/serial.c Переглянути файл

@@ -224,7 +224,7 @@ static void serial_init ( void ) {
224 224
  *	Cleanup our use of the serial port, in particular flush the
225 225
  *	output buffer so we don't accidentially lose characters.
226 226
  */
227
-static void serial_fini ( void ) {
227
+static void serial_fini ( int flags __unused ) {
228 228
 	int i, status;
229 229
 	/* Flush the output buffer to avoid dropping characters,
230 230
 	 * if we are reinitializing the serial port.
@@ -247,6 +247,6 @@ struct init_fn serial_init_fn __init_fn ( INIT_SERIAL ) = {
247 247
 };
248 248
 
249 249
 /** Serial driver startup function */
250
-struct startup_fn serial_startup_fn __startup_fn ( STARTUP_NORMAL ) = {
250
+struct startup_fn serial_startup_fn __startup_fn ( STARTUP_EARLY ) = {
251 251
 	.shutdown = serial_fini,
252 252
 };

+ 0
- 3
src/include/gpxe/device.h Переглянути файл

@@ -105,7 +105,4 @@ struct root_driver {
105 105
 /** Declare a root device */
106 106
 #define __root_device __table ( struct root_device, root_devices, 01 )
107 107
 
108
-extern int probe_devices ( void );
109
-extern void remove_devices ( void );
110
-
111 108
 #endif /* _GPXE_DEVICE_H */

+ 12
- 3
src/include/gpxe/dhcp.h Переглянути файл

@@ -164,7 +164,7 @@ struct dhcp_packet;
164 164
  * priority of multiple option blocks (e.g. options from non-volatile
165 165
  * storage versus options from a DHCP server).
166 166
  */
167
-#define DHCP_EB_PRIORITY DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 1 )
167
+#define DHCP_EB_PRIORITY DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x01 )
168 168
 
169 169
 /** "Your" IP address
170 170
  *
@@ -172,7 +172,7 @@ struct dhcp_packet;
172 172
  * field, in order to provide a consistent approach to storing and
173 173
  * processing options.  It should never be present in a DHCP packet.
174 174
  */
175
-#define DHCP_EB_YIADDR DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 2 )
175
+#define DHCP_EB_YIADDR DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x02 )
176 176
 
177 177
 /** "Server" IP address
178 178
  *
@@ -180,7 +180,16 @@ struct dhcp_packet;
180 180
  * field, in order to provide a consistent approach to storing and
181 181
  * processing options.  It should never be present in a DHCP packet.
182 182
  */
183
-#define DHCP_EB_SIADDR DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 3 )
183
+#define DHCP_EB_SIADDR DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x03 )
184
+
185
+/** Keep SAN drive registered
186
+ *
187
+ * If set to a non-zero value, gPXE will not detach any SAN drive
188
+ * after failing to boot from it.  (This option is required in order
189
+ * to perform a Windows Server 2008 installation direct to an iSCSI
190
+ * target.)
191
+ */
192
+#define DHCP_EB_KEEP_SAN DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x08 )
184 193
 
185 194
 /*
186 195
  * Tags in the range 0x10-0x7f are reserved for feature markers

+ 1
- 0
src/include/gpxe/errfile.h Переглянути файл

@@ -155,6 +155,7 @@
155 155
 #define ERRFILE_ibft		      ( ERRFILE_OTHER | 0x000c0000 )
156 156
 #define ERRFILE_tls		      ( ERRFILE_OTHER | 0x000d0000 )
157 157
 #define ERRFILE_ifmgmt		      ( ERRFILE_OTHER | 0x000e0000 )
158
+#define ERRFILE_iscsiboot	      ( ERRFILE_OTHER | 0x000f0000 )
158 159
 
159 160
 /** @} */
160 161
 

+ 12
- 2
src/include/gpxe/init.h Переглянути файл

@@ -28,6 +28,16 @@ struct init_fn {
28 28
 
29 29
 /** @} */
30 30
 
31
+/** Shutdown flags */
32
+enum shutdown_flags {
33
+	/** Shutdown is in order to exit (return to gPXE's caller) */
34
+	SHUTDOWN_EXIT = 0x0001,
35
+	/** Shutdown is in order to boot an OS */
36
+	SHUTDOWN_BOOT = 0x0002,
37
+	/** Do not remove devices */
38
+	SHUTDOWN_KEEP_DEVICES = 0x0004,
39
+};
40
+
31 41
 /**
32 42
  * A startup/shutdown function
33 43
  *
@@ -36,7 +46,7 @@ struct init_fn {
36 46
  */
37 47
 struct startup_fn {
38 48
 	void ( * startup ) ( void );
39
-	void ( * shutdown ) ( void );
49
+	void ( * shutdown ) ( int flags );
40 50
 };
41 51
 
42 52
 /** Declare a startup/shutdown function */
@@ -58,6 +68,6 @@ struct startup_fn {
58 68
 
59 69
 extern void initialise ( void );
60 70
 extern void startup ( void );
61
-extern void shutdown ( void );
71
+extern void shutdown ( int flags );
62 72
 
63 73
 #endif /* _GPXE_INIT_H */

+ 2
- 0
src/include/usr/autoboot.h Переглянути файл

@@ -7,6 +7,8 @@
7 7
  *
8 8
  */
9 9
 
10
+extern int shutdown_exit_flags;
11
+
10 12
 extern void autoboot ( void );
11 13
 extern int boot_root_path ( const char *root_path );
12 14
 

+ 1
- 1
src/interface/pxe/pxe_preboot.c Переглянути файл

@@ -318,7 +318,7 @@ PXENV_EXIT_t pxenv_stop_undi ( struct s_PXENV_STOP_UNDI *stop_undi ) {
318 318
 	pxe_set_netdev ( NULL );
319 319
 
320 320
 	/* Prepare for unload */
321
-	shutdown();
321
+	shutdown ( SHUTDOWN_BOOT );
322 322
 
323 323
 	stop_undi->Status = PXENV_STATUS_SUCCESS;
324 324
 	return PXENV_EXIT_SUCCESS;

+ 3
- 0
src/usr/autoboot.c Переглянути файл

@@ -41,6 +41,9 @@
41 41
 /** Time to wait for link-up */
42 42
 #define LINK_WAIT_MS 15000
43 43
 
44
+/** Shutdown flags for exit */
45
+int shutdown_exit_flags = 0;
46
+
44 47
 /**
45 48
  * Identify the boot network device
46 49
  *

+ 52
- 19
src/usr/iscsiboot.c Переглянути файл

@@ -1,13 +1,25 @@
1 1
 #include <stdint.h>
2 2
 #include <string.h>
3
+#include <stdlib.h>
3 4
 #include <stdio.h>
5
+#include <errno.h>
4 6
 #include <gpxe/iscsi.h>
5 7
 #include <gpxe/settings.h>
8
+#include <gpxe/dhcp.h>
6 9
 #include <gpxe/netdevice.h>
7 10
 #include <gpxe/ibft.h>
11
+#include <gpxe/init.h>
8 12
 #include <int13.h>
13
+#include <usr/autoboot.h>
9 14
 #include <usr/iscsiboot.h>
10 15
 
16
+struct setting keep_san_setting __setting = {
17
+	.name = "keep-san",
18
+	.description = "Preserve SAN connection",
19
+	.tag = DHCP_EB_KEEP_SAN,
20
+	.type = &setting_type_int8,
21
+};
22
+
11 23
 /**
12 24
  * Guess boot network device
13 25
  *
@@ -25,45 +37,66 @@ static struct net_device * guess_boot_netdev ( void ) {
25 37
 }
26 38
 
27 39
 int iscsiboot ( const char *root_path ) {
28
-	struct scsi_device scsi;
29
-	struct int13_drive drive;
40
+	struct scsi_device *scsi;
41
+	struct int13_drive *drive;
42
+	int keep_san;
30 43
 	int rc;
31 44
 
32
-	memset ( &scsi, 0, sizeof ( scsi ) );
33
-	memset ( &drive, 0, sizeof ( drive ) );
45
+	scsi = zalloc ( sizeof ( *scsi ) );
46
+	if ( ! scsi ) {
47
+		rc = -ENOMEM;
48
+		goto err_alloc_scsi;
49
+	}
50
+	drive = zalloc ( sizeof ( *drive ) );
51
+	if ( ! drive ) {
52
+		rc = -ENOMEM;
53
+		goto err_alloc_drive;
54
+	}
34 55
 
35 56
 	printf ( "iSCSI booting from %s\n", root_path );
36 57
 
37
-	if ( ( rc = iscsi_attach ( &scsi, root_path ) ) != 0 ) {
58
+	if ( ( rc = iscsi_attach ( scsi, root_path ) ) != 0 ) {
38 59
 		printf ( "Could not attach iSCSI device: %s\n",
39 60
 			 strerror ( rc ) );
40
-		goto error_attach;
61
+		goto err_attach;
41 62
 	}
42
-	if ( ( rc = init_scsidev ( &scsi ) ) != 0 ) {
63
+	if ( ( rc = init_scsidev ( scsi ) ) != 0 ) {
43 64
 		printf ( "Could not initialise iSCSI device: %s\n",
44 65
 			 strerror ( rc ) );
45
-		goto error_init;
66
+		goto err_init;
46 67
 	}
47 68
 
48
-	drive.blockdev = &scsi.blockdev;
69
+	drive->blockdev = &scsi->blockdev;
49 70
 
50 71
 	/* FIXME: ugly, ugly hack */
51 72
 	struct net_device *netdev = guess_boot_netdev();
52 73
 	struct iscsi_session *iscsi =
53
-		container_of ( scsi.backend, struct iscsi_session, refcnt );
74
+		container_of ( scsi->backend, struct iscsi_session, refcnt );
54 75
 	ibft_fill_data ( netdev, iscsi );
55 76
 
56
-	register_int13_drive ( &drive );
57
-	printf ( "Registered as BIOS drive %#02x\n", drive.drive );
58
-	printf ( "Booting from BIOS drive %#02x\n", drive.drive );
59
-	rc = int13_boot ( drive.drive );
77
+	register_int13_drive ( drive );
78
+	printf ( "Registered as BIOS drive %#02x\n", drive->drive );
79
+	printf ( "Booting from BIOS drive %#02x\n", drive->drive );
80
+	rc = int13_boot ( drive->drive );
60 81
 	printf ( "Boot failed\n" );
61 82
 
62
-	printf ( "Unregistering BIOS drive %#02x\n", drive.drive );
63
-	unregister_int13_drive ( &drive );
83
+	/* Leave drive registered, if instructed to do so */
84
+	keep_san = fetch_intz_setting ( NULL, &keep_san_setting );
85
+	if ( keep_san ) {
86
+		printf ( "Preserving connection to SAN disk\n" );
87
+		shutdown_exit_flags |= SHUTDOWN_KEEP_DEVICES;
88
+		return rc;
89
+	}
90
+
91
+	printf ( "Unregistering BIOS drive %#02x\n", drive->drive );
92
+	unregister_int13_drive ( drive );
64 93
 
65
- error_init:
66
-	iscsi_detach ( &scsi );
67
- error_attach:
94
+ err_init:
95
+	iscsi_detach ( scsi );
96
+ err_attach:
97
+	free ( drive );
98
+ err_alloc_drive:
99
+	free ( scsi );
100
+ err_alloc_scsi:
68 101
 	return rc;
69 102
 }

Завантаження…
Відмінити
Зберегти