123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715 |
- /*
- * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- * You can also choose to distribute this program under the terms of
- * the Unmodified Binary Distribution Licence (as given in the file
- * COPYING.UBDL), provided that you have satisfied its requirements.
- */
-
- FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
-
- /**
- * @file
- *
- * EFI file protocols
- *
- */
-
- #include <stddef.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <strings.h>
- #include <errno.h>
- #include <wchar.h>
- #include <ipxe/image.h>
- #include <ipxe/efi/efi.h>
- #include <ipxe/efi/Protocol/SimpleFileSystem.h>
- #include <ipxe/efi/Protocol/BlockIo.h>
- #include <ipxe/efi/Protocol/DiskIo.h>
- #include <ipxe/efi/Guid/FileInfo.h>
- #include <ipxe/efi/Guid/FileSystemInfo.h>
- #include <ipxe/efi/efi_strings.h>
- #include <ipxe/efi/efi_file.h>
-
- /** EFI media ID */
- #define EFI_MEDIA_ID_MAGIC 0x69505845
-
- /** An image exposed as an EFI file */
- struct efi_file {
- /** EFI file protocol */
- EFI_FILE_PROTOCOL file;
- /** Image */
- struct image *image;
- /** Current file position */
- size_t pos;
- };
-
- static struct efi_file efi_file_root;
-
- /**
- * Get EFI file name (for debugging)
- *
- * @v file EFI file
- * @ret name Name
- */
- static const char * efi_file_name ( struct efi_file *file ) {
-
- return ( file->image ? file->image->name : "<root>" );
- }
-
- /**
- * Find EFI file image
- *
- * @v wname Filename
- * @ret image Image, or NULL
- */
- static struct image * efi_file_find ( const CHAR16 *wname ) {
- char name[ wcslen ( wname ) + 1 /* NUL */ ];
- struct image *image;
-
- /* Find image */
- snprintf ( name, sizeof ( name ), "%ls", wname );
- list_for_each_entry ( image, &images, list ) {
- if ( strcasecmp ( image->name, name ) == 0 )
- return image;
- }
-
- return NULL;
-
- }
-
- /**
- * Open file
- *
- * @v this EFI file
- * @ret new New EFI file
- * @v wname Filename
- * @v mode File mode
- * @v attributes File attributes (for newly-created files)
- * @ret efirc EFI status code
- */
- static EFI_STATUS EFIAPI
- efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new,
- CHAR16 *wname, UINT64 mode __unused,
- UINT64 attributes __unused ) {
- struct efi_file *file = container_of ( this, struct efi_file, file );
- struct efi_file *new_file;
- struct image *image;
-
- /* Initial '\' indicates opening from the root directory */
- while ( *wname == L'\\' ) {
- file = &efi_file_root;
- wname++;
- }
-
- /* Allow root directory itself to be opened */
- if ( ( wname[0] == L'\0' ) || ( wname[0] == L'.' ) ) {
- *new = &efi_file_root.file;
- return 0;
- }
-
- /* Fail unless opening from the root */
- if ( file->image ) {
- DBGC ( file, "EFIFILE %s is not a directory\n",
- efi_file_name ( file ) );
- return EFI_NOT_FOUND;
- }
-
- /* Identify image */
- image = efi_file_find ( wname );
- if ( ! image ) {
- DBGC ( file, "EFIFILE \"%ls\" does not exist\n", wname );
- return EFI_NOT_FOUND;
- }
-
- /* Fail unless opening read-only */
- if ( mode != EFI_FILE_MODE_READ ) {
- DBGC ( file, "EFIFILE %s cannot be opened in mode %#08llx\n",
- image->name, mode );
- return EFI_WRITE_PROTECTED;
- }
-
- /* Allocate and initialise file */
- new_file = zalloc ( sizeof ( *new_file ) );
- memcpy ( &new_file->file, &efi_file_root.file,
- sizeof ( new_file->file ) );
- new_file->image = image_get ( image );
- *new = &new_file->file;
- DBGC ( new_file, "EFIFILE %s opened\n", efi_file_name ( new_file ) );
-
- return 0;
- }
-
- /**
- * Close file
- *
- * @v this EFI file
- * @ret efirc EFI status code
- */
- static EFI_STATUS EFIAPI efi_file_close ( EFI_FILE_PROTOCOL *this ) {
- struct efi_file *file = container_of ( this, struct efi_file, file );
-
- /* Do nothing if this is the root */
- if ( ! file->image )
- return 0;
-
- /* Close file */
- DBGC ( file, "EFIFILE %s closed\n", efi_file_name ( file ) );
- image_put ( file->image );
- free ( file );
-
- return 0;
- }
-
- /**
- * Close and delete file
- *
- * @v this EFI file
- * @ret efirc EFI status code
- */
- static EFI_STATUS EFIAPI efi_file_delete ( EFI_FILE_PROTOCOL *this ) {
- struct efi_file *file = container_of ( this, struct efi_file, file );
-
- DBGC ( file, "EFIFILE %s cannot be deleted\n", efi_file_name ( file ) );
-
- /* Close file */
- efi_file_close ( this );
-
- /* Warn of failure to delete */
- return EFI_WARN_DELETE_FAILURE;
- }
-
- /**
- * Return variable-length data structure
- *
- * @v base Base data structure (starting with UINT64)
- * @v base_len Length of base data structure
- * @v name Name to append to base data structure
- * @v len Length of data buffer
- * @v data Data buffer
- * @ret efirc EFI status code
- */
- static EFI_STATUS efi_file_varlen ( UINT64 *base, size_t base_len,
- const char *name, UINTN *len, VOID *data ) {
- size_t name_len;
-
- /* Calculate structure length */
- name_len = strlen ( name );
- *base = ( base_len + ( name_len + 1 /* NUL */ ) * sizeof ( wchar_t ) );
- if ( *len < *base ) {
- *len = *base;
- return EFI_BUFFER_TOO_SMALL;
- }
-
- /* Copy data to buffer */
- *len = *base;
- memcpy ( data, base, base_len );
- efi_snprintf ( ( data + base_len ), ( name_len + 1 /* NUL */ ),
- "%s", name );
-
- return 0;
- }
-
- /**
- * Return file information structure
- *
- * @v image Image, or NULL for the root directory
- * @v len Length of data buffer
- * @v data Data buffer
- * @ret efirc EFI status code
- */
- static EFI_STATUS efi_file_info ( struct image *image, UINTN *len,
- VOID *data ) {
- EFI_FILE_INFO info;
- const char *name;
-
- /* Populate file information */
- memset ( &info, 0, sizeof ( info ) );
- if ( image ) {
- info.FileSize = image->len;
- info.PhysicalSize = image->len;
- info.Attribute = EFI_FILE_READ_ONLY;
- name = image->name;
- } else {
- info.Attribute = ( EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY );
- name = "";
- }
-
- return efi_file_varlen ( &info.Size, SIZE_OF_EFI_FILE_INFO, name,
- len, data );
- }
-
- /**
- * Read directory entry
- *
- * @v file EFI file
- * @v len Length to read
- * @v data Data buffer
- * @ret efirc EFI status code
- */
- static EFI_STATUS efi_file_read_dir ( struct efi_file *file, UINTN *len,
- VOID *data ) {
- EFI_STATUS efirc;
- struct image *image;
- unsigned int index;
-
- /* Construct directory entry at current position */
- index = file->pos;
- for_each_image ( image ) {
- if ( index-- == 0 ) {
- efirc = efi_file_info ( image, len, data );
- if ( efirc == 0 )
- file->pos++;
- return efirc;
- }
- }
-
- /* No more entries */
- *len = 0;
- return 0;
- }
-
- /**
- * Read from file
- *
- * @v this EFI file
- * @v len Length to read
- * @v data Data buffer
- * @ret efirc EFI status code
- */
- static EFI_STATUS EFIAPI efi_file_read ( EFI_FILE_PROTOCOL *this,
- UINTN *len, VOID *data ) {
- struct efi_file *file = container_of ( this, struct efi_file, file );
- size_t remaining;
-
- /* If this is the root directory, then construct a directory entry */
- if ( ! file->image )
- return efi_file_read_dir ( file, len, data );
-
- /* Read from the file */
- remaining = ( file->image->len - file->pos );
- if ( *len > remaining )
- *len = remaining;
- DBGC ( file, "EFIFILE %s read [%#08zx,%#08zx)\n",
- efi_file_name ( file ), file->pos,
- ( ( size_t ) ( file->pos + *len ) ) );
- copy_from_user ( data, file->image->data, file->pos, *len );
- file->pos += *len;
- return 0;
- }
-
- /**
- * Write to file
- *
- * @v this EFI file
- * @v len Length to write
- * @v data Data buffer
- * @ret efirc EFI status code
- */
- static EFI_STATUS EFIAPI efi_file_write ( EFI_FILE_PROTOCOL *this,
- UINTN *len, VOID *data __unused ) {
- struct efi_file *file = container_of ( this, struct efi_file, file );
-
- DBGC ( file, "EFIFILE %s cannot write [%#08zx, %#08zx)\n",
- efi_file_name ( file ), file->pos,
- ( ( size_t ) ( file->pos + *len ) ) );
- return EFI_WRITE_PROTECTED;
- }
-
- /**
- * Set file position
- *
- * @v this EFI file
- * @v position New file position
- * @ret efirc EFI status code
- */
- static EFI_STATUS EFIAPI efi_file_set_position ( EFI_FILE_PROTOCOL *this,
- UINT64 position ) {
- struct efi_file *file = container_of ( this, struct efi_file, file );
-
- /* If this is the root directory, reset to the start */
- if ( ! file->image ) {
- DBGC ( file, "EFIFILE root directory rewound\n" );
- file->pos = 0;
- return 0;
- }
-
- /* Check for the magic end-of-file value */
- if ( position == 0xffffffffffffffffULL )
- position = file->image->len;
-
- /* Fail if we attempt to seek past the end of the file (since
- * we do not support writes).
- */
- if ( position > file->image->len ) {
- DBGC ( file, "EFIFILE %s cannot seek to %#08llx of %#08zx\n",
- efi_file_name ( file ), position, file->image->len );
- return EFI_UNSUPPORTED;
- }
-
- /* Set position */
- file->pos = position;
- DBGC ( file, "EFIFILE %s position set to %#08zx\n",
- efi_file_name ( file ), file->pos );
-
- return 0;
- }
-
- /**
- * Get file position
- *
- * @v this EFI file
- * @ret position New file position
- * @ret efirc EFI status code
- */
- static EFI_STATUS EFIAPI efi_file_get_position ( EFI_FILE_PROTOCOL *this,
- UINT64 *position ) {
- struct efi_file *file = container_of ( this, struct efi_file, file );
-
- *position = file->pos;
- return 0;
- }
-
- /**
- * Get file information
- *
- * @v this EFI file
- * @v type Type of information
- * @v len Buffer size
- * @v data Buffer
- * @ret efirc EFI status code
- */
- static EFI_STATUS EFIAPI efi_file_get_info ( EFI_FILE_PROTOCOL *this,
- EFI_GUID *type,
- UINTN *len, VOID *data ) {
- struct efi_file *file = container_of ( this, struct efi_file, file );
- EFI_FILE_SYSTEM_INFO fsinfo;
- struct image *image;
-
- /* Determine information to return */
- if ( memcmp ( type, &efi_file_info_id, sizeof ( *type ) ) == 0 ) {
-
- /* Get file information */
- DBGC ( file, "EFIFILE %s get file information\n",
- efi_file_name ( file ) );
- return efi_file_info ( file->image, len, data );
-
- } else if ( memcmp ( type, &efi_file_system_info_id,
- sizeof ( *type ) ) == 0 ) {
-
- /* Get file system information */
- DBGC ( file, "EFIFILE %s get file system information\n",
- efi_file_name ( file ) );
- memset ( &fsinfo, 0, sizeof ( fsinfo ) );
- fsinfo.ReadOnly = 1;
- for_each_image ( image )
- fsinfo.VolumeSize += image->len;
- return efi_file_varlen ( &fsinfo.Size,
- SIZE_OF_EFI_FILE_SYSTEM_INFO, "iPXE",
- len, data );
- } else {
-
- DBGC ( file, "EFIFILE %s cannot get information of type %s\n",
- efi_file_name ( file ), efi_guid_ntoa ( type ) );
- return EFI_UNSUPPORTED;
- }
- }
-
- /**
- * Set file information
- *
- * @v this EFI file
- * @v type Type of information
- * @v len Buffer size
- * @v data Buffer
- * @ret efirc EFI status code
- */
- static EFI_STATUS EFIAPI
- efi_file_set_info ( EFI_FILE_PROTOCOL *this, EFI_GUID *type,
- UINTN len __unused, VOID *data __unused ) {
- struct efi_file *file = container_of ( this, struct efi_file, file );
-
- DBGC ( file, "EFIFILE %s cannot set information of type %s\n",
- efi_file_name ( file ), efi_guid_ntoa ( type ) );
- return EFI_WRITE_PROTECTED;
- }
-
- /**
- * Flush file modified data
- *
- * @v this EFI file
- * @v type Type of information
- * @v len Buffer size
- * @v data Buffer
- * @ret efirc EFI status code
- */
- static EFI_STATUS EFIAPI efi_file_flush ( EFI_FILE_PROTOCOL *this ) {
- struct efi_file *file = container_of ( this, struct efi_file, file );
-
- DBGC ( file, "EFIFILE %s flushed\n", efi_file_name ( file ) );
- return 0;
- }
-
- /** Root directory */
- static struct efi_file efi_file_root = {
- .file = {
- .Revision = EFI_FILE_PROTOCOL_REVISION,
- .Open = efi_file_open,
- .Close = efi_file_close,
- .Delete = efi_file_delete,
- .Read = efi_file_read,
- .Write = efi_file_write,
- .GetPosition = efi_file_get_position,
- .SetPosition = efi_file_set_position,
- .GetInfo = efi_file_get_info,
- .SetInfo = efi_file_set_info,
- .Flush = efi_file_flush,
- },
- .image = NULL,
- };
-
- /**
- * Open root directory
- *
- * @v filesystem EFI simple file system
- * @ret file EFI file handle
- * @ret efirc EFI status code
- */
- static EFI_STATUS EFIAPI
- efi_file_open_volume ( EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *filesystem __unused,
- EFI_FILE_PROTOCOL **file ) {
-
- DBGC ( &efi_file_root, "EFIFILE open volume\n" );
- *file = &efi_file_root.file;
- return 0;
- }
-
- /** EFI simple file system protocol */
- static EFI_SIMPLE_FILE_SYSTEM_PROTOCOL efi_simple_file_system_protocol = {
- .Revision = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,
- .OpenVolume = efi_file_open_volume,
- };
-
- /** Dummy block I/O reset */
- static EFI_STATUS EFIAPI
- efi_block_io_reset ( EFI_BLOCK_IO_PROTOCOL *this __unused, BOOLEAN extended ) {
-
- DBGC ( &efi_file_root, "EFIFILE block %sreset\n",
- ( extended ? "extended " : "" ) );
- return 0;
- }
-
- /** Dummy block I/O read */
- static EFI_STATUS EFIAPI
- efi_block_io_read_blocks ( EFI_BLOCK_IO_PROTOCOL *this __unused, UINT32 MediaId,
- EFI_LBA lba, UINTN len, VOID *data ) {
-
- DBGC ( &efi_file_root, "EFIFILE block read ID %#08x LBA %#08llx -> "
- "%p+%zx\n", MediaId, ( ( unsigned long long ) lba ),
- data, ( ( size_t ) len ) );
- return EFI_NO_MEDIA;
- }
-
- /** Dummy block I/O write */
- static EFI_STATUS EFIAPI
- efi_block_io_write_blocks ( EFI_BLOCK_IO_PROTOCOL *this __unused,
- UINT32 MediaId, EFI_LBA lba, UINTN len,
- VOID *data ) {
-
- DBGC ( &efi_file_root, "EFIFILE block write ID %#08x LBA %#08llx <- "
- "%p+%zx\n", MediaId, ( ( unsigned long long ) lba ),
- data, ( ( size_t ) len ) );
- return EFI_NO_MEDIA;
- }
-
- /** Dummy block I/O flush */
- static EFI_STATUS EFIAPI
- efi_block_io_flush_blocks ( EFI_BLOCK_IO_PROTOCOL *this __unused ) {
-
- DBGC ( &efi_file_root, "EFIFILE block flush\n" );
- return 0;
- }
-
- /** Dummy block I/O media */
- static EFI_BLOCK_IO_MEDIA efi_block_io_media = {
- .MediaId = EFI_MEDIA_ID_MAGIC,
- .MediaPresent = TRUE,
- .ReadOnly = TRUE,
- .BlockSize = 1,
- };
-
- /** Dummy EFI block I/O protocol */
- static EFI_BLOCK_IO_PROTOCOL efi_block_io_protocol = {
- .Revision = EFI_BLOCK_IO_PROTOCOL_REVISION,
- .Media = &efi_block_io_media,
- .Reset = efi_block_io_reset,
- .ReadBlocks = efi_block_io_read_blocks,
- .WriteBlocks = efi_block_io_write_blocks,
- .FlushBlocks = efi_block_io_flush_blocks,
- };
-
- /** Dummy disk I/O read */
- static EFI_STATUS EFIAPI
- efi_disk_io_read_disk ( EFI_DISK_IO_PROTOCOL *this __unused, UINT32 MediaId,
- UINT64 offset, UINTN len, VOID *data ) {
-
- DBGC ( &efi_file_root, "EFIFILE disk read ID %#08x offset %#08llx -> "
- "%p+%zx\n", MediaId, ( ( unsigned long long ) offset ),
- data, ( ( size_t ) len ) );
- return EFI_NO_MEDIA;
- }
-
- /** Dummy disk I/O write */
- static EFI_STATUS EFIAPI
- efi_disk_io_write_disk ( EFI_DISK_IO_PROTOCOL *this __unused, UINT32 MediaId,
- UINT64 offset, UINTN len, VOID *data ) {
-
- DBGC ( &efi_file_root, "EFIFILE disk write ID %#08x offset %#08llx <- "
- "%p+%zx\n", MediaId, ( ( unsigned long long ) offset ),
- data, ( ( size_t ) len ) );
- return EFI_NO_MEDIA;
- }
-
- /** Dummy EFI disk I/O protocol */
- static EFI_DISK_IO_PROTOCOL efi_disk_io_protocol = {
- .Revision = EFI_DISK_IO_PROTOCOL_REVISION,
- .ReadDisk = efi_disk_io_read_disk,
- .WriteDisk = efi_disk_io_write_disk,
- };
-
- /**
- * Install EFI simple file system protocol
- *
- * @v handle EFI handle
- * @ret rc Return status code
- */
- int efi_file_install ( EFI_HANDLE handle ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- union {
- EFI_DISK_IO_PROTOCOL *diskio;
- void *interface;
- } diskio;
- EFI_STATUS efirc;
- int rc;
-
- /* Reset root directory state */
- efi_file_root.pos = 0;
-
- /* Install the simple file system protocol, block I/O
- * protocol, and disk I/O protocol. We don't have a block
- * device, but large parts of the EDK2 codebase make the
- * assumption that file systems are normally attached to block
- * devices, and so we create a dummy block device on the same
- * handle just to keep things looking normal.
- */
- if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
- &handle,
- &efi_block_io_protocol_guid,
- &efi_block_io_protocol,
- &efi_disk_io_protocol_guid,
- &efi_disk_io_protocol,
- &efi_simple_file_system_protocol_guid,
- &efi_simple_file_system_protocol, NULL ) ) != 0 ) {
- rc = -EEFI ( efirc );
- DBGC ( handle, "Could not install simple file system "
- "protocols: %s\n", strerror ( rc ) );
- goto err_install;
- }
-
- /* The FAT filesystem driver has a bug: if a block device
- * contains no FAT filesystem but does have an
- * EFI_SIMPLE_FILE_SYSTEM_PROTOCOL instance, the FAT driver
- * will assume that it must have previously installed the
- * EFI_SIMPLE_FILE_SYSTEM_PROTOCOL. This causes the FAT
- * driver to claim control of our device, and to refuse to
- * stop driving it, which prevents us from later uninstalling
- * correctly.
- *
- * Work around this bug by opening the disk I/O protocol
- * ourselves, thereby preventing the FAT driver from opening
- * it.
- *
- * Note that the alternative approach of opening the block I/O
- * protocol (and thereby in theory preventing DiskIo from
- * attaching to the block I/O protocol) causes an endless loop
- * of calls to our DRIVER_STOP method when starting the EFI
- * shell. I have no idea why this is.
- */
- if ( ( efirc = bs->OpenProtocol ( handle, &efi_disk_io_protocol_guid,
- &diskio.interface, efi_image_handle,
- handle,
- EFI_OPEN_PROTOCOL_BY_DRIVER ) ) != 0){
- rc = -EEFI ( efirc );
- DBGC ( handle, "Could not open disk I/O protocol: %s\n",
- strerror ( rc ) );
- DBGC_EFI_OPENERS ( handle, handle, &efi_disk_io_protocol_guid );
- goto err_open;
- }
- assert ( diskio.diskio == &efi_disk_io_protocol );
-
- return 0;
-
- bs->CloseProtocol ( handle, &efi_disk_io_protocol_guid,
- efi_image_handle, handle );
- err_open:
- bs->UninstallMultipleProtocolInterfaces (
- handle,
- &efi_simple_file_system_protocol_guid,
- &efi_simple_file_system_protocol,
- &efi_disk_io_protocol_guid,
- &efi_disk_io_protocol,
- &efi_block_io_protocol_guid,
- &efi_block_io_protocol, NULL );
- err_install:
- return rc;
- }
-
- /**
- * Uninstall EFI simple file system protocol
- *
- * @v handle EFI handle
- */
- void efi_file_uninstall ( EFI_HANDLE handle ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- EFI_STATUS efirc;
- int rc;
-
- /* Close our own disk I/O protocol */
- bs->CloseProtocol ( handle, &efi_disk_io_protocol_guid,
- efi_image_handle, handle );
-
- /* We must install the file system protocol first, since
- * otherwise the EDK2 code will attempt to helpfully uninstall
- * it when the block I/O protocol is uninstalled, leading to a
- * system lock-up.
- */
- if ( ( efirc = bs->UninstallMultipleProtocolInterfaces (
- handle,
- &efi_simple_file_system_protocol_guid,
- &efi_simple_file_system_protocol,
- &efi_disk_io_protocol_guid,
- &efi_disk_io_protocol,
- &efi_block_io_protocol_guid,
- &efi_block_io_protocol, NULL ) ) != 0 ) {
- rc = -EEFI ( efirc );
- DBGC ( handle, "Could not uninstall simple file system "
- "protocols: %s\n", strerror ( rc ) );
- /* Oh dear */
- }
- }
|