| /* | |
| * Copyright (C) 2025 Michael Brown <mbrown@fensystems.co.uk>. | |
| * | |
| * 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 <errno.h> | |
| #include <string.h> | |
| #include <ipxe/efi/efi.h> | |
| /* 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 ); | |
| struct efi_dropped_tpl tpl; | |
| 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 ) ); | |
| efi_drop_tpl ( &tpl ); | |
| efirc = bs->ConnectController ( device, drivers, NULL, TRUE ); | |
| efi_undrop_tpl ( &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; | |
| struct efi_dropped_tpl tpl; | |
| 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 ) ); | |
| efi_drop_tpl ( &tpl ); | |
| efirc = bs->DisconnectController ( device, driver, NULL ); | |
| efi_undrop_tpl ( &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; | |
| } |