efi_selftest_controllers.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. /*
  2. * efi_selftest_controllers
  3. *
  4. * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
  5. *
  6. * SPDX-License-Identifier: GPL-2.0+
  7. *
  8. * This unit test checks the following protocol services:
  9. * ConnectController, DisconnectController,
  10. * InstallProtocol, UninstallProtocol,
  11. * OpenProtocol, CloseProtcol, OpenProtocolInformation
  12. */
  13. #include <efi_selftest.h>
  14. #define NUMBER_OF_CHILD_CONTROLLERS 4
  15. static struct efi_boot_services *boottime;
  16. const efi_guid_t guid_driver_binding_protocol =
  17. EFI_DRIVER_BINDING_PROTOCOL_GUID;
  18. static efi_guid_t guid_controller =
  19. EFI_GUID(0xe6ab1d96, 0x6bff, 0xdb42,
  20. 0xaa, 0x05, 0xc8, 0x1f, 0x7f, 0x45, 0x26, 0x34);
  21. static efi_guid_t guid_child_controller =
  22. EFI_GUID(0x1d41f6f5, 0x2c41, 0xddfb,
  23. 0xe2, 0x9b, 0xb8, 0x0e, 0x2e, 0xe8, 0x3a, 0x85);
  24. static efi_handle_t handle_controller;
  25. static efi_handle_t handle_child_controller[NUMBER_OF_CHILD_CONTROLLERS];
  26. static efi_handle_t handle_driver;
  27. /*
  28. * Count child controllers
  29. *
  30. * @handle handle on which child controllers are installed
  31. * @protocol protocol for which the child controlles where installed
  32. * @count number of child controllers
  33. * @return status code
  34. */
  35. static efi_status_t count_child_controllers(efi_handle_t handle,
  36. efi_guid_t *protocol,
  37. efi_uintn_t *count)
  38. {
  39. efi_status_t ret;
  40. efi_uintn_t entry_count;
  41. struct efi_open_protocol_info_entry *entry_buffer;
  42. *count = 0;
  43. ret = boottime->open_protocol_information(handle, protocol,
  44. &entry_buffer, &entry_count);
  45. if (ret != EFI_SUCCESS)
  46. return ret;
  47. if (!entry_count)
  48. return EFI_SUCCESS;
  49. while (entry_count) {
  50. if (entry_buffer[--entry_count].attributes &
  51. EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER)
  52. ++*count;
  53. }
  54. ret = boottime->free_pool(entry_buffer);
  55. if (ret != EFI_SUCCESS)
  56. efi_st_error("Cannot free buffer\n");
  57. return ret;
  58. }
  59. /*
  60. * Check if the driver supports the controller.
  61. *
  62. * @this driver binding protocol
  63. * @controller_handle handle of the controller
  64. * @remaining_device_path path specifying the child controller
  65. * @return status code
  66. */
  67. static efi_status_t EFIAPI supported(
  68. struct efi_driver_binding_protocol *this,
  69. efi_handle_t controller_handle,
  70. struct efi_device_path *remaining_device_path)
  71. {
  72. efi_status_t ret;
  73. void *interface;
  74. ret = boottime->open_protocol(
  75. controller_handle, &guid_controller,
  76. &interface, handle_driver,
  77. controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER);
  78. switch (ret) {
  79. case EFI_ACCESS_DENIED:
  80. case EFI_ALREADY_STARTED:
  81. return ret;
  82. case EFI_SUCCESS:
  83. break;
  84. default:
  85. return EFI_UNSUPPORTED;
  86. }
  87. ret = boottime->close_protocol(
  88. controller_handle, &guid_controller,
  89. handle_driver, controller_handle);
  90. if (ret != EFI_SUCCESS)
  91. ret = EFI_UNSUPPORTED;
  92. return ret;
  93. }
  94. /*
  95. * Create child controllers and attach driver.
  96. *
  97. * @this driver binding protocol
  98. * @controller_handle handle of the controller
  99. * @remaining_device_path path specifying the child controller
  100. * @return status code
  101. */
  102. static efi_status_t EFIAPI start(
  103. struct efi_driver_binding_protocol *this,
  104. efi_handle_t controller_handle,
  105. struct efi_device_path *remaining_device_path)
  106. {
  107. size_t i;
  108. efi_status_t ret;
  109. void *interface;
  110. /* Attach driver to controller */
  111. ret = boottime->open_protocol(
  112. controller_handle, &guid_controller,
  113. &interface, handle_driver,
  114. controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER);
  115. switch (ret) {
  116. case EFI_ACCESS_DENIED:
  117. case EFI_ALREADY_STARTED:
  118. return ret;
  119. case EFI_SUCCESS:
  120. break;
  121. default:
  122. return EFI_UNSUPPORTED;
  123. }
  124. /* Create child controllers */
  125. for (i = 0; i < NUMBER_OF_CHILD_CONTROLLERS; ++i) {
  126. ret = boottime->install_protocol_interface(
  127. &handle_child_controller[i], &guid_child_controller,
  128. EFI_NATIVE_INTERFACE, NULL);
  129. if (ret != EFI_SUCCESS) {
  130. efi_st_error("InstallProtocolInterface failed\n");
  131. return EFI_ST_FAILURE;
  132. }
  133. ret = boottime->open_protocol(
  134. controller_handle, &guid_controller,
  135. &interface, handle_child_controller[i],
  136. handle_child_controller[i],
  137. EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);
  138. if (ret != EFI_SUCCESS) {
  139. efi_st_error("OpenProtocol failed\n");
  140. return EFI_ST_FAILURE;
  141. }
  142. }
  143. return ret;
  144. }
  145. /*
  146. * Remove a single child controller from the parent controller.
  147. *
  148. * @controller_handle parent controller
  149. * @child_handle child controller
  150. * @return status code
  151. */
  152. static efi_status_t disconnect_child(efi_handle_t controller_handle,
  153. efi_handle_t child_handle)
  154. {
  155. efi_status_t ret;
  156. ret = boottime->close_protocol(
  157. controller_handle, &guid_controller,
  158. child_handle, child_handle);
  159. if (ret != EFI_SUCCESS) {
  160. efi_st_error("Cannot close protocol\n");
  161. return ret;
  162. }
  163. ret = boottime->uninstall_protocol_interface(
  164. child_handle, &guid_child_controller, NULL);
  165. if (ret != EFI_SUCCESS) {
  166. efi_st_error("Cannot uninstall protocol interface\n");
  167. return ret;
  168. }
  169. return ret;
  170. }
  171. /*
  172. * Remove child controllers and disconnect the controller.
  173. *
  174. * @this driver binding protocol
  175. * @controller_handle handle of the controller
  176. * @number_of_children number of child controllers to remove
  177. * @child_handle_buffer handles of the child controllers to remove
  178. * @return status code
  179. */
  180. static efi_status_t EFIAPI stop(
  181. struct efi_driver_binding_protocol *this,
  182. efi_handle_t controller_handle,
  183. size_t number_of_children,
  184. efi_handle_t *child_handle_buffer)
  185. {
  186. efi_status_t ret;
  187. efi_uintn_t count;
  188. struct efi_open_protocol_info_entry *entry_buffer;
  189. /* Destroy provided child controllers */
  190. if (number_of_children) {
  191. efi_uintn_t i;
  192. for (i = 0; i < number_of_children; ++i) {
  193. ret = disconnect_child(controller_handle,
  194. child_handle_buffer[i]);
  195. if (ret != EFI_SUCCESS)
  196. return ret;
  197. }
  198. return EFI_SUCCESS;
  199. }
  200. /* Destroy all children */
  201. ret = boottime->open_protocol_information(
  202. controller_handle, &guid_controller,
  203. &entry_buffer, &count);
  204. if (ret != EFI_SUCCESS) {
  205. efi_st_error("OpenProtocolInformation failed\n");
  206. return ret;
  207. }
  208. while (count) {
  209. if (entry_buffer[--count].attributes &
  210. EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
  211. ret = disconnect_child(
  212. controller_handle,
  213. entry_buffer[count].agent_handle);
  214. if (ret != EFI_SUCCESS)
  215. return ret;
  216. }
  217. }
  218. ret = boottime->free_pool(entry_buffer);
  219. if (ret != EFI_SUCCESS)
  220. efi_st_error("Cannot free buffer\n");
  221. /* Detach driver from controller */
  222. ret = boottime->close_protocol(
  223. controller_handle, &guid_controller,
  224. handle_driver, controller_handle);
  225. if (ret != EFI_SUCCESS) {
  226. efi_st_error("Cannot close protocol\n");
  227. return ret;
  228. }
  229. return EFI_SUCCESS;
  230. }
  231. /* Driver binding protocol interface */
  232. static struct efi_driver_binding_protocol binding_interface = {
  233. supported,
  234. start,
  235. stop,
  236. 0xffffffff,
  237. NULL,
  238. NULL,
  239. };
  240. /*
  241. * Setup unit test.
  242. *
  243. * @handle handle of the loaded image
  244. * @systable system table
  245. */
  246. static int setup(const efi_handle_t img_handle,
  247. const struct efi_system_table *systable)
  248. {
  249. efi_status_t ret;
  250. boottime = systable->boottime;
  251. /* Create controller handle */
  252. ret = boottime->install_protocol_interface(
  253. &handle_controller, &guid_controller,
  254. EFI_NATIVE_INTERFACE, NULL);
  255. if (ret != EFI_SUCCESS) {
  256. efi_st_error("InstallProtocolInterface failed\n");
  257. return EFI_ST_FAILURE;
  258. }
  259. /* Create driver handle */
  260. ret = boottime->install_protocol_interface(
  261. &handle_driver, &guid_driver_binding_protocol,
  262. EFI_NATIVE_INTERFACE, &binding_interface);
  263. if (ret != EFI_SUCCESS) {
  264. efi_st_error("InstallProtocolInterface failed\n");
  265. return EFI_ST_FAILURE;
  266. }
  267. return EFI_ST_SUCCESS;
  268. }
  269. /*
  270. * Execute unit test.
  271. *
  272. * The number of child controllers is checked after each of the following
  273. * actions:
  274. *
  275. * Connect a controller to a driver.
  276. * Disconnect and destroy a child controller.
  277. * Disconnect and destroy the remaining child controllers.
  278. *
  279. * Connect a controller to a driver.
  280. * Uninstall the driver protocol from the controller.
  281. */
  282. static int execute(void)
  283. {
  284. efi_status_t ret;
  285. efi_uintn_t count;
  286. /* Connect controller to driver */
  287. ret = boottime->connect_controller(handle_controller, NULL, NULL, 1);
  288. if (ret != EFI_SUCCESS) {
  289. efi_st_error("Failed to connect controller\n");
  290. return EFI_ST_FAILURE;
  291. }
  292. /* Check number of child controllers */
  293. ret = count_child_controllers(handle_controller, &guid_controller,
  294. &count);
  295. if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) {
  296. efi_st_error("Number of children %u != %u\n",
  297. (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS);
  298. }
  299. /* Destroy second child controller */
  300. ret = boottime->disconnect_controller(handle_controller,
  301. handle_driver,
  302. handle_child_controller[1]);
  303. if (ret != EFI_SUCCESS) {
  304. efi_st_error("Failed to disconnect child controller\n");
  305. return EFI_ST_FAILURE;
  306. }
  307. /* Check number of child controllers */
  308. ret = count_child_controllers(handle_controller, &guid_controller,
  309. &count);
  310. if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS - 1) {
  311. efi_st_error("Destroying single child controller failed\n");
  312. return EFI_ST_FAILURE;
  313. }
  314. /* Destroy remaining child controllers and disconnect controller */
  315. ret = boottime->disconnect_controller(handle_controller, NULL, NULL);
  316. if (ret != EFI_SUCCESS) {
  317. efi_st_error("Failed to disconnect controller\n");
  318. return EFI_ST_FAILURE;
  319. }
  320. /* Check number of child controllers */
  321. ret = count_child_controllers(handle_controller, &guid_controller,
  322. &count);
  323. if (ret != EFI_SUCCESS || count) {
  324. efi_st_error("Destroying child controllers failed\n");
  325. return EFI_ST_FAILURE;
  326. }
  327. /* Connect controller to driver */
  328. ret = boottime->connect_controller(handle_controller, NULL, NULL, 1);
  329. if (ret != EFI_SUCCESS) {
  330. efi_st_error("Failed to connect controller\n");
  331. return EFI_ST_FAILURE;
  332. }
  333. /* Check number of child controllers */
  334. ret = count_child_controllers(handle_controller, &guid_controller,
  335. &count);
  336. if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) {
  337. efi_st_error("Number of children %u != %u\n",
  338. (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS);
  339. }
  340. /* Uninstall controller protocol */
  341. ret = boottime->uninstall_protocol_interface(handle_controller,
  342. &guid_controller, NULL);
  343. if (ret != EFI_SUCCESS) {
  344. efi_st_error("Failed to uninstall protocols\n");
  345. return EFI_ST_FAILURE;
  346. }
  347. /* Check number of child controllers */
  348. ret = count_child_controllers(handle_controller, &guid_controller,
  349. &count);
  350. if (ret == EFI_SUCCESS)
  351. efi_st_error("Uninstall failed\n");
  352. return EFI_ST_SUCCESS;
  353. }
  354. EFI_UNIT_TEST(controllers) = {
  355. .name = "controllers",
  356. .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
  357. .setup = setup,
  358. .execute = execute,
  359. };