You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

efi_file.c 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. /*
  2. * Copyright (C) 2013 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. /**
  21. * @file
  22. *
  23. * EFI file protocols
  24. *
  25. */
  26. #include <stddef.h>
  27. #include <stdlib.h>
  28. #include <stdio.h>
  29. #include <string.h>
  30. #include <wchar.h>
  31. #include <ipxe/image.h>
  32. #include <ipxe/efi/efi.h>
  33. #include <ipxe/efi/Protocol/SimpleFileSystem.h>
  34. #include <ipxe/efi/Protocol/BlockIo.h>
  35. #include <ipxe/efi/Guid/FileInfo.h>
  36. #include <ipxe/efi/Guid/FileSystemInfo.h>
  37. #include <ipxe/efi/efi_strings.h>
  38. #include <ipxe/efi/efi_file.h>
  39. /** EFI simple file system protocol GUID */
  40. static EFI_GUID efi_simple_file_system_protocol_guid
  41. = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
  42. /** EFI file information GUID */
  43. static EFI_GUID efi_file_info_id = EFI_FILE_INFO_ID;
  44. /** EFI file system information GUID */
  45. static EFI_GUID efi_file_system_info_id = EFI_FILE_SYSTEM_INFO_ID;
  46. /** EFI block I/O protocol GUID */
  47. static EFI_GUID efi_block_io_protocol_guid
  48. = EFI_BLOCK_IO_PROTOCOL_GUID;
  49. /** EFI media ID */
  50. #define EFI_MEDIA_ID_MAGIC 0x69505845
  51. /** An image exposed as an EFI file */
  52. struct efi_file {
  53. /** EFI file protocol */
  54. EFI_FILE_PROTOCOL file;
  55. /** Image */
  56. struct image *image;
  57. /** Current file position */
  58. size_t pos;
  59. };
  60. static struct efi_file efi_file_root;
  61. /**
  62. * Get EFI file name (for debugging)
  63. *
  64. * @v file EFI file
  65. * @ret name Name
  66. */
  67. static const char * efi_file_name ( struct efi_file *file ) {
  68. return ( file->image ? file->image->name : "<root>" );
  69. }
  70. /**
  71. * Open file
  72. *
  73. * @v this EFI file
  74. * @ret new New EFI file
  75. * @v wname Filename
  76. * @v mode File mode
  77. * @v attributes File attributes (for newly-created files)
  78. * @ret efirc EFI status code
  79. */
  80. static EFI_STATUS EFIAPI
  81. efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new,
  82. CHAR16 *wname, UINT64 mode __unused,
  83. UINT64 attributes __unused ) {
  84. struct efi_file *file = container_of ( this, struct efi_file, file );
  85. char name[ wcslen ( wname ) + 1 /* NUL */ ];
  86. struct efi_file *new_file;
  87. struct image *image;
  88. /* Initial '\' indicates opening from the root directory */
  89. while ( *wname == L'\\' ) {
  90. file = &efi_file_root;
  91. wname++;
  92. }
  93. /* Allow root directory itself to be opened */
  94. if ( ( wname[0] == L'\0' ) || ( wname[0] == L'.' ) ) {
  95. *new = &efi_file_root.file;
  96. return 0;
  97. }
  98. /* Fail unless opening from the root */
  99. if ( file->image ) {
  100. DBGC ( file, "EFIFILE %s is not a directory\n",
  101. efi_file_name ( file ) );
  102. return EFI_NOT_FOUND;
  103. }
  104. /* Identify image */
  105. snprintf ( name, sizeof ( name ), "%ls", wname );
  106. image = find_image ( name );
  107. if ( ! image ) {
  108. DBGC ( file, "EFIFILE \"%s\" does not exist\n", name );
  109. return EFI_NOT_FOUND;
  110. }
  111. /* Fail unless opening read-only */
  112. if ( mode != EFI_FILE_MODE_READ ) {
  113. DBGC ( file, "EFIFILE %s cannot be opened in mode %#08llx\n",
  114. image->name, mode );
  115. return EFI_WRITE_PROTECTED;
  116. }
  117. /* Allocate and initialise file */
  118. new_file = zalloc ( sizeof ( *new_file ) );
  119. memcpy ( &new_file->file, &efi_file_root.file,
  120. sizeof ( new_file->file ) );
  121. new_file->image = image_get ( image );
  122. *new = &new_file->file;
  123. DBGC ( new_file, "EFIFILE %s opened\n", efi_file_name ( new_file ) );
  124. return 0;
  125. }
  126. /**
  127. * Close file
  128. *
  129. * @v this EFI file
  130. * @ret efirc EFI status code
  131. */
  132. static EFI_STATUS EFIAPI efi_file_close ( EFI_FILE_PROTOCOL *this ) {
  133. struct efi_file *file = container_of ( this, struct efi_file, file );
  134. /* Do nothing if this is the root */
  135. if ( ! file->image )
  136. return 0;
  137. /* Close file */
  138. DBGC ( file, "EFIFILE %s closed\n", efi_file_name ( file ) );
  139. image_put ( file->image );
  140. free ( file );
  141. return 0;
  142. }
  143. /**
  144. * Close and delete file
  145. *
  146. * @v this EFI file
  147. * @ret efirc EFI status code
  148. */
  149. static EFI_STATUS EFIAPI efi_file_delete ( EFI_FILE_PROTOCOL *this ) {
  150. struct efi_file *file = container_of ( this, struct efi_file, file );
  151. DBGC ( file, "EFIFILE %s cannot be deleted\n", efi_file_name ( file ) );
  152. /* Close file */
  153. efi_file_close ( this );
  154. /* Warn of failure to delete */
  155. return EFI_WARN_DELETE_FAILURE;
  156. }
  157. /**
  158. * Return variable-length data structure
  159. *
  160. * @v base Base data structure (starting with UINT64)
  161. * @v base_len Length of base data structure
  162. * @v name Name to append to base data structure
  163. * @v len Length of data buffer
  164. * @v data Data buffer
  165. * @ret efirc EFI status code
  166. */
  167. static EFI_STATUS efi_file_varlen ( UINT64 *base, size_t base_len,
  168. const char *name, UINTN *len, VOID *data ) {
  169. size_t name_len;
  170. /* Calculate structure length */
  171. name_len = strlen ( name );
  172. *base = ( base_len + ( name_len + 1 /* NUL */ ) * sizeof ( wchar_t ) );
  173. if ( *len < *base ) {
  174. *len = *base;
  175. return EFI_BUFFER_TOO_SMALL;
  176. }
  177. /* Copy data to buffer */
  178. *len = *base;
  179. memcpy ( data, base, base_len );
  180. efi_snprintf ( ( data + base_len ), ( name_len + 1 /* NUL */ ),
  181. "%s", name );
  182. return 0;
  183. }
  184. /**
  185. * Return file information structure
  186. *
  187. * @v image Image, or NULL for the root directory
  188. * @v len Length of data buffer
  189. * @v data Data buffer
  190. * @ret efirc EFI status code
  191. */
  192. static EFI_STATUS efi_file_info ( struct image *image, UINTN *len,
  193. VOID *data ) {
  194. EFI_FILE_INFO info;
  195. const char *name;
  196. /* Populate file information */
  197. memset ( &info, 0, sizeof ( info ) );
  198. if ( image ) {
  199. info.FileSize = image->len;
  200. info.PhysicalSize = image->len;
  201. info.Attribute = EFI_FILE_READ_ONLY;
  202. name = image->name;
  203. } else {
  204. info.Attribute = ( EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY );
  205. name = "";
  206. }
  207. return efi_file_varlen ( &info.Size, SIZE_OF_EFI_FILE_INFO, name,
  208. len, data );
  209. }
  210. /**
  211. * Read directory entry
  212. *
  213. * @v file EFI file
  214. * @v len Length to read
  215. * @v data Data buffer
  216. * @ret efirc EFI status code
  217. */
  218. static EFI_STATUS efi_file_read_dir ( struct efi_file *file, UINTN *len,
  219. VOID *data ) {
  220. EFI_STATUS efirc;
  221. struct image *image;
  222. unsigned int index;
  223. /* Construct directory entry at current position */
  224. index = file->pos;
  225. for_each_image ( image ) {
  226. if ( index-- == 0 ) {
  227. efirc = efi_file_info ( image, len, data );
  228. if ( efirc == 0 )
  229. file->pos++;
  230. return efirc;
  231. }
  232. }
  233. /* No more entries */
  234. *len = 0;
  235. return 0;
  236. }
  237. /**
  238. * Read from file
  239. *
  240. * @v this EFI file
  241. * @v len Length to read
  242. * @v data Data buffer
  243. * @ret efirc EFI status code
  244. */
  245. static EFI_STATUS EFIAPI efi_file_read ( EFI_FILE_PROTOCOL *this,
  246. UINTN *len, VOID *data ) {
  247. struct efi_file *file = container_of ( this, struct efi_file, file );
  248. size_t remaining;
  249. /* If this is the root directory, then construct a directory entry */
  250. if ( ! file->image )
  251. return efi_file_read_dir ( file, len, data );
  252. /* Read from the file */
  253. remaining = ( file->image->len - file->pos );
  254. if ( *len > remaining )
  255. *len = remaining;
  256. DBGC ( file, "EFIFILE %s read [%#08zx,%#08zx)\n",
  257. efi_file_name ( file ), file->pos,
  258. ( ( size_t ) ( file->pos + *len ) ) );
  259. copy_from_user ( data, file->image->data, file->pos, *len );
  260. file->pos += *len;
  261. return 0;
  262. }
  263. /**
  264. * Write to file
  265. *
  266. * @v this EFI file
  267. * @v len Length to write
  268. * @v data Data buffer
  269. * @ret efirc EFI status code
  270. */
  271. static EFI_STATUS EFIAPI efi_file_write ( EFI_FILE_PROTOCOL *this,
  272. UINTN *len, VOID *data __unused ) {
  273. struct efi_file *file = container_of ( this, struct efi_file, file );
  274. DBGC ( file, "EFIFILE %s cannot write [%#08zx, %#08zx)\n",
  275. efi_file_name ( file ), file->pos,
  276. ( ( size_t ) ( file->pos + *len ) ) );
  277. return EFI_WRITE_PROTECTED;
  278. }
  279. /**
  280. * Set file position
  281. *
  282. * @v this EFI file
  283. * @v position New file position
  284. * @ret efirc EFI status code
  285. */
  286. static EFI_STATUS EFIAPI efi_file_set_position ( EFI_FILE_PROTOCOL *this,
  287. UINT64 position ) {
  288. struct efi_file *file = container_of ( this, struct efi_file, file );
  289. /* If this is the root directory, reset to the start */
  290. if ( ! file->image ) {
  291. DBGC ( file, "EFIFILE root directory rewound\n" );
  292. file->pos = 0;
  293. return 0;
  294. }
  295. /* Check for the magic end-of-file value */
  296. if ( position == 0xffffffffffffffffULL )
  297. position = file->image->len;
  298. /* Fail if we attempt to seek past the end of the file (since
  299. * we do not support writes).
  300. */
  301. if ( position > file->image->len ) {
  302. DBGC ( file, "EFIFILE %s cannot seek to %#08llx of %#08zx\n",
  303. efi_file_name ( file ), position, file->image->len );
  304. return EFI_UNSUPPORTED;
  305. }
  306. /* Set position */
  307. file->pos = position;
  308. DBGC ( file, "EFIFILE %s position set to %#08zx\n",
  309. efi_file_name ( file ), file->pos );
  310. return 0;
  311. }
  312. /**
  313. * Get file position
  314. *
  315. * @v this EFI file
  316. * @ret position New file position
  317. * @ret efirc EFI status code
  318. */
  319. static EFI_STATUS EFIAPI efi_file_get_position ( EFI_FILE_PROTOCOL *this,
  320. UINT64 *position ) {
  321. struct efi_file *file = container_of ( this, struct efi_file, file );
  322. *position = file->pos;
  323. return 0;
  324. }
  325. /**
  326. * Get file information
  327. *
  328. * @v this EFI file
  329. * @v type Type of information
  330. * @v len Buffer size
  331. * @v data Buffer
  332. * @ret efirc EFI status code
  333. */
  334. static EFI_STATUS EFIAPI efi_file_get_info ( EFI_FILE_PROTOCOL *this,
  335. EFI_GUID *type,
  336. UINTN *len, VOID *data ) {
  337. struct efi_file *file = container_of ( this, struct efi_file, file );
  338. EFI_FILE_SYSTEM_INFO fsinfo;
  339. struct image *image;
  340. /* Determine information to return */
  341. if ( memcmp ( type, &efi_file_info_id, sizeof ( *type ) ) == 0 ) {
  342. /* Get file information */
  343. DBGC ( file, "EFIFILE %s get file information\n",
  344. efi_file_name ( file ) );
  345. return efi_file_info ( file->image, len, data );
  346. } else if ( memcmp ( type, &efi_file_system_info_id,
  347. sizeof ( *type ) ) == 0 ) {
  348. /* Get file system information */
  349. DBGC ( file, "EFIFILE %s get file system information\n",
  350. efi_file_name ( file ) );
  351. memset ( &fsinfo, 0, sizeof ( fsinfo ) );
  352. fsinfo.ReadOnly = 1;
  353. for_each_image ( image )
  354. fsinfo.VolumeSize += image->len;
  355. return efi_file_varlen ( &fsinfo.Size,
  356. SIZE_OF_EFI_FILE_SYSTEM_INFO, "iPXE",
  357. len, data );
  358. } else {
  359. DBGC ( file, "EFIFILE %s cannot get information of type %s\n",
  360. efi_file_name ( file ), efi_guid_ntoa ( type ) );
  361. return EFI_UNSUPPORTED;
  362. }
  363. }
  364. /**
  365. * Set file information
  366. *
  367. * @v this EFI file
  368. * @v type Type of information
  369. * @v len Buffer size
  370. * @v data Buffer
  371. * @ret efirc EFI status code
  372. */
  373. static EFI_STATUS EFIAPI
  374. efi_file_set_info ( EFI_FILE_PROTOCOL *this, EFI_GUID *type,
  375. UINTN len __unused, VOID *data __unused ) {
  376. struct efi_file *file = container_of ( this, struct efi_file, file );
  377. DBGC ( file, "EFIFILE %s cannot set information of type %s\n",
  378. efi_file_name ( file ), efi_guid_ntoa ( type ) );
  379. return EFI_WRITE_PROTECTED;
  380. }
  381. /**
  382. * Flush file modified data
  383. *
  384. * @v this EFI file
  385. * @v type Type of information
  386. * @v len Buffer size
  387. * @v data Buffer
  388. * @ret efirc EFI status code
  389. */
  390. static EFI_STATUS EFIAPI efi_file_flush ( EFI_FILE_PROTOCOL *this ) {
  391. struct efi_file *file = container_of ( this, struct efi_file, file );
  392. DBGC ( file, "EFIFILE %s flushed\n", efi_file_name ( file ) );
  393. return 0;
  394. }
  395. /** Root directory */
  396. static struct efi_file efi_file_root = {
  397. .file = {
  398. .Revision = EFI_FILE_PROTOCOL_REVISION,
  399. .Open = efi_file_open,
  400. .Close = efi_file_close,
  401. .Delete = efi_file_delete,
  402. .Read = efi_file_read,
  403. .Write = efi_file_write,
  404. .GetPosition = efi_file_get_position,
  405. .SetPosition = efi_file_set_position,
  406. .GetInfo = efi_file_get_info,
  407. .SetInfo = efi_file_set_info,
  408. .Flush = efi_file_flush,
  409. },
  410. .image = NULL,
  411. };
  412. /**
  413. * Open root directory
  414. *
  415. * @v filesystem EFI simple file system
  416. * @ret file EFI file handle
  417. * @ret efirc EFI status code
  418. */
  419. static EFI_STATUS EFIAPI
  420. efi_file_open_volume ( EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *filesystem __unused,
  421. EFI_FILE_PROTOCOL **file ) {
  422. *file = &efi_file_root.file;
  423. return 0;
  424. }
  425. /** EFI simple file system protocol */
  426. static EFI_SIMPLE_FILE_SYSTEM_PROTOCOL efi_simple_file_system_protocol = {
  427. .Revision = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,
  428. .OpenVolume = efi_file_open_volume,
  429. };
  430. /** Dummy block I/O reset */
  431. static EFI_STATUS EFIAPI
  432. efi_block_io_reset ( EFI_BLOCK_IO_PROTOCOL *this __unused,
  433. BOOLEAN extended __unused ) {
  434. return 0;
  435. }
  436. /** Dummy block I/O read */
  437. static EFI_STATUS EFIAPI
  438. efi_block_io_read_blocks ( EFI_BLOCK_IO_PROTOCOL *this __unused,
  439. UINT32 MediaId __unused, EFI_LBA lba __unused,
  440. UINTN len __unused, VOID *data __unused ) {
  441. return EFI_DEVICE_ERROR;
  442. }
  443. /** Dummy block I/O write */
  444. static EFI_STATUS EFIAPI
  445. efi_block_io_write_blocks ( EFI_BLOCK_IO_PROTOCOL *this __unused,
  446. UINT32 MediaId __unused, EFI_LBA lba __unused,
  447. UINTN len __unused, VOID *data __unused ) {
  448. return EFI_DEVICE_ERROR;
  449. }
  450. /** Dummy block I/O flush */
  451. static EFI_STATUS EFIAPI
  452. efi_block_io_flush_blocks ( EFI_BLOCK_IO_PROTOCOL *this __unused ) {
  453. return 0;
  454. }
  455. /** Dummy block I/O media */
  456. static EFI_BLOCK_IO_MEDIA efi_block_io_media = {
  457. .MediaId = EFI_MEDIA_ID_MAGIC,
  458. .MediaPresent = 1,
  459. .ReadOnly = 1,
  460. .BlockSize = 1,
  461. };
  462. /** Dummy EFI block I/O protocol */
  463. static EFI_BLOCK_IO_PROTOCOL efi_block_io_protocol = {
  464. .Revision = EFI_BLOCK_IO_PROTOCOL_REVISION,
  465. .Media = &efi_block_io_media,
  466. .Reset = efi_block_io_reset,
  467. .ReadBlocks = efi_block_io_read_blocks,
  468. .WriteBlocks = efi_block_io_write_blocks,
  469. .FlushBlocks = efi_block_io_flush_blocks,
  470. };
  471. /**
  472. * Install EFI simple file system protocol
  473. *
  474. * @v handle EFI handle
  475. * @ret rc Return status code
  476. */
  477. int efi_file_install ( EFI_HANDLE *handle ) {
  478. EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
  479. EFI_STATUS efirc;
  480. /* Install the simple file system protocol and the block I/O
  481. * protocol. We don't have a block device, but large parts of
  482. * the EDK2 codebase make the assumption that file systems are
  483. * normally attached to block devices, and so we create a
  484. * dummy block device on the same handle just to keep things
  485. * looking normal.
  486. */
  487. if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
  488. handle,
  489. &efi_block_io_protocol_guid,
  490. &efi_block_io_protocol,
  491. &efi_simple_file_system_protocol_guid,
  492. &efi_simple_file_system_protocol, NULL ) ) != 0 ) {
  493. DBGC ( handle, "Could not install simple file system protocol: "
  494. "%s\n", efi_strerror ( efirc ) );
  495. return EFIRC_TO_RC ( efirc );
  496. }
  497. return 0;
  498. }
  499. /**
  500. * Uninstall EFI simple file system protocol
  501. *
  502. * @v handle EFI handle
  503. */
  504. void efi_file_uninstall ( EFI_HANDLE handle ) {
  505. EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
  506. /* We must install the file system protocol first, since
  507. * otherwise the EDK2 code will attempt to helpfully uninstall
  508. * it when the block I/O protocol is uninstalled, leading to a
  509. * system lock-up.
  510. */
  511. bs->UninstallMultipleProtocolInterfaces (
  512. handle,
  513. &efi_simple_file_system_protocol_guid,
  514. &efi_simple_file_system_protocol,
  515. &efi_block_io_protocol_guid,
  516. &efi_block_io_protocol, NULL );
  517. }