Browse Source

[efi] Allow driver to be unloaded

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

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

@@ -45,5 +45,6 @@ extern EFI_DEVICE_PATH_PROTOCOL *
45 45
 efi_devpath_end ( EFI_DEVICE_PATH_PROTOCOL *path );
46 46
 
47 47
 extern int efi_driver_install ( struct efi_driver *efidrv );
48
+extern void efi_driver_uninstall ( struct efi_driver *efidrv );
48 49
 
49 50
 #endif /* _IPXE_EFI_DRIVER_H */

+ 14
- 2
src/interface/efi/efi_bofm.c View File

@@ -387,7 +387,7 @@ static struct efi_driver efi_bofm_driver =
387 387
  * Install EFI BOFM driver
388 388
  *
389 389
  */
390
-static void efi_bofm_driver_init ( void ) {
390
+static void efi_bofm_driver_startup ( void ) {
391 391
 	struct efi_driver *efidrv = &efi_bofm_driver;
392 392
 	int rc;
393 393
 
@@ -401,7 +401,19 @@ static void efi_bofm_driver_init ( void ) {
401 401
 	DBGC ( efidrv, "EFIBOFM driver installed\n" );
402 402
 }
403 403
 
404
+/**
405
+ * Shut down EFI BOFM driver
406
+ *
407
+ * @v booting		System is shutting down for OS boot
408
+ */
409
+static void efi_bofm_driver_shutdown ( int booting __unused ) {
410
+	struct efi_driver *efidrv = &efi_bofm_driver;
411
+
412
+	efi_driver_uninstall ( efidrv );
413
+}
414
+
404 415
 /** EFI BOFM startup function */
405 416
 struct startup_fn startup_bofm __startup_fn ( STARTUP_EARLY ) = {
406
-	.startup = efi_bofm_driver_init,
417
+	.startup = efi_bofm_driver_startup,
418
+	.shutdown = efi_bofm_driver_shutdown,
407 419
 };

+ 44
- 2
src/interface/efi/efi_driver.c View File

@@ -122,7 +122,7 @@ efi_driver_get_controller_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf __unused,
122 122
  * Install EFI driver
123 123
  *
124 124
  * @v efidrv		EFI driver
125
- * @ret efirc		EFI status code
125
+ * @ret rc		Return status code
126 126
  */
127 127
 int efi_driver_install ( struct efi_driver *efidrv ) {
128 128
 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
@@ -143,7 +143,9 @@ int efi_driver_install ( struct efi_driver *efidrv ) {
143 143
 	efi_snprintf ( efidrv->wname,
144 144
 		       ( sizeof ( efidrv->wname ) /
145 145
 			 sizeof ( efidrv->wname[0] ) ),
146
-		       PRODUCT_SHORT_NAME " - %s", efidrv->name );
146
+		       PRODUCT_SHORT_NAME "%s%s",
147
+		       ( efidrv->name ? " - " : "" ),
148
+		       ( efidrv->name ? efidrv->name : "" ) );
147 149
 
148 150
 	/* Install driver */
149 151
 	if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
@@ -160,3 +162,43 @@ int efi_driver_install ( struct efi_driver *efidrv ) {
160 162
 	DBGC ( efidrv, "EFIDRV %s installed\n", efidrv->name );
161 163
 	return 0;
162 164
 }
165
+
166
+/**
167
+ * Uninstall EFI driver
168
+ *
169
+ * @v efidrv		EFI driver
170
+ */
171
+void efi_driver_uninstall ( struct efi_driver *efidrv ) {
172
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
173
+	EFI_HANDLE *handles;
174
+	UINTN num_handles;
175
+	EFI_STATUS efirc;
176
+	UINTN i;
177
+	int rc;
178
+
179
+	/* Disconnect the driver from its devices */
180
+	if ( ( efirc = bs->LocateHandleBuffer ( AllHandles, NULL, NULL,
181
+						&num_handles,
182
+						&handles ) ) != 0 ) {
183
+		rc = -EEFI ( efirc );
184
+		DBGC ( efidrv, "EFIDRV %s could not list handles: %s\n",
185
+		       efidrv->name, strerror ( rc ) );
186
+		/* No way to disconnect driver; leave it loaded */
187
+		return;
188
+	}
189
+	DBGC ( efidrv, "EFIDRV %s disconnecting devices\n", efidrv->name );
190
+	for ( i = 0 ; i < num_handles ; i++ ) {
191
+		bs->DisconnectController ( handles[i],
192
+					   efidrv->driver.DriverBindingHandle,
193
+					   NULL );
194
+	}
195
+	bs->FreePool ( handles );
196
+
197
+	/* Uninstall the driver */
198
+	bs->UninstallMultipleProtocolInterfaces (
199
+			efidrv->driver.DriverBindingHandle,
200
+			&efi_driver_binding_protocol_guid, &efidrv->driver,
201
+			&efi_component_name2_protocol_guid, &efidrv->wtf,
202
+			NULL );
203
+	DBGC ( efidrv, "EFIDRV %s uninstalled\n", efidrv->name );
204
+}

+ 97
- 0
src/interface/efi/efi_init.c View File

@@ -22,6 +22,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
22 22
 #include <string.h>
23 23
 #include <errno.h>
24 24
 #include <ipxe/efi/efi.h>
25
+#include <ipxe/efi/efi_driver.h>
25 26
 #include <ipxe/efi/Protocol/LoadedImage.h>
26 27
 #include <ipxe/efi/Protocol/DevicePath.h>
27 28
 #include <ipxe/uuid.h>
@@ -50,6 +51,64 @@ static EFI_GUID efi_loaded_image_device_path_protocol_guid
50 51
 /** Event used to signal shutdown */
51 52
 static EFI_EVENT efi_shutdown_event;
52 53
 
54
+/* Forward declarations */
55
+static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle );
56
+
57
+/**
58
+ * Check to see if driver supports a device
59
+ *
60
+ * @v driver		EFI driver
61
+ * @v device		EFI device
62
+ * @v child		Path to child device, if any
63
+ * @ret efirc		EFI status code
64
+ */
65
+static EFI_STATUS EFIAPI
66
+efi_image_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
67
+		    EFI_HANDLE device __unused,
68
+		    EFI_DEVICE_PATH_PROTOCOL *child __unused ) {
69
+
70
+	return EFI_UNSUPPORTED;
71
+}
72
+
73
+/**
74
+ * Attach driver to device
75
+ *
76
+ * @v driver		EFI driver
77
+ * @v device		EFI device
78
+ * @v child		Path to child device, if any
79
+ * @ret efirc		EFI status code
80
+ */
81
+static EFI_STATUS EFIAPI
82
+efi_image_start ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
83
+		EFI_HANDLE device __unused,
84
+		EFI_DEVICE_PATH_PROTOCOL *child __unused ) {
85
+
86
+	return EFI_UNSUPPORTED;
87
+}
88
+
89
+/**
90
+ * Detach driver from device
91
+ *
92
+ * @v driver		EFI driver
93
+ * @v device		EFI device
94
+ * @v pci		PCI device
95
+ * @v num_children	Number of child devices
96
+ * @v children		List of child devices
97
+ * @ret efirc		EFI status code
98
+ */
99
+static EFI_STATUS EFIAPI
100
+efi_image_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
101
+	       EFI_HANDLE device __unused, UINTN num_children __unused,
102
+	       EFI_HANDLE *children __unused ) {
103
+
104
+	return EFI_UNSUPPORTED;
105
+}
106
+
107
+/** EFI loaded image driver */
108
+static struct efi_driver efi_image_driver =
109
+	EFI_DRIVER_INIT ( NULL, efi_image_supported, efi_image_start,
110
+			  efi_image_stop );
111
+
53 112
 /**
54 113
  * Shut down in preparation for booting an OS.
55 114
  *
@@ -189,5 +248,43 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle,
189 248
 		return efirc;
190 249
 	}
191 250
 
251
+	/* Install an EFI driver on the image handle, to allow the
252
+	 * driver to be subsequently unloaded.
253
+	 */
254
+	efi_image_driver.driver.DriverBindingHandle = image_handle;
255
+	if ( ( rc = efi_driver_install ( &efi_image_driver ) ) != 0 ) {
256
+		DBGC ( systab, "EFI could not install loaded image driver: "
257
+		       "%s\n", strerror ( rc ) );
258
+		return EFIRC ( rc );
259
+	}
260
+
261
+	/* Install image unload method */
262
+	efi_loaded_image->Unload = efi_unload;
263
+
264
+	return 0;
265
+}
266
+
267
+/**
268
+ * Shut down EFI environment
269
+ *
270
+ * @v image_handle	Image handle
271
+ */
272
+static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle __unused ) {
273
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
274
+	EFI_SYSTEM_TABLE *systab = efi_systab;
275
+
276
+	DBGC ( systab, "EFI image unloading\n" );
277
+
278
+	/* Shut down */
279
+	shutdown_exit();
280
+
281
+	/* Uninstall exit boot services event */
282
+	bs->CloseEvent ( efi_shutdown_event );
283
+
284
+	/* Uninstall loaded image driver */
285
+	efi_driver_uninstall ( &efi_image_driver );
286
+
287
+	DBGC ( systab, "EFI image unloaded\n" );
288
+
192 289
 	return 0;
193 290
 }

+ 3
- 0
src/interface/efi/efi_pci.c View File

@@ -519,6 +519,9 @@ static void efipci_driver_shutdown ( int booting __unused ) {
519 519
 	struct efi_pci_device *efipci;
520 520
 	struct efi_pci_device *tmp;
521 521
 
522
+	/* Uninstall driver */
523
+	efi_driver_uninstall ( efidrv );
524
+
522 525
 	/* Shut down any remaining devices */
523 526
 	list_for_each_entry_safe ( efipci, tmp, &efi_pci_devices, list ) {
524 527
 		DBGC ( efipci, "EFIPCI " PCI_FMT " still active at shutdown; "

Loading…
Cancel
Save