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(%u) %s: ERROR: Cannot free pool\n", 237 __FILE__, __LINE__, __func__); 238 239 /* Detach driver from controller */ 240 ret = EFI_CALL(systab.boottime->close_protocol( 241 controller_handle, guid_controller, 242 this->driver_binding_handle, controller_handle)); 243 out: 244 return EFI_EXIT(ret); 245 } 246 247 /** 248 * efi_add_driver() - add driver 249 * 250 * @drv: driver to add 251 * Return: status code 252 */ 253 static efi_status_t efi_add_driver(struct driver *drv) 254 { 255 efi_status_t ret; 256 const struct efi_driver_ops *ops = drv->ops; 257 struct efi_driver_binding_extended_protocol *bp; 258 259 debug("EFI: Adding driver '%s'\n", drv->name); 260 if (!ops->protocol) { 261 printf("EFI: ERROR: protocol GUID missing for driver '%s'\n", 262 drv->name); 263 return EFI_INVALID_PARAMETER; 264 } 265 bp = calloc(1, sizeof(struct efi_driver_binding_extended_protocol)); 266 if (!bp) 267 return EFI_OUT_OF_RESOURCES; 268 269 bp->bp.supported = efi_uc_supported; 270 bp->bp.start = efi_uc_start; 271 bp->bp.stop = efi_uc_stop; 272 bp->bp.version = 0xffffffff; 273 bp->ops = drv->ops; 274 275 ret = efi_create_handle(&bp->bp.driver_binding_handle); 276 if (ret != EFI_SUCCESS) { 277 free(bp); 278 goto out; 279 } 280 bp->bp.image_handle = bp->bp.driver_binding_handle; 281 ret = efi_add_protocol(bp->bp.driver_binding_handle, 282 &efi_guid_driver_binding_protocol, bp); 283 if (ret != EFI_SUCCESS) { 284 efi_delete_handle(bp->bp.driver_binding_handle); 285 free(bp); 286 goto out; 287 } 288 out: 289 return ret; 290 } 291 292 /** 293 * efi_driver_init() - initialize the EFI drivers 294 * 295 * Called by efi_init_obj_list(). 296 * 297 * Return: 0 = success, any other value will stop further execution 298 */ 299 efi_status_t efi_driver_init(void) 300 { 301 struct driver *drv; 302 efi_status_t ret = EFI_SUCCESS; 303 304 /* Save 'gd' pointer */ 305 efi_save_gd(); 306 307 debug("EFI: Initializing EFI driver framework\n"); 308 for (drv = ll_entry_start(struct driver, driver); 309 drv < ll_entry_end(struct driver, driver); ++drv) { 310 if (drv->id == UCLASS_EFI) { 311 ret = efi_add_driver(drv); 312 if (ret != EFI_SUCCESS) { 313 printf("EFI: ERROR: failed to add driver %s\n", 314 drv->name); 315 break; 316 } 317 } 318 } 319 return ret; 320 } 321 322 /** 323 * efi_uc_init() - initialize the EFI uclass 324 * 325 * @class: the EFI uclass 326 * Return: 0 = success 327 */ 328 static int efi_uc_init(struct uclass *class) 329 { 330 printf("EFI: Initializing UCLASS_EFI\n"); 331 return 0; 332 } 333 334 /** 335 * efi_uc_destroy() - destroy the EFI uclass 336 * 337 * @class: the EFI uclass 338 * Return: 0 = success 339 */ 340 static int efi_uc_destroy(struct uclass *class) 341 { 342 printf("Destroying UCLASS_EFI\n"); 343 return 0; 344 } 345 346 UCLASS_DRIVER(efi) = { 347 .name = "efi", 348 .id = UCLASS_EFI, 349 .init = efi_uc_init, 350 .destroy = efi_uc_destroy, 351 }; 352