|  | @@ -0,0 +1,237 @@
 | 
		
	
		
			
			|  | 1 | +/*
 | 
		
	
		
			
			|  | 2 | + * Copyright (C) 2019 Michael Brown <mbrown@fensystems.co.uk>.
 | 
		
	
		
			
			|  | 3 | + *
 | 
		
	
		
			
			|  | 4 | + * This program is free software; you can redistribute it and/or
 | 
		
	
		
			
			|  | 5 | + * modify it under the terms of the GNU General Public License as
 | 
		
	
		
			
			|  | 6 | + * published by the Free Software Foundation; either version 2 of the
 | 
		
	
		
			
			|  | 7 | + * License, or any later version.
 | 
		
	
		
			
			|  | 8 | + *
 | 
		
	
		
			
			|  | 9 | + * This program is distributed in the hope that it will be useful, but
 | 
		
	
		
			
			|  | 10 | + * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
		
	
		
			
			|  | 11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
		
	
		
			
			|  | 12 | + * General Public License for more details.
 | 
		
	
		
			
			|  | 13 | + *
 | 
		
	
		
			
			|  | 14 | + * You should have received a copy of the GNU General Public License
 | 
		
	
		
			
			|  | 15 | + * along with this program; if not, write to the Free Software
 | 
		
	
		
			
			|  | 16 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
		
	
		
			
			|  | 17 | + * 02110-1301, USA.
 | 
		
	
		
			
			|  | 18 | + */
 | 
		
	
		
			
			|  | 19 | +
 | 
		
	
		
			
			|  | 20 | +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
		
	
		
			
			|  | 21 | +
 | 
		
	
		
			
			|  | 22 | +#include <stddef.h>
 | 
		
	
		
			
			|  | 23 | +#include <string.h>
 | 
		
	
		
			
			|  | 24 | +#include <errno.h>
 | 
		
	
		
			
			|  | 25 | +#include <ipxe/settings.h>
 | 
		
	
		
			
			|  | 26 | +#include <ipxe/efi/efi.h>
 | 
		
	
		
			
			|  | 27 | +#include <ipxe/efi/Protocol/DriverBinding.h>
 | 
		
	
		
			
			|  | 28 | +#include <ipxe/efi/Protocol/LoadedImage.h>
 | 
		
	
		
			
			|  | 29 | +#include <ipxe/efi/Protocol/ComponentName.h>
 | 
		
	
		
			
			|  | 30 | +#include <ipxe/efi/efi_blacklist.h>
 | 
		
	
		
			
			|  | 31 | +
 | 
		
	
		
			
			|  | 32 | +/** @file
 | 
		
	
		
			
			|  | 33 | + *
 | 
		
	
		
			
			|  | 34 | + * EFI driver blacklist
 | 
		
	
		
			
			|  | 35 | + *
 | 
		
	
		
			
			|  | 36 | + */
 | 
		
	
		
			
			|  | 37 | +
 | 
		
	
		
			
			|  | 38 | +/** A blacklisted driver */
 | 
		
	
		
			
			|  | 39 | +struct efi_blacklist {
 | 
		
	
		
			
			|  | 40 | +	/** Name */
 | 
		
	
		
			
			|  | 41 | +	const char *name;
 | 
		
	
		
			
			|  | 42 | +	/**
 | 
		
	
		
			
			|  | 43 | +	 * Check if driver is blacklisted
 | 
		
	
		
			
			|  | 44 | +	 *
 | 
		
	
		
			
			|  | 45 | +	 * @v binding		Driver binding protocol
 | 
		
	
		
			
			|  | 46 | +	 * @v loaded		Loaded image protocol
 | 
		
	
		
			
			|  | 47 | +	 * @v wtf		Component name protocol, if present
 | 
		
	
		
			
			|  | 48 | +	 * @ret blacklisted	Driver is the blacklisted driver
 | 
		
	
		
			
			|  | 49 | +	 */
 | 
		
	
		
			
			|  | 50 | +	int ( * blacklist ) ( EFI_DRIVER_BINDING_PROTOCOL *binding,
 | 
		
	
		
			
			|  | 51 | +			      EFI_LOADED_IMAGE_PROTOCOL *loaded,
 | 
		
	
		
			
			|  | 52 | +			      EFI_COMPONENT_NAME_PROTOCOL *wtf );
 | 
		
	
		
			
			|  | 53 | +};
 | 
		
	
		
			
			|  | 54 | +
 | 
		
	
		
			
			|  | 55 | +/**
 | 
		
	
		
			
			|  | 56 | + * Blacklist Dell Ip4ConfigDxe driver
 | 
		
	
		
			
			|  | 57 | + *
 | 
		
	
		
			
			|  | 58 | + * @v binding		Driver binding protocol
 | 
		
	
		
			
			|  | 59 | + * @v loaded		Loaded image protocol
 | 
		
	
		
			
			|  | 60 | + * @v wtf		Component name protocol, if present
 | 
		
	
		
			
			|  | 61 | + * @ret blacklisted	Driver is the blacklisted driver
 | 
		
	
		
			
			|  | 62 | + */
 | 
		
	
		
			
			|  | 63 | +static int
 | 
		
	
		
			
			|  | 64 | +efi_blacklist_dell_ip4config ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused,
 | 
		
	
		
			
			|  | 65 | +			       EFI_LOADED_IMAGE_PROTOCOL *loaded __unused,
 | 
		
	
		
			
			|  | 66 | +			       EFI_COMPONENT_NAME_PROTOCOL *wtf ) {
 | 
		
	
		
			
			|  | 67 | +	static const CHAR16 ip4cfg[] = L"IP4 CONFIG Network Service Driver";
 | 
		
	
		
			
			|  | 68 | +	static const char dell[] = "Dell Inc.";
 | 
		
	
		
			
			|  | 69 | +	char manufacturer[ sizeof ( dell ) ];
 | 
		
	
		
			
			|  | 70 | +	CHAR16 *name;
 | 
		
	
		
			
			|  | 71 | +
 | 
		
	
		
			
			|  | 72 | +	/* Check driver name */
 | 
		
	
		
			
			|  | 73 | +	if ( ! wtf )
 | 
		
	
		
			
			|  | 74 | +		return 0;
 | 
		
	
		
			
			|  | 75 | +	if ( wtf->GetDriverName ( wtf, "eng", &name ) != 0 )
 | 
		
	
		
			
			|  | 76 | +		return 0;
 | 
		
	
		
			
			|  | 77 | +	if ( memcmp ( name, ip4cfg, sizeof ( ip4cfg ) ) != 0 )
 | 
		
	
		
			
			|  | 78 | +		return 0;
 | 
		
	
		
			
			|  | 79 | +
 | 
		
	
		
			
			|  | 80 | +	/* Check manufacturer */
 | 
		
	
		
			
			|  | 81 | +	fetch_string_setting ( NULL, &manufacturer_setting, manufacturer,
 | 
		
	
		
			
			|  | 82 | +			       sizeof ( manufacturer ) );
 | 
		
	
		
			
			|  | 83 | +	if ( strcmp ( manufacturer, dell ) != 0 )
 | 
		
	
		
			
			|  | 84 | +		return 0;
 | 
		
	
		
			
			|  | 85 | +
 | 
		
	
		
			
			|  | 86 | +	return 1;
 | 
		
	
		
			
			|  | 87 | +}
 | 
		
	
		
			
			|  | 88 | +
 | 
		
	
		
			
			|  | 89 | +/** Blacklisted drivers */
 | 
		
	
		
			
			|  | 90 | +static struct efi_blacklist efi_blacklists[] = {
 | 
		
	
		
			
			|  | 91 | +	{
 | 
		
	
		
			
			|  | 92 | +		.name = "Dell Ip4Config",
 | 
		
	
		
			
			|  | 93 | +		.blacklist = efi_blacklist_dell_ip4config,
 | 
		
	
		
			
			|  | 94 | +	},
 | 
		
	
		
			
			|  | 95 | +};
 | 
		
	
		
			
			|  | 96 | +
 | 
		
	
		
			
			|  | 97 | +/**
 | 
		
	
		
			
			|  | 98 | + * Find driver blacklisting, if any
 | 
		
	
		
			
			|  | 99 | + *
 | 
		
	
		
			
			|  | 100 | + * @v driver		Driver binding handle
 | 
		
	
		
			
			|  | 101 | + * @ret blacklist	Driver blacklisting, or NULL
 | 
		
	
		
			
			|  | 102 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 103 | + */
 | 
		
	
		
			
			|  | 104 | +static int efi_blacklist ( EFI_HANDLE driver,
 | 
		
	
		
			
			|  | 105 | +			   struct efi_blacklist **blacklist ) {
 | 
		
	
		
			
			|  | 106 | +	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
 | 
		
	
		
			
			|  | 107 | +	union {
 | 
		
	
		
			
			|  | 108 | +		EFI_DRIVER_BINDING_PROTOCOL *binding;
 | 
		
	
		
			
			|  | 109 | +		void *interface;
 | 
		
	
		
			
			|  | 110 | +	} binding;
 | 
		
	
		
			
			|  | 111 | +	union {
 | 
		
	
		
			
			|  | 112 | +		EFI_LOADED_IMAGE_PROTOCOL *loaded;
 | 
		
	
		
			
			|  | 113 | +		void *interface;
 | 
		
	
		
			
			|  | 114 | +	} loaded;
 | 
		
	
		
			
			|  | 115 | +	union {
 | 
		
	
		
			
			|  | 116 | +		EFI_COMPONENT_NAME_PROTOCOL *wtf;
 | 
		
	
		
			
			|  | 117 | +		void *interface;
 | 
		
	
		
			
			|  | 118 | +	} wtf;
 | 
		
	
		
			
			|  | 119 | +	unsigned int i;
 | 
		
	
		
			
			|  | 120 | +	EFI_HANDLE image;
 | 
		
	
		
			
			|  | 121 | +	EFI_STATUS efirc;
 | 
		
	
		
			
			|  | 122 | +	int rc;
 | 
		
	
		
			
			|  | 123 | +
 | 
		
	
		
			
			|  | 124 | +	DBGC2 ( &efi_blacklists, "EFIBL checking %s\n",
 | 
		
	
		
			
			|  | 125 | +		efi_handle_name ( driver ) );
 | 
		
	
		
			
			|  | 126 | +
 | 
		
	
		
			
			|  | 127 | +	/* Mark as not blacklisted */
 | 
		
	
		
			
			|  | 128 | +	*blacklist = NULL;
 | 
		
	
		
			
			|  | 129 | +
 | 
		
	
		
			
			|  | 130 | +	/* Open driver binding protocol */
 | 
		
	
		
			
			|  | 131 | +	if ( ( efirc = bs->OpenProtocol (
 | 
		
	
		
			
			|  | 132 | +			driver, &efi_driver_binding_protocol_guid,
 | 
		
	
		
			
			|  | 133 | +			&binding.interface, efi_image_handle, driver,
 | 
		
	
		
			
			|  | 134 | +			EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) {
 | 
		
	
		
			
			|  | 135 | +		rc = -EEFI ( efirc );
 | 
		
	
		
			
			|  | 136 | +		DBGC ( driver, "EFIBL %s could not open driver binding "
 | 
		
	
		
			
			|  | 137 | +		       "protocol: %s\n", efi_handle_name ( driver ),
 | 
		
	
		
			
			|  | 138 | +		       strerror ( rc ) );
 | 
		
	
		
			
			|  | 139 | +		goto err_binding;
 | 
		
	
		
			
			|  | 140 | +	}
 | 
		
	
		
			
			|  | 141 | +	image = binding.binding->ImageHandle;
 | 
		
	
		
			
			|  | 142 | +
 | 
		
	
		
			
			|  | 143 | +	/* Open loaded image protocol */
 | 
		
	
		
			
			|  | 144 | +	if ( ( efirc = bs->OpenProtocol (
 | 
		
	
		
			
			|  | 145 | +			image, &efi_loaded_image_protocol_guid,
 | 
		
	
		
			
			|  | 146 | +			&loaded.interface, efi_image_handle, image,
 | 
		
	
		
			
			|  | 147 | +			EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) {
 | 
		
	
		
			
			|  | 148 | +		rc = -EEFI ( efirc );
 | 
		
	
		
			
			|  | 149 | +		DBGC ( driver, "EFIBL %s could not open",
 | 
		
	
		
			
			|  | 150 | +		       efi_handle_name ( driver ) );
 | 
		
	
		
			
			|  | 151 | +		DBGC ( driver, " %s loaded image protocol: %s\n",
 | 
		
	
		
			
			|  | 152 | +		       efi_handle_name ( image ), strerror ( rc ) );
 | 
		
	
		
			
			|  | 153 | +		goto err_loaded;
 | 
		
	
		
			
			|  | 154 | +	}
 | 
		
	
		
			
			|  | 155 | +
 | 
		
	
		
			
			|  | 156 | +	/* Open component name protocol, if present*/
 | 
		
	
		
			
			|  | 157 | +	if ( ( efirc = bs->OpenProtocol (
 | 
		
	
		
			
			|  | 158 | +			driver, &efi_component_name_protocol_guid,
 | 
		
	
		
			
			|  | 159 | +			&wtf.interface, efi_image_handle, driver,
 | 
		
	
		
			
			|  | 160 | +			EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) {
 | 
		
	
		
			
			|  | 161 | +		/* Ignore failure; is not required to be present */
 | 
		
	
		
			
			|  | 162 | +		wtf.interface = NULL;
 | 
		
	
		
			
			|  | 163 | +	}
 | 
		
	
		
			
			|  | 164 | +
 | 
		
	
		
			
			|  | 165 | +	/* Check blacklistings */
 | 
		
	
		
			
			|  | 166 | +	for ( i = 0 ; i < ( sizeof ( efi_blacklists ) /
 | 
		
	
		
			
			|  | 167 | +			    sizeof ( efi_blacklists[0] ) ) ; i++ ) {
 | 
		
	
		
			
			|  | 168 | +		if ( efi_blacklists[i].blacklist ( binding.binding,
 | 
		
	
		
			
			|  | 169 | +						   loaded.loaded, wtf.wtf ) ) {
 | 
		
	
		
			
			|  | 170 | +			*blacklist = &efi_blacklists[i];
 | 
		
	
		
			
			|  | 171 | +			break;
 | 
		
	
		
			
			|  | 172 | +		}
 | 
		
	
		
			
			|  | 173 | +	}
 | 
		
	
		
			
			|  | 174 | +
 | 
		
	
		
			
			|  | 175 | +	/* Success */
 | 
		
	
		
			
			|  | 176 | +	rc = 0;
 | 
		
	
		
			
			|  | 177 | +
 | 
		
	
		
			
			|  | 178 | +	/* Close protocols */
 | 
		
	
		
			
			|  | 179 | +	if ( wtf.wtf ) {
 | 
		
	
		
			
			|  | 180 | +		bs->CloseProtocol ( driver, &efi_component_name_protocol_guid,
 | 
		
	
		
			
			|  | 181 | +				    efi_image_handle, driver );
 | 
		
	
		
			
			|  | 182 | +	}
 | 
		
	
		
			
			|  | 183 | +	bs->CloseProtocol ( image, &efi_loaded_image_protocol_guid,
 | 
		
	
		
			
			|  | 184 | +			    efi_image_handle, image );
 | 
		
	
		
			
			|  | 185 | + err_loaded:
 | 
		
	
		
			
			|  | 186 | +	bs->CloseProtocol ( driver, &efi_driver_binding_protocol_guid,
 | 
		
	
		
			
			|  | 187 | +			    efi_image_handle, driver );
 | 
		
	
		
			
			|  | 188 | + err_binding:
 | 
		
	
		
			
			|  | 189 | +	return rc;
 | 
		
	
		
			
			|  | 190 | +}
 | 
		
	
		
			
			|  | 191 | +
 | 
		
	
		
			
			|  | 192 | +/**
 | 
		
	
		
			
			|  | 193 | + * Unload any blacklisted drivers
 | 
		
	
		
			
			|  | 194 | + *
 | 
		
	
		
			
			|  | 195 | + */
 | 
		
	
		
			
			|  | 196 | +void efi_unload_blacklist ( void ) {
 | 
		
	
		
			
			|  | 197 | +	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
 | 
		
	
		
			
			|  | 198 | +	struct efi_blacklist *blacklist;
 | 
		
	
		
			
			|  | 199 | +	EFI_HANDLE *drivers;
 | 
		
	
		
			
			|  | 200 | +	EFI_HANDLE driver;
 | 
		
	
		
			
			|  | 201 | +	UINTN num_drivers;
 | 
		
	
		
			
			|  | 202 | +	unsigned int i;
 | 
		
	
		
			
			|  | 203 | +	EFI_STATUS efirc;
 | 
		
	
		
			
			|  | 204 | +	int rc;
 | 
		
	
		
			
			|  | 205 | +
 | 
		
	
		
			
			|  | 206 | +	/* Locate all driver binding protocol handles */
 | 
		
	
		
			
			|  | 207 | +	if ( ( efirc = bs->LocateHandleBuffer (
 | 
		
	
		
			
			|  | 208 | +			ByProtocol, &efi_driver_binding_protocol_guid,
 | 
		
	
		
			
			|  | 209 | +			NULL, &num_drivers, &drivers ) ) != 0 ) {
 | 
		
	
		
			
			|  | 210 | +		rc = -EEFI ( efirc );
 | 
		
	
		
			
			|  | 211 | +		DBGC ( &efi_blacklists, "EFIBL could not list all drivers: "
 | 
		
	
		
			
			|  | 212 | +		       "%s\n", strerror ( rc ) );
 | 
		
	
		
			
			|  | 213 | +		return;
 | 
		
	
		
			
			|  | 214 | +	}
 | 
		
	
		
			
			|  | 215 | +
 | 
		
	
		
			
			|  | 216 | +	/* Unload any blacklisted drivers */
 | 
		
	
		
			
			|  | 217 | +	for ( i = 0 ; i < num_drivers ; i++ ) {
 | 
		
	
		
			
			|  | 218 | +		driver = drivers[i];
 | 
		
	
		
			
			|  | 219 | +		if ( ( rc = efi_blacklist ( driver, &blacklist ) ) != 0 ) {
 | 
		
	
		
			
			|  | 220 | +			DBGC ( driver, "EFIBL could not determine "
 | 
		
	
		
			
			|  | 221 | +			       "blacklisting for %s: %s\n",
 | 
		
	
		
			
			|  | 222 | +			       efi_handle_name ( driver ), strerror ( rc ) );
 | 
		
	
		
			
			|  | 223 | +			continue;
 | 
		
	
		
			
			|  | 224 | +		}
 | 
		
	
		
			
			|  | 225 | +		if ( ! blacklist )
 | 
		
	
		
			
			|  | 226 | +			continue;
 | 
		
	
		
			
			|  | 227 | +		DBGC ( driver, "EFIBL unloading %s (%s)\n",
 | 
		
	
		
			
			|  | 228 | +		       efi_handle_name ( driver ), blacklist->name );
 | 
		
	
		
			
			|  | 229 | +		if ( ( efirc = bs->UnloadImage ( driver ) ) != 0 ) {
 | 
		
	
		
			
			|  | 230 | +			DBGC ( driver, "EFIBL could not unload %s: %s\n",
 | 
		
	
		
			
			|  | 231 | +			       efi_handle_name ( driver ), strerror ( rc ) );
 | 
		
	
		
			
			|  | 232 | +		}
 | 
		
	
		
			
			|  | 233 | +	}
 | 
		
	
		
			
			|  | 234 | +
 | 
		
	
		
			
			|  | 235 | +	/* Free handle list */
 | 
		
	
		
			
			|  | 236 | +	bs->FreePool ( drivers );
 | 
		
	
		
			
			|  | 237 | +}
 |