Home | History | Annotate | Download | only in efi_driver
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  *  Uclass for EFI drivers
      4  *
      5  *  Copyright (c) 2017 Heinrich Schuchardt
      6  *
      7  * For each EFI driver the uclass
      8  * - creates a handle
      9  * - installs the driver binding protocol
     10  *
     11  * The uclass provides the bind, start, and stop entry points for the driver
     12  * binding protocol.
     13  *
     14  * In bind() and stop() it checks if the controller implements the protocol
     15  * supported by the EFI driver. In the start() function it calls the bind()
     16  * function of the EFI driver. In the stop() function it destroys the child
     17  * controllers.
     18  */
     19 
     20 #include <efi_driver.h>
     21 
     22 /*
     23  * Check node type. We do not support partitions as controller handles.
     24  *
     25  * @handle	handle to be checked
     26  * @return	status code
     27  */
     28 static efi_status_t check_node_type(efi_handle_t handle)
     29 {
     30 	efi_status_t r, ret = EFI_SUCCESS;
     31 	const struct efi_device_path *dp;
     32 
     33 	/* Open the device path protocol */
     34 	r = EFI_CALL(systab.boottime->open_protocol(
     35 			handle, &efi_guid_device_path, (void **)&dp,
     36 			NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL));
     37 	if (r == EFI_SUCCESS && dp) {
     38 		/* Get the last node */
     39 		const struct efi_device_path *node = efi_dp_last_node(dp);
     40 		/* We do not support partitions as controller */
     41 		if (!node || node->type == DEVICE_PATH_TYPE_MEDIA_DEVICE)
     42 			ret = EFI_UNSUPPORTED;
     43 	}
     44 	return ret;
     45 }
     46 
     47 /*
     48  * Check if the driver supports the controller.
     49  *
     50  * @this			driver binding protocol
     51  * @controller_handle		handle of the controller
     52  * @remaining_device_path	path specifying the child controller
     53  * @return			status code
     54  */
     55 static efi_status_t EFIAPI efi_uc_supported(
     56 		struct efi_driver_binding_protocol *this,
     57 		efi_handle_t controller_handle,
     58 		struct efi_device_path *remaining_device_path)
     59 {
     60 	efi_status_t r, ret;
     61 	void *interface;
     62 	struct efi_driver_binding_extended_protocol *bp =
     63 			(struct efi_driver_binding_extended_protocol *)this;
     64 
     65 	EFI_ENTRY("%p, %p, %ls", this, controller_handle,
     66 		  efi_dp_str(remaining_device_path));
     67 
     68 	ret = EFI_CALL(systab.boottime->open_protocol(
     69 			controller_handle, bp->ops->protocol,
     70 			&interface, this->driver_binding_handle,
     71 			controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER));
     72 	switch (ret) {
     73 	case EFI_ACCESS_DENIED:
     74 	case EFI_ALREADY_STARTED:
     75 		goto out;
     76 	case EFI_SUCCESS:
     77 		break;
     78 	default:
     79 		ret = EFI_UNSUPPORTED;
     80 		goto out;
     81 	}
     82 
     83 	ret = check_node_type(controller_handle);
     84 
     85 	r = EFI_CALL(systab.boottime->close_protocol(
     86 				controller_handle, bp->ops->protocol,
     87 				this->driver_binding_handle,
     88 				controller_handle));
     89 	if (r != EFI_SUCCESS)
     90 		ret = EFI_UNSUPPORTED;
     91 out:
     92 	return EFI_EXIT(ret);
     93 }
     94 
     95 /*
     96  * Create child controllers and attach driver.
     97  *
     98  * @this			driver binding protocol
     99  * @controller_handle		handle of the controller
    100  * @remaining_device_path	path specifying the child controller
    101  * @return			status code
    102  */
    103 static efi_status_t EFIAPI efi_uc_start(
    104 		struct efi_driver_binding_protocol *this,
    105 		efi_handle_t controller_handle,
    106 		struct efi_device_path *remaining_device_path)
    107 {
    108 	efi_status_t r, ret;
    109 	void *interface = NULL;
    110 	struct efi_driver_binding_extended_protocol *bp =
    111 			(struct efi_driver_binding_extended_protocol *)this;
    112 
    113 	EFI_ENTRY("%p, %pUl, %ls", this, controller_handle,
    114 		  efi_dp_str(remaining_device_path));
    115 
    116 	/* Attach driver to controller */
    117 	ret = EFI_CALL(systab.boottime->open_protocol(
    118 			controller_handle, bp->ops->protocol,
    119 			&interface, this->driver_binding_handle,
    120 			controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER));
    121 	switch (ret) {
    122 	case EFI_ACCESS_DENIED:
    123 	case EFI_ALREADY_STARTED:
    124 		goto out;
    125 	case EFI_SUCCESS:
    126 		break;
    127 	default:
    128 		ret =  EFI_UNSUPPORTED;
    129 		goto out;
    130 	}
    131 	ret = check_node_type(controller_handle);
    132 	if (ret != EFI_SUCCESS) {
    133 		r = EFI_CALL(systab.boottime->close_protocol(
    134 				controller_handle, bp->ops->protocol,
    135 				this->driver_binding_handle,
    136 				controller_handle));
    137 		if (r != EFI_SUCCESS)
    138 			EFI_PRINT("Failure to close handle\n");
    139 		goto out;
    140 	}
    141 
    142 	/* TODO: driver specific stuff */
    143 	bp->ops->bind(controller_handle, interface);
    144 
    145 out:
    146 	return EFI_EXIT(ret);
    147 }
    148 
    149 /*
    150  * Remove a single child controller from the parent controller.
    151  *
    152  * @controller_handle	parent controller
    153  * @child_handle	child controller
    154  * @return		status code
    155  */
    156 static efi_status_t disconnect_child(efi_handle_t controller_handle,
    157 				     efi_handle_t child_handle)
    158 {
    159 	efi_status_t ret;
    160 	efi_guid_t *guid_controller = NULL;
    161 	efi_guid_t *guid_child_controller = NULL;
    162 
    163 	ret = EFI_CALL(systab.boottime->close_protocol(
    164 				controller_handle, guid_controller,
    165 				child_handle, child_handle));
    166 	if (ret != EFI_SUCCESS) {
    167 		EFI_PRINT("Cannot close protocol\n");
    168 		return ret;
    169 	}
    170 	ret = EFI_CALL(systab.boottime->uninstall_protocol_interface(
    171 				child_handle, guid_child_controller, NULL));
    172 	if (ret != EFI_SUCCESS) {
    173 		EFI_PRINT("Cannot uninstall protocol interface\n");
    174 		return ret;
    175 	}
    176 	return ret;
    177 }
    178 
    179 /*
    180  * Remove child controllers and disconnect the controller.
    181  *
    182  * @this			driver binding protocol
    183  * @controller_handle		handle of the controller
    184  * @number_of_children		number of child controllers to remove
    185  * @child_handle_buffer		handles of the child controllers to remove
    186  * @return			status code
    187  */
    188 static efi_status_t EFIAPI efi_uc_stop(
    189 		struct efi_driver_binding_protocol *this,
    190 		efi_handle_t controller_handle,
    191 		size_t number_of_children,
    192 		efi_handle_t *child_handle_buffer)
    193 {
    194 	efi_status_t ret;
    195 	efi_uintn_t count;
    196 	struct efi_open_protocol_info_entry *entry_buffer;
    197 	efi_guid_t *guid_controller = NULL;
    198 
    199 	EFI_ENTRY("%p, %pUl, %zu, %p", this, controller_handle,
    200 		  number_of_children, child_handle_buffer);
    201 
    202 	/* Destroy provided child controllers */
    203 	if (number_of_children) {
    204 		efi_uintn_t i;
    205 
    206 		for (i = 0; i < number_of_children; ++i) {
    207 			ret = disconnect_child(controller_handle,
    208 					       child_handle_buffer[i]);
    209 			if (ret != EFI_SUCCESS)
    210 				return ret;
    211 		}
    212 		return EFI_SUCCESS;
    213 	}
    214 
    215 	/* Destroy all children */
    216 	ret = EFI_CALL(systab.boottime->open_protocol_information(
    217 					controller_handle, guid_controller,
    218 					&entry_buffer, &count));
    219 	if (ret != EFI_SUCCESS)
    220 		goto out;
    221 	while (count) {
    222 		if (entry_buffer[--count].attributes &
    223 		    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
    224 			ret = disconnect_child(
    225 					controller_handle,
    226 					entry_buffer[count].agent_handle);
    227 			if (ret != EFI_SUCCESS)
    228 				goto out;
    229 		}
    230 	}
    231 	ret = EFI_CALL(systab.boottime->free_pool(entry_buffer));
    232 	if (ret != EFI_SUCCESS)
    233 		printf("%s(%u) %s: ERROR: Cannot free pool\n",
    234 		       __FILE__, __LINE__, __func__);
    235 
    236 	/* Detach driver from controller */
    237 	ret = EFI_CALL(systab.boottime->close_protocol(
    238 			controller_handle, guid_controller,
    239 			this->driver_binding_handle, controller_handle));
    240 out:
    241 	return EFI_EXIT(ret);
    242 }
    243 
    244 static efi_status_t efi_add_driver(struct driver *drv)
    245 {
    246 	efi_status_t ret;
    247 	const struct efi_driver_ops *ops = drv->ops;
    248 	struct efi_driver_binding_extended_protocol *bp;
    249 
    250 	debug("EFI: Adding driver '%s'\n", drv->name);
    251 	if (!ops->protocol) {
    252 		printf("EFI: ERROR: protocol GUID missing for driver '%s'\n",
    253 		       drv->name);
    254 		return EFI_INVALID_PARAMETER;
    255 	}
    256 	bp = calloc(1, sizeof(struct efi_driver_binding_extended_protocol));
    257 	if (!bp)
    258 		return EFI_OUT_OF_RESOURCES;
    259 
    260 	bp->bp.supported = efi_uc_supported;
    261 	bp->bp.start = efi_uc_start;
    262 	bp->bp.stop = efi_uc_stop;
    263 	bp->bp.version = 0xffffffff;
    264 	bp->ops = drv->ops;
    265 
    266 	ret = efi_create_handle(&bp->bp.driver_binding_handle);
    267 	if (ret != EFI_SUCCESS) {
    268 		free(bp);
    269 		goto out;
    270 	}
    271 	bp->bp.image_handle = bp->bp.driver_binding_handle;
    272 	ret = efi_add_protocol(bp->bp.driver_binding_handle,
    273 			       &efi_guid_driver_binding_protocol, bp);
    274 	if (ret != EFI_SUCCESS) {
    275 		efi_delete_handle(bp->bp.driver_binding_handle);
    276 		free(bp);
    277 		goto out;
    278 	}
    279 out:
    280 	return ret;
    281 }
    282 
    283 /*
    284  * Initialize the EFI drivers.
    285  * Called by board_init_r().
    286  *
    287  * @return	0 = success, any other value will stop further execution
    288  */
    289 efi_status_t efi_driver_init(void)
    290 {
    291 	struct driver *drv;
    292 	efi_status_t ret = EFI_SUCCESS;
    293 
    294 	/* Save 'gd' pointer */
    295 	efi_save_gd();
    296 
    297 	debug("EFI: Initializing EFI driver framework\n");
    298 	for (drv = ll_entry_start(struct driver, driver);
    299 	     drv < ll_entry_end(struct driver, driver); ++drv) {
    300 		if (drv->id == UCLASS_EFI) {
    301 			ret = efi_add_driver(drv);
    302 			if (ret != EFI_SUCCESS) {
    303 				printf("EFI: ERROR: failed to add driver %s\n",
    304 				       drv->name);
    305 				break;
    306 			}
    307 		}
    308 	}
    309 	return ret;
    310 }
    311 
    312 static int efi_uc_init(struct uclass *class)
    313 {
    314 	printf("EFI: Initializing UCLASS_EFI\n");
    315 	return 0;
    316 }
    317 
    318 static int efi_uc_destroy(struct uclass *class)
    319 {
    320 	printf("Destroying  UCLASS_EFI\n");
    321 	return 0;
    322 }
    323 
    324 UCLASS_DRIVER(efi) = {
    325 	.name		= "efi",
    326 	.id		= UCLASS_EFI,
    327 	.init		= efi_uc_init,
    328 	.destroy	= efi_uc_destroy,
    329 };
    330