Browse Source

[efi] Ensure that all drivers are shut down before the OS boots

Reported-by: Itay Gazit <itayg@mellanox.co.il>
Suggested-by: Michael R Turner <mikeyt@us.ibm.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 13 years ago
parent
commit
fc7239bdc8
3 changed files with 51 additions and 32 deletions
  1. 0
    30
      src/image/efi_image.c
  2. 29
    0
      src/interface/efi/efi_init.c
  3. 22
    2
      src/interface/efi/efi_pci.c

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

26
 
26
 
27
 FEATURE ( FEATURE_IMAGE, "EFI", DHCP_EB_FEATURE_EFI, 1 );
27
 FEATURE ( FEATURE_IMAGE, "EFI", DHCP_EB_FEATURE_EFI, 1 );
28
 
28
 
29
-/** Event used to signal shutdown */
30
-static EFI_EVENT efi_shutdown_event;
31
-
32
-/**
33
- * Shut down in preparation for booting an OS.
34
- *
35
- * This hook gets called at ExitBootServices time in order to make sure that
36
- * the network cards are properly shut down before the OS takes over.
37
- */
38
-static EFIAPI void efi_shutdown_hook ( EFI_EVENT event __unused,
39
-				       void *context __unused ) {
40
-	shutdown_boot();
41
-}
42
-
43
 /**
29
 /**
44
  * Execute EFI image
30
  * Execute EFI image
45
  *
31
  *
64
 		return -ENOEXEC;
50
 		return -ENOEXEC;
65
 	}
51
 	}
66
 
52
 
67
-	/* Be sure to shut down the NIC at ExitBootServices time, or else
68
-	 * DMA from the card can corrupt the OS.
69
-	 */
70
-	efirc = bs->CreateEvent ( EVT_SIGNAL_EXIT_BOOT_SERVICES,
71
-				  TPL_CALLBACK, efi_shutdown_hook,
72
-				  NULL, &efi_shutdown_event );
73
-	if ( efirc ) {
74
-		rc = EFIRC_TO_RC ( efirc );
75
-		goto done;
76
-	}
77
-
78
 	/* Start the image */
53
 	/* Start the image */
79
 	if ( ( efirc = bs->StartImage ( handle, &exit_data_size,
54
 	if ( ( efirc = bs->StartImage ( handle, &exit_data_size,
80
 					&exit_data ) ) != 0 ) {
55
 					&exit_data ) ) != 0 ) {
81
 		DBGC ( image, "EFIIMAGE %p returned with status %s\n",
56
 		DBGC ( image, "EFIIMAGE %p returned with status %s\n",
82
 		       image, efi_strerror ( efirc ) );
57
 		       image, efi_strerror ( efirc ) );
83
 	}
58
 	}
84
-
85
 	rc = EFIRC_TO_RC ( efirc );
59
 	rc = EFIRC_TO_RC ( efirc );
86
 
60
 
87
-	/* Remove the shutdown hook */
88
-	bs->CloseEvent ( efi_shutdown_event );
89
-
90
-done:
91
 	/* Unload the image.  We can't leave it loaded, because we
61
 	/* Unload the image.  We can't leave it loaded, because we
92
 	 * have no "unload" operation.
62
 	 * have no "unload" operation.
93
 	 */
63
 	 */

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

22
 #include <ipxe/efi/efi.h>
22
 #include <ipxe/efi/efi.h>
23
 #include <ipxe/efi/Protocol/LoadedImage.h>
23
 #include <ipxe/efi/Protocol/LoadedImage.h>
24
 #include <ipxe/uuid.h>
24
 #include <ipxe/uuid.h>
25
+#include <ipxe/init.h>
25
 
26
 
26
 /** Image handle passed to entry point */
27
 /** Image handle passed to entry point */
27
 EFI_HANDLE efi_image_handle;
28
 EFI_HANDLE efi_image_handle;
36
 static EFI_GUID efi_loaded_image_protocol_guid
37
 static EFI_GUID efi_loaded_image_protocol_guid
37
 	= EFI_LOADED_IMAGE_PROTOCOL_GUID;
38
 	= EFI_LOADED_IMAGE_PROTOCOL_GUID;
38
 
39
 
40
+/** Event used to signal shutdown */
41
+static EFI_EVENT efi_shutdown_event;
42
+
43
+/**
44
+ * Shut down in preparation for booting an OS.
45
+ *
46
+ * This hook gets called at ExitBootServices time in order to make
47
+ * sure that everything is properly shut down before the OS takes
48
+ * over.
49
+ */
50
+static EFIAPI void efi_shutdown_hook ( EFI_EVENT event __unused,
51
+				       void *context __unused ) {
52
+	shutdown_boot();
53
+}
54
+
39
 /**
55
 /**
40
  * Look up EFI configuration table
56
  * Look up EFI configuration table
41
  *
57
  *
129
 		}
145
 		}
130
 	}
146
 	}
131
 
147
 
148
+	/* EFI is perfectly capable of gracefully shutting down any
149
+	 * loaded devices if it decides to fall back to a legacy boot.
150
+	 * For no particularly comprehensible reason, it doesn't
151
+	 * bother doing so when ExitBootServices() is called.
152
+	 */
153
+	if ( ( efirc = bs->CreateEvent ( EVT_SIGNAL_EXIT_BOOT_SERVICES,
154
+					 TPL_CALLBACK, efi_shutdown_hook,
155
+					 NULL, &efi_shutdown_event ) ) != 0 ) {
156
+		DBGC ( systab, "EFI could not create ExitBootServices event: "
157
+		       "%s\n", efi_strerror ( efirc ) );
158
+		return efirc;
159
+	}
160
+
132
 	return 0;
161
 	return 0;
133
 }
162
 }

+ 22
- 2
src/interface/efi/efi_pci.c View File

489
  * Install EFI PCI driver
489
  * Install EFI PCI driver
490
  *
490
  *
491
  */
491
  */
492
-static void efipci_driver_init ( void ) {
492
+static void efipci_driver_startup ( void ) {
493
 	struct efi_driver *efidrv = &efipci_driver;
493
 	struct efi_driver *efidrv = &efipci_driver;
494
 	EFI_STATUS efirc;
494
 	EFI_STATUS efirc;
495
 
495
 
503
 	DBGC ( efidrv, "EFIPCI driver installed\n" );
503
 	DBGC ( efidrv, "EFIPCI driver installed\n" );
504
 }
504
 }
505
 
505
 
506
+/**
507
+ * Shut down EFI PCI driver
508
+ *
509
+ * @v booting		System is shutting down for OS boot
510
+ */
511
+static void efipci_driver_shutdown ( int booting __unused ) {
512
+	struct efi_driver *efidrv = &efipci_driver;
513
+	struct efi_pci_device *efipci;
514
+	struct efi_pci_device *tmp;
515
+
516
+	/* Shut down any remaining devices */
517
+	list_for_each_entry_safe ( efipci, tmp, &efi_pci_devices, list ) {
518
+		DBGC ( efipci, "EFIPCI " PCI_FMT " still active at shutdown; "
519
+		       "forcing close\n", PCI_ARGS ( &efipci->pci ) );
520
+		pci_remove ( &efipci->pci );
521
+		efipci_destroy ( efidrv, efipci );
522
+	}
523
+}
524
+
506
 /** EFI PCI startup function */
525
 /** EFI PCI startup function */
507
 struct startup_fn startup_pci __startup_fn ( STARTUP_NORMAL ) = {
526
 struct startup_fn startup_pci __startup_fn ( STARTUP_NORMAL ) = {
508
-	.startup = efipci_driver_init,
527
+	.startup = efipci_driver_startup,
528
+	.shutdown = efipci_driver_shutdown,
509
 };
529
 };

Loading…
Cancel
Save