efi_selftest_block_device.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * efi_selftest_block
  4. *
  5. * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
  6. *
  7. * This test checks the driver for block IO devices.
  8. * A disk image is created in memory.
  9. * A handle is created for the new block IO device.
  10. * The block I/O protocol is installed on the handle.
  11. * ConnectController is used to setup partitions and to install the simple
  12. * file protocol.
  13. * A known file is read from the file system and verified.
  14. * The same block is read via the EFI_BLOCK_IO_PROTOCOL and compared to the file
  15. * contents.
  16. */
  17. #include <efi_selftest.h>
  18. #include "efi_selftest_disk_image.h"
  19. #include <asm/cache.h>
  20. /* Block size of compressed disk image */
  21. #define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8
  22. /* Binary logarithm of the block size */
  23. #define LB_BLOCK_SIZE 9
  24. static struct efi_boot_services *boottime;
  25. static const efi_guid_t block_io_protocol_guid = EFI_BLOCK_IO_PROTOCOL_GUID;
  26. static const efi_guid_t guid_device_path = EFI_DEVICE_PATH_PROTOCOL_GUID;
  27. static const efi_guid_t guid_simple_file_system_protocol =
  28. EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
  29. static const efi_guid_t guid_file_system_info = EFI_FILE_SYSTEM_INFO_GUID;
  30. static efi_guid_t guid_vendor =
  31. EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d,
  32. 0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xb7, 0xb8);
  33. static struct efi_device_path *dp;
  34. /* One 8 byte block of the compressed disk image */
  35. struct line {
  36. size_t addr;
  37. char *line;
  38. };
  39. /* Compressed disk image */
  40. struct compressed_disk_image {
  41. size_t length;
  42. struct line lines[];
  43. };
  44. static const struct compressed_disk_image img = EFI_ST_DISK_IMG;
  45. /* Decompressed disk image */
  46. static u8 *image;
  47. /*
  48. * Reset service of the block IO protocol.
  49. *
  50. * @this block IO protocol
  51. * Return: status code
  52. */
  53. static efi_status_t EFIAPI reset(
  54. struct efi_block_io *this,
  55. char extended_verification)
  56. {
  57. return EFI_SUCCESS;
  58. }
  59. /*
  60. * Read service of the block IO protocol.
  61. *
  62. * @this block IO protocol
  63. * @media_id media id
  64. * @lba start of the read in logical blocks
  65. * @buffer_size number of bytes to read
  66. * @buffer target buffer
  67. * Return: status code
  68. */
  69. static efi_status_t EFIAPI read_blocks(
  70. struct efi_block_io *this, u32 media_id, u64 lba,
  71. efi_uintn_t buffer_size, void *buffer)
  72. {
  73. u8 *start;
  74. if ((lba << LB_BLOCK_SIZE) + buffer_size > img.length)
  75. return EFI_INVALID_PARAMETER;
  76. start = image + (lba << LB_BLOCK_SIZE);
  77. boottime->copy_mem(buffer, start, buffer_size);
  78. return EFI_SUCCESS;
  79. }
  80. /*
  81. * Write service of the block IO protocol.
  82. *
  83. * @this block IO protocol
  84. * @media_id media id
  85. * @lba start of the write in logical blocks
  86. * @buffer_size number of bytes to read
  87. * @buffer source buffer
  88. * Return: status code
  89. */
  90. static efi_status_t EFIAPI write_blocks(
  91. struct efi_block_io *this, u32 media_id, u64 lba,
  92. efi_uintn_t buffer_size, void *buffer)
  93. {
  94. u8 *start;
  95. if ((lba << LB_BLOCK_SIZE) + buffer_size > img.length)
  96. return EFI_INVALID_PARAMETER;
  97. start = image + (lba << LB_BLOCK_SIZE);
  98. boottime->copy_mem(start, buffer, buffer_size);
  99. return EFI_SUCCESS;
  100. }
  101. /*
  102. * Flush service of the block IO protocol.
  103. *
  104. * @this block IO protocol
  105. * Return: status code
  106. */
  107. static efi_status_t EFIAPI flush_blocks(struct efi_block_io *this)
  108. {
  109. return EFI_SUCCESS;
  110. }
  111. /*
  112. * Decompress the disk image.
  113. *
  114. * @image decompressed disk image
  115. * Return: status code
  116. */
  117. static efi_status_t decompress(u8 **image)
  118. {
  119. u8 *buf;
  120. size_t i;
  121. size_t addr;
  122. size_t len;
  123. efi_status_t ret;
  124. ret = boottime->allocate_pool(EFI_LOADER_DATA, img.length,
  125. (void **)&buf);
  126. if (ret != EFI_SUCCESS) {
  127. efi_st_error("Out of memory\n");
  128. return ret;
  129. }
  130. boottime->set_mem(buf, img.length, 0);
  131. for (i = 0; ; ++i) {
  132. if (!img.lines[i].line)
  133. break;
  134. addr = img.lines[i].addr;
  135. len = COMPRESSED_DISK_IMAGE_BLOCK_SIZE;
  136. if (addr + len > img.length)
  137. len = img.length - addr;
  138. boottime->copy_mem(buf + addr, img.lines[i].line, len);
  139. }
  140. *image = buf;
  141. return ret;
  142. }
  143. static struct efi_block_io_media media;
  144. static struct efi_block_io block_io = {
  145. .media = &media,
  146. .reset = reset,
  147. .read_blocks = read_blocks,
  148. .write_blocks = write_blocks,
  149. .flush_blocks = flush_blocks,
  150. };
  151. /* Handle for the block IO device */
  152. static efi_handle_t disk_handle;
  153. /*
  154. * Setup unit test.
  155. *
  156. * @handle: handle of the loaded image
  157. * @systable: system table
  158. * Return: EFI_ST_SUCCESS for success
  159. */
  160. static int setup(const efi_handle_t handle,
  161. const struct efi_system_table *systable)
  162. {
  163. efi_status_t ret;
  164. struct efi_device_path_vendor vendor_node;
  165. struct efi_device_path end_node;
  166. boottime = systable->boottime;
  167. decompress(&image);
  168. block_io.media->block_size = 1 << LB_BLOCK_SIZE;
  169. block_io.media->last_block = (img.length >> LB_BLOCK_SIZE) - 1;
  170. ret = boottime->install_protocol_interface(
  171. &disk_handle, &block_io_protocol_guid,
  172. EFI_NATIVE_INTERFACE, &block_io);
  173. if (ret != EFI_SUCCESS) {
  174. efi_st_error("Failed to install block I/O protocol\n");
  175. return EFI_ST_FAILURE;
  176. }
  177. ret = boottime->allocate_pool(EFI_LOADER_DATA,
  178. sizeof(struct efi_device_path_vendor) +
  179. sizeof(struct efi_device_path),
  180. (void **)&dp);
  181. if (ret != EFI_SUCCESS) {
  182. efi_st_error("Out of memory\n");
  183. return EFI_ST_FAILURE;
  184. }
  185. vendor_node.dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
  186. vendor_node.dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
  187. vendor_node.dp.length = sizeof(struct efi_device_path_vendor);
  188. boottime->copy_mem(&vendor_node.guid, &guid_vendor,
  189. sizeof(efi_guid_t));
  190. boottime->copy_mem(dp, &vendor_node,
  191. sizeof(struct efi_device_path_vendor));
  192. end_node.type = DEVICE_PATH_TYPE_END;
  193. end_node.sub_type = DEVICE_PATH_SUB_TYPE_END;
  194. end_node.length = sizeof(struct efi_device_path);
  195. boottime->copy_mem((char *)dp + sizeof(struct efi_device_path_vendor),
  196. &end_node, sizeof(struct efi_device_path));
  197. ret = boottime->install_protocol_interface(&disk_handle,
  198. &guid_device_path,
  199. EFI_NATIVE_INTERFACE,
  200. dp);
  201. if (ret != EFI_SUCCESS) {
  202. efi_st_error("InstallProtocolInterface failed\n");
  203. return EFI_ST_FAILURE;
  204. }
  205. return EFI_ST_SUCCESS;
  206. }
  207. /*
  208. * Tear down unit test.
  209. *
  210. * Return: EFI_ST_SUCCESS for success
  211. */
  212. static int teardown(void)
  213. {
  214. efi_status_t r = EFI_ST_SUCCESS;
  215. if (disk_handle) {
  216. r = boottime->uninstall_protocol_interface(disk_handle,
  217. &guid_device_path,
  218. dp);
  219. if (r != EFI_SUCCESS) {
  220. efi_st_error("Uninstall device path failed\n");
  221. return EFI_ST_FAILURE;
  222. }
  223. r = boottime->uninstall_protocol_interface(
  224. disk_handle, &block_io_protocol_guid,
  225. &block_io);
  226. if (r != EFI_SUCCESS) {
  227. efi_st_error(
  228. "Failed to uninstall block I/O protocol\n");
  229. return EFI_ST_FAILURE;
  230. }
  231. }
  232. if (image) {
  233. r = boottime->free_pool(image);
  234. if (r != EFI_SUCCESS) {
  235. efi_st_error("Failed to free image\n");
  236. return EFI_ST_FAILURE;
  237. }
  238. }
  239. return r;
  240. }
  241. /*
  242. * Get length of device path without end tag.
  243. *
  244. * @dp device path
  245. * Return: length of device path in bytes
  246. */
  247. static efi_uintn_t dp_size(struct efi_device_path *dp)
  248. {
  249. struct efi_device_path *pos = dp;
  250. while (pos->type != DEVICE_PATH_TYPE_END)
  251. pos = (struct efi_device_path *)((char *)pos + pos->length);
  252. return (char *)pos - (char *)dp;
  253. }
  254. /*
  255. * Execute unit test.
  256. *
  257. * Return: EFI_ST_SUCCESS for success
  258. */
  259. static int execute(void)
  260. {
  261. efi_status_t ret;
  262. efi_uintn_t no_handles, i, len;
  263. efi_handle_t *handles;
  264. efi_handle_t handle_partition = NULL;
  265. struct efi_device_path *dp_partition;
  266. struct efi_block_io *block_io_protocol;
  267. struct efi_simple_file_system_protocol *file_system;
  268. struct efi_file_handle *root, *file;
  269. struct {
  270. struct efi_file_system_info info;
  271. u16 label[12];
  272. } system_info;
  273. efi_uintn_t buf_size;
  274. char buf[16] __aligned(ARCH_DMA_MINALIGN);
  275. u32 part1_size;
  276. u64 pos;
  277. char block_io_aligned[1 << LB_BLOCK_SIZE] __aligned(1 << LB_BLOCK_SIZE);
  278. /* Connect controller to virtual disk */
  279. ret = boottime->connect_controller(disk_handle, NULL, NULL, 1);
  280. if (ret != EFI_SUCCESS) {
  281. efi_st_error("Failed to connect controller\n");
  282. return EFI_ST_FAILURE;
  283. }
  284. /* Get the handle for the partition */
  285. ret = boottime->locate_handle_buffer(
  286. BY_PROTOCOL, &guid_device_path, NULL,
  287. &no_handles, &handles);
  288. if (ret != EFI_SUCCESS) {
  289. efi_st_error("Failed to locate handles\n");
  290. return EFI_ST_FAILURE;
  291. }
  292. len = dp_size(dp);
  293. for (i = 0; i < no_handles; ++i) {
  294. ret = boottime->open_protocol(handles[i], &guid_device_path,
  295. (void **)&dp_partition,
  296. NULL, NULL,
  297. EFI_OPEN_PROTOCOL_GET_PROTOCOL);
  298. if (ret != EFI_SUCCESS) {
  299. efi_st_error("Failed to open device path protocol\n");
  300. return EFI_ST_FAILURE;
  301. }
  302. if (len >= dp_size(dp_partition))
  303. continue;
  304. if (memcmp(dp, dp_partition, len))
  305. continue;
  306. handle_partition = handles[i];
  307. break;
  308. }
  309. ret = boottime->free_pool(handles);
  310. if (ret != EFI_SUCCESS) {
  311. efi_st_error("Failed to free pool memory\n");
  312. return EFI_ST_FAILURE;
  313. }
  314. if (!handle_partition) {
  315. efi_st_error("Partition handle not found\n");
  316. return EFI_ST_FAILURE;
  317. }
  318. /* Open the block_io_protocol */
  319. ret = boottime->open_protocol(handle_partition,
  320. &block_io_protocol_guid,
  321. (void **)&block_io_protocol, NULL, NULL,
  322. EFI_OPEN_PROTOCOL_GET_PROTOCOL);
  323. if (ret != EFI_SUCCESS) {
  324. efi_st_error("Failed to open block IO protocol\n");
  325. return EFI_ST_FAILURE;
  326. }
  327. /* Get size of first MBR partition */
  328. memcpy(&part1_size, image + 0x1ca, sizeof(u32));
  329. if (block_io_protocol->media->last_block != part1_size - 1) {
  330. efi_st_error("Last LBA of partition %x, expected %x\n",
  331. (unsigned int)block_io_protocol->media->last_block,
  332. part1_size - 1);
  333. return EFI_ST_FAILURE;
  334. }
  335. /* Open the simple file system protocol */
  336. ret = boottime->open_protocol(handle_partition,
  337. &guid_simple_file_system_protocol,
  338. (void **)&file_system, NULL, NULL,
  339. EFI_OPEN_PROTOCOL_GET_PROTOCOL);
  340. if (ret != EFI_SUCCESS) {
  341. efi_st_error("Failed to open simple file system protocol\n");
  342. return EFI_ST_FAILURE;
  343. }
  344. /* Open volume */
  345. ret = file_system->open_volume(file_system, &root);
  346. if (ret != EFI_SUCCESS) {
  347. efi_st_error("Failed to open volume\n");
  348. return EFI_ST_FAILURE;
  349. }
  350. buf_size = sizeof(system_info);
  351. ret = root->getinfo(root, &guid_file_system_info, &buf_size,
  352. &system_info);
  353. if (ret != EFI_SUCCESS) {
  354. efi_st_error("Failed to get file system info\n");
  355. return EFI_ST_FAILURE;
  356. }
  357. if (system_info.info.block_size != 512) {
  358. efi_st_error("Wrong block size %u, expected 512\n",
  359. system_info.info.block_size);
  360. return EFI_ST_FAILURE;
  361. }
  362. if (efi_st_strcmp_16_8(system_info.info.volume_label, "U-BOOT TEST")) {
  363. efi_st_todo(
  364. "Wrong volume label '%ps', expected 'U-BOOT TEST'\n",
  365. system_info.info.volume_label);
  366. }
  367. /* Read file */
  368. ret = root->open(root, &file, u"hello.txt", EFI_FILE_MODE_READ,
  369. 0);
  370. if (ret != EFI_SUCCESS) {
  371. efi_st_error("Failed to open file\n");
  372. return EFI_ST_FAILURE;
  373. }
  374. ret = file->setpos(file, 1);
  375. if (ret != EFI_SUCCESS) {
  376. efi_st_error("SetPosition failed\n");
  377. return EFI_ST_FAILURE;
  378. }
  379. buf_size = sizeof(buf) - 1;
  380. ret = file->read(file, &buf_size, buf);
  381. if (ret != EFI_SUCCESS) {
  382. efi_st_error("Failed to read file\n");
  383. return EFI_ST_FAILURE;
  384. }
  385. if (buf_size != 12) {
  386. efi_st_error("Wrong number of bytes read: %u\n",
  387. (unsigned int)buf_size);
  388. return EFI_ST_FAILURE;
  389. }
  390. if (memcmp(buf, "ello world!", 11)) {
  391. efi_st_error("Unexpected file content\n");
  392. return EFI_ST_FAILURE;
  393. }
  394. ret = file->getpos(file, &pos);
  395. if (ret != EFI_SUCCESS) {
  396. efi_st_error("GetPosition failed\n");
  397. return EFI_ST_FAILURE;
  398. }
  399. if (pos != 13) {
  400. efi_st_error("GetPosition returned %u, expected 13\n",
  401. (unsigned int)pos);
  402. return EFI_ST_FAILURE;
  403. }
  404. ret = file->close(file);
  405. if (ret != EFI_SUCCESS) {
  406. efi_st_error("Failed to close file\n");
  407. return EFI_ST_FAILURE;
  408. }
  409. /*
  410. * Test that read_blocks() can read same file data.
  411. *
  412. * In the test data, the partition starts at block 1 and the file
  413. * hello.txt with the content 'Hello world!' is located at 0x5000
  414. * of the disk. Here we read block 0x27 (offset 0x4e00 of the
  415. * partition) and expect the string 'Hello world!' to be at the
  416. * start of block.
  417. */
  418. ret = block_io_protocol->read_blocks(block_io_protocol,
  419. block_io_protocol->media->media_id,
  420. (0x5000 >> LB_BLOCK_SIZE) - 1,
  421. block_io_protocol->media->block_size,
  422. block_io_aligned);
  423. if (ret != EFI_SUCCESS) {
  424. efi_st_error("ReadBlocks failed\n");
  425. return EFI_ST_FAILURE;
  426. }
  427. if (memcmp(block_io_aligned + 1, buf, 11)) {
  428. efi_st_error("Unexpected block content\n");
  429. return EFI_ST_FAILURE;
  430. }
  431. #ifdef CONFIG_FAT_WRITE
  432. /* Write file */
  433. ret = root->open(root, &file, u"u-boot.txt", EFI_FILE_MODE_READ |
  434. EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0);
  435. if (ret != EFI_SUCCESS) {
  436. efi_st_error("Failed to open file\n");
  437. return EFI_ST_FAILURE;
  438. }
  439. buf_size = 7;
  440. boottime->set_mem(buf, sizeof(buf), 0);
  441. boottime->copy_mem(buf, "U-Boot", buf_size);
  442. ret = file->write(file, &buf_size, buf);
  443. if (ret != EFI_SUCCESS || buf_size != 7) {
  444. efi_st_error("Failed to write file\n");
  445. return EFI_ST_FAILURE;
  446. }
  447. ret = file->getpos(file, &pos);
  448. if (ret != EFI_SUCCESS) {
  449. efi_st_error("GetPosition failed\n");
  450. return EFI_ST_FAILURE;
  451. }
  452. if (pos != 7) {
  453. efi_st_error("GetPosition returned %u, expected 7\n",
  454. (unsigned int)pos);
  455. return EFI_ST_FAILURE;
  456. }
  457. ret = file->close(file);
  458. if (ret != EFI_SUCCESS) {
  459. efi_st_error("Failed to close file\n");
  460. return EFI_ST_FAILURE;
  461. }
  462. /* Verify file */
  463. boottime->set_mem(buf, sizeof(buf), 0);
  464. ret = root->open(root, &file, u"u-boot.txt", EFI_FILE_MODE_READ,
  465. 0);
  466. if (ret != EFI_SUCCESS) {
  467. efi_st_error("Failed to open file\n");
  468. return EFI_ST_FAILURE;
  469. }
  470. buf_size = sizeof(buf) - 1;
  471. ret = file->read(file, &buf_size, buf);
  472. if (ret != EFI_SUCCESS) {
  473. efi_st_error("Failed to read file\n");
  474. return EFI_ST_FAILURE;
  475. }
  476. if (buf_size != 7) {
  477. efi_st_error("Wrong number of bytes read: %u\n",
  478. (unsigned int)buf_size);
  479. return EFI_ST_FAILURE;
  480. }
  481. if (memcmp(buf, "U-Boot", 7)) {
  482. efi_st_error("Unexpected file content %s\n", buf);
  483. return EFI_ST_FAILURE;
  484. }
  485. ret = file->close(file);
  486. if (ret != EFI_SUCCESS) {
  487. efi_st_error("Failed to close file\n");
  488. return EFI_ST_FAILURE;
  489. }
  490. #else
  491. efi_st_todo("CONFIG_FAT_WRITE is not set\n");
  492. #endif /* CONFIG_FAT_WRITE */
  493. /* Close volume */
  494. ret = root->close(root);
  495. if (ret != EFI_SUCCESS) {
  496. efi_st_error("Failed to close volume\n");
  497. return EFI_ST_FAILURE;
  498. }
  499. return EFI_ST_SUCCESS;
  500. }
  501. EFI_UNIT_TEST(blkdev) = {
  502. .name = "block device",
  503. .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
  504. .setup = setup,
  505. .execute = execute,
  506. .teardown = teardown,
  507. };