123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /*
  2. * Copyright (C) 2011 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. FILE_LICENCE ( GPL2_OR_LATER );
  20. #include <stddef.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <errno.h>
  24. #include <ipxe/version.h>
  25. #include <ipxe/efi/efi.h>
  26. #include <ipxe/efi/Protocol/DriverBinding.h>
  27. #include <ipxe/efi/Protocol/ComponentName2.h>
  28. #include <ipxe/efi/efi_strings.h>
  29. #include <ipxe/efi/efi_driver.h>
  30. /** @file
  31. *
  32. * EFI driver interface
  33. *
  34. */
  35. /** EFI driver binding protocol GUID */
  36. static EFI_GUID efi_driver_binding_protocol_guid
  37. = EFI_DRIVER_BINDING_PROTOCOL_GUID;
  38. /** EFI component name protocol GUID */
  39. static EFI_GUID efi_component_name2_protocol_guid
  40. = EFI_COMPONENT_NAME2_PROTOCOL_GUID;
  41. /**
  42. * Find end of device path
  43. *
  44. * @v path Path to device
  45. * @ret path_end End of device path
  46. */
  47. EFI_DEVICE_PATH_PROTOCOL * efi_devpath_end ( EFI_DEVICE_PATH_PROTOCOL *path ) {
  48. while ( path->Type != END_DEVICE_PATH_TYPE ) {
  49. path = ( ( ( void * ) path ) +
  50. /* There's this amazing new-fangled thing known as
  51. * a UINT16, but who wants to use one of those? */
  52. ( ( path->Length[1] << 8 ) | path->Length[0] ) );
  53. }
  54. return path;
  55. }
  56. /**
  57. * Look up driver name
  58. *
  59. * @v wtf Component name protocol
  60. * @v language Language to use
  61. * @v driver_name Driver name to fill in
  62. * @ret efirc EFI status code
  63. */
  64. static EFI_STATUS EFIAPI
  65. efi_driver_get_driver_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf,
  66. CHAR8 *language __unused, CHAR16 **driver_name ) {
  67. struct efi_driver *efidrv =
  68. container_of ( wtf, struct efi_driver, wtf );
  69. *driver_name = efidrv->wname;
  70. return 0;
  71. }
  72. /**
  73. * Look up controller name
  74. *
  75. * @v wtf Component name protocol
  76. * @v device Device
  77. * @v child Child device, or NULL
  78. * @v language Language to use
  79. * @v driver_name Device name to fill in
  80. * @ret efirc EFI status code
  81. */
  82. static EFI_STATUS EFIAPI
  83. efi_driver_get_controller_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf __unused,
  84. EFI_HANDLE device, EFI_HANDLE child,
  85. CHAR8 *language, CHAR16 **controller_name ) {
  86. EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
  87. union {
  88. EFI_COMPONENT_NAME2_PROTOCOL *name2;
  89. void *interface;
  90. } name2;
  91. EFI_STATUS efirc;
  92. /* Delegate to the EFI_COMPONENT_NAME2_PROTOCOL instance
  93. * installed on child handle, if present.
  94. */
  95. if ( ( child != NULL ) &&
  96. ( ( efirc = bs->OpenProtocol (
  97. child, &efi_component_name2_protocol_guid,
  98. &name2.interface, NULL, NULL,
  99. EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) == 0 ) ) {
  100. return name2.name2->GetControllerName ( name2.name2, device,
  101. child, language,
  102. controller_name );
  103. }
  104. /* Otherwise, let EFI use the default Device Path Name */
  105. return EFI_UNSUPPORTED;
  106. }
  107. /**
  108. * Try to connect EFI driver
  109. *
  110. * @v efidrv EFI driver
  111. * @v handle Controller handle
  112. */
  113. static void efi_driver_connect ( struct efi_driver *efidrv, EFI_HANDLE handle ){
  114. EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
  115. EFI_HANDLE drivers[2] = { efidrv->driver.DriverBindingHandle, NULL };
  116. bs->ConnectController ( handle, drivers, NULL, FALSE );
  117. }
  118. /**
  119. * Try to disconnect EFI driver
  120. *
  121. * @v efidrv EFI driver
  122. * @v handle Controller handle
  123. */
  124. static void efi_driver_disconnect ( struct efi_driver *efidrv,
  125. EFI_HANDLE handle ) {
  126. EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
  127. bs->DisconnectController ( handle, efidrv->driver.DriverBindingHandle,
  128. NULL );
  129. }
  130. /**
  131. * Connect/disconnect EFI driver from all handles
  132. *
  133. * @v efidrv EFI driver
  134. * @v method Connect/disconnect method
  135. * @ret rc Return status code
  136. */
  137. static int efi_driver_handles ( struct efi_driver *efidrv,
  138. void ( * method ) ( struct efi_driver *efidrv,
  139. EFI_HANDLE handle ) ) {
  140. EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
  141. EFI_HANDLE *handles;
  142. UINTN num_handles;
  143. EFI_STATUS efirc;
  144. UINTN i;
  145. int rc;
  146. /* Enumerate all handles */
  147. if ( ( efirc = bs->LocateHandleBuffer ( AllHandles, NULL, NULL,
  148. &num_handles,
  149. &handles ) ) != 0 ) {
  150. rc = -EEFI ( efirc );
  151. DBGC ( efidrv, "EFIDRV %s could not list handles: %s\n",
  152. efidrv->name, strerror ( rc ) );
  153. return rc;
  154. }
  155. /* Connect/disconnect driver from all handles */
  156. for ( i = 0 ; i < num_handles ; i++ )
  157. method ( efidrv, handles[i] );
  158. /* Free list of handles */
  159. bs->FreePool ( handles );
  160. return 0;
  161. }
  162. /**
  163. * Install EFI driver
  164. *
  165. * @v efidrv EFI driver
  166. * @ret rc Return status code
  167. */
  168. int efi_driver_install ( struct efi_driver *efidrv ) {
  169. EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
  170. EFI_DRIVER_BINDING_PROTOCOL *driver = &efidrv->driver;
  171. EFI_COMPONENT_NAME2_PROTOCOL *wtf = &efidrv->wtf;
  172. EFI_STATUS efirc;
  173. int rc;
  174. /* Configure driver binding protocol */
  175. driver->ImageHandle = efi_image_handle;
  176. /* Configure component name protocol */
  177. wtf->GetDriverName = efi_driver_get_driver_name;
  178. wtf->GetControllerName = efi_driver_get_controller_name;
  179. wtf->SupportedLanguages = "en";
  180. /* Fill in driver name */
  181. efi_snprintf ( efidrv->wname,
  182. ( sizeof ( efidrv->wname ) /
  183. sizeof ( efidrv->wname[0] ) ),
  184. "%s%s%s", product_short_name,
  185. ( efidrv->name ? " - " : "" ),
  186. ( efidrv->name ? efidrv->name : "" ) );
  187. /* Install driver */
  188. if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
  189. &driver->DriverBindingHandle,
  190. &efi_driver_binding_protocol_guid, driver,
  191. &efi_component_name2_protocol_guid, wtf,
  192. NULL ) ) != 0 ) {
  193. rc = -EEFI ( efirc );
  194. DBGC ( efidrv, "EFIDRV %s could not install protocol: %s\n",
  195. efidrv->name, strerror ( rc ) );
  196. return rc;
  197. }
  198. /* Connect devices */
  199. DBGC ( efidrv, "EFIDRV %s connecting devices\n", efidrv->name );
  200. efi_driver_handles ( efidrv, efi_driver_connect );
  201. DBGC ( efidrv, "EFIDRV %s installed\n", efidrv->name );
  202. return 0;
  203. }
  204. /**
  205. * Uninstall EFI driver
  206. *
  207. * @v efidrv EFI driver
  208. */
  209. void efi_driver_uninstall ( struct efi_driver *efidrv ) {
  210. EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
  211. /* Disconnect the driver from its devices */
  212. DBGC ( efidrv, "EFIDRV %s disconnecting devices\n", efidrv->name );
  213. efi_driver_handles ( efidrv, efi_driver_disconnect );
  214. /* Uninstall the driver */
  215. bs->UninstallMultipleProtocolInterfaces (
  216. efidrv->driver.DriverBindingHandle,
  217. &efi_driver_binding_protocol_guid, &efidrv->driver,
  218. &efi_component_name2_protocol_guid, &efidrv->wtf,
  219. NULL );
  220. DBGC ( efidrv, "EFIDRV %s uninstalled\n", efidrv->name );
  221. }