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