/* * Copyright (C) 2025 Michael Brown . * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. * * You can also choose to distribute this program under the terms of * the Unmodified Binary Distribution Licence (as given in the file * COPYING.UBDL), provided that you have satisfied its requirements. */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); FILE_SECBOOT ( PERMITTED ); /** @file * * EFI driver connection and disconnection * */ #include #include #include /* Disambiguate the various error causes */ #define EINFO_EEFI_CONNECT \ __einfo_uniqify ( EINFO_EPLATFORM, 0x01, \ "Could not connect controllers" ) #define EINFO_EEFI_CONNECT_PROHIBITED \ __einfo_platformify ( EINFO_EEFI_CONNECT, \ EFI_SECURITY_VIOLATION, \ "Connecting controllers prohibited by " \ "security policy" ) #define EEFI_CONNECT_PROHIBITED \ __einfo_error ( EINFO_EEFI_CONNECT_PROHIBITED ) #define EEFI_CONNECT( efirc ) EPLATFORM ( EINFO_EEFI_CONNECT, efirc, \ EEFI_CONNECT_PROHIBITED ) /** * Connect UEFI driver(s) * * @v device EFI device handle * @v driver EFI driver handle, or NULL * @ret rc Return status code */ int efi_connect ( EFI_HANDLE device, EFI_HANDLE driver ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_HANDLE driverlist[2] = { driver, NULL }; EFI_HANDLE *drivers = ( driver ? driverlist : NULL ); EFI_STATUS efirc; int rc; /* Attempt connection at external TPL */ DBGC ( device, "EFI %s connecting ", efi_handle_name ( device ) ); DBGC ( device, "%s driver at %s TPL\n", ( driver ? efi_handle_name ( driver ) : "any" ), efi_tpl_name ( efi_external_tpl ) ); bs->RestoreTPL ( efi_external_tpl ); efirc = bs->ConnectController ( device, drivers, NULL, TRUE ); bs->RaiseTPL ( efi_internal_tpl ); if ( efirc != 0 ) { rc = -EEFI_CONNECT ( efirc ); DBGC ( device, "EFI %s could not connect: %s\n", efi_handle_name ( device ), strerror ( rc ) ); return rc; } return 0; } /** * Disconnect UEFI driver(s) * * @v device EFI device handle * @v driver EFI driver handle, or NULL * @ret rc Return status code */ int efi_disconnect ( EFI_HANDLE device, EFI_HANDLE driver ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_STATUS efirc; int rc; /* Attempt disconnection at external TPL */ DBGC ( device, "EFI %s disconnecting ", efi_handle_name ( device ) ); DBGC ( device, "%s driver at %s TPL\n", ( driver ? efi_handle_name ( driver ) : "any" ), efi_tpl_name ( efi_external_tpl ) ); bs->RestoreTPL ( efi_external_tpl ); efirc = bs->DisconnectController ( device, driver, NULL ); bs->RaiseTPL ( efi_internal_tpl ); if ( ( efirc != 0 ) && ( efirc != EFI_NOT_FOUND ) ) { rc = -EEFI ( efirc ); DBGC ( device, "EFI %s could not disconnect: %s\n", efi_handle_name ( device ), strerror ( rc ) ); return rc; } return 0; }