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