summaryrefslogtreecommitdiffstats
path: root/src/interface/efi/efi_local.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/interface/efi/efi_local.c')
-rw-r--r--src/interface/efi/efi_local.c88
1 files changed, 85 insertions, 3 deletions
diff --git a/src/interface/efi/efi_local.c b/src/interface/efi/efi_local.c
index ec6d93a1..b2881424 100644
--- a/src/interface/efi/efi_local.c
+++ b/src/interface/efi/efi_local.c
@@ -247,6 +247,62 @@ static int efi_local_open_root ( struct efi_local *local, EFI_HANDLE device,
}
/**
+ * Open root filesystem of specified volume by index
+ *
+ * @v local Local file
+ * @v index Volume index
+ * @ret rc Return status code
+ */
+static int efi_local_open_volume_index ( struct efi_local *local,
+ UINTN index ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_GUID *protocol = &efi_simple_file_system_protocol_guid;
+ EFI_FILE_PROTOCOL *root;
+ EFI_HANDLE *handles;
+ EFI_HANDLE device;
+ UINTN num_handles;
+ EFI_STATUS efirc;
+ int rc;
+
+ /* Locate all filesystem handles */
+ if ( ( efirc = bs->LocateHandleBuffer ( ByProtocol, protocol,
+ NULL, &num_handles,
+ &handles ) ) != 0 ) {
+ rc = -EEFI ( efirc );
+ DBGC ( local, "LOCAL %p could not enumerate handles: "
+ "%s\n", local, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Find matching handle */
+ if ( index >= num_handles ) {
+ rc = -ENOENT;
+ } else {
+ /* Get this device handle */
+ device = handles[index];
+
+ /* Open root directory */
+ if ( ( rc = efi_local_open_root ( local, device, &root ) ) == 0 && root ) {
+ local->root = root;
+ rc = 0;
+ } else {
+ rc = -EACCES;
+ }
+ }
+
+ /* Free handles, if applicable */
+ bs->FreePool ( handles );
+
+ /* Fail if we found no matching handle */
+ if ( ! local->root ) {
+ DBGC ( local, "LOCAL %p found no matching device with index %u\n",
+ local, (unsigned int)index );
+ }
+
+ return rc;
+}
+
+/**
* Open root filesystem of specified volume
*
* @v local Local file
@@ -581,19 +637,45 @@ static struct process_descriptor efi_local_process_desc =
*/
static int efi_local_open ( struct interface *xfer, struct uri *uri ) {
struct efi_local *local;
+ int vol;
+ int rc = 0;
/* Allocate and initialise structure */
local = zalloc ( sizeof ( *local ) );
if ( ! local )
return -ENOMEM;
ref_init ( &local->refcnt, efi_local_free );
- intf_init ( &local->xfer, &efi_local_xfer_desc, &local->refcnt );
- process_init_stopped ( &local->process, &efi_local_process_desc,
- &local->refcnt );
local->uri = uri_get ( uri );
local->volume = ( ( uri->host && uri->host[0] ) ? uri->host : NULL );
local->path = ( uri->opaque ? uri->opaque : uri->path );
+ if ( local->path && local->volume && strcmp ( local->volume, "*" ) == 0 ) {
+ /* Open on any volume */
+ vol = 0;
+ while ( ( rc = efi_local_open_volume_index ( local, vol++ ) ) != -ENOENT ) {
+ if ( rc != 0 )
+ continue;
+ /* Open specified path */
+ if ( ( rc = efi_local_open_path ( local ) ) != 0 ) {
+ local->root->Close ( local->root );
+ local->root = NULL;
+ continue;
+ }
+ /* Success */
+ break;
+ }
+ if ( rc != 0 ) {
+ DBGC ( local, "LOCAL %p could not find %s on any partition\n",
+ local, local->path );
+ ref_put ( &local->refcnt );
+ return -ENOENT;
+ }
+ }
+
+ intf_init ( &local->xfer, &efi_local_xfer_desc, &local->refcnt );
+ process_init_stopped ( &local->process, &efi_local_process_desc,
+ &local->refcnt );
+
/* Start download process */
process_add ( &local->process );