mirror of
https://github.com/ipxe/ipxe
synced 2026-02-28 03:11:18 +03:00
[efi] Allow for non-image-backed virtual files
Restructure the EFI_SIMPLE_FILE_SYSTEM_PROTOCOL implementation to allow for the existence of virtual files that are not simply backed by a single underlying image. Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
@@ -50,18 +50,54 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||||||
/** EFI media ID */
|
/** EFI media ID */
|
||||||
#define EFI_MEDIA_ID_MAGIC 0x69505845
|
#define EFI_MEDIA_ID_MAGIC 0x69505845
|
||||||
|
|
||||||
/** An image exposed as an EFI file */
|
/** An EFI virtual file reader */
|
||||||
|
struct efi_file_reader {
|
||||||
|
/** EFI file */
|
||||||
|
struct efi_file *file;
|
||||||
|
/** Position within virtual file */
|
||||||
|
size_t pos;
|
||||||
|
/** Output data buffer */
|
||||||
|
void *data;
|
||||||
|
/** Length of output data buffer */
|
||||||
|
size_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** An EFI file */
|
||||||
struct efi_file {
|
struct efi_file {
|
||||||
|
/** Reference count */
|
||||||
|
struct refcnt refcnt;
|
||||||
/** EFI file protocol */
|
/** EFI file protocol */
|
||||||
EFI_FILE_PROTOCOL file;
|
EFI_FILE_PROTOCOL file;
|
||||||
/** Image */
|
/** Image (if any) */
|
||||||
struct image *image;
|
struct image *image;
|
||||||
|
/** Filename */
|
||||||
|
const char *name;
|
||||||
/** Current file position */
|
/** Current file position */
|
||||||
size_t pos;
|
size_t pos;
|
||||||
|
/**
|
||||||
|
* Read from file
|
||||||
|
*
|
||||||
|
* @v reader File reader
|
||||||
|
* @ret len Length read
|
||||||
|
*/
|
||||||
|
size_t ( * read ) ( struct efi_file_reader *reader );
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct efi_file efi_file_root;
|
static struct efi_file efi_file_root;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free EFI file
|
||||||
|
*
|
||||||
|
* @v refcnt Reference count
|
||||||
|
*/
|
||||||
|
static void efi_file_free ( struct refcnt *refcnt ) {
|
||||||
|
struct efi_file *file =
|
||||||
|
container_of ( refcnt, struct efi_file, refcnt );
|
||||||
|
|
||||||
|
image_put ( file->image );
|
||||||
|
free ( file );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get EFI file name (for debugging)
|
* Get EFI file name (for debugging)
|
||||||
*
|
*
|
||||||
@@ -70,28 +106,140 @@ static struct efi_file efi_file_root;
|
|||||||
*/
|
*/
|
||||||
static const char * efi_file_name ( struct efi_file *file ) {
|
static const char * efi_file_name ( struct efi_file *file ) {
|
||||||
|
|
||||||
return ( file->image ? file->image->name : "<root>" );
|
return ( file == &efi_file_root ? "<root>" : file->name );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find EFI file image
|
* Find EFI file image
|
||||||
*
|
*
|
||||||
* @v wname Filename
|
* @v name Filename
|
||||||
* @ret image Image, or NULL
|
* @ret image Image, or NULL
|
||||||
*/
|
*/
|
||||||
static struct image * efi_file_find ( const CHAR16 *wname ) {
|
static struct image * efi_file_find ( const char *name ) {
|
||||||
char name[ wcslen ( wname ) + 1 /* NUL */ ];
|
|
||||||
struct image *image;
|
struct image *image;
|
||||||
|
|
||||||
/* Find image */
|
/* Find image */
|
||||||
snprintf ( name, sizeof ( name ), "%ls", wname );
|
|
||||||
list_for_each_entry ( image, &images, list ) {
|
list_for_each_entry ( image, &images, list ) {
|
||||||
if ( strcasecmp ( image->name, name ) == 0 )
|
if ( strcasecmp ( image->name, name ) == 0 )
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get length of EFI file
|
||||||
|
*
|
||||||
|
* @v file EFI file
|
||||||
|
* @ret len Length of file
|
||||||
|
*/
|
||||||
|
static size_t efi_file_len ( struct efi_file *file ) {
|
||||||
|
struct efi_file_reader reader;
|
||||||
|
|
||||||
|
/* If this is the root directory, then treat as length zero */
|
||||||
|
if ( ! file->read )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Initialise reader */
|
||||||
|
reader.file = file;
|
||||||
|
reader.pos = 0;
|
||||||
|
reader.data = NULL;
|
||||||
|
reader.len = 0;
|
||||||
|
|
||||||
|
/* Perform dummy read to determine file length */
|
||||||
|
file->read ( &reader );
|
||||||
|
|
||||||
|
return reader.pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read chunk of EFI file
|
||||||
|
*
|
||||||
|
* @v reader EFI file reader
|
||||||
|
* @v data Input data, or UNULL to zero-fill
|
||||||
|
* @v len Length of input data
|
||||||
|
* @ret len Length of output data
|
||||||
|
*/
|
||||||
|
static size_t efi_file_read_chunk ( struct efi_file_reader *reader,
|
||||||
|
userptr_t data, size_t len ) {
|
||||||
|
struct efi_file *file = reader->file;
|
||||||
|
size_t offset;
|
||||||
|
|
||||||
|
/* Calculate offset into input data */
|
||||||
|
offset = ( file->pos - reader->pos );
|
||||||
|
|
||||||
|
/* Consume input data range */
|
||||||
|
reader->pos += len;
|
||||||
|
|
||||||
|
/* Calculate output length */
|
||||||
|
if ( offset < len ) {
|
||||||
|
len -= offset;
|
||||||
|
} else {
|
||||||
|
len = 0;
|
||||||
|
}
|
||||||
|
if ( len > reader->len )
|
||||||
|
len = reader->len;
|
||||||
|
|
||||||
|
/* Copy or zero output data */
|
||||||
|
if ( data ) {
|
||||||
|
copy_from_user ( reader->data, data, offset, len );
|
||||||
|
} else {
|
||||||
|
memset ( reader->data, 0, len );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Consume output buffer */
|
||||||
|
file->pos += len;
|
||||||
|
reader->data += len;
|
||||||
|
reader->len -= len;
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read from image-backed file
|
||||||
|
*
|
||||||
|
* @v reader EFI file reader
|
||||||
|
* @ret len Length read
|
||||||
|
*/
|
||||||
|
static size_t efi_file_read_image ( struct efi_file_reader *reader ) {
|
||||||
|
struct efi_file *file = reader->file;
|
||||||
|
struct image *image = file->image;
|
||||||
|
|
||||||
|
/* Read from file */
|
||||||
|
return efi_file_read_chunk ( reader, image->data, image->len );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open fixed file
|
||||||
|
*
|
||||||
|
* @v file EFI file
|
||||||
|
* @v new New EFI file
|
||||||
|
* @ret efirc EFI status code
|
||||||
|
*/
|
||||||
|
static EFI_STATUS efi_file_open_fixed ( struct efi_file *file,
|
||||||
|
EFI_FILE_PROTOCOL **new ) {
|
||||||
|
|
||||||
|
/* Increment reference count */
|
||||||
|
ref_get ( &file->refcnt );
|
||||||
|
|
||||||
|
/* Return opened file */
|
||||||
|
*new = &file->file;
|
||||||
|
|
||||||
|
DBGC ( file, "EFIFILE %s opened\n", efi_file_name ( file ) );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Associate file with image
|
||||||
|
*
|
||||||
|
* @v file EFI file
|
||||||
|
* @v image Image
|
||||||
|
*/
|
||||||
|
static void efi_file_image ( struct efi_file *file, struct image *image ) {
|
||||||
|
|
||||||
|
file->image = image;
|
||||||
|
file->name = image->name;
|
||||||
|
file->read = efi_file_read_image;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -106,50 +254,56 @@ static struct image * efi_file_find ( const CHAR16 *wname ) {
|
|||||||
*/
|
*/
|
||||||
static EFI_STATUS EFIAPI
|
static EFI_STATUS EFIAPI
|
||||||
efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new,
|
efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new,
|
||||||
CHAR16 *wname, UINT64 mode __unused,
|
CHAR16 *wname, UINT64 mode, UINT64 attributes __unused ) {
|
||||||
UINT64 attributes __unused ) {
|
|
||||||
struct efi_file *file = container_of ( this, struct efi_file, file );
|
struct efi_file *file = container_of ( this, struct efi_file, file );
|
||||||
|
char buf[ wcslen ( wname ) + 1 /* NUL */ ];
|
||||||
struct efi_file *new_file;
|
struct efi_file *new_file;
|
||||||
struct image *image;
|
struct image *image;
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
/* Convert name to ASCII */
|
||||||
|
snprintf ( buf, sizeof ( buf ), "%ls", wname );
|
||||||
|
name = buf;
|
||||||
|
|
||||||
/* Initial '\' indicates opening from the root directory */
|
/* Initial '\' indicates opening from the root directory */
|
||||||
while ( *wname == L'\\' ) {
|
while ( *name == '\\' ) {
|
||||||
file = &efi_file_root;
|
file = &efi_file_root;
|
||||||
wname++;
|
name++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allow root directory itself to be opened */
|
/* Allow root directory itself to be opened */
|
||||||
if ( ( wname[0] == L'\0' ) || ( wname[0] == L'.' ) ) {
|
if ( ( name[0] == '\0' ) || ( name[0] == '.' ) )
|
||||||
*new = &efi_file_root.file;
|
return efi_file_open_fixed ( &efi_file_root, new );
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fail unless opening from the root */
|
/* Fail unless opening from the root */
|
||||||
if ( file->image ) {
|
if ( file != &efi_file_root ) {
|
||||||
DBGC ( file, "EFIFILE %s is not a directory\n",
|
DBGC ( file, "EFIFILE %s is not a directory\n",
|
||||||
efi_file_name ( file ) );
|
efi_file_name ( file ) );
|
||||||
return EFI_NOT_FOUND;
|
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 */
|
/* Fail unless opening read-only */
|
||||||
if ( mode != EFI_FILE_MODE_READ ) {
|
if ( mode != EFI_FILE_MODE_READ ) {
|
||||||
DBGC ( file, "EFIFILE %s cannot be opened in mode %#08llx\n",
|
DBGC ( file, "EFIFILE %s cannot be opened in mode %#08llx\n",
|
||||||
image->name, mode );
|
name, mode );
|
||||||
return EFI_WRITE_PROTECTED;
|
return EFI_WRITE_PROTECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Identify image */
|
||||||
|
image = efi_file_find ( name );
|
||||||
|
if ( ! image ) {
|
||||||
|
DBGC ( file, "EFIFILE %s does not exist\n", name );
|
||||||
|
return EFI_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
/* Allocate and initialise file */
|
/* Allocate and initialise file */
|
||||||
new_file = zalloc ( sizeof ( *new_file ) );
|
new_file = zalloc ( sizeof ( *new_file ) );
|
||||||
|
if ( ! new_file )
|
||||||
|
return EFI_OUT_OF_RESOURCES;
|
||||||
|
ref_init ( &file->refcnt, efi_file_free );
|
||||||
memcpy ( &new_file->file, &efi_file_root.file,
|
memcpy ( &new_file->file, &efi_file_root.file,
|
||||||
sizeof ( new_file->file ) );
|
sizeof ( new_file->file ) );
|
||||||
new_file->image = image_get ( image );
|
efi_file_image ( new_file, image_get ( image ) );
|
||||||
*new = &new_file->file;
|
*new = &new_file->file;
|
||||||
DBGC ( new_file, "EFIFILE %s opened\n", efi_file_name ( new_file ) );
|
DBGC ( new_file, "EFIFILE %s opened\n", efi_file_name ( new_file ) );
|
||||||
|
|
||||||
@@ -165,14 +319,9 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new,
|
|||||||
static EFI_STATUS EFIAPI efi_file_close ( EFI_FILE_PROTOCOL *this ) {
|
static EFI_STATUS EFIAPI efi_file_close ( EFI_FILE_PROTOCOL *this ) {
|
||||||
struct efi_file *file = container_of ( this, struct efi_file, file );
|
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 */
|
/* Close file */
|
||||||
DBGC ( file, "EFIFILE %s closed\n", efi_file_name ( file ) );
|
DBGC ( file, "EFIFILE %s closed\n", efi_file_name ( file ) );
|
||||||
image_put ( file->image );
|
ref_put ( &file->refcnt );
|
||||||
free ( file );
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -229,30 +378,29 @@ static EFI_STATUS efi_file_varlen ( UINT64 *base, size_t base_len,
|
|||||||
/**
|
/**
|
||||||
* Return file information structure
|
* Return file information structure
|
||||||
*
|
*
|
||||||
* @v image Image, or NULL for the root directory
|
* @v file EFI file
|
||||||
* @v len Length of data buffer
|
* @v len Length of data buffer
|
||||||
* @v data Data buffer
|
* @v data Data buffer
|
||||||
* @ret efirc EFI status code
|
* @ret efirc EFI status code
|
||||||
*/
|
*/
|
||||||
static EFI_STATUS efi_file_info ( struct image *image, UINTN *len,
|
static EFI_STATUS efi_file_info ( struct efi_file *file, UINTN *len,
|
||||||
VOID *data ) {
|
VOID *data ) {
|
||||||
EFI_FILE_INFO info;
|
EFI_FILE_INFO info;
|
||||||
const char *name;
|
size_t file_len;
|
||||||
|
|
||||||
|
/* Get file length */
|
||||||
|
file_len = efi_file_len ( file );
|
||||||
|
|
||||||
/* Populate file information */
|
/* Populate file information */
|
||||||
memset ( &info, 0, sizeof ( info ) );
|
memset ( &info, 0, sizeof ( info ) );
|
||||||
if ( image ) {
|
info.FileSize = file_len;
|
||||||
info.FileSize = image->len;
|
info.PhysicalSize = file_len;
|
||||||
info.PhysicalSize = image->len;
|
info.Attribute = EFI_FILE_READ_ONLY;
|
||||||
info.Attribute = EFI_FILE_READ_ONLY;
|
if ( file == &efi_file_root )
|
||||||
name = image->name;
|
info.Attribute |= EFI_FILE_DIRECTORY;
|
||||||
} else {
|
|
||||||
info.Attribute = ( EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY );
|
|
||||||
name = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
return efi_file_varlen ( &info.Size, SIZE_OF_EFI_FILE_INFO, name,
|
return efi_file_varlen ( &info.Size, SIZE_OF_EFI_FILE_INFO,
|
||||||
len, data );
|
file->name, len, data );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -266,14 +414,16 @@ static EFI_STATUS efi_file_info ( struct image *image, UINTN *len,
|
|||||||
static EFI_STATUS efi_file_read_dir ( struct efi_file *file, UINTN *len,
|
static EFI_STATUS efi_file_read_dir ( struct efi_file *file, UINTN *len,
|
||||||
VOID *data ) {
|
VOID *data ) {
|
||||||
EFI_STATUS efirc;
|
EFI_STATUS efirc;
|
||||||
|
struct efi_file entry;
|
||||||
struct image *image;
|
struct image *image;
|
||||||
unsigned int index;
|
unsigned int index;
|
||||||
|
|
||||||
/* Construct directory entry at current position */
|
/* Construct directory entries for image-backed files */
|
||||||
index = file->pos;
|
index = file->pos;
|
||||||
for_each_image ( image ) {
|
for_each_image ( image ) {
|
||||||
if ( index-- == 0 ) {
|
if ( index-- == 0 ) {
|
||||||
efirc = efi_file_info ( image, len, data );
|
efi_file_image ( &entry, image );
|
||||||
|
efirc = efi_file_info ( &entry, len, data );
|
||||||
if ( efirc == 0 )
|
if ( efirc == 0 )
|
||||||
file->pos++;
|
file->pos++;
|
||||||
return efirc;
|
return efirc;
|
||||||
@@ -296,21 +446,25 @@ static EFI_STATUS efi_file_read_dir ( struct efi_file *file, UINTN *len,
|
|||||||
static EFI_STATUS EFIAPI efi_file_read ( EFI_FILE_PROTOCOL *this,
|
static EFI_STATUS EFIAPI efi_file_read ( EFI_FILE_PROTOCOL *this,
|
||||||
UINTN *len, VOID *data ) {
|
UINTN *len, VOID *data ) {
|
||||||
struct efi_file *file = container_of ( this, struct efi_file, file );
|
struct efi_file *file = container_of ( this, struct efi_file, file );
|
||||||
size_t remaining;
|
struct efi_file_reader reader;
|
||||||
|
size_t pos = file->pos;
|
||||||
|
|
||||||
/* If this is the root directory, then construct a directory entry */
|
/* If this is the root directory, then construct a directory entry */
|
||||||
if ( ! file->image )
|
if ( ! file->read )
|
||||||
return efi_file_read_dir ( file, len, data );
|
return efi_file_read_dir ( file, len, data );
|
||||||
|
|
||||||
|
/* Initialise reader */
|
||||||
|
reader.file = file;
|
||||||
|
reader.pos = 0;
|
||||||
|
reader.data = data;
|
||||||
|
reader.len = *len;
|
||||||
|
|
||||||
/* Read from the file */
|
/* Read from the file */
|
||||||
remaining = ( file->image->len - file->pos );
|
|
||||||
if ( *len > remaining )
|
|
||||||
*len = remaining;
|
|
||||||
DBGC ( file, "EFIFILE %s read [%#08zx,%#08zx)\n",
|
DBGC ( file, "EFIFILE %s read [%#08zx,%#08zx)\n",
|
||||||
efi_file_name ( file ), file->pos,
|
efi_file_name ( file ), pos, file->pos );
|
||||||
( ( size_t ) ( file->pos + *len ) ) );
|
*len = file->read ( &reader );
|
||||||
copy_from_user ( data, file->image->data, file->pos, *len );
|
assert ( ( pos + *len ) == file->pos );
|
||||||
file->pos += *len;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,24 +496,21 @@ static EFI_STATUS EFIAPI efi_file_write ( EFI_FILE_PROTOCOL *this,
|
|||||||
static EFI_STATUS EFIAPI efi_file_set_position ( EFI_FILE_PROTOCOL *this,
|
static EFI_STATUS EFIAPI efi_file_set_position ( EFI_FILE_PROTOCOL *this,
|
||||||
UINT64 position ) {
|
UINT64 position ) {
|
||||||
struct efi_file *file = container_of ( this, struct efi_file, file );
|
struct efi_file *file = container_of ( this, struct efi_file, file );
|
||||||
|
size_t len;
|
||||||
|
|
||||||
/* If this is the root directory, reset to the start */
|
/* Get file length */
|
||||||
if ( ! file->image ) {
|
len = efi_file_len ( file );
|
||||||
DBGC ( file, "EFIFILE root directory rewound\n" );
|
|
||||||
file->pos = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check for the magic end-of-file value */
|
/* Check for the magic end-of-file value */
|
||||||
if ( position == 0xffffffffffffffffULL )
|
if ( position == 0xffffffffffffffffULL )
|
||||||
position = file->image->len;
|
position = len;
|
||||||
|
|
||||||
/* Fail if we attempt to seek past the end of the file (since
|
/* Fail if we attempt to seek past the end of the file (since
|
||||||
* we do not support writes).
|
* we do not support writes).
|
||||||
*/
|
*/
|
||||||
if ( position > file->image->len ) {
|
if ( position > len ) {
|
||||||
DBGC ( file, "EFIFILE %s cannot seek to %#08llx of %#08zx\n",
|
DBGC ( file, "EFIFILE %s cannot seek to %#08llx of %#08zx\n",
|
||||||
efi_file_name ( file ), position, file->image->len );
|
efi_file_name ( file ), position, len );
|
||||||
return EFI_UNSUPPORTED;
|
return EFI_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,7 +559,7 @@ static EFI_STATUS EFIAPI efi_file_get_info ( EFI_FILE_PROTOCOL *this,
|
|||||||
/* Get file information */
|
/* Get file information */
|
||||||
DBGC ( file, "EFIFILE %s get file information\n",
|
DBGC ( file, "EFIFILE %s get file information\n",
|
||||||
efi_file_name ( file ) );
|
efi_file_name ( file ) );
|
||||||
return efi_file_info ( file->image, len, data );
|
return efi_file_info ( file, len, data );
|
||||||
|
|
||||||
} else if ( memcmp ( type, &efi_file_system_info_id,
|
} else if ( memcmp ( type, &efi_file_system_info_id,
|
||||||
sizeof ( *type ) ) == 0 ) {
|
sizeof ( *type ) ) == 0 ) {
|
||||||
@@ -468,6 +619,7 @@ static EFI_STATUS EFIAPI efi_file_flush ( EFI_FILE_PROTOCOL *this ) {
|
|||||||
|
|
||||||
/** Root directory */
|
/** Root directory */
|
||||||
static struct efi_file efi_file_root = {
|
static struct efi_file efi_file_root = {
|
||||||
|
.refcnt = REF_INIT ( ref_no_free ),
|
||||||
.file = {
|
.file = {
|
||||||
.Revision = EFI_FILE_PROTOCOL_REVISION,
|
.Revision = EFI_FILE_PROTOCOL_REVISION,
|
||||||
.Open = efi_file_open,
|
.Open = efi_file_open,
|
||||||
@@ -482,6 +634,7 @@ static struct efi_file efi_file_root = {
|
|||||||
.Flush = efi_file_flush,
|
.Flush = efi_file_flush,
|
||||||
},
|
},
|
||||||
.image = NULL,
|
.image = NULL,
|
||||||
|
.name = "",
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -496,8 +649,7 @@ efi_file_open_volume ( EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *filesystem __unused,
|
|||||||
EFI_FILE_PROTOCOL **file ) {
|
EFI_FILE_PROTOCOL **file ) {
|
||||||
|
|
||||||
DBGC ( &efi_file_root, "EFIFILE open volume\n" );
|
DBGC ( &efi_file_root, "EFIFILE open volume\n" );
|
||||||
*file = &efi_file_root.file;
|
return efi_file_open_fixed ( &efi_file_root, file );
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** EFI simple file system protocol */
|
/** EFI simple file system protocol */
|
||||||
|
|||||||
Reference in New Issue
Block a user