Procházet zdrojové kódy

[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 před 13 roky
rodič
revize
fc7239bdc8
3 změnil soubory, kde provedl 51 přidání a 32 odebrání
  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 Zobrazit soubor

@@ -26,20 +26,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
26 26
 
27 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 30
  * Execute EFI image
45 31
  *
@@ -64,30 +50,14 @@ static int efi_image_exec ( struct image *image ) {
64 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 53
 	/* Start the image */
79 54
 	if ( ( efirc = bs->StartImage ( handle, &exit_data_size,
80 55
 					&exit_data ) ) != 0 ) {
81 56
 		DBGC ( image, "EFIIMAGE %p returned with status %s\n",
82 57
 		       image, efi_strerror ( efirc ) );
83 58
 	}
84
-
85 59
 	rc = EFIRC_TO_RC ( efirc );
86 60
 
87
-	/* Remove the shutdown hook */
88
-	bs->CloseEvent ( efi_shutdown_event );
89
-
90
-done:
91 61
 	/* Unload the image.  We can't leave it loaded, because we
92 62
 	 * have no "unload" operation.
93 63
 	 */

+ 29
- 0
src/interface/efi/efi_init.c Zobrazit soubor

@@ -22,6 +22,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
22 22
 #include <ipxe/efi/efi.h>
23 23
 #include <ipxe/efi/Protocol/LoadedImage.h>
24 24
 #include <ipxe/uuid.h>
25
+#include <ipxe/init.h>
25 26
 
26 27
 /** Image handle passed to entry point */
27 28
 EFI_HANDLE efi_image_handle;
@@ -36,6 +37,21 @@ EFI_SYSTEM_TABLE *efi_systab;
36 37
 static EFI_GUID efi_loaded_image_protocol_guid
37 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 56
  * Look up EFI configuration table
41 57
  *
@@ -129,5 +145,18 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle,
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 161
 	return 0;
133 162
 }

+ 22
- 2
src/interface/efi/efi_pci.c Zobrazit soubor

@@ -489,7 +489,7 @@ static struct efi_driver efipci_driver =
489 489
  * Install EFI PCI driver
490 490
  *
491 491
  */
492
-static void efipci_driver_init ( void ) {
492
+static void efipci_driver_startup ( void ) {
493 493
 	struct efi_driver *efidrv = &efipci_driver;
494 494
 	EFI_STATUS efirc;
495 495
 
@@ -503,7 +503,27 @@ static void efipci_driver_init ( void ) {
503 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 525
 /** EFI PCI startup function */
507 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
 };

Načítá se…
Zrušit
Uložit