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 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715
  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. * You can also choose to distribute this program under the terms of
  20. * the Unmodified Binary Distribution Licence (as given in the file
  21. * COPYING.UBDL), provided that you have satisfied its requirements.
  22. */
  23. FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  24. /**
  25. * @file
  26. *
  27. * EFI file protocols
  28. *
  29. */
  30. #include <stddef.h>
  31. #include <stdlib.h>
  32. #include <stdio.h>
  33. #include <string.h>
  34. #include <strings.h>
  35. #include <errno.h>
  36. #include <wchar.h>
  37. #include <ipxe/image.h>
  38. #include <ipxe/efi/efi.h>
  39. #include <ipxe/efi/Protocol/SimpleFileSystem.h>
  40. #include <ipxe/efi/Protocol/BlockIo.h>
  41. #include <ipxe/efi/Protocol/DiskIo.h>
  42. #include <ipxe/efi/Guid/FileInfo.h>
  43. #include <ipxe/efi/Guid/FileSystemInfo.h>
  44. #include <ipxe/efi/efi_strings.h>
  45. #include <ipxe/efi/efi_file.h>
  46. /** EFI media ID */
  47. #define EFI_MEDIA_ID_MAGIC 0x69505845
  48. /** An image exposed as an EFI file */
  49. struct efi_file {
  50. /** EFI file protocol */
  51. EFI_FILE_PROTOCOL file;
  52. /** Image */
  53. struct image *image;
  54. /** Current file position */
  55. size_t pos;
  56. };
  57. static struct efi_file efi_file_root;
  58. /**
  59. * Get EFI file name (for debugging)
  60. *
  61. * @v file EFI file
  62. * @ret name Name
  63. */
  64. static const char * efi_file_name ( struct efi_file *file ) {
  65. return ( file->image ? file->image->name : "<root>" );
  66. }
  67. /**
  68. * Find EFI file image
  69. *
  70. * @v wname Filename
  71. * @ret image Image, or NULL
  72. */
  73. static struct image * efi_file_find ( const CHAR16 *wname ) {
  74. char name[ wcslen ( wname ) + 1 /* NUL */ ];
  75. struct image *image;
  76. /* Find image */
  77. snprintf ( name, sizeof ( name ), "%ls", wname );
  78. list_for_each_entry ( image, &images, list ) {
  79. if ( strcasecmp ( image->name, name ) == 0 )
  80. return image;
  81. }
  82. return NULL;
  83. }
  84. /**
  85. * Open file
  86. *
  87. * @v this EFI file
  88. * @ret new New EFI file
  89. * @v wname Filename
  90. * @v mode File mode
  91. * @v attributes File attributes (for newly-created files)
  92. * @ret efirc EFI status code
  93. */
  94. static EFI_STATUS EFIAPI
  95. efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new,
  96. CHAR16 *wname, UINT64 mode __unused,
  97. UINT64 attributes __unused ) {
  98. struct efi_file *file = container_of ( this, struct efi_file, file );
  99. struct efi_file *new_file;
  100. struct image *image;
  101. /* Initial '\' indicates opening from the root directory */
  102. while ( *wname == L'\\' ) {
  103. file = &efi_file_root;
  104. wname++;
  105. }
  106. /* Allow root directory itself to be opened */
  107. if ( ( wname[0] == L'\0' ) || ( wname[0] == L'.' ) ) {
  108. *new = &efi_file_root.file;
  109. return 0;
  110. }
  111. /* Fail unless opening from the root */
  112. if ( file->image ) {
  113. DBGC ( file, "EFIFILE %s is not a directory\n",
  114. efi_file_name ( file ) );
  115. return EFI_NOT_FOUND;
  116. }
  117. /* Identify image */
  118. image = efi_file_find ( wname );
  119. if ( ! image ) {
  120. DBGC ( file, "EFIFILE \"%ls\" does not exist\n", wname );
  121. return EFI_NOT_FOUND;
  122. }
  123. /* Fail unless opening read-only */
  124. if ( mode != EFI_FILE_MODE_READ ) {
  125. DBGC ( file, "EFIFILE %s cannot be opened in mode %#08llx\n",
  126. image->name, mode );
  127. return EFI_WRITE_PROTECTED;
  128. }
  129. /* Allocate and initialise file */
  130. new_file = zalloc ( sizeof ( *new_file ) );
  131. memcpy ( &new_file->file, &efi_file_root.file,
  132. sizeof ( new_file->file ) );
  133. new_file->image = image_get ( image );
  134. *new = &new_file->file;
  135. DBGC ( new_file, "EFIFILE %s opened\n", efi_file_name ( new_file ) );
  136. return 0;
  137. }
  138. /**
  139. * Close file
  140. *
  141. * @v this EFI file
  142. * @ret efirc EFI status code
  143. */
  144. static EFI_STATUS EFIAPI efi_file_close ( EFI_FILE_PROTOCOL *this ) {
  145. struct efi_file *file = container_of ( this, struct efi_file, file );
  146. /* Do nothing if this is the root */
  147. if ( ! file->image )
  148. return 0;
  149. /* Close file */
  150. DBGC ( file, "EFIFILE %s closed\n", efi_file_name ( file ) );
  151. image_put ( file->image );
  152. free ( file );
  153. return 0;
  154. }
  155. /**
  156. * Close and delete file
  157. *
  158. * @v this EFI file
  159. * @ret efirc EFI status code
  160. */
  161. static EFI_STATUS EFIAPI efi_file_delete ( EFI_FILE_PROTOCOL *this ) {
  162. struct efi_file *file = container_of ( this, struct efi_file, file );
  163. DBGC ( file, "EFIFILE %s cannot be deleted\n", efi_file_name ( file ) );
  164. /* Close file */
  165. efi_file_close ( this );
  166. /* Warn of failure to delete */
  167. return EFI_WARN_DELETE_FAILURE;
  168. }
  169. /**
  170. * Return variable-length data structure
  171. *
  172. * @v base Base data structure (starting with UINT64)
  173. * @v base_len Length of base data structure
  174. * @v name Name to append to base data structure
  175. * @v len Length of data buffer
  176. * @v data Data buffer
  177. * @ret efirc EFI status code
  178. */
  179. static EFI_STATUS efi_file_varlen ( UINT64 *base, size_t base_len,
  180. const char *name, UINTN *len, VOID *data ) {
  181. size_t name_len;
  182. /* Calculate structure length */
  183. name_len = strlen ( name );
  184. *base = ( base_len + ( name_len + 1 /* NUL */ ) * sizeof ( wchar_t ) );
  185. if ( *len < *base ) {
  186. *len = *base;
  187. return EFI_BUFFER_TOO_SMALL;
  188. }
  189. /* Copy data to buffer */
  190. *len = *base;
  191. memcpy ( data, base, base_len );
  192. efi_snprintf ( ( data + base_len ), ( name_len + 1 /* NUL */ ),
  193. "%s", name );
  194. return 0;
  195. }
  196. /**
  197. * Return file information structure
  198. *
  199. * @v image Image, or NULL for the root directory
  200. * @v len Length of data buffer
  201. * @v data Data buffer
  202. * @ret efirc EFI status code
  203. */
  204. static EFI_STATUS efi_file_info ( struct image *image, UINTN *len,
  205. VOID *data ) {
  206. EFI_FILE_INFO info;
  207. const char *name;
  208. /* Populate file information */
  209. memset ( &info, 0, sizeof ( info ) );
  210. if ( image ) {
  211. info.FileSize = image->len;
  212. info.PhysicalSize = image->len;
  213. info.Attribute = EFI_FILE_READ_ONLY;
  214. name = image->name;
  215. } else {
  216. info.Attribute = ( EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY );
  217. name = "";
  218. }
  219. return efi_file_varlen ( &info.Size, SIZE_OF_EFI_FILE_INFO, name,
  220. len, data );
  221. }
  222. /**
  223. * Read directory entry
  224. *
  225. * @v file EFI file
  226. * @v len Length to read
  227. * @v data Data buffer
  228. * @ret efirc EFI status code
  229. */
  230. static EFI_STATUS efi_file_read_dir ( struct efi_file *file, UINTN *len,
  231. VOID *data ) {
  232. EFI_STATUS efirc;
  233. struct image *image;
  234. unsigned int index;
  235. /* Construct directory entry at current position */
  236. index = file->pos;
  237. for_each_image ( image ) {
  238. if ( index-- == 0 ) {
  239. efirc = efi_file_info ( image, len, data );
  240. if ( efirc == 0 )
  241. file->pos++;
  242. return efirc;
  243. }
  244. }
  245. /* No more entries */
  246. *len = 0;
  247. return 0;
  248. }
  249. /**
  250. * Read from file
  251. *
  252. * @v this EFI file
  253. * @v len Length to read
  254. * @v data Data buffer
  255. * @ret efirc EFI status code
  256. */
  257. static EFI_STATUS EFIAPI efi_file_read ( EFI_FILE_PROTOCOL *this,
  258. UINTN *len, VOID *data ) {
  259. struct efi_file *file = container_of ( this, struct efi_file, file );
  260. size_t remaining;
  261. /* If this is the root directory, then construct a directory entry */
  262. if ( ! file->image )
  263. return efi_file_read_dir ( file, len, data );
  264. /* Read from the file */
  265. remaining = ( file->image->len - file->pos );
  266. if ( *len > remaining )
  267. *len = remaining;
  268. DBGC ( file, "EFIFILE %s read [%#08zx,%#08zx)\n",
  269. efi_file_name ( file ), file->pos,
  270. ( ( size_t ) ( file->pos + *len ) ) );
  271. copy_from_user ( data, file->image->data, file->pos, *len );
  272. file->pos += *len;
  273. return 0;
  274. }
  275. /**
  276. * Write to file
  277. *
  278. * @v this EFI file
  279. * @v len Length to write
  280. * @v data Data buffer
  281. * @ret efirc EFI status code
  282. */
  283. static EFI_STATUS EFIAPI efi_file_write ( EFI_FILE_PROTOCOL *this,
  284. UINTN *len, VOID *data __unused ) {
  285. struct efi_file *file = container_of ( this, struct efi_file, file );
  286. DBGC ( file, "EFIFILE %s cannot write [%#08zx, %#08zx)\n",
  287. efi_file_name ( file ), file->pos,
  288. ( ( size_t ) ( file->pos + *len ) ) );
  289. return EFI_WRITE_PROTECTED;
  290. }
  291. /**
  292. * Set file position
  293. *
  294. * @v this EFI file
  295. * @v position New file position
  296. * @ret efirc EFI status code
  297. */
  298. static EFI_STATUS EFIAPI efi_file_set_position ( EFI_FILE_PROTOCOL *this,
  299. UINT64 position ) {
  300. struct efi_file *file = container_of ( this, struct efi_file, file );
  301. /* If this is the root directory, reset to the start */
  302. if ( ! file->image ) {
  303. DBGC ( file, "EFIFILE root directory rewound\n" );
  304. file->pos = 0;
  305. return 0;
  306. }
  307. /* Check for the magic end-of-file value */
  308. if ( position == 0xffffffffffffffffULL )
  309. position = file->image->len;
  310. /* Fail if we attempt to seek past the end of the file (since
  311. * we do not support writes).
  312. */
  313. if ( position > file->image->len ) {
  314. DBGC ( file, "EFIFILE %s cannot seek to %#08llx of %#08zx\n",
  315. efi_file_name ( file ), position, file->image->len );
  316. return EFI_UNSUPPORTED;
  317. }
  318. /* Set position */
  319. file->pos = position;
  320. DBGC ( file, "EFIFILE %s position set to %#08zx\n",
  321. efi_file_name ( file ), file->pos );
  322. return 0;
  323. }
  324. /**
  325. * Get file position
  326. *
  327. * @v this EFI file
  328. * @ret position New file position
  329. * @ret efirc EFI status code
  330. */
  331. static EFI_STATUS EFIAPI efi_file_get_position ( EFI_FILE_PROTOCOL *this,
  332. UINT64 *position ) {
  333. struct efi_file *file = container_of ( this, struct efi_file, file );
  334. *position = file->pos;
  335. return 0;
  336. }
  337. /**
  338. * Get file information
  339. *
  340. * @v this EFI file
  341. * @v type Type of information
  342. * @v len Buffer size
  343. * @v data Buffer
  344. * @ret efirc EFI status code
  345. */
  346. static EFI_STATUS EFIAPI efi_file_get_info ( EFI_FILE_PROTOCOL *this,
  347. EFI_GUID *type,
  348. UINTN *len, VOID *data ) {
  349. struct efi_file *file = container_of ( this, struct efi_file, file );
  350. EFI_FILE_SYSTEM_INFO fsinfo;
  351. struct image *image;
  352. /* Determine information to return */
  353. if ( memcmp ( type, &efi_file_info_id, sizeof ( *type ) ) == 0 ) {
  354. /* Get file information */
  355. DBGC ( file, "EFIFILE %s get file information\n",
  356. efi_file_name ( file ) );
  357. return efi_file_info ( file->image, len, data );
  358. } else if ( memcmp ( type, &efi_file_system_info_id,
  359. sizeof ( *type ) ) == 0 ) {
  360. /* Get file system information */
  361. DBGC ( file, "EFIFILE %s get file system information\n",
  362. efi_file_name ( file ) );
  363. memset ( &fsinfo, 0, sizeof ( fsinfo ) );
  364. fsinfo.ReadOnly = 1;
  365. for_each_image ( image )
  366. fsinfo.VolumeSize += image->len;
  367. return efi_file_varlen ( &fsinfo.Size,
  368. SIZE_OF_EFI_FILE_SYSTEM_INFO, "iPXE",
  369. len, data );
  370. } else {
  371. DBGC ( file, "EFIFILE %s cannot get information of type %s\n",
  372. efi_file_name ( file ), efi_guid_ntoa ( type ) );
  373. return EFI_UNSUPPORTED;
  374. }
  375. }
  376. /**
  377. * Set file information
  378. *
  379. * @v this EFI file
  380. * @v type Type of information
  381. * @v len Buffer size
  382. * @v data Buffer
  383. * @ret efirc EFI status code
  384. */
  385. static EFI_STATUS EFIAPI
  386. efi_file_set_info ( EFI_FILE_PROTOCOL *this, EFI_GUID *type,
  387. UINTN len __unused, VOID *data __unused ) {
  388. struct efi_file *file = container_of ( this, struct efi_file, file );
  389. DBGC ( file, "EFIFILE %s cannot set information of type %s\n",
  390. efi_file_name ( file ), efi_guid_ntoa ( type ) );
  391. return EFI_WRITE_PROTECTED;
  392. }
  393. /**
  394. * Flush file modified data
  395. *
  396. * @v this EFI file
  397. * @v type Type of information
  398. * @v len Buffer size
  399. * @v data Buffer
  400. * @ret efirc EFI status code
  401. */
  402. static EFI_STATUS EFIAPI efi_file_flush ( EFI_FILE_PROTOCOL *this ) {
  403. struct efi_file *file = container_of ( this, struct efi_file, file );
  404. DBGC ( file, "EFIFILE %s flushed\n", efi_file_name ( file ) );
  405. return 0;
  406. }
  407. /** Root directory */
  408. static struct efi_file efi_file_root = {
  409. .file = {
  410. .Revision = EFI_FILE_PROTOCOL_REVISION,
  411. .Open = efi_file_open,
  412. .Close = efi_file_close,
  413. .Delete = efi_file_delete,
  414. .Read = efi_file_read,
  415. .Write = efi_file_write,
  416. .GetPosition = efi_file_get_position,
  417. .SetPosition = efi_file_set_position,
  418. .GetInfo = efi_file_get_info,
  419. .SetInfo = efi_file_set_info,
  420. .Flush = efi_file_flush,
  421. },
  422. .image = NULL,
  423. };
  424. /**
  425. * Open root directory
  426. *
  427. * @v filesystem EFI simple file system
  428. * @ret file EFI file handle
  429. * @ret efirc EFI status code
  430. */
  431. static EFI_STATUS EFIAPI
  432. efi_file_open_volume ( EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *filesystem __unused,
  433. EFI_FILE_PROTOCOL **file ) {
  434. DBGC ( &efi_file_root, "EFIFILE open volume\n" );
  435. *file = &efi_file_root.file;
  436. return 0;
  437. }
  438. /** EFI simple file system protocol */
  439. static EFI_SIMPLE_FILE_SYSTEM_PROTOCOL efi_simple_file_system_protocol = {
  440. .Revision = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,
  441. .OpenVolume = efi_file_open_volume,
  442. };
  443. /** Dummy block I/O reset */
  444. static EFI_STATUS EFIAPI
  445. efi_block_io_reset ( EFI_BLOCK_IO_PROTOCOL *this __unused, BOOLEAN extended ) {
  446. DBGC ( &efi_file_root, "EFIFILE block %sreset\n",
  447. ( extended ? "extended " : "" ) );
  448. return 0;
  449. }
  450. /** Dummy block I/O read */
  451. static EFI_STATUS EFIAPI
  452. efi_block_io_read_blocks ( EFI_BLOCK_IO_PROTOCOL *this __unused, UINT32 MediaId,
  453. EFI_LBA lba, UINTN len, VOID *data ) {
  454. DBGC ( &efi_file_root, "EFIFILE block read ID %#08x LBA %#08llx -> "
  455. "%p+%zx\n", MediaId, ( ( unsigned long long ) lba ),
  456. data, ( ( size_t ) len ) );
  457. return EFI_NO_MEDIA;
  458. }
  459. /** Dummy block I/O write */
  460. static EFI_STATUS EFIAPI
  461. efi_block_io_write_blocks ( EFI_BLOCK_IO_PROTOCOL *this __unused,
  462. UINT32 MediaId, EFI_LBA lba, UINTN len,
  463. VOID *data ) {
  464. DBGC ( &efi_file_root, "EFIFILE block write ID %#08x LBA %#08llx <- "
  465. "%p+%zx\n", MediaId, ( ( unsigned long long ) lba ),
  466. data, ( ( size_t ) len ) );
  467. return EFI_NO_MEDIA;
  468. }
  469. /** Dummy block I/O flush */
  470. static EFI_STATUS EFIAPI
  471. efi_block_io_flush_blocks ( EFI_BLOCK_IO_PROTOCOL *this __unused ) {
  472. DBGC ( &efi_file_root, "EFIFILE block flush\n" );
  473. return 0;
  474. }
  475. /** Dummy block I/O media */
  476. static EFI_BLOCK_IO_MEDIA efi_block_io_media = {
  477. .MediaId = EFI_MEDIA_ID_MAGIC,
  478. .MediaPresent = TRUE,
  479. .ReadOnly = TRUE,
  480. .BlockSize = 1,
  481. };
  482. /** Dummy EFI block I/O protocol */
  483. static EFI_BLOCK_IO_PROTOCOL efi_block_io_protocol = {
  484. .Revision = EFI_BLOCK_IO_PROTOCOL_REVISION,
  485. .Media = &efi_block_io_media,
  486. .Reset = efi_block_io_reset,
  487. .ReadBlocks = efi_block_io_read_blocks,
  488. .WriteBlocks = efi_block_io_write_blocks,
  489. .FlushBlocks = efi_block_io_flush_blocks,
  490. };
  491. /** Dummy disk I/O read */
  492. static EFI_STATUS EFIAPI
  493. efi_disk_io_read_disk ( EFI_DISK_IO_PROTOCOL *this __unused, UINT32 MediaId,
  494. UINT64 offset, UINTN len, VOID *data ) {
  495. DBGC ( &efi_file_root, "EFIFILE disk read ID %#08x offset %#08llx -> "
  496. "%p+%zx\n", MediaId, ( ( unsigned long long ) offset ),
  497. data, ( ( size_t ) len ) );
  498. return EFI_NO_MEDIA;
  499. }
  500. /** Dummy disk I/O write */
  501. static EFI_STATUS EFIAPI
  502. efi_disk_io_write_disk ( EFI_DISK_IO_PROTOCOL *this __unused, UINT32 MediaId,
  503. UINT64 offset, UINTN len, VOID *data ) {
  504. DBGC ( &efi_file_root, "EFIFILE disk write ID %#08x offset %#08llx <- "
  505. "%p+%zx\n", MediaId, ( ( unsigned long long ) offset ),
  506. data, ( ( size_t ) len ) );
  507. return EFI_NO_MEDIA;
  508. }
  509. /** Dummy EFI disk I/O protocol */
  510. static EFI_DISK_IO_PROTOCOL efi_disk_io_protocol = {
  511. .Revision = EFI_DISK_IO_PROTOCOL_REVISION,
  512. .ReadDisk = efi_disk_io_read_disk,
  513. .WriteDisk = efi_disk_io_write_disk,
  514. };
  515. /**
  516. * Install EFI simple file system protocol
  517. *
  518. * @v handle EFI handle
  519. * @ret rc Return status code
  520. */
  521. int efi_file_install ( EFI_HANDLE handle ) {
  522. EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
  523. union {
  524. EFI_DISK_IO_PROTOCOL *diskio;
  525. void *interface;
  526. } diskio;
  527. EFI_STATUS efirc;
  528. int rc;
  529. /* Reset root directory state */
  530. efi_file_root.pos = 0;
  531. /* Install the simple file system protocol, block I/O
  532. * protocol, and disk I/O protocol. We don't have a block
  533. * device, but large parts of the EDK2 codebase make the
  534. * assumption that file systems are normally attached to block
  535. * devices, and so we create a dummy block device on the same
  536. * handle just to keep things looking normal.
  537. */
  538. if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
  539. &handle,
  540. &efi_block_io_protocol_guid,
  541. &efi_block_io_protocol,
  542. &efi_disk_io_protocol_guid,
  543. &efi_disk_io_protocol,
  544. &efi_simple_file_system_protocol_guid,
  545. &efi_simple_file_system_protocol, NULL ) ) != 0 ) {
  546. rc = -EEFI ( efirc );
  547. DBGC ( handle, "Could not install simple file system "
  548. "protocols: %s\n", strerror ( rc ) );
  549. goto err_install;
  550. }
  551. /* The FAT filesystem driver has a bug: if a block device
  552. * contains no FAT filesystem but does have an
  553. * EFI_SIMPLE_FILE_SYSTEM_PROTOCOL instance, the FAT driver
  554. * will assume that it must have previously installed the
  555. * EFI_SIMPLE_FILE_SYSTEM_PROTOCOL. This causes the FAT
  556. * driver to claim control of our device, and to refuse to
  557. * stop driving it, which prevents us from later uninstalling
  558. * correctly.
  559. *
  560. * Work around this bug by opening the disk I/O protocol
  561. * ourselves, thereby preventing the FAT driver from opening
  562. * it.
  563. *
  564. * Note that the alternative approach of opening the block I/O
  565. * protocol (and thereby in theory preventing DiskIo from
  566. * attaching to the block I/O protocol) causes an endless loop
  567. * of calls to our DRIVER_STOP method when starting the EFI
  568. * shell. I have no idea why this is.
  569. */
  570. if ( ( efirc = bs->OpenProtocol ( handle, &efi_disk_io_protocol_guid,
  571. &diskio.interface, efi_image_handle,
  572. handle,
  573. EFI_OPEN_PROTOCOL_BY_DRIVER ) ) != 0){
  574. rc = -EEFI ( efirc );
  575. DBGC ( handle, "Could not open disk I/O protocol: %s\n",
  576. strerror ( rc ) );
  577. DBGC_EFI_OPENERS ( handle, handle, &efi_disk_io_protocol_guid );
  578. goto err_open;
  579. }
  580. assert ( diskio.diskio == &efi_disk_io_protocol );
  581. return 0;
  582. bs->CloseProtocol ( handle, &efi_disk_io_protocol_guid,
  583. efi_image_handle, handle );
  584. err_open:
  585. bs->UninstallMultipleProtocolInterfaces (
  586. handle,
  587. &efi_simple_file_system_protocol_guid,
  588. &efi_simple_file_system_protocol,
  589. &efi_disk_io_protocol_guid,
  590. &efi_disk_io_protocol,
  591. &efi_block_io_protocol_guid,
  592. &efi_block_io_protocol, NULL );
  593. err_install:
  594. return rc;
  595. }
  596. /**
  597. * Uninstall EFI simple file system protocol
  598. *
  599. * @v handle EFI handle
  600. */
  601. void efi_file_uninstall ( EFI_HANDLE handle ) {
  602. EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
  603. EFI_STATUS efirc;
  604. int rc;
  605. /* Close our own disk I/O protocol */
  606. bs->CloseProtocol ( handle, &efi_disk_io_protocol_guid,
  607. efi_image_handle, handle );
  608. /* We must install the file system protocol first, since
  609. * otherwise the EDK2 code will attempt to helpfully uninstall
  610. * it when the block I/O protocol is uninstalled, leading to a
  611. * system lock-up.
  612. */
  613. if ( ( efirc = bs->UninstallMultipleProtocolInterfaces (
  614. handle,
  615. &efi_simple_file_system_protocol_guid,
  616. &efi_simple_file_system_protocol,
  617. &efi_disk_io_protocol_guid,
  618. &efi_disk_io_protocol,
  619. &efi_block_io_protocol_guid,
  620. &efi_block_io_protocol, NULL ) ) != 0 ) {
  621. rc = -EEFI ( efirc );
  622. DBGC ( handle, "Could not uninstall simple file system "
  623. "protocols: %s\n", strerror ( rc ) );
  624. /* Oh dear */
  625. }
  626. }