iPXE
efi_file.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 /**
00027  * @file
00028  *
00029  * EFI file protocols
00030  *
00031  */
00032 
00033 #include <stddef.h>
00034 #include <stdlib.h>
00035 #include <stdio.h>
00036 #include <string.h>
00037 #include <strings.h>
00038 #include <errno.h>
00039 #include <wchar.h>
00040 #include <ipxe/image.h>
00041 #include <ipxe/efi/efi.h>
00042 #include <ipxe/efi/Protocol/SimpleFileSystem.h>
00043 #include <ipxe/efi/Protocol/BlockIo.h>
00044 #include <ipxe/efi/Protocol/DiskIo.h>
00045 #include <ipxe/efi/Guid/FileInfo.h>
00046 #include <ipxe/efi/Guid/FileSystemInfo.h>
00047 #include <ipxe/efi/efi_strings.h>
00048 #include <ipxe/efi/efi_file.h>
00049 
00050 /** EFI media ID */
00051 #define EFI_MEDIA_ID_MAGIC 0x69505845
00052 
00053 /** An image exposed as an EFI file */
00054 struct efi_file {
00055         /** EFI file protocol */
00056         EFI_FILE_PROTOCOL file;
00057         /** Image */
00058         struct image *image;
00059         /** Current file position */
00060         size_t pos;
00061 };
00062 
00063 static struct efi_file efi_file_root;
00064 
00065 /**
00066  * Get EFI file name (for debugging)
00067  *
00068  * @v file              EFI file
00069  * @ret name            Name
00070  */
00071 static const char * efi_file_name ( struct efi_file *file ) {
00072 
00073         return ( file->image ? file->image->name : "<root>" );
00074 }
00075 
00076 /**
00077  * Find EFI file image
00078  *
00079  * @v wname             Filename
00080  * @ret image           Image, or NULL
00081  */
00082 static struct image * efi_file_find ( const CHAR16 *wname ) {
00083         char name[ wcslen ( wname ) + 1 /* NUL */ ];
00084         struct image *image;
00085 
00086         /* Find image */
00087         snprintf ( name, sizeof ( name ), "%ls", wname );
00088         list_for_each_entry ( image, &images, list ) {
00089                 if ( strcasecmp ( image->name, name ) == 0 )
00090                         return image;
00091         }
00092 
00093         return NULL;
00094 
00095 }
00096 
00097 /**
00098  * Open file
00099  *
00100  * @v this              EFI file
00101  * @ret new             New EFI file
00102  * @v wname             Filename
00103  * @v mode              File mode
00104  * @v attributes        File attributes (for newly-created files)
00105  * @ret efirc           EFI status code
00106  */
00107 static EFI_STATUS EFIAPI
00108 efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new,
00109                 CHAR16 *wname, UINT64 mode __unused,
00110                 UINT64 attributes __unused ) {
00111         struct efi_file *file = container_of ( this, struct efi_file, file );
00112         struct efi_file *new_file;
00113         struct image *image;
00114 
00115         /* Initial '\' indicates opening from the root directory */
00116         while ( *wname == L'\\' ) {
00117                 file = &efi_file_root;
00118                 wname++;
00119         }
00120 
00121         /* Allow root directory itself to be opened */
00122         if ( ( wname[0] == L'\0' ) || ( wname[0] == L'.' ) ) {
00123                 *new = &efi_file_root.file;
00124                 return 0;
00125         }
00126 
00127         /* Fail unless opening from the root */
00128         if ( file->image ) {
00129                 DBGC ( file, "EFIFILE %s is not a directory\n",
00130                        efi_file_name ( file ) );
00131                 return EFI_NOT_FOUND;
00132         }
00133 
00134         /* Identify image */
00135         image = efi_file_find ( wname );
00136         if ( ! image ) {
00137                 DBGC ( file, "EFIFILE \"%ls\" does not exist\n", wname );
00138                 return EFI_NOT_FOUND;
00139         }
00140 
00141         /* Fail unless opening read-only */
00142         if ( mode != EFI_FILE_MODE_READ ) {
00143                 DBGC ( file, "EFIFILE %s cannot be opened in mode %#08llx\n",
00144                        image->name, mode );
00145                 return EFI_WRITE_PROTECTED;
00146         }
00147 
00148         /* Allocate and initialise file */
00149         new_file = zalloc ( sizeof ( *new_file ) );
00150         memcpy ( &new_file->file, &efi_file_root.file,
00151                  sizeof ( new_file->file ) );
00152         new_file->image = image_get ( image );
00153         *new = &new_file->file;
00154         DBGC ( new_file, "EFIFILE %s opened\n", efi_file_name ( new_file ) );
00155 
00156         return 0;
00157 }
00158 
00159 /**
00160  * Close file
00161  *
00162  * @v this              EFI file
00163  * @ret efirc           EFI status code
00164  */
00165 static EFI_STATUS EFIAPI efi_file_close ( EFI_FILE_PROTOCOL *this ) {
00166         struct efi_file *file = container_of ( this, struct efi_file, file );
00167 
00168         /* Do nothing if this is the root */
00169         if ( ! file->image )
00170                 return 0;
00171 
00172         /* Close file */
00173         DBGC ( file, "EFIFILE %s closed\n", efi_file_name ( file ) );
00174         image_put ( file->image );
00175         free ( file );
00176 
00177         return 0;
00178 }
00179 
00180 /**
00181  * Close and delete file
00182  *
00183  * @v this              EFI file
00184  * @ret efirc           EFI status code
00185  */
00186 static EFI_STATUS EFIAPI efi_file_delete ( EFI_FILE_PROTOCOL *this ) {
00187         struct efi_file *file = container_of ( this, struct efi_file, file );
00188 
00189         DBGC ( file, "EFIFILE %s cannot be deleted\n", efi_file_name ( file ) );
00190 
00191         /* Close file */
00192         efi_file_close ( this );
00193 
00194         /* Warn of failure to delete */
00195         return EFI_WARN_DELETE_FAILURE;
00196 }
00197 
00198 /**
00199  * Return variable-length data structure
00200  *
00201  * @v base              Base data structure (starting with UINT64)
00202  * @v base_len          Length of base data structure
00203  * @v name              Name to append to base data structure
00204  * @v len               Length of data buffer
00205  * @v data              Data buffer
00206  * @ret efirc           EFI status code
00207  */
00208 static EFI_STATUS efi_file_varlen ( UINT64 *base, size_t base_len,
00209                                     const char *name, UINTN *len, VOID *data ) {
00210         size_t name_len;
00211 
00212         /* Calculate structure length */
00213         name_len = strlen ( name );
00214         *base = ( base_len + ( name_len + 1 /* NUL */ ) * sizeof ( wchar_t ) );
00215         if ( *len < *base ) {
00216                 *len = *base;
00217                 return EFI_BUFFER_TOO_SMALL;
00218         }
00219 
00220         /* Copy data to buffer */
00221         *len = *base;
00222         memcpy ( data, base, base_len );
00223         efi_snprintf ( ( data + base_len ), ( name_len + 1 /* NUL */ ),
00224                        "%s", name );
00225 
00226         return 0;
00227 }
00228 
00229 /**
00230  * Return file information structure
00231  *
00232  * @v image             Image, or NULL for the root directory
00233  * @v len               Length of data buffer
00234  * @v data              Data buffer
00235  * @ret efirc           EFI status code
00236  */
00237 static EFI_STATUS efi_file_info ( struct image *image, UINTN *len,
00238                                   VOID *data ) {
00239         EFI_FILE_INFO info;
00240         const char *name;
00241 
00242         /* Populate file information */
00243         memset ( &info, 0, sizeof ( info ) );
00244         if ( image ) {
00245                 info.FileSize = image->len;
00246                 info.PhysicalSize = image->len;
00247                 info.Attribute = EFI_FILE_READ_ONLY;
00248                 name = image->name;
00249         } else {
00250                 info.Attribute = ( EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY );
00251                 name = "";
00252         }
00253 
00254         return efi_file_varlen ( &info.Size, SIZE_OF_EFI_FILE_INFO, name,
00255                                  len, data );
00256 }
00257 
00258 /**
00259  * Read directory entry
00260  *
00261  * @v file              EFI file
00262  * @v len               Length to read
00263  * @v data              Data buffer
00264  * @ret efirc           EFI status code
00265  */
00266 static EFI_STATUS efi_file_read_dir ( struct efi_file *file, UINTN *len,
00267                                       VOID *data ) {
00268         EFI_STATUS efirc;
00269         struct image *image;
00270         unsigned int index;
00271 
00272         /* Construct directory entry at current position */
00273         index = file->pos;
00274         for_each_image ( image ) {
00275                 if ( index-- == 0 ) {
00276                         efirc = efi_file_info ( image, len, data );
00277                         if ( efirc == 0 )
00278                                 file->pos++;
00279                         return efirc;
00280                 }
00281         }
00282 
00283         /* No more entries */
00284         *len = 0;
00285         return 0;
00286 }
00287 
00288 /**
00289  * Read from file
00290  *
00291  * @v this              EFI file
00292  * @v len               Length to read
00293  * @v data              Data buffer
00294  * @ret efirc           EFI status code
00295  */
00296 static EFI_STATUS EFIAPI efi_file_read ( EFI_FILE_PROTOCOL *this,
00297                                          UINTN *len, VOID *data ) {
00298         struct efi_file *file = container_of ( this, struct efi_file, file );
00299         size_t remaining;
00300 
00301         /* If this is the root directory, then construct a directory entry */
00302         if ( ! file->image )
00303                 return efi_file_read_dir ( file, len, data );
00304 
00305         /* Read from the file */
00306         remaining = ( file->image->len - file->pos );
00307         if ( *len > remaining )
00308                 *len = remaining;
00309         DBGC ( file, "EFIFILE %s read [%#08zx,%#08zx)\n",
00310                efi_file_name ( file ), file->pos,
00311                ( ( size_t ) ( file->pos + *len ) ) );
00312         copy_from_user ( data, file->image->data, file->pos, *len );
00313         file->pos += *len;
00314         return 0;
00315 }
00316 
00317 /**
00318  * Write to file
00319  *
00320  * @v this              EFI file
00321  * @v len               Length to write
00322  * @v data              Data buffer
00323  * @ret efirc           EFI status code
00324  */
00325 static EFI_STATUS EFIAPI efi_file_write ( EFI_FILE_PROTOCOL *this,
00326                                           UINTN *len, VOID *data __unused ) {
00327         struct efi_file *file = container_of ( this, struct efi_file, file );
00328 
00329         DBGC ( file, "EFIFILE %s cannot write [%#08zx, %#08zx)\n",
00330                efi_file_name ( file ), file->pos,
00331                ( ( size_t ) ( file->pos + *len ) ) );
00332         return EFI_WRITE_PROTECTED;
00333 }
00334 
00335 /**
00336  * Set file position
00337  *
00338  * @v this              EFI file
00339  * @v position          New file position
00340  * @ret efirc           EFI status code
00341  */
00342 static EFI_STATUS EFIAPI efi_file_set_position ( EFI_FILE_PROTOCOL *this,
00343                                                  UINT64 position ) {
00344         struct efi_file *file = container_of ( this, struct efi_file, file );
00345 
00346         /* If this is the root directory, reset to the start */
00347         if ( ! file->image ) {
00348                 DBGC ( file, "EFIFILE root directory rewound\n" );
00349                 file->pos = 0;
00350                 return 0;
00351         }
00352 
00353         /* Check for the magic end-of-file value */
00354         if ( position == 0xffffffffffffffffULL )
00355                 position = file->image->len;
00356 
00357         /* Fail if we attempt to seek past the end of the file (since
00358          * we do not support writes).
00359          */
00360         if ( position > file->image->len ) {
00361                 DBGC ( file, "EFIFILE %s cannot seek to %#08llx of %#08zx\n",
00362                        efi_file_name ( file ), position, file->image->len );
00363                 return EFI_UNSUPPORTED;
00364         }
00365 
00366         /* Set position */
00367         file->pos = position;
00368         DBGC ( file, "EFIFILE %s position set to %#08zx\n",
00369                efi_file_name ( file ), file->pos );
00370 
00371         return 0;
00372 }
00373 
00374 /**
00375  * Get file position
00376  *
00377  * @v this              EFI file
00378  * @ret position        New file position
00379  * @ret efirc           EFI status code
00380  */
00381 static EFI_STATUS EFIAPI efi_file_get_position ( EFI_FILE_PROTOCOL *this,
00382                                                  UINT64 *position ) {
00383         struct efi_file *file = container_of ( this, struct efi_file, file );
00384 
00385         *position = file->pos;
00386         return 0;
00387 }
00388 
00389 /**
00390  * Get file information
00391  *
00392  * @v this              EFI file
00393  * @v type              Type of information
00394  * @v len               Buffer size
00395  * @v data              Buffer
00396  * @ret efirc           EFI status code
00397  */
00398 static EFI_STATUS EFIAPI efi_file_get_info ( EFI_FILE_PROTOCOL *this,
00399                                              EFI_GUID *type,
00400                                              UINTN *len, VOID *data ) {
00401         struct efi_file *file = container_of ( this, struct efi_file, file );
00402         EFI_FILE_SYSTEM_INFO fsinfo;
00403         struct image *image;
00404 
00405         /* Determine information to return */
00406         if ( memcmp ( type, &efi_file_info_id, sizeof ( *type ) ) == 0 ) {
00407 
00408                 /* Get file information */
00409                 DBGC ( file, "EFIFILE %s get file information\n",
00410                        efi_file_name ( file ) );
00411                 return efi_file_info ( file->image, len, data );
00412 
00413         } else if ( memcmp ( type, &efi_file_system_info_id,
00414                              sizeof ( *type ) ) == 0 ) {
00415 
00416                 /* Get file system information */
00417                 DBGC ( file, "EFIFILE %s get file system information\n",
00418                        efi_file_name ( file ) );
00419                 memset ( &fsinfo, 0, sizeof ( fsinfo ) );
00420                 fsinfo.ReadOnly = 1;
00421                 for_each_image ( image )
00422                         fsinfo.VolumeSize += image->len;
00423                 return efi_file_varlen ( &fsinfo.Size,
00424                                          SIZE_OF_EFI_FILE_SYSTEM_INFO, "iPXE",
00425                                          len, data );
00426         } else {
00427 
00428                 DBGC ( file, "EFIFILE %s cannot get information of type %s\n",
00429                        efi_file_name ( file ), efi_guid_ntoa ( type ) );
00430                 return EFI_UNSUPPORTED;
00431         }
00432 }
00433 
00434 /**
00435  * Set file information
00436  *
00437  * @v this              EFI file
00438  * @v type              Type of information
00439  * @v len               Buffer size
00440  * @v data              Buffer
00441  * @ret efirc           EFI status code
00442  */
00443 static EFI_STATUS EFIAPI
00444 efi_file_set_info ( EFI_FILE_PROTOCOL *this, EFI_GUID *type,
00445                     UINTN len __unused, VOID *data __unused ) {
00446         struct efi_file *file = container_of ( this, struct efi_file, file );
00447 
00448         DBGC ( file, "EFIFILE %s cannot set information of type %s\n",
00449                efi_file_name ( file ), efi_guid_ntoa ( type ) );
00450         return EFI_WRITE_PROTECTED;
00451 }
00452 
00453 /**
00454  * Flush file modified data
00455  *
00456  * @v this              EFI file
00457  * @v type              Type of information
00458  * @v len               Buffer size
00459  * @v data              Buffer
00460  * @ret efirc           EFI status code
00461  */
00462 static EFI_STATUS EFIAPI efi_file_flush ( EFI_FILE_PROTOCOL *this ) {
00463         struct efi_file *file = container_of ( this, struct efi_file, file );
00464 
00465         DBGC ( file, "EFIFILE %s flushed\n", efi_file_name ( file ) );
00466         return 0;
00467 }
00468 
00469 /** Root directory */
00470 static struct efi_file efi_file_root = {
00471         .file = {
00472                 .Revision = EFI_FILE_PROTOCOL_REVISION,
00473                 .Open = efi_file_open,
00474                 .Close = efi_file_close,
00475                 .Delete = efi_file_delete,
00476                 .Read = efi_file_read,
00477                 .Write = efi_file_write,
00478                 .GetPosition = efi_file_get_position,
00479                 .SetPosition = efi_file_set_position,
00480                 .GetInfo = efi_file_get_info,
00481                 .SetInfo = efi_file_set_info,
00482                 .Flush = efi_file_flush,
00483         },
00484         .image = NULL,
00485 };
00486 
00487 /**
00488  * Open root directory
00489  *
00490  * @v filesystem        EFI simple file system
00491  * @ret file            EFI file handle
00492  * @ret efirc           EFI status code
00493  */
00494 static EFI_STATUS EFIAPI
00495 efi_file_open_volume ( EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *filesystem __unused,
00496                        EFI_FILE_PROTOCOL **file ) {
00497 
00498         DBGC ( &efi_file_root, "EFIFILE open volume\n" );
00499         *file = &efi_file_root.file;
00500         return 0;
00501 }
00502 
00503 /** EFI simple file system protocol */
00504 static EFI_SIMPLE_FILE_SYSTEM_PROTOCOL efi_simple_file_system_protocol = {
00505         .Revision = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,
00506         .OpenVolume = efi_file_open_volume,
00507 };
00508 
00509 /** Dummy block I/O reset */
00510 static EFI_STATUS EFIAPI
00511 efi_block_io_reset ( EFI_BLOCK_IO_PROTOCOL *this __unused, BOOLEAN extended ) {
00512 
00513         DBGC ( &efi_file_root, "EFIFILE block %sreset\n",
00514                ( extended ? "extended " : "" ) );
00515         return 0;
00516 }
00517 
00518 /** Dummy block I/O read */
00519 static EFI_STATUS EFIAPI
00520 efi_block_io_read_blocks ( EFI_BLOCK_IO_PROTOCOL *this __unused, UINT32 MediaId,
00521                            EFI_LBA lba, UINTN len, VOID *data ) {
00522 
00523         DBGC ( &efi_file_root, "EFIFILE block read ID %#08x LBA %#08llx -> "
00524                "%p+%zx\n", MediaId, ( ( unsigned long long ) lba ),
00525                data, ( ( size_t ) len ) );
00526         return EFI_NO_MEDIA;
00527 }
00528 
00529 /** Dummy block I/O write */
00530 static EFI_STATUS EFIAPI
00531 efi_block_io_write_blocks ( EFI_BLOCK_IO_PROTOCOL *this __unused,
00532                             UINT32 MediaId, EFI_LBA lba, UINTN len,
00533                             VOID *data ) {
00534 
00535         DBGC ( &efi_file_root, "EFIFILE block write ID %#08x LBA %#08llx <- "
00536                "%p+%zx\n", MediaId, ( ( unsigned long long ) lba ),
00537                data, ( ( size_t ) len ) );
00538         return EFI_NO_MEDIA;
00539 }
00540 
00541 /** Dummy block I/O flush */
00542 static EFI_STATUS EFIAPI
00543 efi_block_io_flush_blocks ( EFI_BLOCK_IO_PROTOCOL *this __unused ) {
00544 
00545         DBGC ( &efi_file_root, "EFIFILE block flush\n" );
00546         return 0;
00547 }
00548 
00549 /** Dummy block I/O media */
00550 static EFI_BLOCK_IO_MEDIA efi_block_io_media = {
00551         .MediaId = EFI_MEDIA_ID_MAGIC,
00552         .MediaPresent = TRUE,
00553         .ReadOnly = TRUE,
00554         .BlockSize = 1,
00555 };
00556 
00557 /** Dummy EFI block I/O protocol */
00558 static EFI_BLOCK_IO_PROTOCOL efi_block_io_protocol = {
00559         .Revision = EFI_BLOCK_IO_PROTOCOL_REVISION,
00560         .Media = &efi_block_io_media,
00561         .Reset = efi_block_io_reset,
00562         .ReadBlocks = efi_block_io_read_blocks,
00563         .WriteBlocks = efi_block_io_write_blocks,
00564         .FlushBlocks = efi_block_io_flush_blocks,
00565 };
00566 
00567 /** Dummy disk I/O read */
00568 static EFI_STATUS EFIAPI
00569 efi_disk_io_read_disk ( EFI_DISK_IO_PROTOCOL *this __unused, UINT32 MediaId,
00570                         UINT64 offset, UINTN len, VOID *data ) {
00571 
00572         DBGC ( &efi_file_root, "EFIFILE disk read ID %#08x offset %#08llx -> "
00573                "%p+%zx\n", MediaId, ( ( unsigned long long ) offset ),
00574                data, ( ( size_t ) len ) );
00575         return EFI_NO_MEDIA;
00576 }
00577 
00578 /** Dummy disk I/O write */
00579 static EFI_STATUS EFIAPI
00580 efi_disk_io_write_disk ( EFI_DISK_IO_PROTOCOL *this __unused, UINT32 MediaId,
00581                          UINT64 offset, UINTN len, VOID *data ) {
00582 
00583         DBGC ( &efi_file_root, "EFIFILE disk write ID %#08x offset %#08llx <- "
00584                "%p+%zx\n", MediaId, ( ( unsigned long long ) offset ),
00585                data, ( ( size_t ) len ) );
00586         return EFI_NO_MEDIA;
00587 }
00588 
00589 /** Dummy EFI disk I/O protocol */
00590 static EFI_DISK_IO_PROTOCOL efi_disk_io_protocol = {
00591         .Revision = EFI_DISK_IO_PROTOCOL_REVISION,
00592         .ReadDisk = efi_disk_io_read_disk,
00593         .WriteDisk = efi_disk_io_write_disk,
00594 };
00595 
00596 /**
00597  * Install EFI simple file system protocol
00598  *
00599  * @v handle            EFI handle
00600  * @ret rc              Return status code
00601  */
00602 int efi_file_install ( EFI_HANDLE handle ) {
00603         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
00604         union {
00605                 EFI_DISK_IO_PROTOCOL *diskio;
00606                 void *interface;
00607         } diskio;
00608         EFI_STATUS efirc;
00609         int rc;
00610 
00611         /* Reset root directory state */
00612         efi_file_root.pos = 0;
00613 
00614         /* Install the simple file system protocol, block I/O
00615          * protocol, and disk I/O protocol.  We don't have a block
00616          * device, but large parts of the EDK2 codebase make the
00617          * assumption that file systems are normally attached to block
00618          * devices, and so we create a dummy block device on the same
00619          * handle just to keep things looking normal.
00620          */
00621         if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
00622                         &handle,
00623                         &efi_block_io_protocol_guid,
00624                         &efi_block_io_protocol,
00625                         &efi_disk_io_protocol_guid,
00626                         &efi_disk_io_protocol,
00627                         &efi_simple_file_system_protocol_guid,
00628                         &efi_simple_file_system_protocol, NULL ) ) != 0 ) {
00629                 rc = -EEFI ( efirc );
00630                 DBGC ( handle, "Could not install simple file system "
00631                        "protocols: %s\n", strerror ( rc ) );
00632                 goto err_install;
00633         }
00634 
00635         /* The FAT filesystem driver has a bug: if a block device
00636          * contains no FAT filesystem but does have an
00637          * EFI_SIMPLE_FILE_SYSTEM_PROTOCOL instance, the FAT driver
00638          * will assume that it must have previously installed the
00639          * EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.  This causes the FAT
00640          * driver to claim control of our device, and to refuse to
00641          * stop driving it, which prevents us from later uninstalling
00642          * correctly.
00643          *
00644          * Work around this bug by opening the disk I/O protocol
00645          * ourselves, thereby preventing the FAT driver from opening
00646          * it.
00647          *
00648          * Note that the alternative approach of opening the block I/O
00649          * protocol (and thereby in theory preventing DiskIo from
00650          * attaching to the block I/O protocol) causes an endless loop
00651          * of calls to our DRIVER_STOP method when starting the EFI
00652          * shell.  I have no idea why this is.
00653          */
00654         if ( ( efirc = bs->OpenProtocol ( handle, &efi_disk_io_protocol_guid,
00655                                           &diskio.interface, efi_image_handle,
00656                                           handle,
00657                                           EFI_OPEN_PROTOCOL_BY_DRIVER ) ) != 0){
00658                 rc = -EEFI ( efirc );
00659                 DBGC ( handle, "Could not open disk I/O protocol: %s\n",
00660                        strerror ( rc ) );
00661                 DBGC_EFI_OPENERS ( handle, handle, &efi_disk_io_protocol_guid );
00662                 goto err_open;
00663         }
00664         assert ( diskio.diskio == &efi_disk_io_protocol );
00665 
00666         return 0;
00667 
00668         bs->CloseProtocol ( handle, &efi_disk_io_protocol_guid,
00669                             efi_image_handle, handle );
00670  err_open:
00671         bs->UninstallMultipleProtocolInterfaces (
00672                         handle,
00673                         &efi_simple_file_system_protocol_guid,
00674                         &efi_simple_file_system_protocol,
00675                         &efi_disk_io_protocol_guid,
00676                         &efi_disk_io_protocol,
00677                         &efi_block_io_protocol_guid,
00678                         &efi_block_io_protocol, NULL );
00679  err_install:
00680         return rc;
00681 }
00682 
00683 /**
00684  * Uninstall EFI simple file system protocol
00685  *
00686  * @v handle            EFI handle
00687  */
00688 void efi_file_uninstall ( EFI_HANDLE handle ) {
00689         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
00690         EFI_STATUS efirc;
00691         int rc;
00692 
00693         /* Close our own disk I/O protocol */
00694         bs->CloseProtocol ( handle, &efi_disk_io_protocol_guid,
00695                             efi_image_handle, handle );
00696 
00697         /* We must install the file system protocol first, since
00698          * otherwise the EDK2 code will attempt to helpfully uninstall
00699          * it when the block I/O protocol is uninstalled, leading to a
00700          * system lock-up.
00701          */
00702         if ( ( efirc = bs->UninstallMultipleProtocolInterfaces (
00703                         handle,
00704                         &efi_simple_file_system_protocol_guid,
00705                         &efi_simple_file_system_protocol,
00706                         &efi_disk_io_protocol_guid,
00707                         &efi_disk_io_protocol,
00708                         &efi_block_io_protocol_guid,
00709                         &efi_block_io_protocol, NULL ) ) != 0 ) {
00710                 rc = -EEFI ( efirc );
00711                 DBGC ( handle, "Could not uninstall simple file system "
00712                        "protocols: %s\n", strerror ( rc ) );
00713                 /* Oh dear */
00714         }
00715 }