Browse Source

[efi] Disable SNP devices when running iPXE as the application

Some UEFI builds will set up a timer to continuously poll any SNP
devices.  This can drain packets from the network device's receive
queue before iPXE gets a chance to process them.

Use netdev_rx_[un]freeze() to explicitly indicate when we expect our
network devices to be driven via the external SNP API (as we do with
the UNDI API on the standard BIOS build), and disable the SNP API
except when receive queue processing is frozen.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 10 years ago
parent
commit
f473b9c3f6

+ 4
- 2
src/arch/x86/prefix/efidrvprefix.c View File

22
 #include <stdlib.h>
22
 #include <stdlib.h>
23
 #include <ipxe/init.h>
23
 #include <ipxe/init.h>
24
 #include <ipxe/efi/efi.h>
24
 #include <ipxe/efi/efi.h>
25
+#include <ipxe/efi/efi_snp.h>
25
 
26
 
26
 /**
27
 /**
27
  * EFI entry point
28
  * EFI entry point
42
 	initialise();
43
 	initialise();
43
 	startup();
44
 	startup();
44
 
45
 
46
+	/* Release network devices for use via SNP */
47
+	efi_snp_release();
48
+
45
 	return 0;
49
 	return 0;
46
 }
50
 }
47
-
48
-REQUIRE_OBJECT ( efi_snp );

+ 4
- 0
src/image/efi_image.c View File

219
 	loaded.image->LoadOptionsSize =
219
 	loaded.image->LoadOptionsSize =
220
 		( ( wcslen ( cmdline ) + 1 /* NUL */ ) * sizeof ( wchar_t ) );
220
 		( ( wcslen ( cmdline ) + 1 /* NUL */ ) * sizeof ( wchar_t ) );
221
 
221
 
222
+	/* Release network devices for use via SNP */
223
+	efi_snp_release();
224
+
222
 	/* Start the image */
225
 	/* Start the image */
223
 	if ( ( efirc = bs->StartImage ( handle, NULL, NULL ) ) != 0 ) {
226
 	if ( ( efirc = bs->StartImage ( handle, NULL, NULL ) ) != 0 ) {
224
 		rc = -EEFI_START ( efirc );
227
 		rc = -EEFI_START ( efirc );
231
 	rc = 0;
234
 	rc = 0;
232
 
235
 
233
  err_start_image:
236
  err_start_image:
237
+	efi_snp_claim();
234
  err_open_protocol:
238
  err_open_protocol:
235
 	/* Unload the image.  We can't leave it loaded, because we
239
 	/* Unload the image.  We can't leave it loaded, because we
236
 	 * have no "unload" operation.
240
 	 * have no "unload" operation.

+ 4
- 0
src/include/ipxe/efi/efi_snp.h View File

32
 	EFI_SIMPLE_NETWORK_PROTOCOL snp;
32
 	EFI_SIMPLE_NETWORK_PROTOCOL snp;
33
 	/** The SNP "mode" (parameters) */
33
 	/** The SNP "mode" (parameters) */
34
 	EFI_SIMPLE_NETWORK_MODE mode;
34
 	EFI_SIMPLE_NETWORK_MODE mode;
35
+	/** Started flag */
36
+	int started;
35
 	/** Outstanding TX packet count (via "interrupt status")
37
 	/** Outstanding TX packet count (via "interrupt status")
36
 	 *
38
 	 *
37
 	 * Used in order to generate TX completions.
39
 	 * Used in order to generate TX completions.
75
 extern int efi_snp_hii_install ( struct efi_snp_device *snpdev );
77
 extern int efi_snp_hii_install ( struct efi_snp_device *snpdev );
76
 extern void efi_snp_hii_uninstall ( struct efi_snp_device *snpdev );
78
 extern void efi_snp_hii_uninstall ( struct efi_snp_device *snpdev );
77
 extern struct efi_snp_device * last_opened_snpdev ( void );
79
 extern struct efi_snp_device * last_opened_snpdev ( void );
80
+extern void efi_snp_claim ( void );
81
+extern void efi_snp_release ( void );
78
 
82
 
79
 #endif /* _IPXE_EFI_SNP_H */
83
 #endif /* _IPXE_EFI_SNP_H */

+ 126
- 7
src/interface/efi/efi_snp.c View File

69
 /** List of SNP devices */
69
 /** List of SNP devices */
70
 static LIST_HEAD ( efi_snp_devices );
70
 static LIST_HEAD ( efi_snp_devices );
71
 
71
 
72
+/**
73
+ * Set EFI SNP mode state
74
+ *
75
+ * @v snp		SNP interface
76
+ */
77
+static void efi_snp_set_state ( struct efi_snp_device *snpdev ) {
78
+	struct net_device *netdev = snpdev->netdev;
79
+	EFI_SIMPLE_NETWORK_MODE *mode = &snpdev->mode;
80
+
81
+	/* Calculate state */
82
+	if ( ! snpdev->started ) {
83
+		/* Start() method not called; report as Stopped */
84
+		mode->State = EfiSimpleNetworkStopped;
85
+	} else if ( ! netdev_is_open ( netdev ) ) {
86
+		/* Network device not opened; report as Started */
87
+		mode->State = EfiSimpleNetworkStarted;
88
+	} else if ( ! netdev_rx_frozen ( netdev ) ) {
89
+		/* Network device opened but claimed for use by iPXE; report
90
+		 * as Started to inhibit receive polling.
91
+		 */
92
+		mode->State = EfiSimpleNetworkStarted;
93
+	} else {
94
+		/* Network device opened and available for use via SNP; report
95
+		 * as Initialized.
96
+		 */
97
+		mode->State = EfiSimpleNetworkInitialized;
98
+	}
99
+}
100
+
72
 /**
101
 /**
73
  * Set EFI SNP mode based on iPXE net device parameters
102
  * Set EFI SNP mode based on iPXE net device parameters
74
  *
103
  *
134
 
163
 
135
 	DBGC2 ( snpdev, "SNPDEV %p START\n", snpdev );
164
 	DBGC2 ( snpdev, "SNPDEV %p START\n", snpdev );
136
 
165
 
137
-	snpdev->mode.State = EfiSimpleNetworkStarted;
166
+	/* Fail if net device is currently claimed for use by iPXE */
167
+	if ( ! netdev_rx_frozen ( snpdev->netdev ) )
168
+		return EFI_NOT_READY;
169
+
170
+	snpdev->started = 1;
171
+	efi_snp_set_state ( snpdev );
138
 	return 0;
172
 	return 0;
139
 }
173
 }
140
 
174
 
151
 
185
 
152
 	DBGC2 ( snpdev, "SNPDEV %p STOP\n", snpdev );
186
 	DBGC2 ( snpdev, "SNPDEV %p STOP\n", snpdev );
153
 
187
 
154
-	snpdev->mode.State = EfiSimpleNetworkStopped;
188
+	/* Fail if net device is currently claimed for use by iPXE */
189
+	if ( ! netdev_rx_frozen ( snpdev->netdev ) )
190
+		return EFI_NOT_READY;
191
+
192
+	snpdev->started = 0;
193
+	efi_snp_set_state ( snpdev );
155
 	return 0;
194
 	return 0;
156
 }
195
 }
157
 
196
 
174
 		snpdev, ( ( unsigned long ) extra_rx_bufsize ),
213
 		snpdev, ( ( unsigned long ) extra_rx_bufsize ),
175
 		( ( unsigned long ) extra_tx_bufsize ) );
214
 		( ( unsigned long ) extra_tx_bufsize ) );
176
 
215
 
216
+	/* Fail if net device is currently claimed for use by iPXE */
217
+	if ( ! netdev_rx_frozen ( snpdev->netdev ) )
218
+		return EFI_NOT_READY;
219
+
177
 	if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
220
 	if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
178
 		DBGC ( snpdev, "SNPDEV %p could not open %s: %s\n",
221
 		DBGC ( snpdev, "SNPDEV %p could not open %s: %s\n",
179
 		       snpdev, snpdev->netdev->name, strerror ( rc ) );
222
 		       snpdev, snpdev->netdev->name, strerror ( rc ) );
180
 		return EFIRC ( rc );
223
 		return EFIRC ( rc );
181
 	}
224
 	}
225
+	efi_snp_set_state ( snpdev );
182
 
226
 
183
-	snpdev->mode.State = EfiSimpleNetworkInitialized;
184
 	return 0;
227
 	return 0;
185
 }
228
 }
186
 
229
 
200
 	DBGC2 ( snpdev, "SNPDEV %p RESET (%s extended verification)\n",
243
 	DBGC2 ( snpdev, "SNPDEV %p RESET (%s extended verification)\n",
201
 		snpdev, ( ext_verify ? "with" : "without" ) );
244
 		snpdev, ( ext_verify ? "with" : "without" ) );
202
 
245
 
246
+	/* Fail if net device is currently claimed for use by iPXE */
247
+	if ( ! netdev_rx_frozen ( snpdev->netdev ) )
248
+		return EFI_NOT_READY;
249
+
203
 	netdev_close ( snpdev->netdev );
250
 	netdev_close ( snpdev->netdev );
204
-	snpdev->mode.State = EfiSimpleNetworkStarted;
251
+	efi_snp_set_state ( snpdev );
205
 
252
 
206
 	if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
253
 	if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
207
 		DBGC ( snpdev, "SNPDEV %p could not reopen %s: %s\n",
254
 		DBGC ( snpdev, "SNPDEV %p could not reopen %s: %s\n",
208
 		       snpdev, snpdev->netdev->name, strerror ( rc ) );
255
 		       snpdev, snpdev->netdev->name, strerror ( rc ) );
209
 		return EFIRC ( rc );
256
 		return EFIRC ( rc );
210
 	}
257
 	}
258
+	efi_snp_set_state ( snpdev );
211
 
259
 
212
-	snpdev->mode.State = EfiSimpleNetworkInitialized;
213
 	return 0;
260
 	return 0;
214
 }
261
 }
215
 
262
 
226
 
273
 
227
 	DBGC2 ( snpdev, "SNPDEV %p SHUTDOWN\n", snpdev );
274
 	DBGC2 ( snpdev, "SNPDEV %p SHUTDOWN\n", snpdev );
228
 
275
 
276
+	/* Fail if net device is currently claimed for use by iPXE */
277
+	if ( ! netdev_rx_frozen ( snpdev->netdev ) )
278
+		return EFI_NOT_READY;
279
+
229
 	netdev_close ( snpdev->netdev );
280
 	netdev_close ( snpdev->netdev );
230
-	snpdev->mode.State = EfiSimpleNetworkStarted;
281
+	efi_snp_set_state ( snpdev );
282
+
231
 	return 0;
283
 	return 0;
232
 }
284
 }
233
 
285
 
258
 			    snpdev->netdev->ll_protocol->ll_addr_len );
310
 			    snpdev->netdev->ll_protocol->ll_addr_len );
259
 	}
311
 	}
260
 
312
 
313
+	/* Fail if net device is currently claimed for use by iPXE */
314
+	if ( ! netdev_rx_frozen ( snpdev->netdev ) )
315
+		return EFI_NOT_READY;
316
+
261
 	/* Lie through our teeth, otherwise MNP refuses to accept us */
317
 	/* Lie through our teeth, otherwise MNP refuses to accept us */
262
 	return 0;
318
 	return 0;
263
 }
319
 }
280
 	DBGC2 ( snpdev, "SNPDEV %p STATION_ADDRESS %s\n", snpdev,
336
 	DBGC2 ( snpdev, "SNPDEV %p STATION_ADDRESS %s\n", snpdev,
281
 		( reset ? "reset" : ll_protocol->ntoa ( new ) ) );
337
 		( reset ? "reset" : ll_protocol->ntoa ( new ) ) );
282
 
338
 
339
+	/* Fail if net device is currently claimed for use by iPXE */
340
+	if ( ! netdev_rx_frozen ( snpdev->netdev ) )
341
+		return EFI_NOT_READY;
342
+
283
 	/* Set the MAC address */
343
 	/* Set the MAC address */
284
 	if ( reset )
344
 	if ( reset )
285
 		new = &snpdev->mode.PermanentAddress;
345
 		new = &snpdev->mode.PermanentAddress;
313
 	DBGC2 ( snpdev, "SNPDEV %p STATISTICS%s", snpdev,
373
 	DBGC2 ( snpdev, "SNPDEV %p STATISTICS%s", snpdev,
314
 		( reset ? " reset" : "" ) );
374
 		( reset ? " reset" : "" ) );
315
 
375
 
376
+	/* Fail if net device is currently claimed for use by iPXE */
377
+	if ( ! netdev_rx_frozen ( snpdev->netdev ) )
378
+		return EFI_NOT_READY;
379
+
316
 	/* Gather statistics */
380
 	/* Gather statistics */
317
 	memset ( &stats_buf, 0, sizeof ( stats_buf ) );
381
 	memset ( &stats_buf, 0, sizeof ( stats_buf ) );
318
 	stats_buf.TxGoodFrames = snpdev->netdev->tx_stats.good;
382
 	stats_buf.TxGoodFrames = snpdev->netdev->tx_stats.good;
361
 		   inet_ntoa ( *( ( struct in_addr * ) ip ) ) );
425
 		   inet_ntoa ( *( ( struct in_addr * ) ip ) ) );
362
 	DBGC2 ( snpdev, "SNPDEV %p MCAST_IP_TO_MAC %s\n", snpdev, ip_str );
426
 	DBGC2 ( snpdev, "SNPDEV %p MCAST_IP_TO_MAC %s\n", snpdev, ip_str );
363
 
427
 
428
+	/* Fail if net device is currently claimed for use by iPXE */
429
+	if ( ! netdev_rx_frozen ( snpdev->netdev ) )
430
+		return EFI_NOT_READY;
431
+
364
 	/* Try to hash the address */
432
 	/* Try to hash the address */
365
 	if ( ( rc = ll_protocol->mc_hash ( ( ipv6 ? AF_INET6 : AF_INET ),
433
 	if ( ( rc = ll_protocol->mc_hash ( ( ipv6 ? AF_INET6 : AF_INET ),
366
 					   ip, mac ) ) != 0 ) {
434
 					   ip, mac ) ) != 0 ) {
394
 	if ( ! read )
462
 	if ( ! read )
395
 		DBGC2_HDA ( snpdev, offset, data, len );
463
 		DBGC2_HDA ( snpdev, offset, data, len );
396
 
464
 
465
+	/* Fail if net device is currently claimed for use by iPXE */
466
+	if ( ! netdev_rx_frozen ( snpdev->netdev ) )
467
+		return EFI_NOT_READY;
468
+
397
 	return EFI_UNSUPPORTED;
469
 	return EFI_UNSUPPORTED;
398
 }
470
 }
399
 
471
 
413
 
485
 
414
 	DBGC2 ( snpdev, "SNPDEV %p GET_STATUS", snpdev );
486
 	DBGC2 ( snpdev, "SNPDEV %p GET_STATUS", snpdev );
415
 
487
 
488
+	/* Fail if net device is currently claimed for use by iPXE */
489
+	if ( ! netdev_rx_frozen ( snpdev->netdev ) )
490
+		return EFI_NOT_READY;
491
+
416
 	/* Poll the network device */
492
 	/* Poll the network device */
417
 	efi_snp_poll ( snpdev );
493
 	efi_snp_poll ( snpdev );
418
 
494
 
508
 	}
584
 	}
509
 	DBGC2 ( snpdev, "\n" );
585
 	DBGC2 ( snpdev, "\n" );
510
 
586
 
587
+	/* Fail if net device is currently claimed for use by iPXE */
588
+	if ( ! netdev_rx_frozen ( snpdev->netdev ) )
589
+		return EFI_NOT_READY;
590
+
511
 	/* Sanity checks */
591
 	/* Sanity checks */
512
 	if ( ll_header_len ) {
592
 	if ( ll_header_len ) {
513
 		if ( ll_header_len != ll_protocol->ll_header_len ) {
593
 		if ( ll_header_len != ll_protocol->ll_header_len ) {
616
 	DBGC2 ( snpdev, "SNPDEV %p RECEIVE %p(+%lx)", snpdev, data,
696
 	DBGC2 ( snpdev, "SNPDEV %p RECEIVE %p(+%lx)", snpdev, data,
617
 		( ( unsigned long ) *len ) );
697
 		( ( unsigned long ) *len ) );
618
 
698
 
699
+	/* Fail if net device is currently claimed for use by iPXE */
700
+	if ( ! netdev_rx_frozen ( snpdev->netdev ) )
701
+		return EFI_NOT_READY;
702
+
619
 	/* Poll the network device */
703
 	/* Poll the network device */
620
 	efi_snp_poll ( snpdev );
704
 	efi_snp_poll ( snpdev );
621
 
705
 
655
 
739
 
656
  out_bad_ll_header:
740
  out_bad_ll_header:
657
 	free_iob ( iobuf );
741
 	free_iob ( iobuf );
658
-out_no_packet:
742
+ out_no_packet:
659
 	return EFIRC ( rc );
743
 	return EFIRC ( rc );
660
 }
744
 }
661
 
745
 
676
 	if ( ! netdev_is_open ( snpdev->netdev ) )
760
 	if ( ! netdev_is_open ( snpdev->netdev ) )
677
 		return;
761
 		return;
678
 
762
 
763
+	/* Do nothing if net device is currently claimed for use by iPXE */
764
+	if ( ! netdev_rx_frozen ( snpdev->netdev ) )
765
+		return;
766
+
679
 	/* Poll the network device */
767
 	/* Poll the network device */
680
 	efi_snp_poll ( snpdev );
768
 	efi_snp_poll ( snpdev );
681
 
769
 
785
 		return EFI_UNSUPPORTED;
873
 		return EFI_UNSUPPORTED;
786
 	}
874
 	}
787
 
875
 
876
+	/* Claim network devices for use by iPXE */
877
+	efi_snp_claim();
878
+
788
 	/* Boot from network device */
879
 	/* Boot from network device */
789
 	ipxe ( netdev );
880
 	ipxe ( netdev );
790
 
881
 
882
+	/* Release network devices for use via SNP */
883
+	efi_snp_release();
884
+
791
 	/* Assume boot process was aborted */
885
 	/* Assume boot process was aborted */
792
 	return EFI_ABORTED;
886
 	return EFI_ABORTED;
793
 }
887
 }
1011
 		( netdev_link_ok ( netdev ) ? TRUE : FALSE );
1105
 		( netdev_link_ok ( netdev ) ? TRUE : FALSE );
1012
 	DBGC ( snpdev, "SNPDEV %p link is %s\n", snpdev,
1106
 	DBGC ( snpdev, "SNPDEV %p link is %s\n", snpdev,
1013
 	       ( snpdev->mode.MediaPresent ? "up" : "down" ) );
1107
 	       ( snpdev->mode.MediaPresent ? "up" : "down" ) );
1108
+
1109
+	/* Update mode state */
1110
+	efi_snp_set_state ( snpdev );
1014
 }
1111
 }
1015
 
1112
 
1016
 /**
1113
 /**
1069
 
1166
 
1070
 	return efi_snp_demux ( netdev );
1167
 	return efi_snp_demux ( netdev );
1071
 }
1168
 }
1169
+
1170
+/**
1171
+ * Claim network devices for use by iPXE
1172
+ *
1173
+ */
1174
+void efi_snp_claim ( void ) {
1175
+	struct net_device *netdev;
1176
+
1177
+	for_each_netdev ( netdev )
1178
+		netdev_rx_unfreeze ( netdev );
1179
+}
1180
+
1181
+/**
1182
+ * Release network devices for use via SNP
1183
+ *
1184
+ */
1185
+void efi_snp_release ( void ) {
1186
+	struct net_device *netdev;
1187
+
1188
+	for_each_netdev ( netdev )
1189
+		netdev_rx_freeze ( netdev );
1190
+}

Loading…
Cancel
Save