Browse Source

[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 years ago
parent
commit
7b3cc18462

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

389
  */
389
  */
390
 static int snpnet_pci_info ( struct efi_device *efidev, struct device *dev ) {
390
 static int snpnet_pci_info ( struct efi_device *efidev, struct device *dev ) {
391
 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
391
 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
392
-	EFI_DEVICE_PATH_PROTOCOL *devpath = efidev->path;
393
 	EFI_HANDLE device = efidev->device;
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
 	struct pci_device pci;
398
 	struct pci_device pci;
395
 	EFI_HANDLE pci_device;
399
 	EFI_HANDLE pci_device;
396
 	EFI_STATUS efirc;
400
 	EFI_STATUS efirc;
397
 	int rc;
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
 	/* Check for presence of PCI I/O protocol */
416
 	/* Check for presence of PCI I/O protocol */
400
 	if ( ( efirc = bs->LocateDevicePath ( &efi_pci_io_protocol_guid,
417
 	if ( ( efirc = bs->LocateDevicePath ( &efi_pci_io_protocol_guid,
401
 					      &devpath, &pci_device ) ) != 0 ) {
418
 					      &devpath, &pci_device ) ) != 0 ) {
419
+		rc = -EEFI ( efirc );
402
 		DBGC ( device, "SNP %p %s is not a PCI device\n",
420
 		DBGC ( device, "SNP %p %s is not a PCI device\n",
403
 		       device, efi_handle_name ( device ) );
421
 		       device, efi_handle_name ( device ) );
404
-		return -EEFI ( efirc );
422
+		goto err_locate_pci_io;
405
 	}
423
 	}
406
 
424
 
407
 	/* Get PCI device information */
425
 	/* Get PCI device information */
408
 	if ( ( rc = efipci_info ( pci_device, &pci ) ) != 0 ) {
426
 	if ( ( rc = efipci_info ( pci_device, &pci ) ) != 0 ) {
409
 		DBGC ( device, "SNP %p %s could not get PCI information: %s\n",
427
 		DBGC ( device, "SNP %p %s could not get PCI information: %s\n",
410
 		       device, efi_handle_name ( device ), strerror ( rc ) );
428
 		       device, efi_handle_name ( device ), strerror ( rc ) );
411
-		return rc;
429
+		goto err_efipci_info;
412
 	}
430
 	}
413
 
431
 
414
 	/* Populate SNP device information */
432
 	/* Populate SNP device information */
415
 	memcpy ( &dev->desc, &pci.dev.desc, sizeof ( dev->desc ) );
433
 	memcpy ( &dev->desc, &pci.dev.desc, sizeof ( dev->desc ) );
416
 	snprintf ( dev->name, sizeof ( dev->name ), "SNP-%s", pci.dev.name );
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 View File

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

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

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

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

66
 	wchar_t driver_name[16];
66
 	wchar_t driver_name[16];
67
 	/** Controller name */
67
 	/** Controller name */
68
 	wchar_t controller_name[64];
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
 extern int efi_snp_hii_install ( struct efi_snp_device *snpdev );
73
 extern int efi_snp_hii_install ( struct efi_snp_device *snpdev );

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

208
 static EFI_STATUS EFIAPI
208
 static EFI_STATUS EFIAPI
209
 efi_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
209
 efi_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
210
 		   EFI_HANDLE device, EFI_DEVICE_PATH_PROTOCOL *child ) {
210
 		   EFI_HANDLE device, EFI_DEVICE_PATH_PROTOCOL *child ) {
211
-	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
212
 	struct efi_driver *efidrv;
211
 	struct efi_driver *efidrv;
213
 	struct efi_device *efidev;
212
 	struct efi_device *efidev;
214
-	union {
215
-		EFI_DEVICE_PATH_PROTOCOL *devpath;
216
-		void *interface;
217
-	} devpath;
218
 	EFI_STATUS efirc;
213
 	EFI_STATUS efirc;
219
 	int rc;
214
 	int rc;
220
 
215
 
244
 	INIT_LIST_HEAD ( &efidev->dev.children );
239
 	INIT_LIST_HEAD ( &efidev->dev.children );
245
 	list_add ( &efidev->dev.siblings, &efi_devices );
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
 	/* Try to start this device */
242
 	/* Try to start this device */
264
 	for_each_table_entry ( efidrv, EFI_DRIVERS ) {
243
 	for_each_table_entry ( efidrv, EFI_DRIVERS ) {
265
 		if ( ( rc = efidrv->supported ( device ) ) != 0 ) {
244
 		if ( ( rc = efidrv->supported ( device ) ) != 0 ) {
282
 	}
261
 	}
283
 	efirc = EFI_UNSUPPORTED;
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
 	list_del ( &efidev->dev.siblings );
264
 	list_del ( &efidev->dev.siblings );
289
 	free ( efidev );
265
 	free ( efidev );
290
  err_alloc:
266
  err_alloc:
306
 efi_driver_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
282
 efi_driver_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
307
 		  EFI_HANDLE device, UINTN num_children,
283
 		  EFI_HANDLE device, UINTN num_children,
308
 		  EFI_HANDLE *children ) {
284
 		  EFI_HANDLE *children ) {
309
-	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
310
 	struct efi_driver *efidrv;
285
 	struct efi_driver *efidrv;
311
 	struct efi_device *efidev;
286
 	struct efi_device *efidev;
312
 	UINTN i;
287
 	UINTN i;
331
 	efidrv = efidev->driver;
306
 	efidrv = efidev->driver;
332
 	assert ( efidrv != NULL );
307
 	assert ( efidrv != NULL );
333
 	efidrv->stop ( efidev );
308
 	efidrv->stop ( efidev );
334
-	bs->CloseProtocol ( efidev->device, &efi_device_path_protocol_guid,
335
-			    efi_image_handle, efidev->device );
336
 	list_del ( &efidev->dev.siblings );
309
 	list_del ( &efidev->dev.siblings );
337
 	free ( efidev );
310
 	free ( efidev );
338
 
311
 

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

909
 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
909
 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
910
 	struct efi_device *efidev;
910
 	struct efi_device *efidev;
911
 	struct efi_snp_device *snpdev;
911
 	struct efi_snp_device *snpdev;
912
+	union {
913
+		EFI_DEVICE_PATH_PROTOCOL *path;
914
+		void *interface;
915
+	} path;
912
 	EFI_DEVICE_PATH_PROTOCOL *path_end;
916
 	EFI_DEVICE_PATH_PROTOCOL *path_end;
913
 	MAC_ADDR_DEVICE_PATH *macpath;
917
 	MAC_ADDR_DEVICE_PATH *macpath;
914
 	size_t path_prefix_len = 0;
918
 	size_t path_prefix_len = 0;
923
 		goto err_no_efidev;
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
 	/* Allocate the SNP device */
930
 	/* Allocate the SNP device */
932
-	snpdev = zalloc ( sizeof ( *snpdev ) + path_prefix_len +
933
-			  sizeof ( *macpath ) );
931
+	snpdev = zalloc ( sizeof ( *snpdev ) );
934
 	if ( ! snpdev ) {
932
 	if ( ! snpdev ) {
935
 		rc = -ENOMEM;
933
 		rc = -ENOMEM;
936
 		goto err_alloc_snp;
934
 		goto err_alloc_snp;
993
 				       sizeof ( snpdev->name[0] ) ),
991
 				       sizeof ( snpdev->name[0] ) ),
994
 		       "%s", netdev->name );
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
 	/* Populate the device path */
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
 	path_end = ( ( void * ) ( macpath + 1 ) );
1020
 	path_end = ( ( void * ) ( macpath + 1 ) );
1000
 	memset ( macpath, 0, sizeof ( *macpath ) );
1021
 	memset ( macpath, 0, sizeof ( *macpath ) );
1001
 	macpath->Header.Type = MESSAGING_DEVICE_PATH;
1022
 	macpath->Header.Type = MESSAGING_DEVICE_PATH;
1013
 	if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
1034
 	if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
1014
 			&snpdev->handle,
1035
 			&snpdev->handle,
1015
 			&efi_simple_network_protocol_guid, &snpdev->snp,
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
 			&efi_nii_protocol_guid, &snpdev->nii,
1038
 			&efi_nii_protocol_guid, &snpdev->nii,
1018
 			&efi_nii31_protocol_guid, &snpdev->nii,
1039
 			&efi_nii31_protocol_guid, &snpdev->nii,
1019
 			&efi_component_name2_protocol_guid, &snpdev->name2,
1040
 			&efi_component_name2_protocol_guid, &snpdev->name2,
1046
 	/* Add to list of SNP devices */
1067
 	/* Add to list of SNP devices */
1047
 	list_add ( &snpdev->list, &efi_snp_devices );
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
 	DBGC ( snpdev, "SNPDEV %p installed for %s as device %p %s\n",
1074
 	DBGC ( snpdev, "SNPDEV %p installed for %s as device %p %s\n",
1050
 	       snpdev, netdev->name, snpdev->handle,
1075
 	       snpdev, netdev->name, snpdev->handle,
1051
 	       efi_handle_name ( snpdev->handle ) );
1076
 	       efi_handle_name ( snpdev->handle ) );
1058
 	bs->UninstallMultipleProtocolInterfaces (
1083
 	bs->UninstallMultipleProtocolInterfaces (
1059
 			snpdev->handle,
1084
 			snpdev->handle,
1060
 			&efi_simple_network_protocol_guid, &snpdev->snp,
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
 			&efi_nii_protocol_guid, &snpdev->nii,
1087
 			&efi_nii_protocol_guid, &snpdev->nii,
1063
 			&efi_nii31_protocol_guid, &snpdev->nii,
1088
 			&efi_nii31_protocol_guid, &snpdev->nii,
1064
 			&efi_component_name2_protocol_guid, &snpdev->name2,
1089
 			&efi_component_name2_protocol_guid, &snpdev->name2,
1065
 			&efi_load_file_protocol_guid, &snpdev->load_file,
1090
 			&efi_load_file_protocol_guid, &snpdev->load_file,
1066
 			NULL );
1091
 			NULL );
1067
  err_install_protocol_interface:
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
 	bs->CloseEvent ( snpdev->snp.WaitForPacket );
1098
 	bs->CloseEvent ( snpdev->snp.WaitForPacket );
1069
  err_create_event:
1099
  err_create_event:
1070
  err_ll_addr_len:
1100
  err_ll_addr_len:
1124
 	bs->UninstallMultipleProtocolInterfaces (
1154
 	bs->UninstallMultipleProtocolInterfaces (
1125
 			snpdev->handle,
1155
 			snpdev->handle,
1126
 			&efi_simple_network_protocol_guid, &snpdev->snp,
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
 			&efi_nii_protocol_guid, &snpdev->nii,
1158
 			&efi_nii_protocol_guid, &snpdev->nii,
1129
 			&efi_nii31_protocol_guid, &snpdev->nii,
1159
 			&efi_nii31_protocol_guid, &snpdev->nii,
1130
 			&efi_component_name2_protocol_guid, &snpdev->name2,
1160
 			&efi_component_name2_protocol_guid, &snpdev->name2,
1131
 			&efi_load_file_protocol_guid, &snpdev->load_file,
1161
 			&efi_load_file_protocol_guid, &snpdev->load_file,
1132
 			NULL );
1162
 			NULL );
1163
+	free ( snpdev->path );
1133
 	bs->CloseEvent ( snpdev->snp.WaitForPacket );
1164
 	bs->CloseEvent ( snpdev->snp.WaitForPacket );
1134
 	netdev_put ( snpdev->netdev );
1165
 	netdev_put ( snpdev->netdev );
1135
 	free ( snpdev );
1166
 	free ( snpdev );

Loading…
Cancel
Save