mirror of
https://github.com/ipxe/ipxe
synced 2025-12-22 21:11:03 +03:00
[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>
This commit is contained in:
@@ -22,6 +22,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
#include <ipxe/efi/efi.h>
|
||||
#include <ipxe/efi/Protocol/LoadedImage.h>
|
||||
#include <ipxe/uuid.h>
|
||||
#include <ipxe/init.h>
|
||||
|
||||
/** Image handle passed to entry point */
|
||||
EFI_HANDLE efi_image_handle;
|
||||
@@ -36,6 +37,21 @@ EFI_SYSTEM_TABLE *efi_systab;
|
||||
static EFI_GUID efi_loaded_image_protocol_guid
|
||||
= EFI_LOADED_IMAGE_PROTOCOL_GUID;
|
||||
|
||||
/** Event used to signal shutdown */
|
||||
static EFI_EVENT efi_shutdown_event;
|
||||
|
||||
/**
|
||||
* Shut down in preparation for booting an OS.
|
||||
*
|
||||
* This hook gets called at ExitBootServices time in order to make
|
||||
* sure that everything is properly shut down before the OS takes
|
||||
* over.
|
||||
*/
|
||||
static EFIAPI void efi_shutdown_hook ( EFI_EVENT event __unused,
|
||||
void *context __unused ) {
|
||||
shutdown_boot();
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up EFI configuration table
|
||||
*
|
||||
@@ -129,5 +145,18 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle,
|
||||
}
|
||||
}
|
||||
|
||||
/* EFI is perfectly capable of gracefully shutting down any
|
||||
* loaded devices if it decides to fall back to a legacy boot.
|
||||
* For no particularly comprehensible reason, it doesn't
|
||||
* bother doing so when ExitBootServices() is called.
|
||||
*/
|
||||
if ( ( efirc = bs->CreateEvent ( EVT_SIGNAL_EXIT_BOOT_SERVICES,
|
||||
TPL_CALLBACK, efi_shutdown_hook,
|
||||
NULL, &efi_shutdown_event ) ) != 0 ) {
|
||||
DBGC ( systab, "EFI could not create ExitBootServices event: "
|
||||
"%s\n", efi_strerror ( efirc ) );
|
||||
return efirc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -489,7 +489,7 @@ static struct efi_driver efipci_driver =
|
||||
* Install EFI PCI driver
|
||||
*
|
||||
*/
|
||||
static void efipci_driver_init ( void ) {
|
||||
static void efipci_driver_startup ( void ) {
|
||||
struct efi_driver *efidrv = &efipci_driver;
|
||||
EFI_STATUS efirc;
|
||||
|
||||
@@ -503,7 +503,27 @@ static void efipci_driver_init ( void ) {
|
||||
DBGC ( efidrv, "EFIPCI driver installed\n" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Shut down EFI PCI driver
|
||||
*
|
||||
* @v booting System is shutting down for OS boot
|
||||
*/
|
||||
static void efipci_driver_shutdown ( int booting __unused ) {
|
||||
struct efi_driver *efidrv = &efipci_driver;
|
||||
struct efi_pci_device *efipci;
|
||||
struct efi_pci_device *tmp;
|
||||
|
||||
/* Shut down any remaining devices */
|
||||
list_for_each_entry_safe ( efipci, tmp, &efi_pci_devices, list ) {
|
||||
DBGC ( efipci, "EFIPCI " PCI_FMT " still active at shutdown; "
|
||||
"forcing close\n", PCI_ARGS ( &efipci->pci ) );
|
||||
pci_remove ( &efipci->pci );
|
||||
efipci_destroy ( efidrv, efipci );
|
||||
}
|
||||
}
|
||||
|
||||
/** EFI PCI startup function */
|
||||
struct startup_fn startup_pci __startup_fn ( STARTUP_NORMAL ) = {
|
||||
.startup = efipci_driver_init,
|
||||
.startup = efipci_driver_startup,
|
||||
.shutdown = efipci_driver_shutdown,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user