efi_selftest_devicepath.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * efi_selftest_devicepath
  4. *
  5. * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
  6. *
  7. * This unit test checks the following protocol services:
  8. * DevicePathToText
  9. */
  10. #include <efi_selftest.h>
  11. static struct efi_boot_services *boottime;
  12. static efi_handle_t handle1;
  13. static efi_handle_t handle2;
  14. static efi_handle_t handle3;
  15. struct interface {
  16. void (EFIAPI * inc)(void);
  17. } interface;
  18. static efi_guid_t guid_device_path = EFI_DEVICE_PATH_PROTOCOL_GUID;
  19. static efi_guid_t guid_device_path_to_text_protocol =
  20. EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
  21. static efi_guid_t guid_protocol =
  22. EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d,
  23. 0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0x7d);
  24. static efi_guid_t guid_vendor1 =
  25. EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d,
  26. 0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0xb1);
  27. static efi_guid_t guid_vendor2 =
  28. EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d,
  29. 0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0xa2);
  30. static efi_guid_t guid_vendor3 =
  31. EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d,
  32. 0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0xc3);
  33. static u8 *dp1;
  34. static u8 *dp2;
  35. static u8 *dp3;
  36. static struct {
  37. struct efi_device_path_sd_mmc_path sd1;
  38. struct efi_device_path sep1;
  39. struct efi_device_path_sd_mmc_path sd2;
  40. struct efi_device_path sep2;
  41. struct efi_device_path_sd_mmc_path sd3;
  42. struct efi_device_path end;
  43. } multi_part_dp = {
  44. {
  45. {
  46. DEVICE_PATH_TYPE_MESSAGING_DEVICE,
  47. DEVICE_PATH_SUB_TYPE_MSG_SD,
  48. sizeof(struct efi_device_path_sd_mmc_path),
  49. },
  50. 0,
  51. },
  52. {
  53. DEVICE_PATH_TYPE_END,
  54. DEVICE_PATH_SUB_TYPE_INSTANCE_END,
  55. sizeof(struct efi_device_path),
  56. },
  57. {
  58. {
  59. DEVICE_PATH_TYPE_MESSAGING_DEVICE,
  60. DEVICE_PATH_SUB_TYPE_MSG_SD,
  61. sizeof(struct efi_device_path_sd_mmc_path),
  62. },
  63. 1,
  64. },
  65. {
  66. DEVICE_PATH_TYPE_END,
  67. DEVICE_PATH_SUB_TYPE_INSTANCE_END,
  68. sizeof(struct efi_device_path),
  69. },
  70. {
  71. {
  72. DEVICE_PATH_TYPE_MESSAGING_DEVICE,
  73. DEVICE_PATH_SUB_TYPE_MSG_SD,
  74. sizeof(struct efi_device_path_sd_mmc_path),
  75. },
  76. 2,
  77. },
  78. {
  79. DEVICE_PATH_TYPE_END,
  80. DEVICE_PATH_SUB_TYPE_END,
  81. sizeof(struct efi_device_path),
  82. },
  83. };
  84. struct efi_device_path_to_text_protocol *device_path_to_text;
  85. /*
  86. * Setup unit test.
  87. *
  88. * Create three handles. Install a new protocol on two of them and
  89. * provide device paths.
  90. *
  91. * handle1
  92. * guid interface
  93. * handle2
  94. * guid interface
  95. * handle3
  96. *
  97. * @handle: handle of the loaded image
  98. * @systable: system table
  99. */
  100. static int setup(const efi_handle_t img_handle,
  101. const struct efi_system_table *systable)
  102. {
  103. struct efi_device_path_vendor vendor_node;
  104. struct efi_device_path end_node;
  105. efi_status_t ret;
  106. boottime = systable->boottime;
  107. ret = boottime->locate_protocol(&guid_device_path_to_text_protocol,
  108. NULL, (void **)&device_path_to_text);
  109. if (ret != EFI_SUCCESS) {
  110. device_path_to_text = NULL;
  111. efi_st_error(
  112. "Device path to text protocol is not available.\n");
  113. return EFI_ST_FAILURE;
  114. }
  115. ret = boottime->allocate_pool(EFI_LOADER_DATA,
  116. sizeof(struct efi_device_path_vendor) +
  117. sizeof(struct efi_device_path),
  118. (void **)&dp1);
  119. if (ret != EFI_SUCCESS)
  120. goto out_of_memory;
  121. ret = boottime->allocate_pool(EFI_LOADER_DATA, 2 *
  122. sizeof(struct efi_device_path_vendor) +
  123. sizeof(struct efi_device_path),
  124. (void **)&dp2);
  125. if (ret != EFI_SUCCESS)
  126. goto out_of_memory;
  127. ret = boottime->allocate_pool(EFI_LOADER_DATA, 3 *
  128. sizeof(struct efi_device_path_vendor) +
  129. sizeof(struct efi_device_path),
  130. (void **)&dp3);
  131. if (ret != EFI_SUCCESS)
  132. goto out_of_memory;
  133. vendor_node.dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
  134. vendor_node.dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
  135. vendor_node.dp.length = sizeof(struct efi_device_path_vendor);
  136. boottime->copy_mem(&vendor_node.guid, &guid_vendor1,
  137. sizeof(efi_guid_t));
  138. boottime->copy_mem(dp1, &vendor_node,
  139. sizeof(struct efi_device_path_vendor));
  140. boottime->copy_mem(dp2, &vendor_node,
  141. sizeof(struct efi_device_path_vendor));
  142. boottime->copy_mem(dp3, &vendor_node,
  143. sizeof(struct efi_device_path_vendor));
  144. boottime->copy_mem(&vendor_node.guid, &guid_vendor2,
  145. sizeof(efi_guid_t));
  146. boottime->copy_mem(dp2 + sizeof(struct efi_device_path_vendor),
  147. &vendor_node, sizeof(struct efi_device_path_vendor));
  148. boottime->copy_mem(dp3 + sizeof(struct efi_device_path_vendor),
  149. &vendor_node, sizeof(struct efi_device_path_vendor));
  150. boottime->copy_mem(&vendor_node.guid, &guid_vendor3,
  151. sizeof(efi_guid_t));
  152. boottime->copy_mem(dp3 + 2 * sizeof(struct efi_device_path_vendor),
  153. &vendor_node, sizeof(struct efi_device_path_vendor));
  154. end_node.type = DEVICE_PATH_TYPE_END;
  155. end_node.sub_type = DEVICE_PATH_SUB_TYPE_END;
  156. end_node.length = sizeof(struct efi_device_path);
  157. boottime->copy_mem(dp1 + sizeof(struct efi_device_path_vendor),
  158. &end_node, sizeof(struct efi_device_path));
  159. boottime->copy_mem(dp2 + 2 * sizeof(struct efi_device_path_vendor),
  160. &end_node, sizeof(struct efi_device_path));
  161. boottime->copy_mem(dp3 + 3 * sizeof(struct efi_device_path_vendor),
  162. &end_node, sizeof(struct efi_device_path));
  163. ret = boottime->install_protocol_interface(&handle1,
  164. &guid_device_path,
  165. EFI_NATIVE_INTERFACE,
  166. dp1);
  167. if (ret != EFI_SUCCESS) {
  168. efi_st_error("InstallProtocolInterface failed\n");
  169. return EFI_ST_FAILURE;
  170. }
  171. ret = boottime->install_protocol_interface(&handle1,
  172. &guid_protocol,
  173. EFI_NATIVE_INTERFACE,
  174. &interface);
  175. if (ret != EFI_SUCCESS) {
  176. efi_st_error("InstallProtocolInterface failed\n");
  177. return EFI_ST_FAILURE;
  178. }
  179. ret = boottime->install_protocol_interface(&handle2,
  180. &guid_device_path,
  181. EFI_NATIVE_INTERFACE,
  182. dp2);
  183. if (ret != EFI_SUCCESS) {
  184. efi_st_error("InstallProtocolInterface failed\n");
  185. return EFI_ST_FAILURE;
  186. }
  187. ret = boottime->install_protocol_interface(&handle2,
  188. &guid_protocol,
  189. EFI_NATIVE_INTERFACE,
  190. &interface);
  191. if (ret != EFI_SUCCESS) {
  192. efi_st_error("InstallProtocolInterface failed\n");
  193. return EFI_ST_FAILURE;
  194. }
  195. ret = boottime->install_protocol_interface(&handle3,
  196. &guid_device_path,
  197. EFI_NATIVE_INTERFACE,
  198. dp3);
  199. if (ret != EFI_SUCCESS) {
  200. efi_st_error("InstallProtocolInterface failed\n");
  201. return EFI_ST_FAILURE;
  202. }
  203. return EFI_ST_SUCCESS;
  204. out_of_memory:
  205. efi_st_error("Out of memory\n");
  206. return EFI_ST_FAILURE;
  207. }
  208. /*
  209. * Tear down unit test.
  210. *
  211. */
  212. static int teardown(void)
  213. {
  214. efi_status_t ret;
  215. ret = boottime->uninstall_protocol_interface(handle1,
  216. &guid_device_path,
  217. dp1);
  218. if (ret != EFI_SUCCESS) {
  219. efi_st_error("UninstallProtocolInterface failed\n");
  220. return EFI_ST_FAILURE;
  221. }
  222. ret = boottime->uninstall_protocol_interface(handle1,
  223. &guid_protocol,
  224. &interface);
  225. if (ret != EFI_SUCCESS) {
  226. efi_st_error("UninstallProtocolInterface failed\n");
  227. return EFI_ST_FAILURE;
  228. }
  229. ret = boottime->uninstall_protocol_interface(handle2,
  230. &guid_device_path,
  231. dp2);
  232. if (ret != EFI_SUCCESS) {
  233. efi_st_error("UninstallProtocolInterface failed\n");
  234. return EFI_ST_FAILURE;
  235. }
  236. ret = boottime->uninstall_protocol_interface(handle2,
  237. &guid_protocol,
  238. &interface);
  239. if (ret != EFI_SUCCESS) {
  240. efi_st_error("UninstallProtocolInterface failed\n");
  241. return EFI_ST_FAILURE;
  242. }
  243. ret = boottime->uninstall_protocol_interface(handle3,
  244. &guid_device_path,
  245. dp3);
  246. if (ret != EFI_SUCCESS) {
  247. efi_st_error("UninstallProtocolInterface failed\n");
  248. return EFI_ST_FAILURE;
  249. }
  250. if (dp1) {
  251. ret = boottime->free_pool(dp1);
  252. if (ret != EFI_SUCCESS) {
  253. efi_st_error("FreePool failed\n");
  254. return EFI_ST_FAILURE;
  255. }
  256. }
  257. if (dp2) {
  258. ret = boottime->free_pool(dp2);
  259. if (ret != EFI_SUCCESS) {
  260. efi_st_error("FreePool failed\n");
  261. return EFI_ST_FAILURE;
  262. }
  263. }
  264. if (dp3) {
  265. ret = boottime->free_pool(dp3);
  266. if (ret != EFI_SUCCESS) {
  267. efi_st_error("FreePool failed\n");
  268. return EFI_ST_FAILURE;
  269. }
  270. }
  271. return EFI_ST_SUCCESS;
  272. }
  273. /*
  274. * Execute unit test.
  275. *
  276. */
  277. static int execute(void)
  278. {
  279. struct efi_device_path *remaining_dp;
  280. efi_handle_t handle;
  281. /*
  282. * This device path node ends with the letter 't' of 'u-boot'.
  283. * The following '.bin' does not belong to the node but is
  284. * helps to test the correct truncation.
  285. */
  286. struct {
  287. struct efi_device_path dp;
  288. u16 text[12];
  289. } __packed dp_node = {
  290. { DEVICE_PATH_TYPE_MEDIA_DEVICE,
  291. DEVICE_PATH_SUB_TYPE_FILE_PATH,
  292. sizeof(struct efi_device_path) + 12},
  293. L"u-boot.bin",
  294. };
  295. u16 *string;
  296. efi_status_t ret;
  297. efi_uintn_t i, no_handles;
  298. efi_handle_t *handles;
  299. struct efi_device_path *dp;
  300. /* Display all available device paths */
  301. ret = boottime->locate_handle_buffer(BY_PROTOCOL,
  302. &guid_device_path,
  303. NULL, &no_handles, &handles);
  304. if (ret != EFI_SUCCESS) {
  305. efi_st_error("Cannot retrieve device path protocols.\n");
  306. return EFI_ST_FAILURE;
  307. }
  308. efi_st_printf("Installed device path protocols:\n");
  309. for (i = 0; i < no_handles; ++i) {
  310. ret = boottime->open_protocol(handles[i], &guid_device_path,
  311. (void **)&dp, NULL, NULL,
  312. EFI_OPEN_PROTOCOL_GET_PROTOCOL);
  313. if (ret != EFI_SUCCESS) {
  314. efi_st_error("Cannot open device path protocol.\n");
  315. return EFI_ST_FAILURE;
  316. }
  317. string = device_path_to_text->convert_device_path_to_text(
  318. dp, true, false);
  319. if (!string) {
  320. efi_st_error("ConvertDevicePathToText failed\n");
  321. return EFI_ST_FAILURE;
  322. }
  323. efi_st_printf("%ps\n", string);
  324. ret = boottime->free_pool(string);
  325. if (ret != EFI_SUCCESS) {
  326. efi_st_error("FreePool failed\n");
  327. return EFI_ST_FAILURE;
  328. }
  329. /*
  330. * CloseProtocol cannot be called without agent handle.
  331. * There is no need to close the device path protocol.
  332. */
  333. }
  334. ret = boottime->free_pool(handles);
  335. if (ret != EFI_SUCCESS) {
  336. efi_st_error("FreePool failed\n");
  337. return EFI_ST_FAILURE;
  338. }
  339. /* Test ConvertDevicePathToText */
  340. string = device_path_to_text->convert_device_path_to_text(
  341. (struct efi_device_path *)dp2, true, false);
  342. if (!string) {
  343. efi_st_error("ConvertDevicePathToText failed\n");
  344. return EFI_ST_FAILURE;
  345. }
  346. if (efi_st_strcmp_16_8(
  347. string,
  348. "/VenHw(dbca4c98-6cb0-694d-0872-819c650cbbb1)/VenHw(dbca4c98-6cb0-694d-0872-819c650cbba2)")
  349. ) {
  350. efi_st_printf("dp2: %ps\n", string);
  351. efi_st_error("Incorrect text from ConvertDevicePathToText\n");
  352. return EFI_ST_FAILURE;
  353. }
  354. ret = boottime->free_pool(string);
  355. if (ret != EFI_SUCCESS) {
  356. efi_st_error("FreePool failed\n");
  357. return EFI_ST_FAILURE;
  358. }
  359. string = device_path_to_text->convert_device_path_to_text(
  360. (struct efi_device_path *)&multi_part_dp, true, false);
  361. if (efi_st_strcmp_16_8(
  362. string,
  363. "/SD(0),/SD(1),/SD(2)")
  364. ) {
  365. efi_st_printf("multi_part_dp: %ps\n", string);
  366. efi_st_error("Incorrect text from ConvertDevicePathToText\n");
  367. return EFI_ST_FAILURE;
  368. }
  369. ret = boottime->free_pool(string);
  370. if (ret != EFI_SUCCESS) {
  371. efi_st_error("FreePool failed\n");
  372. return EFI_ST_FAILURE;
  373. }
  374. /* Test ConvertDeviceNodeToText */
  375. string = device_path_to_text->convert_device_node_to_text(
  376. (struct efi_device_path *)&dp_node, true, false);
  377. if (!string) {
  378. efi_st_error("ConvertDeviceNodeToText failed\n");
  379. return EFI_ST_FAILURE;
  380. }
  381. if (efi_st_strcmp_16_8(string, "u-boot")) {
  382. efi_st_printf("dp_node: %ps\n", string);
  383. efi_st_error(
  384. "Incorrect conversion by ConvertDeviceNodeToText\n");
  385. return EFI_ST_FAILURE;
  386. }
  387. ret = boottime->free_pool(string);
  388. if (ret != EFI_SUCCESS) {
  389. efi_st_error("FreePool failed\n");
  390. return EFI_ST_FAILURE;
  391. }
  392. /* Test LocateDevicePath */
  393. remaining_dp = (struct efi_device_path *)dp3;
  394. ret = boottime->locate_device_path(&guid_protocol, &remaining_dp,
  395. &handle);
  396. if (ret != EFI_SUCCESS) {
  397. efi_st_error("LocateDevicePath failed\n");
  398. return EFI_ST_FAILURE;
  399. }
  400. if (handle != handle2) {
  401. efi_st_error("LocateDevicePath returned wrong handle\n");
  402. return EFI_ST_FAILURE;
  403. }
  404. string = device_path_to_text->convert_device_path_to_text(remaining_dp,
  405. true, false);
  406. if (!string) {
  407. efi_st_error("ConvertDevicePathToText failed\n");
  408. return EFI_ST_FAILURE;
  409. }
  410. if (efi_st_strcmp_16_8(string,
  411. "/VenHw(dbca4c98-6cb0-694d-0872-819c650cbbc3)")
  412. ) {
  413. efi_st_printf("remaining device path: %ps\n", string);
  414. efi_st_error("LocateDevicePath: wrong remaining device path\n");
  415. return EFI_ST_FAILURE;
  416. }
  417. ret = boottime->free_pool(string);
  418. if (ret != EFI_SUCCESS) {
  419. efi_st_error("FreePool failed\n");
  420. return EFI_ST_FAILURE;
  421. }
  422. return EFI_ST_SUCCESS;
  423. }
  424. EFI_UNIT_TEST(devicepath) = {
  425. .name = "device path",
  426. .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
  427. .setup = setup,
  428. .execute = execute,
  429. .teardown = teardown,
  430. };