Sfoglia il codice sorgente

[efi] Open device path protocol only at point of use

Some EFI 1.10 systems (observed on an Apple iMac) do not allow us to
open the device path protocol with an attribute of
EFI_OPEN_PROTOCOL_BY_DRIVER and so we cannot maintain a safe,
long-lived pointer to the device path.  Work around this by instead
opening the device path protocol with an attribute of
EFI_OPEN_PROTOCOL_GET_PROTOCOL whenever we need to use it.

Debugged-by: Curtis Larsen <larsen@dixie.edu>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 10 anni fa
parent
commit
7b3cc18462

+ 27
- 4
src/drivers/net/efi/snpnet.c Vedi File

@@ -389,33 +389,56 @@ static struct net_device_operations snpnet_operations = {
389 389
  */
390 390
 static int snpnet_pci_info ( struct efi_device *efidev, struct device *dev ) {
391 391
 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
392
-	EFI_DEVICE_PATH_PROTOCOL *devpath = efidev->path;
393 392
 	EFI_HANDLE device = efidev->device;
393
+	union {
394
+		EFI_DEVICE_PATH_PROTOCOL *path;
395
+		void *interface;
396
+	} path;
397
+	EFI_DEVICE_PATH_PROTOCOL *devpath;
394 398
 	struct pci_device pci;
395 399
 	EFI_HANDLE pci_device;
396 400
 	EFI_STATUS efirc;
397 401
 	int rc;
398 402
 
403
+	/* Get device path */
404
+	if ( ( efirc = bs->OpenProtocol ( device,
405
+					  &efi_device_path_protocol_guid,
406
+					  &path.interface,
407
+					  efi_image_handle, device,
408
+					  EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
409
+		rc = -EEFI ( efirc );
410
+		DBGC ( device, "SNP %p %s cannot open device path: %s\n",
411
+		       device, efi_handle_name ( device ), strerror ( rc ) );
412
+		goto err_open_device_path;
413
+	}
414
+	devpath = path.path;
415
+
399 416
 	/* Check for presence of PCI I/O protocol */
400 417
 	if ( ( efirc = bs->LocateDevicePath ( &efi_pci_io_protocol_guid,
401 418
 					      &devpath, &pci_device ) ) != 0 ) {
419
+		rc = -EEFI ( efirc );
402 420
 		DBGC ( device, "SNP %p %s is not a PCI device\n",
403 421
 		       device, efi_handle_name ( device ) );
404
-		return -EEFI ( efirc );
422
+		goto err_locate_pci_io;
405 423
 	}
406 424
 
407 425
 	/* Get PCI device information */
408 426
 	if ( ( rc = efipci_info ( pci_device, &pci ) ) != 0 ) {
409 427
 		DBGC ( device, "SNP %p %s could not get PCI information: %s\n",
410 428
 		       device, efi_handle_name ( device ), strerror ( rc ) );
411
-		return rc;
429
+		goto err_efipci_info;
412 430
 	}
413 431
 
414 432
 	/* Populate SNP device information */
415 433
 	memcpy ( &dev->desc, &pci.dev.desc, sizeof ( dev->desc ) );
416 434
 	snprintf ( dev->name, sizeof ( dev->name ), "SNP-%s", pci.dev.name );
417 435
 
418
-	return 0;
436
+ err_efipci_info:
437
+ err_locate_pci_io:
438
+	bs->CloseProtocol ( device, &efi_device_path_protocol_guid,
439
+			    efi_image_handle, device );
440
+ err_open_device_path:
441
+	return rc;
419 442
 }
420 443
 
421 444
 /**

+ 1
- 1
src/image/efi_image.c Vedi File

@@ -167,7 +167,7 @@ static int efi_image_exec ( struct image *image ) {
167 167
 	}
168 168
 
169 169
 	/* Create device path for image */
170
-	path = efi_image_path ( image, &snpdev->path );
170
+	path = efi_image_path ( image, snpdev->path );
171 171
 	if ( ! path ) {
172 172
 		DBGC ( image, "EFIIMAGE %p could not create device path\n",
173 173
 		       image );

+ 0
- 2
src/include/ipxe/efi/efi_driver.h Vedi File

@@ -19,8 +19,6 @@ struct efi_device {
19 19
 	struct device dev;
20 20
 	/** EFI device handle */
21 21
 	EFI_HANDLE device;
22
-	/** Device path */
23
-	EFI_DEVICE_PATH_PROTOCOL *path;
24 22
 	/** Driver for this device */
25 23
 	struct efi_driver *driver;
26 24
 	/** Driver-private data */

+ 2
- 6
src/include/ipxe/efi/efi_snp.h Vedi File

@@ -66,12 +66,8 @@ struct efi_snp_device {
66 66
 	wchar_t driver_name[16];
67 67
 	/** Controller name */
68 68
 	wchar_t controller_name[64];
69
-	/** The device path
70
-	 *
71
-	 * This field is variable in size and must appear at the end
72
-	 * of the structure.
73
-	 */
74
-	EFI_DEVICE_PATH_PROTOCOL path;
69
+	/** The device path */
70
+	EFI_DEVICE_PATH_PROTOCOL *path;
75 71
 };
76 72
 
77 73
 extern int efi_snp_hii_install ( struct efi_snp_device *snpdev );

+ 0
- 27
src/interface/efi/efi_driver.c Vedi File

@@ -208,13 +208,8 @@ efi_driver_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
208 208
 static EFI_STATUS EFIAPI
209 209
 efi_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
210 210
 		   EFI_HANDLE device, EFI_DEVICE_PATH_PROTOCOL *child ) {
211
-	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
212 211
 	struct efi_driver *efidrv;
213 212
 	struct efi_device *efidev;
214
-	union {
215
-		EFI_DEVICE_PATH_PROTOCOL *devpath;
216
-		void *interface;
217
-	} devpath;
218 213
 	EFI_STATUS efirc;
219 214
 	int rc;
220 215
 
@@ -244,22 +239,6 @@ efi_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
244 239
 	INIT_LIST_HEAD ( &efidev->dev.children );
245 240
 	list_add ( &efidev->dev.siblings, &efi_devices );
246 241
 
247
-	/* Open device path protocol */
248
-	if ( ( efirc = bs->OpenProtocol ( device,
249
-					  &efi_device_path_protocol_guid,
250
-					  &devpath.interface,
251
-					  efi_image_handle, device,
252
-					  EFI_OPEN_PROTOCOL_BY_DRIVER ) ) != 0){
253
-		rc = -EEFI ( efirc );
254
-		DBGC ( device, "EFIDRV %p %s could not open device path: %s\n",
255
-		       device, efi_handle_name ( device ),
256
-		       strerror ( rc ) );
257
-		DBGC_EFI_OPENERS ( device, device,
258
-				   &efi_device_path_protocol_guid );
259
-		goto err_no_device_path;
260
-	}
261
-	efidev->path = devpath.devpath;
262
-
263 242
 	/* Try to start this device */
264 243
 	for_each_table_entry ( efidrv, EFI_DRIVERS ) {
265 244
 		if ( ( rc = efidrv->supported ( device ) ) != 0 ) {
@@ -282,9 +261,6 @@ efi_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
282 261
 	}
283 262
 	efirc = EFI_UNSUPPORTED;
284 263
 
285
-	bs->CloseProtocol ( device, &efi_device_path_protocol_guid,
286
-			    efi_image_handle, device );
287
- err_no_device_path:
288 264
 	list_del ( &efidev->dev.siblings );
289 265
 	free ( efidev );
290 266
  err_alloc:
@@ -306,7 +282,6 @@ static EFI_STATUS EFIAPI
306 282
 efi_driver_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
307 283
 		  EFI_HANDLE device, UINTN num_children,
308 284
 		  EFI_HANDLE *children ) {
309
-	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
310 285
 	struct efi_driver *efidrv;
311 286
 	struct efi_device *efidev;
312 287
 	UINTN i;
@@ -331,8 +306,6 @@ efi_driver_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
331 306
 	efidrv = efidev->driver;
332 307
 	assert ( efidrv != NULL );
333 308
 	efidrv->stop ( efidev );
334
-	bs->CloseProtocol ( efidev->device, &efi_device_path_protocol_guid,
335
-			    efi_image_handle, efidev->device );
336 309
 	list_del ( &efidev->dev.siblings );
337 310
 	free ( efidev );
338 311
 

+ 43
- 12
src/interface/efi/efi_snp.c Vedi File

@@ -909,6 +909,10 @@ static int efi_snp_probe ( struct net_device *netdev ) {
909 909
 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
910 910
 	struct efi_device *efidev;
911 911
 	struct efi_snp_device *snpdev;
912
+	union {
913
+		EFI_DEVICE_PATH_PROTOCOL *path;
914
+		void *interface;
915
+	} path;
912 916
 	EFI_DEVICE_PATH_PROTOCOL *path_end;
913 917
 	MAC_ADDR_DEVICE_PATH *macpath;
914 918
 	size_t path_prefix_len = 0;
@@ -923,14 +927,8 @@ static int efi_snp_probe ( struct net_device *netdev ) {
923 927
 		goto err_no_efidev;
924 928
 	}
925 929
 
926
-	/* Calculate device path prefix length */
927
-	path_end = efi_devpath_end ( efidev->path );
928
-	path_prefix_len = ( ( ( void * ) path_end ) -
929
-			    ( ( void * ) efidev->path ) );
930
-
931 930
 	/* Allocate the SNP device */
932
-	snpdev = zalloc ( sizeof ( *snpdev ) + path_prefix_len +
933
-			  sizeof ( *macpath ) );
931
+	snpdev = zalloc ( sizeof ( *snpdev ) );
934 932
 	if ( ! snpdev ) {
935 933
 		rc = -ENOMEM;
936 934
 		goto err_alloc_snp;
@@ -993,9 +991,32 @@ static int efi_snp_probe ( struct net_device *netdev ) {
993 991
 				       sizeof ( snpdev->name[0] ) ),
994 992
 		       "%s", netdev->name );
995 993
 
994
+	/* Get the parent device path */
995
+	if ( ( efirc = bs->OpenProtocol ( efidev->device,
996
+					  &efi_device_path_protocol_guid,
997
+					  &path.interface, efi_image_handle,
998
+					  efidev->device,
999
+					  EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
1000
+		rc = -EEFI ( efirc );
1001
+		DBGC ( snpdev, "SNPDEV %p cannot get %p %s device path: %s\n",
1002
+		       snpdev, efidev->device,
1003
+		       efi_handle_name ( efidev->device ), strerror ( rc ) );
1004
+		goto err_open_device_path;
1005
+	}
1006
+
1007
+	/* Allocate the new device path */
1008
+	path_end = efi_devpath_end ( path.path );
1009
+	path_prefix_len = ( ( ( void * ) path_end ) - ( ( void * ) path.path ));
1010
+	snpdev->path = zalloc ( path_prefix_len + sizeof ( *macpath ) +
1011
+				sizeof ( *path_end ) );
1012
+	if ( ! snpdev->path ) {
1013
+		rc = -ENOMEM;
1014
+		goto err_alloc_device_path;
1015
+	}
1016
+
996 1017
 	/* Populate the device path */
997
-	memcpy ( &snpdev->path, efidev->path, path_prefix_len );
998
-	macpath = ( ( ( void * ) &snpdev->path ) + path_prefix_len );
1018
+	memcpy ( snpdev->path, path.path, path_prefix_len );
1019
+	macpath = ( ( ( void * ) snpdev->path ) + path_prefix_len );
999 1020
 	path_end = ( ( void * ) ( macpath + 1 ) );
1000 1021
 	memset ( macpath, 0, sizeof ( *macpath ) );
1001 1022
 	macpath->Header.Type = MESSAGING_DEVICE_PATH;
@@ -1013,7 +1034,7 @@ static int efi_snp_probe ( struct net_device *netdev ) {
1013 1034
 	if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
1014 1035
 			&snpdev->handle,
1015 1036
 			&efi_simple_network_protocol_guid, &snpdev->snp,
1016
-			&efi_device_path_protocol_guid, &snpdev->path,
1037
+			&efi_device_path_protocol_guid, snpdev->path,
1017 1038
 			&efi_nii_protocol_guid, &snpdev->nii,
1018 1039
 			&efi_nii31_protocol_guid, &snpdev->nii,
1019 1040
 			&efi_component_name2_protocol_guid, &snpdev->name2,
@@ -1046,6 +1067,10 @@ static int efi_snp_probe ( struct net_device *netdev ) {
1046 1067
 	/* Add to list of SNP devices */
1047 1068
 	list_add ( &snpdev->list, &efi_snp_devices );
1048 1069
 
1070
+	/* Close device path */
1071
+	bs->CloseProtocol ( efidev->device, &efi_device_path_protocol_guid,
1072
+			    efi_image_handle, efidev->device );
1073
+
1049 1074
 	DBGC ( snpdev, "SNPDEV %p installed for %s as device %p %s\n",
1050 1075
 	       snpdev, netdev->name, snpdev->handle,
1051 1076
 	       efi_handle_name ( snpdev->handle ) );
@@ -1058,13 +1083,18 @@ static int efi_snp_probe ( struct net_device *netdev ) {
1058 1083
 	bs->UninstallMultipleProtocolInterfaces (
1059 1084
 			snpdev->handle,
1060 1085
 			&efi_simple_network_protocol_guid, &snpdev->snp,
1061
-			&efi_device_path_protocol_guid, &snpdev->path,
1086
+			&efi_device_path_protocol_guid, snpdev->path,
1062 1087
 			&efi_nii_protocol_guid, &snpdev->nii,
1063 1088
 			&efi_nii31_protocol_guid, &snpdev->nii,
1064 1089
 			&efi_component_name2_protocol_guid, &snpdev->name2,
1065 1090
 			&efi_load_file_protocol_guid, &snpdev->load_file,
1066 1091
 			NULL );
1067 1092
  err_install_protocol_interface:
1093
+	free ( snpdev->path );
1094
+ err_alloc_device_path:
1095
+	bs->CloseProtocol ( efidev->device, &efi_device_path_protocol_guid,
1096
+			    efi_image_handle, efidev->device );
1097
+ err_open_device_path:
1068 1098
 	bs->CloseEvent ( snpdev->snp.WaitForPacket );
1069 1099
  err_create_event:
1070 1100
  err_ll_addr_len:
@@ -1124,12 +1154,13 @@ static void efi_snp_remove ( struct net_device *netdev ) {
1124 1154
 	bs->UninstallMultipleProtocolInterfaces (
1125 1155
 			snpdev->handle,
1126 1156
 			&efi_simple_network_protocol_guid, &snpdev->snp,
1127
-			&efi_device_path_protocol_guid, &snpdev->path,
1157
+			&efi_device_path_protocol_guid, snpdev->path,
1128 1158
 			&efi_nii_protocol_guid, &snpdev->nii,
1129 1159
 			&efi_nii31_protocol_guid, &snpdev->nii,
1130 1160
 			&efi_component_name2_protocol_guid, &snpdev->name2,
1131 1161
 			&efi_load_file_protocol_guid, &snpdev->load_file,
1132 1162
 			NULL );
1163
+	free ( snpdev->path );
1133 1164
 	bs->CloseEvent ( snpdev->snp.WaitForPacket );
1134 1165
 	netdev_put ( snpdev->netdev );
1135 1166
 	free ( snpdev );

Loading…
Annulla
Salva